n-api: cache Symbol.hasInstance

This improves the performance of napi_instanceof() by retrieving
Symbol.hasInstance from the global object once and then storing a
persistent reference to it in the env.

PR-URL: https://github.com/nodejs/node/pull/12246
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
Gabriel Schulhof 2017-03-31 16:40:33 +03:00 committed by Michael Dawson
parent ca8ccb9176
commit 8fbace163a

View File

@ -23,12 +23,16 @@ void napi_clear_last_error(napi_env env);
class napi_env__ { class napi_env__ {
public: public:
explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate), last_error() {} explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate),
has_instance_available(true), last_error() {}
~napi_env__() { ~napi_env__() {
last_exception.Reset(); last_exception.Reset();
has_instance.Reset();
} }
v8::Isolate* isolate; v8::Isolate* isolate;
v8::Persistent<v8::Value> last_exception; v8::Persistent<v8::Value> last_exception;
v8::Persistent<v8::Value> has_instance;
bool has_instance_available;
napi_extended_error_info last_error; napi_extended_error_info last_error;
}; };
@ -2156,11 +2160,13 @@ napi_status napi_instanceof(napi_env env,
return napi_set_last_error(env, napi_function_expected); return napi_set_last_error(env, napi_function_expected);
} }
napi_value value, js_result; if (env->has_instance_available) {
napi_value value, js_result, has_instance = nullptr;
napi_status status; napi_status status;
napi_valuetype value_type; napi_valuetype value_type;
// Get "Symbol" from the global object // Get "Symbol" from the global object
if (env->has_instance.IsEmpty()) {
status = napi_get_global(env, &value); status = napi_get_global(env, &value);
if (status != napi_ok) return status; if (status != napi_ok) return status;
status = napi_get_named_property(env, value, "Symbol", &value); status = napi_get_named_property(env, value, "Symbol", &value);
@ -2175,9 +2181,22 @@ napi_status napi_instanceof(napi_env env,
status = napi_typeof(env, value, &value_type); status = napi_typeof(env, value, &value_type);
if (status != napi_ok) return status; if (status != napi_ok) return status;
// Retrieve the function at the Symbol(hasInstance) key of the constructor // Store Symbol.hasInstance in a global persistent reference
if (value_type == napi_symbol) { if (value_type == napi_symbol) {
status = napi_get_property(env, constructor, value, &value); env->has_instance.Reset(env->isolate,
v8impl::V8LocalValueFromJsValue(value));
if (status != napi_ok) return status;
has_instance = value;
}
}
} else {
has_instance = v8impl::JsValueFromV8LocalValue(
v8::Local<v8::Value>::New(env->isolate, env->has_instance));
if (status != napi_ok) return status;
}
if (has_instance) {
status = napi_get_property(env, constructor, has_instance, &value);
if (status != napi_ok) return status; if (status != napi_ok) return status;
status = napi_typeof(env, value, &value_type); status = napi_typeof(env, value, &value_type);
if (status != napi_ok) return status; if (status != napi_ok) return status;
@ -2191,6 +2210,8 @@ napi_status napi_instanceof(napi_env env,
return napi_get_value_bool(env, js_result, result); 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 // If running constructor[Symbol.hasInstance](object) did not work, we perform