-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
module: use compileFunction over Module.wrap #21573
Changes from 12 commits
113d0b7
7cf60fb
c352906
3146e19
15db986
ed4af45
8008e59
687d82c
9a152a3
cb604f2
9fbbd27
09cc845
35e209e
9284715
ba89f2d
b35b5ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -286,6 +286,14 @@ void ContextifyContext::WeakCallback( | |||||||||
delete context; | ||||||||||
} | ||||||||||
|
||||||||||
void ContextifyContext::WeakCallbackCompileFn( | ||||||||||
const WeakCallbackInfo<CompileFnEntry>& data) { | ||||||||||
CompileFnEntry* entry = data.GetParameter(); | ||||||||||
entry->env->id_to_function_map[entry->id].Reset(); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you clarify what you mean in the code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @guybedford The suggestion is to replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Btw, this does get interesting for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh thanks so much for explaining, that makes sense. I've switched to the Node persistent now, please review. Also if you have a code suggestion for the Reset emplace issue that would be welcome too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point is pretty much just that it We don’t keep track of all There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Btw, I think I could come up with an example patch for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was just looking at implementing the second option of maintaining a set of the CompileFnEntry items on the env record to dispose. If you think the BaseObject approach is preferable though that works too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can feel free to do that, sure. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I've implemented this in the latest commit. Review would be appreciated :) Also to note again - this entire architecture should be changed soon, in case that isn't completely obvious. |
||||||||||
entry->env->id_to_function_map.erase(entry->id); | ||||||||||
delete entry; | ||||||||||
} | ||||||||||
|
||||||||||
// static | ||||||||||
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox( | ||||||||||
Environment* env, | ||||||||||
|
@@ -1007,7 +1015,30 @@ void ContextifyContext::CompileFunction( | |||||||||
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); | ||||||||||
} | ||||||||||
|
||||||||||
ScriptOrigin origin(filename, line_offset, column_offset, True(isolate)); | ||||||||||
// Get the function id | ||||||||||
uint32_t id = env->get_next_function_id(); | ||||||||||
|
||||||||||
// Set host_defined_options | ||||||||||
Local<PrimitiveArray> host_defined_options = | ||||||||||
PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength); | ||||||||||
host_defined_options->Set( | ||||||||||
isolate, | ||||||||||
loader::HostDefinedOptions::kType, | ||||||||||
Number::New(isolate, loader::ScriptType::kFunction)); | ||||||||||
host_defined_options->Set( | ||||||||||
isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id)); | ||||||||||
|
||||||||||
guybedford marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
ScriptOrigin origin(filename, | ||||||||||
line_offset, // line offset | ||||||||||
column_offset, // column offset | ||||||||||
True(isolate), // is cross origin | ||||||||||
Local<Integer>(), // script id | ||||||||||
Local<Value>(), // source map URL | ||||||||||
False(isolate), // is opaque (?) | ||||||||||
False(isolate), // is WASM | ||||||||||
False(isolate), // is ES Module | ||||||||||
host_defined_options); | ||||||||||
|
||||||||||
ScriptCompiler::Source source(code, origin, cached_data); | ||||||||||
ScriptCompiler::CompileOptions options; | ||||||||||
if (source.GetCachedData() == nullptr) { | ||||||||||
|
@@ -1041,38 +1072,43 @@ void ContextifyContext::CompileFunction( | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm so sorry I sucked the fun out of this... :P There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So mean of you... |
||||||||||
MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext( | ||||||||||
parsing_context, &source, params.size(), params.data(), | ||||||||||
context_extensions.size(), context_extensions.data(), options); | ||||||||||
|
||||||||||
Local<Function> fun; | ||||||||||
if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) { | ||||||||||
if (maybe_fn.IsEmpty()) { | ||||||||||
DecorateErrorStack(env, try_catch); | ||||||||||
try_catch.ReThrow(); | ||||||||||
return; | ||||||||||
} | ||||||||||
Local<Function> fn = maybe_fn.ToLocalChecked(); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure you want to do this? What if this assumption is false and this statement fails? Even if it doesn't, what's wrong about the way I originally intended to do it? I'm sorry but I am more cautious since such assumptions have kicked me in the balls in the past while working with the V8 API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I'm aware any There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be fine to do this since there is an IsEmtpy guard above |
||||||||||
env->id_to_function_map[id].Reset(isolate, fn); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be better to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I must admit this is where I have a C++/v8 knowledge gap - if I try There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (for what its worth this pattern comes from module_wrap.cc) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the idea would be to do something like this:
Suggested change
|
||||||||||
CompileFnEntry* gc_entry = new CompileFnEntry(env, id); | ||||||||||
env->id_to_function_map[id].SetWeak(gc_entry, | ||||||||||
WeakCallbackCompileFn, | ||||||||||
v8::WeakCallbackType::kParameter); | ||||||||||
|
||||||||||
if (produce_cached_data) { | ||||||||||
const std::unique_ptr<ScriptCompiler::CachedData> cached_data( | ||||||||||
ScriptCompiler::CreateCodeCacheForFunction(fun)); | ||||||||||
ScriptCompiler::CreateCodeCacheForFunction(fn)); | ||||||||||
bool cached_data_produced = cached_data != nullptr; | ||||||||||
if (cached_data_produced) { | ||||||||||
MaybeLocal<Object> buf = Buffer::Copy( | ||||||||||
env, | ||||||||||
reinterpret_cast<const char*>(cached_data->data), | ||||||||||
cached_data->length); | ||||||||||
if (fun->Set( | ||||||||||
if (fn->Set( | ||||||||||
parsing_context, | ||||||||||
env->cached_data_string(), | ||||||||||
buf.ToLocalChecked()).IsNothing()) return; | ||||||||||
} | ||||||||||
if (fun->Set( | ||||||||||
if (fn->Set( | ||||||||||
parsing_context, | ||||||||||
env->cached_data_produced_string(), | ||||||||||
Boolean::New(isolate, cached_data_produced)).IsNothing()) return; | ||||||||||
} | ||||||||||
|
||||||||||
args.GetReturnValue().Set(fun); | ||||||||||
args.GetReturnValue().Set(fn); | ||||||||||
} | ||||||||||
|
||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,12 +55,19 @@ class ContextifyContext { | |
static ContextifyContext* Get(const v8::PropertyCallbackInfo<T>& args); | ||
|
||
private: | ||
struct CompileFnEntry { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sorry, but I don't understand what the need for this and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the only fix needed to your previous work is the change of making the Function reference So the WeakCallbackCompileFn is a GC callback that then cleans up the map entry, so that we do not have a Node.js core memory leak :) This was a compromise approach discussed exhaustively with @devsnek to get it to work but not memory leak. |
||
Environment* env; | ||
uint32_t id; | ||
CompileFnEntry(Environment* env, uint32_t id): env(env), id(id) {} | ||
}; | ||
static void MakeContext(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
static void IsContext(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
static void CompileFunction( | ||
const v8::FunctionCallbackInfo<v8::Value>& args); | ||
static void WeakCallback( | ||
const v8::WeakCallbackInfo<ContextifyContext>& data); | ||
static void WeakCallbackCompileFn( | ||
guybedford marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const v8::WeakCallbackInfo<CompileFnEntry>& data); | ||
static void PropertyGetterCallback( | ||
v8::Local<v8::Name> property, | ||
const v8::PropertyCallbackInfo<v8::Value>& args); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const assert = require('assert'); | ||
const m = require('module'); | ||
|
||
global.mwc = 0; | ||
m.wrapper[0] += 'global.mwc = (global.mwc || 0 ) + 1;'; | ||
|
||
require('./not-main-module.js'); | ||
assert.strictEqual(mwc, 1); | ||
delete global.mwc; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part would still be important in case
wrap
orwrapper
get monkey patched since the line would then not start at an offset of zero. It won't be a big issue though as the assertion will just fall back to the messagefalse != true
.