Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: js fast path for cached bindings #18365

Closed
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions lib/internal/bootstrap_node.js
Original file line number Diff line number Diff line change
@@ -21,9 +21,6 @@

setupProcessObject();

internalBinding = process._internalBinding;
delete process._internalBinding;

// do this good and early, since it handles errors.
setupProcessFatal();

@@ -246,6 +243,42 @@
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
}

{
const bindingObj = Object.create(null);

const getBinding = process.binding;
process.binding = function binding(module) {
module = String(module);
if (typeof bindingObj[module] === 'object')
return bindingObj[module];
bindingObj[module] = getBinding(module);
return bindingObj[module];
};

const getLinkedBinding = process._linkedBinding;
process._linkedBinding = function _linkedBinding(module) {
module = String(module);
if (typeof bindingObj[module] === 'object')
return bindingObj[module];
bindingObj[module] = getLinkedBinding(module);
return bindingObj[module];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor anti-pattern, looking up twice. Do this instead:

let mod = bindingObj[module];
if (typeof mod !== 'object')
  mod = bindingObj[module] = getBinding(module);
return mod;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, don't know what I was thinking :) Updated.

};
}

{
const bindingObj = Object.create(null);

const getInternalBinding = process._internalBinding;
delete process._internalBinding;

internalBinding = function internalBinding(module) {
if (typeof bindingObj[module] === 'object')
return bindingObj[module];
bindingObj[module] = getInternalBinding(module);
return bindingObj[module];
};
}

function setupProcessObject() {
process._setupProcessObject(pushValueToArray);

10 changes: 0 additions & 10 deletions src/env-inl.h
Original file line number Diff line number Diff line change
@@ -329,16 +329,6 @@ inline Environment::Environment(IsolateData* isolate_data,
v8::Context::Scope context_scope(context);
set_as_external(v8::External::New(isolate(), this));

v8::Local<v8::Primitive> null = v8::Null(isolate());
v8::Local<v8::Object> binding_cache_object = v8::Object::New(isolate());
CHECK(binding_cache_object->SetPrototype(context, null).FromJust());
set_binding_cache_object(binding_cache_object);

v8::Local<v8::Object> internal_binding_cache_object =
v8::Object::New(isolate());
CHECK(internal_binding_cache_object->SetPrototype(context, null).FromJust());
set_internal_binding_cache_object(internal_binding_cache_object);

set_module_load_list_array(v8::Array::New(isolate()));

AssignToContext(context, ContextInfo(""));
2 changes: 0 additions & 2 deletions src/env.h
Original file line number Diff line number Diff line change
@@ -277,8 +277,6 @@ class ModuleWrap;
V(async_hooks_after_function, v8::Function) \
V(async_hooks_promise_resolve_function, v8::Function) \
V(async_hooks_binding, v8::Object) \
V(binding_cache_object, v8::Object) \
V(internal_binding_cache_object, v8::Object) \
V(buffer_prototype_object, v8::Object) \
V(context, v8::Context) \
V(host_import_module_dynamically_callback, v8::Function) \
44 changes: 6 additions & 38 deletions src/node.cc
Original file line number Diff line number Diff line change
@@ -2526,22 +2526,6 @@ Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
}


static bool PullFromCache(Environment* env,
const FunctionCallbackInfo<Value>& args,
Local<String> module,
Local<Object> cache) {
Local<Context> context = env->context();
Local<Value> exports_v;
Local<Object> exports;
if (cache->Get(context, module).ToLocal(&exports_v) &&
exports_v->IsObject() &&
exports_v->ToObject(context).ToLocal(&exports)) {
args.GetReturnValue().Set(exports);
return true;
}
return false;
}

static Local<Object> InitModule(Environment* env,
node_module* mod,
Local<String> module) {
@@ -2569,13 +2553,9 @@ static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
static void Binding(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Local<String> module;
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
CHECK(args[0]->IsString());

Local<Object> cache = env->binding_cache_object();

if (PullFromCache(env, args, module, cache))
return;
Local<String> module = args[0].As<String>();

// Append a string to process.moduleLoadList
char buf[1024];
@@ -2601,21 +2581,16 @@ static void Binding(const FunctionCallbackInfo<Value>& args) {
} else {
return ThrowIfNoSuchModule(env, *module_v);
}
cache->Set(module, exports);

args.GetReturnValue().Set(exports);
}

static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Local<String> module;
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
CHECK(args[0]->IsString());

Local<Object> cache = env->internal_binding_cache_object();

if (PullFromCache(env, args, module, cache))
return;
Local<String> module = args[0].As<String>();

// Append a string to process.moduleLoadList
char buf[1024];
@@ -2629,22 +2604,16 @@ static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
node_module* mod = get_internal_module(*module_v);
if (mod == nullptr) return ThrowIfNoSuchModule(env, *module_v);
Local<Object> exports = InitModule(env, mod, module);
cache->Set(module, exports);

args.GetReturnValue().Set(exports);
}

static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());

Local<String> module_name;
if (!args[0]->ToString(env->context()).ToLocal(&module_name)) return;

Local<Object> cache = env->binding_cache_object();
Local<Value> exports_v = cache->Get(module_name);
CHECK(args[0]->IsString());

if (exports_v->IsObject())
return args.GetReturnValue().Set(exports_v.As<Object>());
Local<String> module_name = args[0].As<String>();

node::Utf8Value module_name_v(env->isolate(), module_name);
node_module* mod = get_linked_module(*module_name_v);
@@ -2675,7 +2644,6 @@ static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
}

auto effective_exports = module->Get(exports_prop);
cache->Set(module_name, effective_exports);

args.GetReturnValue().Set(effective_exports);
}