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());
}