| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ce748f6 commit 0ec1d18
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5984,6 +5984,10 @@ the runtime. | |||
| 5984 | 5984 | <!-- YAML | |
| 5985 | 5985 | added: v8.6.0 | |
| 5986 | 5986 | napiVersion: 1 | |
| 5987 | + changes: | ||
| 5988 | + - version: REPLACEME | ||
| 5989 | + pr-url: https://github.com/nodejs/node/pull/59828 | ||
| 5990 | + description: The `async_resource` object will now be held as a strong reference. | ||
| 5987 | 5991 | --> | |
| 5988 | 5992 | ||
| 5989 | 5993 | ```c | |
@@ -6003,23 +6007,19 @@ napi_status napi_async_init(napi_env env, | |||
| 6003 | 6007 | ||
| 6004 | 6008 | Returns `napi_ok` if the API succeeded. | |
| 6005 | 6009 | ||
| 6006 | - The `async_resource` object needs to be kept alive until | ||
| 6007 | - [`napi_async_destroy`][] to keep `async_hooks` related API acts correctly. In | ||
| 6008 | - order to retain ABI compatibility with previous versions, `napi_async_context`s | ||
| 6009 | - are not maintaining the strong reference to the `async_resource` objects to | ||
| 6010 | - avoid introducing causing memory leaks. However, if the `async_resource` is | ||
| 6011 | - garbage collected by JavaScript engine before the `napi_async_context` was | ||
| 6012 | - destroyed by `napi_async_destroy`, calling `napi_async_context` related APIs | ||
| 6013 | - like [`napi_open_callback_scope`][] and [`napi_make_callback`][] can cause | ||
| 6014 | - problems like loss of async context when using the `AsyncLocalStorage` API. | ||
| 6015 | - | ||
| 6016 | 6010 | In order to retain ABI compatibility with previous versions, passing `NULL` | |
| 6017 | 6011 | for `async_resource` does not result in an error. However, this is not | |
| 6018 | 6012 | recommended as this will result in undesirable behavior with `async_hooks` | |
| 6019 | 6013 | [`init` hooks][] and `async_hooks.executionAsyncResource()` as the resource is | |
| 6020 | 6014 | now required by the underlying `async_hooks` implementation in order to provide | |
| 6021 | 6015 | the linkage between async callbacks. | |
| 6022 | 6016 | ||
| 6017 | + Previous versions of this API were not maintaining a strong reference to | ||
| 6018 | + `async_resource` while the `napi_async_context` object existed and instead | ||
| 6019 | + expected the caller to hold a strong reference. This has been changed, as a | ||
| 6020 | + corresponding call to [`napi_async_destroy`][] for every call to | ||
| 6021 | + `napi_async_init()` is a requirement in any case to avoid memory leaks. | ||
| 6022 | + | ||
| 6023 | 6023 | ### `napi_async_destroy` | |
| 6024 | 6024 | ||
| 6025 | 6025 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -538,19 +538,13 @@ class AsyncContext { | |||
| 538 | 538 | public: | |
| 539 | 539 | AsyncContext(node_napi_env env, | |
| 540 | 540 | v8::Local<v8::Object> resource_object, | |
| 541 | - const v8::Local<v8::String> resource_name, | ||
| 542 | - bool externally_managed_resource) | ||
| 541 | + v8::Local<v8::String> resource_name) | ||
| 543 | 542 | : env_(env) { | |
| 544 | 543 | async_id_ = node_env()->new_async_id(); | |
| 545 | 544 | trigger_async_id_ = node_env()->get_default_trigger_async_id(); | |
| 546 | 545 | v8::Isolate* isolate = node_env()->isolate(); | |
| 547 | 546 | resource_.Reset(isolate, resource_object); | |
| 548 | 547 | context_frame_.Reset(isolate, node::async_context_frame::current(isolate)); | |
| 549 | - lost_reference_ = false; | ||
| 550 | - if (externally_managed_resource) { | ||
| 551 | - resource_.SetWeak( | ||
| 552 | - this, AsyncContext::WeakCallback, v8::WeakCallbackType::kParameter); | ||
| 553 | - } | ||
| 554 | 548 | ||
| 555 | 549 | node::AsyncWrap::EmitAsyncInit(node_env(), | |
| 556 | 550 | resource_object, | |
@@ -559,18 +553,13 @@ class AsyncContext { | |||
| 559 | 553 | trigger_async_id_); | |
| 560 | 554 | } | |
| 561 | 555 | ||
| 562 | - ~AsyncContext() { | ||
| 563 | - resource_.Reset(); | ||
| 564 | - lost_reference_ = true; | ||
| 565 | - node::AsyncWrap::EmitDestroy(node_env(), async_id_); | ||
| 566 | - } | ||
| 556 | + ~AsyncContext() { node::AsyncWrap::EmitDestroy(node_env(), async_id_); } | ||
| 567 | 557 | ||
| 568 | 558 | inline v8::MaybeLocal<v8::Value> MakeCallback( | |
| 569 | 559 | v8::Local<v8::Object> recv, | |
| 570 | 560 | const v8::Local<v8::Function> callback, | |
| 571 | 561 | int argc, | |
| 572 | 562 | v8::Local<v8::Value> argv[]) { | |
| 573 | - EnsureReference(); | ||
| 574 | 563 | return node::InternalMakeCallback( | |
| 575 | 564 | node_env(), | |
| 576 | 565 | resource(), | |
@@ -583,21 +572,11 @@ class AsyncContext { | |||
| 583 | 572 | } | |
| 584 | 573 | ||
| 585 | 574 | inline napi_callback_scope OpenCallbackScope() { | |
| 586 | - EnsureReference(); | ||
| 587 | 575 | auto scope = new HeapAllocatedCallbackScope(this); | |
| 588 | 576 | env_->open_callback_scopes++; | |
| 589 | 577 | return scope->to_opaque(); | |
| 590 | 578 | } | |
| 591 | 579 | ||
| 592 | - inline void EnsureReference() { | ||
| 593 | - if (lost_reference_) { | ||
| 594 | - const v8::HandleScope handle_scope(node_env()->isolate()); | ||
| 595 | - resource_.Reset(node_env()->isolate(), | ||
| 596 | - v8::Object::New(node_env()->isolate())); | ||
| 597 | - lost_reference_ = false; | ||
| 598 | - } | ||
| 599 | - } | ||
| 600 | - | ||
| 601 | 580 | inline node::Environment* node_env() { return env_->node_env(); } | |
| 602 | 581 | inline v8::Local<v8::Object> resource() { | |
| 603 | 582 | return resource_.Get(node_env()->isolate()); | |
@@ -609,15 +588,10 @@ class AsyncContext { | |||
| 609 | 588 | static inline void CloseCallbackScope(node_napi_env env, | |
| 610 | 589 | napi_callback_scope s) { | |
| 611 | 590 | delete HeapAllocatedCallbackScope::FromOpaque(s); | |
| 591 | + CHECK_GT(env->open_callback_scopes, 0); | ||
| 612 | 592 | env->open_callback_scopes--; | |
| 613 | 593 | } | |
| 614 | 594 | ||
| 615 | - static void WeakCallback(const v8::WeakCallbackInfo<AsyncContext>& data) { | ||
| 616 | - AsyncContext* async_context = data.GetParameter(); | ||
| 617 | - async_context->resource_.Reset(); | ||
| 618 | - async_context->lost_reference_ = true; | ||
| 619 | - } | ||
| 620 | - | ||
| 621 | 595 | private: | |
| 622 | 596 | class HeapAllocatedCallbackScope final { | |
| 623 | 597 | public: | |
@@ -629,23 +603,18 @@ class AsyncContext { | |||
| 629 | 603 | } | |
| 630 | 604 | ||
| 631 | 605 | explicit HeapAllocatedCallbackScope(AsyncContext* async_context) | |
| 632 | - : resource_storage_(async_context->node_env()->isolate(), | ||
| 633 | - async_context->resource_.Get( | ||
| 634 | - async_context->node_env()->isolate())), | ||
| 635 | - cs_(async_context->node_env(), | ||
| 636 | - &resource_storage_, | ||
| 606 | + : cs_(async_context->node_env(), | ||
| 607 | + &async_context->resource_, | ||
| 637 | 608 | async_context->async_context()) {} | |
| 638 | 609 | ||
| 639 | 610 | private: | |
| 640 | - v8::Global<v8::Object> resource_storage_; | ||
| 641 | 611 | node::CallbackScope cs_; | |
| 642 | 612 | }; | |
| 643 | 613 | ||
| 644 | 614 | node_napi_env env_; | |
| 645 | 615 | double async_id_; | |
| 646 | 616 | double trigger_async_id_; | |
| 647 | 617 | v8::Global<v8::Object> resource_; | |
| 648 | - bool lost_reference_; | ||
| 649 | 618 | v8::Global<v8::Value> context_frame_; | |
| 650 | 619 | }; | |
| 651 | 620 | ||
@@ -943,23 +912,17 @@ napi_status NAPI_CDECL napi_async_init(napi_env env, | |||
| 943 | 912 | v8::Local<v8::Context> context = env->context(); | |
| 944 | 913 | ||
| 945 | 914 | v8::Local<v8::Object> v8_resource; | |
| 946 | - bool externally_managed_resource; | ||
| 947 | 915 | if (async_resource != nullptr) { | |
| 948 | 916 | CHECK_TO_OBJECT(env, context, v8_resource, async_resource); | |
| 949 | - externally_managed_resource = true; | ||
| 950 | 917 | } else { | |
| 951 | 918 | v8_resource = v8::Object::New(isolate); | |
| 952 | - externally_managed_resource = false; | ||
| 953 | 919 | } | |
| 954 | 920 | ||
| 955 | 921 | v8::Local<v8::String> v8_resource_name; | |
| 956 | 922 | CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name); | |
| 957 | 923 | ||
| 958 | - v8impl::AsyncContext* async_context = | ||
| 959 | - new v8impl::AsyncContext(reinterpret_cast<node_napi_env>(env), | ||
| 960 | - v8_resource, | ||
| 961 | - v8_resource_name, | ||
| 962 | - externally_managed_resource); | ||
| 924 | + v8impl::AsyncContext* async_context = new v8impl::AsyncContext( | ||
| 925 | + reinterpret_cast<node_napi_env>(env), v8_resource, v8_resource_name); | ||
| 963 | 926 | ||
| 964 | 927 | *result = reinterpret_cast<napi_async_context>(async_context); | |
| 965 | 928 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -50,13 +50,10 @@ setImmediate(() => { | |||
| 50 | 50 | assert.strictEqual(hook_result.destroy_called, false); | |
| 51 | 51 | makeCallback(asyncResource, process, () => { | |
| 52 | 52 | const executionAsyncResource = async_hooks.executionAsyncResource(); | |
| 53 | - // Assuming the executionAsyncResource was created for the absence of the | ||
| 54 | - // initial `{ foo: 'bar' }`. | ||
| 55 | - // This is the worst path of `napi_async_context` related API of | ||
| 56 | - // recovering from the condition and not break the executionAsyncResource | ||
| 57 | - // shape, although the executionAsyncResource might not be correct. | ||
| 53 | + // Previous versions of Node-API would have gargbage-collected | ||
| 54 | + // the `asyncResource` object, now we can just assert that it is intact. | ||
| 58 | 55 | assert.strictEqual(typeof executionAsyncResource, 'object'); | |
| 59 | - assert.strictEqual(executionAsyncResource.foo, undefined); | ||
| 56 | + assert.strictEqual(executionAsyncResource.foo, 'bar'); | ||
| 60 | 57 | destroyAsyncResource(asyncResource); | |
| 61 | 58 | setImmediate(() => { | |
| 62 | 59 | assert.strictEqual(hook_result.destroy_called, true); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments