Browse Source

n-api: reimplement instanceof using V8 API

This uses the v8::Value::InstanceOf API exposed in V8 6.0 and should
be performance neutral, if not improve it. By using V8's API, there
is no longer the need to cache Symbol.hasInstance.

PR-URL: https://github.com/nodejs/node/pull/16143
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
v9.x-staging
Yang Guo 7 years ago
committed by Franziska Hinkelmann
parent
commit
c81fd7c5ea
  1. 101
      src/node_api.cc

101
src/node_api.cc

@ -29,21 +29,18 @@ napi_status napi_clear_last_error(napi_env env);
struct napi_env__ {
explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate),
has_instance_available(true), last_error() {}
last_error() {}
~napi_env__() {
last_exception.Reset();
has_instance.Reset();
wrap_template.Reset();
function_data_template.Reset();
accessor_data_template.Reset();
}
v8::Isolate* isolate;
v8::Persistent<v8::Value> last_exception;
v8::Persistent<v8::Value> has_instance;
v8::Persistent<v8::ObjectTemplate> wrap_template;
v8::Persistent<v8::ObjectTemplate> function_data_template;
v8::Persistent<v8::ObjectTemplate> accessor_data_template;
bool has_instance_available;
napi_extended_error_info last_error;
};
@ -2693,98 +2690,12 @@ napi_status napi_instanceof(napi_env env,
return napi_set_last_error(env, napi_function_expected);
}
if (env->has_instance_available) {
napi_value value, js_result = nullptr, has_instance = nullptr;
napi_status status = napi_generic_failure;
napi_valuetype value_type;
// Get "Symbol" from the global object
if (env->has_instance.IsEmpty()) {
status = napi_get_global(env, &value);
if (status != napi_ok) return status;
status = napi_get_named_property(env, value, "Symbol", &value);
if (status != napi_ok) return status;
status = napi_typeof(env, value, &value_type);
if (status != napi_ok) return status;
// Get "hasInstance" from Symbol
if (value_type == napi_function) {
status = napi_get_named_property(env, value, "hasInstance", &value);
if (status != napi_ok) return status;
status = napi_typeof(env, value, &value_type);
if (status != napi_ok) return status;
// Store Symbol.hasInstance in a global persistent reference
if (value_type == napi_symbol) {
env->has_instance.Reset(env->isolate,
v8impl::V8LocalValueFromJsValue(value));
has_instance = value;
}
}
} else {
has_instance = v8impl::JsValueFromV8LocalValue(
v8::Local<v8::Value>::New(env->isolate, env->has_instance));
}
if (has_instance) {
status = napi_get_property(env, constructor, has_instance, &value);
if (status != napi_ok) return status;
status = napi_typeof(env, value, &value_type);
if (status != napi_ok) return status;
// Call the function to determine whether the object is an instance of the
// constructor
if (value_type == napi_function) {
status = napi_call_function(env, constructor, value, 1, &object,
&js_result);
if (status != napi_ok) return status;
return napi_get_value_bool(env, js_result, result);
}
}
env->has_instance_available = false;
}
// If running constructor[Symbol.hasInstance](object) did not work, we perform
// a traditional instanceof (early Node.js 6.x).
v8::Local<v8::String> prototype_string;
CHECK_NEW_FROM_UTF8(env, prototype_string, "prototype");
auto maybe_prototype = ctor->Get(context, prototype_string);
CHECK_MAYBE_EMPTY(env, maybe_prototype, napi_generic_failure);
v8::Local<v8::Value> prototype_property = maybe_prototype.ToLocalChecked();
if (!prototype_property->IsObject()) {
napi_throw_type_error(
env,
"ERR_NAPI_CONS_PROTOTYPE_OBJECT",
"Constructor.prototype must be an object");
return napi_set_last_error(env, napi_object_expected);
}
auto maybe_ctor = prototype_property->ToObject(context);
CHECK_MAYBE_EMPTY(env, maybe_ctor, napi_generic_failure);
ctor = maybe_ctor.ToLocalChecked();
v8::Local<v8::Value> current_obj = v8impl::V8LocalValueFromJsValue(object);
if (!current_obj->StrictEquals(ctor)) {
for (v8::Local<v8::Value> original_obj = current_obj;
!(current_obj->IsNull() || current_obj->IsUndefined());) {
if (current_obj->StrictEquals(ctor)) {
*result = !(original_obj->IsNumber() ||
original_obj->IsBoolean() ||
original_obj->IsString());
break;
}
v8::Local<v8::Object> obj;
CHECK_TO_OBJECT(env, context, obj, v8impl::JsValueFromV8LocalValue(
current_obj));
current_obj = obj->GetPrototype();
}
}
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);
}

Loading…
Cancel
Save