| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -91,6 +91,8 @@ class ModuleWrap; | |||
| 91 | 91 | V(decorated_private_symbol, "node:decorated") \ | |
| 92 | 92 | V(npn_buffer_private_symbol, "node:npnBuffer") \ | |
| 93 | 93 | V(selected_npn_buffer_private_symbol, "node:selectedNpnBuffer") \ | |
| 94 | + V(napi_env, "node:napi:env") \ | ||
| 95 | + V(napi_wrapper, "node:napi:wrapper") \ | ||
| 94 | 96 | ||
| 95 | 97 | // Strings are per-isolate primitives but Environment proxies them | |
| 96 | 98 | // for the sake of convenience. Strings should be ASCII-only. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,6 +17,7 @@ | |||
| 17 | 17 | #include <vector> | |
| 18 | 18 | #include "node_api.h" | |
| 19 | 19 | #include "node_internals.h" | |
| 20 | + #include "env.h" | ||
| 20 | 21 | ||
| 21 | 22 | static | |
| 22 | 23 | napi_status napi_set_last_error(napi_env env, napi_status error_code, | |
@@ -46,6 +47,9 @@ struct napi_env__ { | |||
| 46 | 47 | uv_loop_t* loop = nullptr; | |
| 47 | 48 | }; | |
| 48 | 49 | ||
| 50 | + #define NAPI_PRIVATE_KEY(context, suffix) \ | ||
| 51 | + (node::Environment::GetCurrent((context))->napi_ ## suffix()) | ||
| 52 | + | ||
| 49 | 53 | #define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \ | |
| 50 | 54 | do { \ | |
| 51 | 55 | if ((env)->prefix ## _template.IsEmpty()) { \ | |
@@ -373,6 +377,10 @@ class Reference : private Finalizer { | |||
| 373 | 377 | } | |
| 374 | 378 | ||
| 375 | 379 | public: | |
| 380 | + void* Data() { | ||
| 381 | + return _finalize_data; | ||
| 382 | + } | ||
| 383 | + | ||
| 376 | 384 | static Reference* New(napi_env env, | |
| 377 | 385 | v8::Local<v8::Value> value, | |
| 378 | 386 | uint32_t initial_refcount, | |
@@ -732,45 +740,6 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env, | |||
| 732 | 740 | return cbdata; | |
| 733 | 741 | } | |
| 734 | 742 | ||
| 735 | - int kWrapperFields = 3; | ||
| 736 | - | ||
| 737 | - // Pointer used to identify items wrapped by N-API. Used by FindWrapper and | ||
| 738 | - // napi_wrap(). | ||
| 739 | - const char napi_wrap_name[] = "N-API Wrapper"; | ||
| 740 | - | ||
| 741 | - // Search the object's prototype chain for the wrapper object. Usually the | ||
| 742 | - // wrapper would be the first in the chain, but it is OK for other objects to | ||
| 743 | - // be inserted in the prototype chain. | ||
| 744 | - static | ||
| 745 | - bool FindWrapper(v8::Local<v8::Object> obj, | ||
| 746 | - v8::Local<v8::Object>* result = nullptr, | ||
| 747 | - v8::Local<v8::Object>* parent = nullptr) { | ||
| 748 | - v8::Local<v8::Object> wrapper = obj; | ||
| 749 | - | ||
| 750 | - do { | ||
| 751 | - v8::Local<v8::Value> proto = wrapper->GetPrototype(); | ||
| 752 | - if (proto.IsEmpty() || !proto->IsObject()) { | ||
| 753 | - return false; | ||
| 754 | - } | ||
| 755 | - if (parent != nullptr) { | ||
| 756 | - *parent = wrapper; | ||
| 757 | - } | ||
| 758 | - wrapper = proto.As<v8::Object>(); | ||
| 759 | - if (wrapper->InternalFieldCount() == kWrapperFields) { | ||
| 760 | - v8::Local<v8::Value> external = wrapper->GetInternalField(1); | ||
| 761 | - if (external->IsExternal() && | ||
| 762 | - external.As<v8::External>()->Value() == v8impl::napi_wrap_name) { | ||
| 763 | - break; | ||
| 764 | - } | ||
| 765 | - } | ||
| 766 | - } while (true); | ||
| 767 | - | ||
| 768 | - if (result != nullptr) { | ||
| 769 | - *result = wrapper; | ||
| 770 | - } | ||
| 771 | - return true; | ||
| 772 | - } | ||
| 773 | - | ||
| 774 | 743 | static void DeleteEnv(napi_env env, void* data, void* hint) { | |
| 775 | 744 | delete env; | |
| 776 | 745 | } | |
@@ -787,11 +756,8 @@ napi_env GetEnv(v8::Local<v8::Context> context) { | |||
| 787 | 756 | // because we need to stop hard if either of them is empty. | |
| 788 | 757 | // | |
| 789 | 758 | // Re https://github.com/nodejs/node/pull/14217#discussion_r128775149 | |
| 790 | - auto key = v8::Private::ForApi(isolate, | ||
| 791 | - v8::String::NewFromOneByte(isolate, | ||
| 792 | - reinterpret_cast<const uint8_t*>("N-API Environment"), | ||
| 793 | - v8::NewStringType::kInternalized).ToLocalChecked()); | ||
| 794 | - auto value = global->GetPrivate(context, key).ToLocalChecked(); | ||
| 759 | + auto value = global->GetPrivate(context, NAPI_PRIVATE_KEY(context, env)) | ||
| 760 | + .ToLocalChecked(); | ||
| 795 | 761 | ||
| 796 | 762 | if (value->IsExternal()) { | |
| 797 | 763 | result = static_cast<napi_env>(value.As<v8::External>()->Value()); | |
@@ -801,7 +767,8 @@ napi_env GetEnv(v8::Local<v8::Context> context) { | |||
| 801 | 767 | ||
| 802 | 768 | // We must also stop hard if the result of assigning the env to the global | |
| 803 | 769 | // is either nothing or false. | |
| 804 | - CHECK(global->SetPrivate(context, key, external).FromJust()); | ||
| 770 | + CHECK(global->SetPrivate(context, NAPI_PRIVATE_KEY(context, env), external) | ||
| 771 | + .FromJust()); | ||
| 805 | 772 | ||
| 806 | 773 | // Create a self-destructing reference to external that will get rid of the | |
| 807 | 774 | // napi_env when external goes out of scope. | |
@@ -811,28 +778,46 @@ napi_env GetEnv(v8::Local<v8::Context> context) { | |||
| 811 | 778 | return result; | |
| 812 | 779 | } | |
| 813 | 780 | ||
| 781 | + enum UnwrapAction { | ||
| 782 | + KeepWrap, | ||
| 783 | + RemoveWrap | ||
| 784 | + }; | ||
| 785 | + | ||
| 814 | 786 | static | |
| 815 | 787 | napi_status Unwrap(napi_env env, | |
| 816 | 788 | napi_value js_object, | |
| 817 | 789 | void** result, | |
| 818 | - v8::Local<v8::Object>* wrapper, | ||
| 819 | - v8::Local<v8::Object>* parent = nullptr) { | ||
| 790 | + UnwrapAction action) { | ||
| 791 | + NAPI_PREAMBLE(env); | ||
| 820 | 792 | CHECK_ARG(env, js_object); | |
| 821 | - CHECK_ARG(env, result); | ||
| 793 | + if (action == KeepWrap) { | ||
| 794 | + CHECK_ARG(env, result); | ||
| 795 | + } | ||
| 796 | + | ||
| 797 | + v8::Isolate* isolate = env->isolate; | ||
| 798 | + v8::Local<v8::Context> context = isolate->GetCurrentContext(); | ||
| 822 | 799 | ||
| 823 | 800 | v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object); | |
| 824 | 801 | RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); | |
| 825 | 802 | v8::Local<v8::Object> obj = value.As<v8::Object>(); | |
| 826 | 803 | ||
| 827 | - RETURN_STATUS_IF_FALSE( | ||
| 828 | - env, v8impl::FindWrapper(obj, wrapper, parent), napi_invalid_arg); | ||
| 804 | + auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper)) | ||
| 805 | + .ToLocalChecked(); | ||
| 806 | + RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg); | ||
| 807 | + Reference* reference = | ||
| 808 | + static_cast<v8impl::Reference*>(val.As<v8::External>()->Value()); | ||
| 829 | 809 | ||
| 830 | - v8::Local<v8::Value> unwrappedValue = (*wrapper)->GetInternalField(0); | ||
| 831 | - RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg); | ||
| 810 | + if (result) { | ||
| 811 | + *result = reference->Data(); | ||
| 812 | + } | ||
| 832 | 813 | ||
| 833 | - *result = unwrappedValue.As<v8::External>()->Value(); | ||
| 814 | + if (action == RemoveWrap) { | ||
| 815 | + CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper)) | ||
| 816 | + .FromJust()); | ||
| 817 | + Reference::Delete(reference); | ||
| 818 | + } | ||
| 834 | 819 | ||
| 835 | - return napi_ok; | ||
| 820 | + return GET_RETURN_STATUS(env); | ||
| 836 | 821 | } | |
| 837 | 822 | ||
| 838 | 823 | static | |
@@ -2391,26 +2376,9 @@ napi_status napi_wrap(napi_env env, | |||
| 2391 | 2376 | v8::Local<v8::Object> obj = value.As<v8::Object>(); | |
| 2392 | 2377 | ||
| 2393 | 2378 | // If we've already wrapped this object, we error out. | |
| 2394 | - RETURN_STATUS_IF_FALSE(env, !v8impl::FindWrapper(obj), napi_invalid_arg); | ||
| 2395 | - | ||
| 2396 | - // Create a wrapper object with an internal field to hold the wrapped pointer | ||
| 2397 | - // and a second internal field to identify the owner as N-API. | ||
| 2398 | - v8::Local<v8::ObjectTemplate> wrapper_template; | ||
| 2399 | - ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, v8impl::kWrapperFields); | ||
| 2400 | - | ||
| 2401 | - auto maybe_object = wrapper_template->NewInstance(context); | ||
| 2402 | - CHECK_MAYBE_EMPTY(env, maybe_object, napi_generic_failure); | ||
| 2403 | - v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked(); | ||
| 2404 | - | ||
| 2405 | - // Store the pointer as an external in the wrapper. | ||
| 2406 | - wrapper->SetInternalField(0, v8::External::New(isolate, native_object)); | ||
| 2407 | - wrapper->SetInternalField(1, v8::External::New(isolate, | ||
| 2408 | - reinterpret_cast<void*>(const_cast<char*>(v8impl::napi_wrap_name)))); | ||
| 2409 | - | ||
| 2410 | - // Insert the wrapper into the object's prototype chain. | ||
| 2411 | - v8::Local<v8::Value> proto = obj->GetPrototype(); | ||
| 2412 | - CHECK(wrapper->SetPrototype(context, proto).FromJust()); | ||
| 2413 | - CHECK(obj->SetPrototype(context, wrapper).FromJust()); | ||
| 2379 | + RETURN_STATUS_IF_FALSE(env, | ||
| 2380 | + !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper)).FromJust(), | ||
| 2381 | + napi_invalid_arg); | ||
| 2414 | 2382 | ||
| 2415 | 2383 | v8impl::Reference* reference = nullptr; | |
| 2416 | 2384 | if (result != nullptr) { | |
@@ -2422,52 +2390,24 @@ napi_status napi_wrap(napi_env env, | |||
| 2422 | 2390 | reference = v8impl::Reference::New( | |
| 2423 | 2391 | env, obj, 0, false, finalize_cb, native_object, finalize_hint); | |
| 2424 | 2392 | *result = reinterpret_cast<napi_ref>(reference); | |
| 2425 | - } else if (finalize_cb != nullptr) { | ||
| 2426 | - // Create a self-deleting reference just for the finalize callback. | ||
| 2427 | - reference = v8impl::Reference::New( | ||
| 2428 | - env, obj, 0, true, finalize_cb, native_object, finalize_hint); | ||
| 2393 | + } else { | ||
| 2394 | + // Create a self-deleting reference. | ||
| 2395 | + reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb, | ||
| 2396 | + native_object, finalize_cb == nullptr ? nullptr : finalize_hint); | ||
| 2429 | 2397 | } | |
| 2430 | 2398 | ||
| 2431 | - if (reference != nullptr) { | ||
| 2432 | - wrapper->SetInternalField(2, v8::External::New(isolate, reference)); | ||
| 2433 | - } | ||
| 2399 | + CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper), | ||
| 2400 | + v8::External::New(isolate, reference)).FromJust()); | ||
| 2434 | 2401 | ||
| 2435 | 2402 | return GET_RETURN_STATUS(env); | |
| 2436 | 2403 | } | |
| 2437 | 2404 | ||
| 2438 | 2405 | napi_status napi_unwrap(napi_env env, napi_value obj, void** result) { | |
| 2439 | - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw | ||
| 2440 | - // JS exceptions. | ||
| 2441 | - CHECK_ENV(env); | ||
| 2442 | - v8::Local<v8::Object> wrapper; | ||
| 2443 | - return napi_set_last_error(env, v8impl::Unwrap(env, obj, result, &wrapper)); | ||
| 2406 | + return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap); | ||
| 2444 | 2407 | } | |
| 2445 | 2408 | ||
| 2446 | 2409 | napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) { | |
| 2447 | - NAPI_PREAMBLE(env); | ||
| 2448 | - v8::Local<v8::Object> wrapper; | ||
| 2449 | - v8::Local<v8::Object> parent; | ||
| 2450 | - napi_status status = v8impl::Unwrap(env, obj, result, &wrapper, &parent); | ||
| 2451 | - if (status != napi_ok) { | ||
| 2452 | - return napi_set_last_error(env, status); | ||
| 2453 | - } | ||
| 2454 | - | ||
| 2455 | - v8::Local<v8::Value> external = wrapper->GetInternalField(2); | ||
| 2456 | - if (external->IsExternal()) { | ||
| 2457 | - v8impl::Reference::Delete( | ||
| 2458 | - static_cast<v8impl::Reference*>(external.As<v8::External>()->Value())); | ||
| 2459 | - } | ||
| 2460 | - | ||
| 2461 | - if (!parent.IsEmpty()) { | ||
| 2462 | - v8::Maybe<bool> maybe = parent->SetPrototype( | ||
| 2463 | - env->isolate->GetCurrentContext(), wrapper->GetPrototype()); | ||
| 2464 | - CHECK_MAYBE_NOTHING(env, maybe, napi_generic_failure); | ||
| 2465 | - if (!maybe.FromMaybe(false)) { | ||
| 2466 | - return napi_set_last_error(env, napi_generic_failure); | ||
| 2467 | - } | ||
| 2468 | - } | ||
| 2469 | - | ||
| 2470 | - return GET_RETURN_STATUS(env); | ||
| 2410 | + return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap); | ||
| 2471 | 2411 | } | |
| 2472 | 2412 | ||
| 2473 | 2413 | napi_status napi_create_external(napi_env env, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments