8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 5b0c57c commit 7973bd3Copy full SHA for 7973bd3
doc/api/n-api.md
@@ -2876,8 +2876,8 @@ napi_status napi_wrap(napi_env env,
2876
2877
Returns `napi_ok` if the API succeeded.
2878
2879
-Wraps a native instance in JavaScript object of the corresponding type.
2880
-The native instance can be retrieved later using `napi_unwrap()`.
+Wraps a native instance in a JavaScript object. The native instance can be
+retrieved later using `napi_unwrap()`.
2881
2882
When JavaScript code invokes a constructor for a class that was defined using
2883
`napi_define_class()`, the `napi_callback` for the constructor is invoked.
@@ -2905,6 +2905,10 @@ required in order to enable correct proper of the reference.
2905
Afterward, additional manipulation of the wrapper's prototype chain may cause
2906
`napi_unwrap()` to fail.
2907
2908
+*Note*: Calling `napi_wrap()` a second time on an object that already has a
2909
+native instance associated with it by virtue of a previous call to
2910
+`napi_wrap()` will cause an error to be returned.
2911
+
2912
### *napi_unwrap*
2913
<!-- YAML
2914
added: v8.0.0
src/node_api.cc
@@ -678,6 +678,38 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
678
return cbdata;
679
}
680
681
+// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
682
+// napi_wrap().
683
+const char napi_wrap_name[] = "N-API Wrapper";
684
685
+// Search the object's prototype chain for the wrapper object. Usually the
686
+// wrapper would be the first in the chain, but it is OK for other objects to
687
+// be inserted in the prototype chain.
688
+bool FindWrapper(v8::Local<v8::Object> obj,
689
+ v8::Local<v8::Object>* result = nullptr) {
690
+ v8::Local<v8::Object> wrapper = obj;
691
692
+ do {
693
+ v8::Local<v8::Value> proto = wrapper->GetPrototype();
694
+ if (proto.IsEmpty() || !proto->IsObject()) {
695
+ return false;
696
+ }
697
+ wrapper = proto.As<v8::Object>();
698
+ if (wrapper->InternalFieldCount() == 2) {
699
+ v8::Local<v8::Value> external = wrapper->GetInternalField(1);
700
+ if (external->IsExternal() &&
701
+ external.As<v8::External>()->Value() == v8impl::napi_wrap_name) {
702
+ break;
703
704
705
+ } while (true);
706
707
+ if (result != nullptr) {
708
+ *result = wrapper;
709
710
+ return true;
711
+}
712
713
} // end of namespace v8impl
714
715
// Intercepts the Node-V8 module registration callback. Converts parameters
@@ -2049,11 +2081,22 @@ napi_status napi_wrap(napi_env env,
2049
2081
RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
2050
2082
v8::Local<v8::Object> obj = value.As<v8::Object>();
2051
2083
2052
- // Create a wrapper object with an internal field to hold the wrapped pointer.
2084
+ // If we've already wrapped this object, we error out.
2085
+ RETURN_STATUS_IF_FALSE(env, !v8impl::FindWrapper(obj), napi_invalid_arg);
2086
2087
+ // Create a wrapper object with an internal field to hold the wrapped pointer
2088
+ // and a second internal field to identify the owner as N-API.
2053
2089
v8::Local<v8::ObjectTemplate> wrapper_template;
2054
- ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, 1);
2055
- v8::Local<v8::Object> wrapper =
2056
- wrapper_template->NewInstance(context).ToLocalChecked();
2090
+ ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, 2);
2091
2092
+ auto maybe_object = wrapper_template->NewInstance(context);
2093
+ CHECK_MAYBE_EMPTY(env, maybe_object, napi_generic_failure);
2094
2095
+ v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked();
2096
+ wrapper->SetInternalField(1, v8::External::New(isolate,
2097
+ reinterpret_cast<void*>(const_cast<char*>(v8impl::napi_wrap_name))));
2098
2099
+ // Store the pointer as an external in the wrapper.
2057
2100
wrapper->SetInternalField(0, v8::External::New(isolate, native_object));
2058
2101
2059
2102
// Insert the wrapper into the object's prototype chain.
@@ -2090,16 +2133,9 @@ napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) {
2133
2134
2135
- // Search the object's prototype chain for the wrapper with an internal field.
- // Usually the wrapper would be the first in the chain, but it is OK for
- // other objects to be inserted in the prototype chain.
- v8::Local<v8::Object> wrapper = obj;
- do {
- v8::Local<v8::Value> proto = wrapper->GetPrototype();
- RETURN_STATUS_IF_FALSE(
- env, !proto.IsEmpty() && proto->IsObject(), napi_invalid_arg);
- wrapper = proto.As<v8::Object>();
- } while (wrapper->InternalFieldCount() != 1);
2136
+ v8::Local<v8::Object> wrapper;
2137
+ RETURN_STATUS_IF_FALSE(
2138
+ env, v8impl::FindWrapper(obj, &wrapper), napi_invalid_arg);
2103
2139
2104
2140
v8::Local<v8::Value> unwrappedValue = wrapper->GetInternalField(0);
2105
2141
RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg);
test/addons-napi/test_general/test.js
@@ -50,3 +50,11 @@ assert.strictEqual(test_general.testGetVersion(), 1);
50
// since typeof in js return object need to validate specific case
51
// for null
52
assert.strictEqual(test_general.testNapiTypeof(null), 'null');
53
54
+const x = {};
55
56
+// Assert that wrapping twice fails.
57
+test_general.wrap(x, 25);
58
+assert.throws(function() {
59
+ test_general.wrap(x, 'Blah');
60
+}, Error);
test/addons-napi/test_general/test_general.c
@@ -119,6 +119,24 @@ napi_value testNapiTypeof(napi_env env, napi_callback_info info) {
119
return result;
120
121
122
+static void deref_item(napi_env env, void* data, void* hint) {
123
+ (void) hint;
124
125
+ NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, (napi_ref)data));
126
127
128
+napi_value wrap(napi_env env, napi_callback_info info) {
129
+ size_t argc = 2;
130
+ napi_value argv[2];
131
+ napi_ref payload;
132
133
+ NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
134
+ NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &payload));
135
+ NAPI_CALL(env, napi_wrap(env, argv[0], payload, deref_item, NULL, NULL));
136
137
+ return NULL;
138
139
140
void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
141
napi_property_descriptor descriptors[] = {
142
DECLARE_NAPI_PROPERTY("testStrictEquals", testStrictEquals),
@@ -130,6 +148,7 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
148
DECLARE_NAPI_PROPERTY("createNapiError", createNapiError),
149
DECLARE_NAPI_PROPERTY("testNapiErrorCleanup", testNapiErro 534A rCleanup),
150
DECLARE_NAPI_PROPERTY("testNapiTypeof", testNapiTypeof),
151
+ DECLARE_NAPI_PROPERTY("wrap", wrap),
152
};
153
154
NAPI_CALL_RETURN_VOID(env, napi_define_properties(