Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlegendecas <legendecas@gmail.com>2020-10-06 21:05:15 +0300
committerNode.js GitHub Bot <github-bot@iojs.org>2020-10-31 03:17:59 +0300
commit3a7537de7dd6c833cbe3f14b58e289c0a905afa5 (patch)
tree5f85a2026d2b199faf32337320359505285fab4e /src/node_api.cc
parent5da2512a72f56031a11c928792392110d4001b24 (diff)
n-api: napi_make_callback emit async init with resource of async_context
instead of emit async init with receiver of the callback. PR-URL: https://github.com/nodejs/node/pull/32930 Fixes: https://github.com/nodejs/node/issues/32898 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Diffstat (limited to 'src/node_api.cc')
-rw-r--r--src/node_api.cc187
1 files changed, 143 insertions, 44 deletions
diff --git a/src/node_api.cc b/src/node_api.cc
index 12f369a8097..4e932c19c2b 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -1,12 +1,15 @@
+#include "async_wrap-inl.h"
#include "env-inl.h"
#define NAPI_EXPERIMENTAL
#include "js_native_api_v8.h"
+#include "memory_tracker-inl.h"
#include "node_api.h"
#include "node_binding.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "node_internals.h"
#include "threadpoolwork-inl.h"
+#include "tracing/traced_value.h"
#include "util-inl.h"
#include <memory>
@@ -104,16 +107,6 @@ static inline napi_env NewEnv(v8::Local<v8::Context> context) {
return result;
}
-static inline napi_callback_scope
-JsCallbackScopeFromV8CallbackScope(node::CallbackScope* s) {
- return reinterpret_cast<napi_callback_scope>(s);
-}
-
-static inline node::CallbackScope*
-V8CallbackScopeFromJsCallbackScope(napi_callback_scope s) {
- return reinterpret_cast<node::CallbackScope*>(s);
-}
-
static inline void trigger_fatal_exception(
napi_env env, v8::Local<v8::Value> local_err) {
v8::Local<v8::Message> local_msg =
@@ -435,6 +428,111 @@ class ThreadSafeFunction : public node::AsyncResource {
bool handles_closing;
};
+/**
+ * Compared to node::AsyncResource, the resource object in AsyncContext is
+ * gc-able. AsyncContext holds a weak reference to the resource object.
+ * AsyncContext::MakeCallback doesn't implicitly set the receiver of the
+ * callback to the resource object.
+ */
+class AsyncContext {
+ public:
+ AsyncContext(node_napi_env env,
+ v8::Local<v8::Object> resource_object,
+ const v8::Local<v8::String> resource_name,
+ bool externally_managed_resource)
+ : env_(env) {
+ async_id_ = node_env()->new_async_id();
+ trigger_async_id_ = node_env()->get_default_trigger_async_id();
+ resource_.Reset(node_env()->isolate(), resource_object);
+ lost_reference_ = false;
+ if (externally_managed_resource) {
+ resource_.SetWeak(
+ this, AsyncContext::WeakCallback, v8::WeakCallbackType::kParameter);
+ }
+
+ node::AsyncWrap::EmitAsyncInit(node_env(),
+ resource_object,
+ resource_name,
+ async_id_,
+ trigger_async_id_);
+ }
+
+ ~AsyncContext() {
+ resource_.Reset();
+ lost_reference_ = true;
+ node::AsyncWrap::EmitDestroy(node_env(), async_id_);
+ }
+
+ inline v8::MaybeLocal<v8::Value> MakeCallback(
+ v8::Local<v8::Object> recv,
+ const v8::Local<v8::Function> callback,
+ int argc,
+ v8::Local<v8::Value> argv[]) {
+ EnsureReference();
+ return node::InternalMakeCallback(node_env(),
+ resource(),
+ recv,
+ callback,
+ argc,
+ argv,
+ {async_id_, trigger_async_id_});
+ }
+
+ inline napi_callback_scope OpenCallbackScope() {
+ EnsureReference();
+ napi_callback_scope it =
+ reinterpret_cast<napi_callback_scope>(new CallbackScope(this));
+ env_->open_callback_scopes++;
+ return it;
+ }
+
+ inline void EnsureReference() {
+ if (lost_reference_) {
+ const v8::HandleScope handle_scope(node_env()->isolate());
+ resource_.Reset(node_env()->isolate(),
+ v8::Object::New(node_env()->isolate()));
+ lost_reference_ = false;
+ }
+ }
+
+ inline node::Environment* node_env() { return env_->node_env(); }
+ inline v8::Local<v8::Object> resource() {
+ return resource_.Get(node_env()->isolate());
+ }
+ inline node::async_context async_context() {
+ return {async_id_, trigger_async_id_};
+ }
+
+ static inline void CloseCallbackScope(node_napi_env env,
+ napi_callback_scope s) {
+ CallbackScope* callback_scope = reinterpret_cast<CallbackScope*>(s);
+ delete callback_scope;
+ env->open_callback_scopes--;
+ }
+
+ static void WeakCallback(const v8::WeakCallbackInfo<AsyncContext>& data) {
+ AsyncContext* async_context = data.GetParameter();
+ async_context->resource_.Reset();
+ async_context->lost_reference_ = true;
+ }
+
+ private:
+ class CallbackScope : public node::CallbackScope {
+ public:
+ explicit CallbackScope(AsyncContext* async_context)
+ : node::CallbackScope(async_context->node_env()->isolate(),
+ async_context->resource_.Get(
+ async_context->node_env()->isolate()),
+ async_context->async_context()) {}
+ };
+
+ node_napi_env env_;
+ double async_id_;
+ double trigger_async_id_;
+ v8::Global<v8::Object> resource_;
+ bool lost_reference_;
+};
+
} // end of anonymous namespace
} // end of namespace v8impl
@@ -627,7 +725,7 @@ NAPI_NO_RETURN void napi_fatal_error(const char* location,
}
napi_status napi_open_callback_scope(napi_env env,
- napi_value resource_object,
+ napi_value /** ignored */,
napi_async_context async_context_handle,
napi_callback_scope* result) {
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
@@ -635,20 +733,11 @@ napi_status napi_open_callback_scope(napi_env env,
CHECK_ENV(env);
CHECK_ARG(env, result);
- v8::Local<v8::Context> context = env->context();
-
- node::async_context* node_async_context =
- reinterpret_cast<node::async_context*>(async_context_handle);
-
- v8::Local<v8::Object> resource;
- CHECK_TO_OBJECT(env, context, resource, resource_object);
+ v8impl::AsyncContext* node_async_context =
+ reinterpret_cast<v8impl::AsyncContext*>(async_context_handle);
- *result = v8impl::JsCallbackScopeFromV8CallbackScope(
- new node::CallbackScope(env->isolate,
- resource,
- *node_async_context));
+ *result = node_async_context->OpenCallbackScope();
- env->open_callback_scopes++;
return napi_clear_last_error(env);
}
@@ -661,8 +750,9 @@ napi_status napi_close_callback_scope(napi_env env, napi_callback_scope scope) {
return napi_callback_scope_mismatch;
}
- env->open_callback_scopes--;
- delete v8impl::V8CallbackScopeFromJsCallbackScope(scope);
+ v8impl::AsyncContext::CloseCallbackScope(reinterpret_cast<node_napi_env>(env),
+ scope);
+
return napi_clear_last_error(env);
}
@@ -678,20 +768,24 @@ napi_status napi_async_init(napi_env env,
v8::Local<v8::Context> context = env->context();
v8::Local<v8::Object> v8_resource;
+ bool externally_managed_resource;
if (async_resource != nullptr) {
CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
+ externally_managed_resource = true;
} else {
v8_resource = v8::Object::New(isolate);
+ externally_managed_resource = false;
}
v8::Local<v8::String> v8_resource_name;
CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
- // TODO(jasongin): Consider avoiding allocation here by using
- // a tagged pointer with 2×31 bit fields instead.
- node::async_context* async_context = new node::async_context();
+ auto async_context =
+ new v8impl::AsyncContext(reinterpret_cast<node_napi_env>(env),
+ v8_resource,
+ v8_resource_name,
+ externally_managed_resource);
- *async_context = node::EmitAsyncInit(isolate, v8_resource, v8_resource_name);
*result = reinterpret_cast<napi_async_context>(async_context);
return napi_clear_last_error(env);
@@ -702,11 +796,8 @@ napi_status napi_async_destroy(napi_env env,
CHECK_ENV(env);
CHECK_ARG(env, async_context);
- node::async_context* node_async_context =
- reinterpret_cast<node::async_context*>(async_context);
- node::EmitAsyncDestroy(
- reinterpret_cast<node_napi_env>(env)->node_env(),
- *node_async_context);
+ v8impl::AsyncContext* node_async_context =
+ reinterpret_cast<v8impl::AsyncContext*>(async_context);
delete node_async_context;
@@ -734,17 +825,25 @@ napi_status napi_make_callback(napi_env env,
v8::Local<v8::Function> v8func;
CHECK_TO_FUNCTION(env, v8func, func);
- node::async_context* node_async_context =
- reinterpret_cast<node::async_context*>(async_context);
- if (node_async_context == nullptr) {
- static node::async_context empty_context = { 0, 0 };
- node_async_context = &empty_context;
- }
+ v8::MaybeLocal<v8::Value> callback_result;
- v8::MaybeLocal<v8::Value> callback_result = node::MakeCallback(
- env->isolate, v8recv, v8func, argc,
- reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
- *node_async_context);
+ if (async_context == nullptr) {
+ callback_result = node::MakeCallback(
+ env->isolate,
+ v8recv,
+ v8func,
+ argc,
+ reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
+ {0, 0});
+ } else {
+ auto node_async_context =
+ reinterpret_cast<v8impl::AsyncContext*>(async_context);
+ callback_result = node_async_context->MakeCallback(
+ v8recv,
+ v8func,
+ argc,
+ reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
+ }
if (try_catch.HasCaught()) {
return napi_set_last_error(env, napi_pending_exception);