diff --git a/README.md b/README.md index 31f6e382..7ddb11d1 100644 --- a/README.md +++ b/README.md @@ -303,6 +303,7 @@ The hooks to access V8 internals—including GC and statistics—are different a - Nan::GetInternalFieldPointer() - Nan::SetInternalFieldPointer() - Nan::AdjustExternalMemory() + - Nan::GetExternalValue() ### Miscellaneous V8 Helpers diff --git a/doc/v8_internals.md b/doc/v8_internals.md index 2e7c918b..1c36469d 100644 --- a/doc/v8_internals.md +++ b/doc/v8_internals.md @@ -17,6 +17,7 @@ The hooks to access V8 internals—including GC and statistics—are different a - Nan::GetInternalFieldPointer() - Nan::SetInternalFieldPointer() - Nan::AdjustExternalMemory() + - Nan::GetExternalValue() @@ -197,3 +198,14 @@ int Nan::AdjustExternalMemory(int bytesChange) Calls V8's [`AdjustAmountOfExternalAllocatedMemory()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#ae1a59cac60409d3922582c4af675473e). + +### Nan::GetExternalValue() + +Reads the pointer stored in a `v8::External`. On V8 versions that require an `ExternalPointerTypeTag` on `v8::External::Value()`, the default tag is applied (matching the tag used when the External is created via `Nan::New()`). + +Signature: + +```c++ +void* Nan::GetExternalValue(v8::Local ext) +``` + diff --git a/nan_callbacks_12_inl.h b/nan_callbacks_12_inl.h index ff3b654d..bc18c837 100644 --- a/nan_callbacks_12_inl.h +++ b/nan_callbacks_12_inl.h @@ -178,14 +178,27 @@ class PropertyCallbackInfo { NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfo) }; +// Gated on V8_EXTERNAL_POINTER_TAG_COUNT (defined alongside the tagged +// Value() API) rather than a V8_MAJOR_VERSION cutoff, since Node and +// Chromium/Electron ship divergent V8 snapshots under the same major. +// Tag must match the one used by imp::NewExternal. +inline void* GetExternalValue(v8::Local ext) { +#ifdef V8_EXTERNAL_POINTER_TAG_COUNT + return ext->Value(v8::kExternalPointerTypeTagDefault); +#else + return ext->Value(); +#endif +} + namespace imp { + static void FunctionCallbackWrapper(const v8::FunctionCallbackInfo &info) { v8::Local obj = info.Data().As(); FunctionCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kFunctionIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kFunctionIndex) + .As().As()))); FunctionCallbackInfo cbinfo(info, obj->GetInternalField(kDataIndex).As()); callback(cbinfo); @@ -203,8 +216,8 @@ void GetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); GetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kGetterIndex) + .As().As()))); callback(property.As(), cbinfo); } @@ -221,8 +234,8 @@ void SetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); SetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kSetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kSetterIndex) + .As().As()))); callback(property.As(), value, cbinfo); } @@ -240,8 +253,8 @@ void GetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); GetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kGetterIndex) + .As().As()))); callback(property, cbinfo); } @@ -258,8 +271,8 @@ void SetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); SetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kSetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kSetterIndex) + .As().As()))); callback(property, value, cbinfo); } @@ -282,8 +295,8 @@ v8::Intercepted PropertyGetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyGetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyGetterIndex) + .As().As()))); return callback(property.As(), cbinfo); } @@ -300,8 +313,8 @@ v8::Intercepted PropertySetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertySetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertySetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertySetterIndex) + .As().As()))); return callback(property.As(), value, cbinfo); } @@ -320,8 +333,8 @@ void PropertyGetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyGetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyGetterIndex) + .As().As()))); callback(property.As(), cbinfo); } @@ -338,8 +351,8 @@ void PropertySetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertySetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertySetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertySetterIndex) + .As().As()))); callback(property.As(), value, cbinfo); } @@ -357,8 +370,8 @@ void PropertyEnumeratorCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyEnumeratorCallback callback = reinterpret_cast(reinterpret_cast( - obj->GetInternalField(kPropertyEnumeratorIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyEnumeratorIndex) + .As().As()))); callback(cbinfo); } @@ -376,8 +389,8 @@ v8::Intercepted PropertyDeleterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyDeleterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyDeleterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyDeleterIndex) + .As().As()))); return callback(property.As(), cbinfo); } @@ -394,8 +407,8 @@ v8::Intercepted PropertyQueryCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyQueryCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyQueryIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyQueryIndex) + .As().As()))); return callback(property.As(), cbinfo); } @@ -411,8 +424,8 @@ void PropertyDeleterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyDeleterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyDeleterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyDeleterIndex) + .As().As()))); callback(property.As(), cbinfo); } @@ -428,8 +441,8 @@ void PropertyQueryCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyQueryCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyQueryIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyQueryIndex) + .As().As()))); callback(property.As(), cbinfo); } @@ -446,8 +459,8 @@ void PropertyGetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyGetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyGetterIndex) + .As().As()))); callback(property, cbinfo); } @@ -464,8 +477,8 @@ void PropertySetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertySetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertySetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertySetterIndex) + .As().As()))); callback(property, value, cbinfo); } @@ -482,8 +495,8 @@ void PropertyEnumeratorCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyEnumeratorCallback callback = reinterpret_cast(reinterpret_cast( - obj->GetInternalField(kPropertyEnumeratorIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyEnumeratorIndex) + .As().As()))); callback(cbinfo); } @@ -499,8 +512,8 @@ void PropertyDeleterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyDeleterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyDeleterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyDeleterIndex) + .As().As()))); callback(property, cbinfo); } @@ -516,8 +529,8 @@ void PropertyQueryCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); PropertyQueryCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kPropertyQueryIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kPropertyQueryIndex) + .As().As()))); callback(property, cbinfo); } @@ -535,8 +548,8 @@ v8::Intercepted IndexGetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexGetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertyGetterIndex) + .As().As()))); return callback(index, cbinfo); } @@ -553,8 +566,8 @@ v8::Intercepted IndexSetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexSetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertySetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertySetterIndex) + .As().As()))); return callback(index, value, cbinfo); } @@ -572,8 +585,8 @@ void IndexGetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexGetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyGetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertyGetterIndex) + .As().As()))); callback(index, cbinfo); } @@ -589,8 +602,8 @@ void IndexSetterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexSetterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertySetterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertySetterIndex) + .As().As()))); callback(index, value, cbinfo); } @@ -609,9 +622,9 @@ void IndexEnumeratorCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexEnumeratorCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField( + Nan::GetExternalValue(obj->GetInternalField( kIndexPropertyEnumeratorIndex) - .As().As()->Value())); + .As().As()))); callback(cbinfo); } @@ -628,8 +641,9 @@ v8::Intercepted IndexDeleterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexDeleterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyDeleterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField( + kIndexPropertyDeleterIndex) + .As().As()))); return callback(index, cbinfo); } @@ -644,8 +658,8 @@ v8::Intercepted IndexQueryCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexQueryCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyQueryIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertyQueryIndex) + .As().As()))); return callback(index, cbinfo); } @@ -660,8 +674,9 @@ void IndexDeleterCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexDeleterCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyDeleterIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField( + kIndexPropertyDeleterIndex) + .As().As()))); callback(index, cbinfo); } @@ -676,8 +691,8 @@ void IndexQueryCallbackWrapper( cbinfo(info, obj->GetInternalField(kDataIndex).As()); IndexQueryCallback callback = reinterpret_cast( reinterpret_cast( - obj->GetInternalField(kIndexPropertyQueryIndex) - .As().As()->Value())); + Nan::GetExternalValue(obj->GetInternalField(kIndexPropertyQueryIndex) + .As().As()))); callback(index, cbinfo); } diff --git a/nan_callbacks_pre_12_inl.h b/nan_callbacks_pre_12_inl.h index 74861e20..9195e3fc 100644 --- a/nan_callbacks_pre_12_inl.h +++ b/nan_callbacks_pre_12_inl.h @@ -287,6 +287,10 @@ class PropertyCallbackInfo : } }; +inline void* GetExternalValue(v8::Local ext) { + return ext->Value(); +} + namespace imp { template class ReturnValueImp : public ReturnValue { diff --git a/nan_implementation_12_inl.h b/nan_implementation_12_inl.h index 255293ac..79731c76 100644 --- a/nan_implementation_12_inl.h +++ b/nan_implementation_12_inl.h @@ -14,6 +14,22 @@ namespace imp { +// Recent V8 versions (currently Chromium/Electron's V8 snapshot; not yet in +// any released Node) gained an ExternalPointerTypeTag parameter on +// v8::External::New(). Detect that API via the V8_EXTERNAL_POINTER_TAG_COUNT +// macro (defined in alongside the new signature) rather than +// a V8_MAJOR_VERSION cutoff, since Node and Chromium ship divergent V8 +// snapshots under the same major version. Externals created via this helper +// are read back through imp::GetExternalPointer in nan_callbacks_12_inl.h, +// which uses the matching kExternalPointerTypeTagDefault tag. +inline v8::Local NewExternal(v8::Isolate* isolate, void* value) { +#ifdef V8_EXTERNAL_POINTER_TAG_COUNT + return v8::External::New(isolate, value, v8::kExternalPointerTypeTagDefault); +#else + return v8::External::New(isolate, value); +#endif +} + //=== Array ==================================================================== Factory::return_t @@ -76,7 +92,7 @@ Factory::New(double value) { Factory::return_t Factory::New(void * value) { - return v8::External::New(v8::Isolate::GetCurrent(), value); + return imp::NewExternal(v8::Isolate::GetCurrent(), value); } //=== Function ================================================================= @@ -92,7 +108,7 @@ Factory::New( FunctionCallback callback obj->SetInternalField( imp::kFunctionIndex - , v8::External::New(isolate, reinterpret_cast(callback))); + , imp::NewExternal(isolate, reinterpret_cast(callback))); v8::Local val = v8::Local::New(isolate, data); @@ -128,7 +144,7 @@ Factory::New( FunctionCallback callback obj->SetInternalField( imp::kFunctionIndex - , v8::External::New(isolate, reinterpret_cast(callback))); + , imp::NewExternal(isolate, reinterpret_cast(callback))); v8::Local val = v8::Local::New(isolate, data); if (!val.IsEmpty()) { diff --git a/test/cpp/nannew.cpp b/test/cpp/nannew.cpp index e36ce4f8..8c6c6c10 100644 --- a/test/cpp/nannew.cpp +++ b/test/cpp/nannew.cpp @@ -136,7 +136,7 @@ NAN_METHOD(testExternal) { t.plan(2); - t.ok(_(New(&ttt)->Value() == &ttt)); + t.ok(_(GetExternalValue(New(&ttt)) == &ttt)); t.ok(_( assertType(New(&ttt)))); info.GetReturnValue().SetUndefined(); diff --git a/test/cpp/news.cpp b/test/cpp/news.cpp index 3597f0fc..eb2febcb 100644 --- a/test/cpp/news.cpp +++ b/test/cpp/news.cpp @@ -93,7 +93,7 @@ NAN_METHOD(NewBooleanObject) { NAN_METHOD(NewExternal) { v8::Local ext = New(&magic); - assert(*static_cast(ext->Value()) == 1337); + assert(*static_cast(GetExternalValue(ext)) == 1337); info.GetReturnValue().Set(New("passed").ToLocalChecked()); }