Repository navigation
Is it possible to determine the type of an NAPI::Object in a non-global context? #764
Description
Activity
Object.InstanceOf ends up calling
napi_instanceofwhich has the following implementationnapi_status napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool* result) { NAPI_PREAMBLE(env); CHECK_ARG(env, object); CHECK_ARG(env, result); *result = false; v8::Local<v8::Object> ctor; v8::Local<v8::Context> context = env->context(); CHECK_TO_OBJECT(env, context, ctor, constructor); if (!ctor->IsFunction()) { napi_throw_type_error(env, "ERR_NAPI_CONS_FUNCTION", "Constructor must be a function"); return napi_set_last_error(env, napi_function_expected); } napi_status status = napi_generic_failure; v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object); auto maybe_result = val->InstanceOf(context, ctor); CHECK_MAYBE_NOTHING(env, maybe_result, status); *result = maybe_result.FromJust(); return GET_RETURN_STATUS(env); }
I assume the problem is that mismatch between the context that was active when the env was created and the context active when the call is made.
@gabrielschulhof, @addaleax some methods call
v8::Local<v8::Context> context = env->isolate->GetCurrentContext();instead of v8::Localv8::Context context = env->context();` do you remember off hand why we would use one in some places and the other for other cases?I'm wondering if for napi_instanceof we should be using
env->isolate->GetCurrentContext();but then that lead to the question if why/when we would use env->context().I assume the problem is that mismatch between the context that was active when the env was created and the context active when the call is made.
Yes. The
instanceofoperator checks whether the.prototypeproperty of the right-hand side appears in the prototype chain of the left-hand side. Each vm Context comes with its own set of builtins, includingDateandDate.prototype. As a consequence, theDate.prototypefrom one Context does not show up in the prototype chain of aDateinstance from another context, andinstanceofreturns false. In particular, this is not specific to N-API.do you remember off hand why we would use one in some places and the other for other cases?
I'm wondering if for napi_instanceof we should be using
env->isolate->GetCurrentContext();but then that lead to the question if why/when we would use env->context().Currently, this is irrelevant because Node.js is not actually supporting multi-Context addons. Once we do, using
env->isolate->GetCurrentContext()(or storing the context on theenvitself) would be the right thing in a lot of situations. However, that mismatch is not related to this issue, passing either context would result in the same return value.(For the most part, passing a context to V8 functions is relevant for cases in which a new Error object is being thrown – e.g. because the right-hand side isn’t a constructor.)
The author of the
node-sqlite3issue has identified theIsDatemethod as a way to address this issue. But is there another more general approach that would work to identify type of an NAPI::Object in a non-global context?napi_typeofand thenapi_is_...family are the only native brand checks that I know of. However, the relevant question is what you are actually wanting to find out about the object – if you wantnapi_get_date_value(), then yes,napi_is_date()will give you the right answer. But if you want to use some other API, e.g.date.getUTCDay(), then you’d best check for the presence of that method (since it can be overriden or removed, andnapi_is_datedoes not provide that information).Thanks for the clarification on contexts. Would you agree that the 2 places we
env->isolate->GetCurrentContext()should be updated to useenv->context()to be consistent with the rest of the places we use the context?Would you agree that the 2 places we
env->isolate->GetCurrentContext()should be updated to useenv->context()to be consistent with the rest of the places we use the context?I think that would be fine, yes.
In summary, it sounds like proper support for native add-ons to correctly support
vm.runInNewContext()needs to be built from the core on up.@jschlight I think this has been answered, is it ok to close ?
- added a commit that references this issue
on Nov 10, 2020 - added a commit that references this issue
on Nov 17, 2020 - added a commit that references this issue
on Nov 22, 2020 Yes @mhdawson Thanks for the ping.
This question is related to an interesting issue raised on the
node-sqlite3project:TryGhost/node-sqlite3#1355
The JavaScript code from the issue looks like:
The pertinent code using
node-addon-apilooks like:The code to determine if
sourceis aDateobject is failing apparently becausesourcehas been allocated outside the global context.The author of the
node-sqlite3issue has identified theIsDatemethod as a way to address this issue. But is there another more general approach that would work to identify type of an NAPI::Object in a non-global context?