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
Show file tree
Hide file tree
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
Expand Up @@ -21,9 +21,6 @@

setupProcessObject();

internalBinding = process._internalBinding;
delete process._internalBinding;

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

Expand Down Expand Up @@ -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
Member 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);

Expand Down
10 changes: 0 additions & 10 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(""));
Expand Down
2 changes: 0 additions & 2 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
44 changes: 6 additions & 38 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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];
Expand All @@ -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];
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down