Skip to content

Conversation

agracio
Copy link
Contributor

@agracio agracio commented Oct 17, 2025

Reason for this PR

Adding compatibility with v8 version 14.3

WriteUtf8V2() method

  • WriteUtf8V2() method was introduced in v8 13.4 and has a slightly different signature compared to WriteUtf8().
  • Deprecated WriteUtf8() method and associated enum were removed in v8 14.3.
enum WriteOptions {
    NO_OPTIONS = 0,
    HINT_MANY_WRITES_EXPECTED = 1,
    NO_NULL_TERMINATION = 2,
    PRESERVE_ONE_BYTE_NULL = 4,
    // Used by WriteUtf8 to replace orphan surrogate code units with the
    // unicode replacement character. Needs to be set to guarantee valid UTF-8
    // output.
    REPLACE_INVALID_UTF8 = 8
  };

V8_DEPRECATED("Use WriteUtf8V2 instead.")
int WriteUtf8(Isolate* isolate, char* buffer, int length = -1,
              int* nchars_ref = nullptr, int options = NO_OPTIONS) const;

struct WriteFlags {
    enum {
      kNone = 0,
      // Indicates that the output string should be null-terminated. In that
      // case, the output buffer must include sufficient space for the
      // additional null character.
      kNullTerminate = 1,
      // Used by WriteUtf8 to replace orphan surrogate code units with the
      // unicode replacement character. Needs to be set to guarantee valid UTF-8
      // output.
      kReplaceInvalidUtf8 = 2
    };
  };
size_t WriteUtf8V2(Isolate* isolate, char* buffer, size_t capacity,
                   int flags = WriteFlags::kNone,
                   size_t* processed_characters_return = nullptr) const;

SetPrototypeV2() method

  • SetPrototypeV2() method was introduced in v8 14.0 with same signature as SetPrototype().
  • Deprecated SetPrototype() method was removed in v8 14.3.
  V8_DEPRECATED(
      "V8 will stop providing access to hidden prototype (i.e. "
      "JSGlobalObject). Use SetPrototypeV2() instead. "
      "See http://crbug.com/333672197.")
  V8_WARN_UNUSED_RESULT Maybe<bool> SetPrototype(Local<Context> context,
                                                 Local<Value> prototype);

  V8_WARN_UNUSED_RESULT Maybe<bool> SetPrototypeV2(Local<Context> context,
                                                   Local<Value> prototype);

CI Changes

  • GitHub actions: added Node.js 25 and Windows arm64 runner.
  • AppVeyor: removed Node.js 16 - 24 from build since it is tested on GitHub.

CI Results

@agracio
Copy link
Contributor Author

agracio commented Oct 17, 2025

CI on Node.js 17.x was not failing in my branch: https://github.com/agracio/nan/actions/runs/18606064924.
It is most likely an issue with GitHub runner and should clear on re-run.

@agracio agracio changed the title Adding WriteUtf8V2() and SetPrototypeV2() methods Adding WriteUtf8V2() and SetPrototypeV2() methods to support v8 14.3 Oct 18, 2025
@kkoopa
Copy link
Collaborator

kkoopa commented Oct 20, 2025

Thank you. This looks fine to me, still need to look at the the WriteUtf8 bit in some more detail, since it is fairly complicated, but presumably all should be good.

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

Found another issue with v8 14.3, this one is trickier to address.

v8 12.8 - 14.2

enum V8_DEPRECATE_SOON(
    "This enum is no longer used and will be removed in V8 12.9.")
    AccessControl {
      DEFAULT V8_ENUM_DEPRECATE_SOON("not used") = 0,
    };

v8 14.3

enum V8_DEPRECATED(
    "This enum is no longer used and will be removed in V8 14.3.")
    AccessControl {
      DEFAULT V8_ENUM_DEPRECATED("not used") = 0,
    };

I am not sure how it manages to have a deprecation notice in v8 14.3 while being marked for deprecation in the same version. However don't think it is worth taking any chances.

Context: initially I had another issue masking this warning and only saw it yesterday, v8 14.3 modules currently compile but with a warning.

This enum is used in nan.h SetAccessor() method making it much harder to remove.
Give me a day or so to figure it out or we can have it in separate PR, up to you.

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

@kkoopa apologies for direct ping, but could you confirm that nan is currently targeting Node.js version 8 and above and no longer officially support earlier versions in latest release? There are some inconsistences in SetAccessor() methods and one of them (only one for some reason) has a Node.js version dependency >=6 that I believe is no longer needed.

Unfortunately I do not think it would be possible to address AccessControl enum deprecation issue without having multiple SetAccessor() methods depending on v8 version.

Example of code inconsistency SetNativeDataProperty() is invoked for v8 >=12.5, but settings property is passed for v8 >11.

// ... SetAccessor() code
#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 \
            || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \
            && V8_MINOR_VERSION >= 5))
  tpl->SetNativeDataProperty(
#else
  tpl->SetAccessor(
#endif
      name
    , getter_
    , setter_
    , obj
#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 12
    , settings
#endif
    , attribute
  );

@kkoopa
Copy link
Collaborator

kkoopa commented Oct 22, 2025 via email

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

I would not say removing older versions is strictly necessary just makes the code considerably more convoluted. One of the changes I already pushed in this PR did make an assumption that 0.x versions are no longer supported.

@kkoopa
Copy link
Collaborator

kkoopa commented Oct 22, 2025 via email

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

For this code it is part of PR #977.

// void SetAccessor()

#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 \
            || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \
            && V8_MINOR_VERSION >= 5))
  tpl->SetNativeDataProperty(
#else
  tpl->SetAccessor(
#endif
      name
    , getter_
    , setter_
    , obj
#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 12
    , settings
#endif
    , attribute
  );

However as part of the same PR the 3rd bool SetAccessor() has a different logic that appears to be more consistent.

// bool SetAccessor()

#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
#if defined(V8_MAJOR_VERSION) &&                                               \
    (V8_MAJOR_VERSION > 12 ||                                                  \
     (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) &&                   \
      V8_MINOR_VERSION >= 5))
  return obj->SetNativeDataProperty(
      GetCurrentContext()
    , name
    , getter_
    , setter_
    , dataobj
    , attribute).FromMaybe(false);
#else
  return obj->SetAccessor(
      GetCurrentContext()
    , name
    , getter_
    , setter_
    , dataobj
    , settings
    , attribute).FromMaybe(false);
#endif
#else
  return obj->SetAccessor(
      name
    , getter_
    , setter_
    , dataobj
    , settings
    , attribute);
#endif

For v8 14.3 and above SetAccessor() method signature will change because v8::AccessControl settings is deprecated and has to be removed, I am not sure how this is going to affect any modules that are rely on nan, will check my own modules.

Current signature of one of the methods:

inline void SetAccessor(
    v8::Local<v8::ObjectTemplate> tpl
  , v8::Local<v8::String> name
  , GetterCallback getter
  , SetterCallback setter = 0
  , v8::Local<v8::Value> data = v8::Local<v8::Value>()
  , v8::AccessControl settings = v8::DEFAULT // v8::AccessControl has to be removed
  , v8::PropertyAttribute attribute = v8::None)

@kkoopa
Copy link
Collaborator

kkoopa commented Oct 22, 2025 via email

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

So should I proceed with changes to SetAccessor() signature for v8 >=14.3?
I do not see any possibility to keep method signature backward compatible.

@kkoopa
Copy link
Collaborator

kkoopa commented Oct 22, 2025 via email

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

Sorry maybe I have not explained the change properly.

Current nan SetAccessor() method parameters include parameter v8::AccessControl settings = v8::DEFAULT. When this enum is removed from v8 the parameter can no longer be part of the method signature.
Removing this parameter will change the signature of this method unless I am missing something and there is some kind of way to preserve it.
My proposal would be to create new SetAccessor() methods with new signatures for v8 >= 14.3 while keeping the old methods for older versions of v8.

nan SetAccessor() current signature

inline void SetAccessor(
    v8::Local<v8::ObjectTemplate> tpl
  , v8::Local<v8::String> name
  , GetterCallback getter
  , SetterCallback setter = 0
  , v8::Local<v8::Value> data = v8::Local<v8::Value>()
  , v8::AccessControl settings = v8::DEFAULT // v8::AccessControl has to be removed
  , v8::PropertyAttribute attribute = v8::None)

@kkoopa
Copy link
Collaborator

kkoopa commented Oct 22, 2025 via email

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

Not sure that I am 100% following you but do you mean something along these lines?

#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 14 \
            || (V8_MAJOR_VERSION == 14 && defined(V8_MINOR_VERSION) \
            && V8_MINOR_VERSION >= 3))

// v8::AccessControl settings = v8::DEFAULT parameter is not defined in signature
inline void SetAccessor(
    v8::Local<v8::ObjectTemplate> tpl
  , v8::Local<v8::String> name
  , GetterCallback getter
  , SetterCallback setter = 0
  , v8::Local<v8::Value> data = v8::Local<v8::Value>()
  , v8::PropertyAttribute attribute = v8::None) {

	SetAccessor(
		tpl,
		name,
		getter,
		setter,
		data, 
		0, // v8::AccessControl settings = v8::DEFAULT - v8::DEFAULT equals 0 according to the docs, 
		attribute);
}

#else

inline void SetAccessor(
    v8::Local<v8::ObjectTemplate> tpl
  , v8::Local<v8::String> name
  , GetterCallback getter
  , SetterCallback setter = 0
  , v8::Local<v8::Value> data = v8::Local<v8::Value>()
  , v8::AccessControl settings = v8::DEFAULT
  , v8::PropertyAttribute attribute = v8::None) {

  // original code
}

#endif

@agracio
Copy link
Contributor Author

agracio commented Oct 22, 2025

Nvm this does not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants