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

lib: modify NativeModule to use compileFunction #23837

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
46 changes: 22 additions & 24 deletions lib/internal/bootstrap/loaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@

// Create this WeakMap in js-land because V8 has no C++ API for WeakMap
internalBinding('module_wrap').callbackMap = new WeakMap();
const { ContextifyScript } = internalBinding('contextify');
const { compileFunction } = internalBinding('contextify');

// Set up NativeModule
function NativeModule(id) {
Expand All @@ -120,7 +120,6 @@
this.exportKeys = undefined;
this.loaded = false;
this.loading = false;
this.script = null; // The ContextifyScript of the module
ryzokuken marked this conversation as resolved.
Show resolved Hide resolved
}

NativeModule._source = getInternalBinding('natives');
Expand Down Expand Up @@ -220,25 +219,23 @@
return NativeModule._source[id];
};

NativeModule.wrap = function(script) {
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
};

NativeModule.wrapper = [
'(function (exports, require, module, process, internalBinding) {',
'\n});'
];

const getOwn = (target, property, receiver) => {
return ReflectApply(ObjectHasOwnProperty, target, [property]) ?
ReflectGet(target, property, receiver) :
undefined;
};

NativeModule.parameters = Object.freeze([
'exports',
'require',
'module',
'process',
'internalBinding'
]);

NativeModule.prototype.compile = function() {
const id = this.id;
let source = NativeModule.getSource(id);
source = NativeModule.wrap(source);
const source = NativeModule.getSource(id);

this.loading = true;

Expand Down Expand Up @@ -270,29 +267,30 @@
const cache = codeCacheHash[id] &&
(codeCacheHash[id] === sourceHash[id]) ? codeCache[id] : undefined;

ryzokuken marked this conversation as resolved.
Show resolved Hide resolved
// (code, filename, lineOffset, columnOffset
// cachedData, produceCachedData, parsingContext)
const script = new ContextifyScript(
source, this.filename, 0, 0,
cache, false, undefined
// TODO(@joyee): figure out way to expose wrapped source for code cache
const fn = compileFunction(
source, // source code
this.filename, // filename
0, // line offset
0, // column offset
cache, // cached data
false, // produce cached data
undefined, // parsing context
undefined, // context extensions
NativeModule.parameters // arguments to the function
);

// This will be used to create code cache in tools/generate_code_cache.js
this.script = script;

// One of these conditions may be false when any of the inputs
// of the `node_js2c` target in node.gyp is modified.
// FIXME(joyeecheung): Figure out how to resolve the dependency issue.
// When the code cache was introduced we were at a point where refactoring
// node.gyp may not be worth the effort.
if (!cache || script.cachedDataRejected) {
ryzokuken marked this conversation as resolved.
Show resolved Hide resolved
if (!cache || fn.cachedDataRejected) {
compiledWithoutCache.push(this.id);
} else {
compiledWithCache.push(this.id);
}

// Arguments: timeout, displayErrors, breakOnSigint
const fn = script.runInThisContext(-1, true, false);
const requireFn = this.id.startsWith('internal/deps/') ?
NativeModule.requireForDeps :
NativeModule.require;
Expand Down
11 changes: 11 additions & 0 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1099,12 +1099,23 @@ void ContextifyContext::CompileFunction(
env->cached_data_string(),
buf.ToLocalChecked()).IsNothing()) return;
}

// Report if cache was produced.
Copy link
Member

Choose a reason for hiding this comment

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

I looked into the implementation a bit, and I wonder if we can just wrap ScriptCompiler::CreateCodeCacheForFunction in another binding that takes a function as argument? That way we can just manipulate the return values in the JS land, and also enable the code cache generator to use the exact function compiled to generate the cache if we simply return fn in NativeModule.prototype.compile - also, we don't actually need that argument handling complexity in the compileFunction C++ binding, vm.compileFunction can handle produce_cached_data in JS land and NativeModule.prototype.compile doesn't even need it at all.

Copy link
Member

Choose a reason for hiding this comment

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

Also I just noticed that the docs of vm.compileFunction did not mention its return value. Is that intentional?

Copy link
Member

Choose a reason for hiding this comment

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

(and the returned values are not tested either?)

if (fun->Set(
parsing_context,
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).IsNothing()) return;
}

// Report if cache was rejected.
if (options == ScriptCompiler::kConsumeCodeCache) {
if (fun->Set(parsing_context,
env->cached_data_rejected_string(),
Boolean::New(isolate, source.GetCachedData()->rejected))
.IsNothing())
return;
}
ryzokuken marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down