-
Notifications
You must be signed in to change notification settings - Fork 0
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
wip #1
wip #1
Conversation
lib/internal/modules/cjs/loader.js
Outdated
@@ -122,14 +122,9 @@ var modulePaths = []; | |||
Module.globalPaths = []; | |||
|
|||
Module.wrap = function(script) { | |||
return Module.wrapper[0] + script + Module.wrapper[1]; | |||
return vm.wrapFunction(script); |
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.
As discussed, let's rename this. Maybe to getWrappedFunction
.
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.
Also, the old way offered code caching. We should make this possible too. v8::ScriptCompiler::CompileFunctionInContext
actually provides code caching functionality.
src/node_contextify.cc
Outdated
}; | ||
|
||
TryCatch try_catch(env->isolate()); | ||
Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env); |
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.
I don't think you need this. TryCatch catches the exception.
src/node_contextify.cc
Outdated
|
||
Local<Function> fun = maybe_fun.ToLocalChecked(); | ||
CHECK(!fun.IsEmpty()); | ||
CHECK(!try_catch.HasCaught()); |
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 should be written as
Local<Function> fun;
if (maybe_fun.ToLocal(&fun)) {
// set return value to fun
} else {
// rethrow exception
}
src/node_contextify.cc
Outdated
CHECK(!fun.IsEmpty()); | ||
CHECK(!try_catch.HasCaught()); | ||
|
||
Local<String> result = fun->ToString(context).ToLocalChecked(); |
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 is precisely what we do not want to do. Do not turn the function into a string. We want the function itself.
test/parallel/test-vm-basic.js
Outdated
|
||
// vm.wrapFunction | ||
{ | ||
assert.strictEqual( |
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.
More tests for
- calling the function with arguments and check that the arguments can be used as expected, e.g. can be returned.
- another syntax error with random garbage as source
Would you expect the user to send Cache as a second argument to the function? |
lib/internal/modules/cjs/loader.js
Outdated
displayErrors: true | ||
}); | ||
const func = vm.getWrappedFunction(content, false); | ||
var compiledWrapped = func(); // FIXME(ryzokuken): This won't work. |
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.
I think you don’t want to call func
yet, but instead have compiledWrapper = vm.getWrappedFunction(…)
and leave the rest?
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.
originally, compilerWrapper
would return a v8::Value
that'd be returned as the result of your script, which it'll receive by calling script->Run()
.
All that I think needs to be done here is somehow calling the function (func->Call()
) with the same context (env->context()
). All the needed vars (require
, __dirname
, etc) will be in there, right?
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.
@addaleax on second thought, you're probably right.
9c0cfb8
to
2accbab
Compare
src/node_contextify.cc
Outdated
env->module_parameter_module(), | ||
env->module_parameter_filename(), | ||
env->module_parameter_dirname() | ||
}; |
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.
It might actually be nice if we could pass these in as arguments to for GetWrappedFunction()
?
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.
That would be nice, yes. That way this function only provides a primitive to build upon.
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.
@addaleax like... accepting the params array as arguments? Do I fallback to these values as defaults, or do I pass these into the primitive function which requires them?
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.
do I pass these into the primitive function which requires them?
Yes, that. (Assuming “requires” = “accepts as arguments”)
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.
no, by require I mean that you need to pass them in as opposed to optionally specifying them in which case they fallback to defaults.
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.
I think an empty array would make a sensible default here
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.
@addaleax cool. So should I add the said primitive in this PR, or should I follow up with a PR that refactors most of the current code into the primitive, with extra code to handle params as args to the new function would just call the primitive with these params as an arg?
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.
not sure which parts you are referring to by “current code”, but generally, you can use a single PR that contains two logically separate commits:
- One that adds the CompileFunctionInContext binding to the vm module and does not touch the module load
- One that makes the CJS loader use that binding and doesn’t touch the VM module
Does that help?
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.
It does.
@addaleax @hashseed while all complications seem to have gone away, ESLint seems to be failing: Cannot read config file: /Users/ryzokuken/Code/nodejs/node/.eslintrc.js
Error: The "path" argument must be of type string. Received type undefined
TypeError [ERR_INVALID_ARG_TYPE]: Cannot read config file: /Users/ryzokuken/Code/nodejs/node/.eslintrc.js
Error: The "path" argument must be of type string. Received type undefined
at assertPath (path.js:39:11)
at Object.dirname (path.js:1270:5)
at module.exports (<anonymous>:11:34)
at loadJSConfigFile (<anonymous>:154:16)
at loadConfigFile (<anonymous>:209:22)
at loadFromDisk (<anonymous>:495:18)
at Object.load (<anonymous>:559:20)
at Config.getLocalConfigHierarchy (<anonymous>:227:44)
at Config.getConfigHierarchy (<anonymous>:179:43)
at Config.getConfigVector (<anonymous>:286:21) any idea how any of my changes could trigger this? |
We're somehow not helping with the file paths? |
Wait, it's probably because I'm not using the |
@ryzokuken Maybe look at the existing usage of (In the end, you probably want a function that resembles the existing |
@addaleax tests run now finally, yay. |
ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents(); | ||
uint8_t* data = static_cast<uint8_t*>(contents.Data()); | ||
cached_data = new ScriptCompiler::CachedData( | ||
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); |
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.
All this can really be done inside the if-block where you checked args[2]
. That way you can also define cached_data_buf
inside the block.
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.
I did it in this particular fashion to mimic what New
did, so I have no preferences here whatsoever. Will do this.
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.
I see. In that case it's alright then.
src/node_contextify.cc
Outdated
|
||
ScriptCompiler::CompileOptions options; | ||
if (source.GetCachedData() == nullptr) { | ||
options = ScriptCompiler::kNoCompileOptions; |
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 option can also be set inside the if-block for args[2]
.
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.
Same as above, will do.
env, | ||
reinterpret_cast<const char*>(cached_data->data), | ||
cached_data->length); | ||
fun->Set(env->cached_data_string(), buf.ToLocalChecked()); |
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.
@addaleax do you have a suggestions as to where the resulting buffer could be better stored?
Alternatively, we don't offer this at all, and expose a separate binding for ScriptCompiler::CreateCodeCacheForFunction
similar to how we also recently exposed ScriptCompiler::CreateCodeCache
. That way this function gets a bit simpler, but then it would also lose symmetry to ContextifyScript::New
.
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.
since the option for ContextifyScript::New is deprecated in my pr i think its best not to mimic it.
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.
@devsnek could you drop me a link to it? Currently it Set
s the two on the returned function object itself, which sounds like similar (if not the same) to what we're doing in ContextifyScript::New
. Would love to see any alternatives you have in mind.
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.
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.
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.
well... it will be docs-dep for 10, runtime dep for 11, and removed in 12.
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.
In that case it would be reasonable to not introduce it here in the first place :)
test/parallel/test-vm-basic.js
Outdated
// vm.getWrappedFunction | ||
{ | ||
assert.strictEqual( | ||
vm.getWrappedFunction('console.log("Hello, World!");'), |
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.
Can we have a .toString()
here to be explicit about what we are comparing here?
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.
definitely. The tests haven't been updated to reflect the latest changes made in the code.
type: SyntaxError, | ||
message: 'Unexpected token }' | ||
}); | ||
} |
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.
I thought you had more tests :)
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.
Yeah, I commented out these as well, for now. Now that the existing tests all pass, will focus on covering as many cases as possible with tests.
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.
Yeah, I commented out these as well, for now. Now that the existing tests all pass, will focus on covering as many cases as possible with tests.
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.
Yeah, I commented out these as well, for now. Now that the existing tests all pass, will focus on covering as many cases as possible with tests.
This. The new binding should mirror the old code path as closely as possible. |
Agreed. This will definitely be a priority. BTW, @hashseed @addaleax at this point, all existing tests on master pass, so I personally feel good enough about this, code-wise (we could definitely add more functionality though). LMK whenever you're okay with this going to a public PR. The TODOs for now are:
|
@ryzokuken I think the priorities might be another way – making this as similar as possible to |
src/node_contextify.cc
Outdated
Context::Scope scope(context); | ||
|
||
MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext( | ||
context, &source, 5, params, 0, nullptr, options); |
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.
would be nice to also support the extensions param
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.
@devsnek definitely. I had been thinking of shipping in primitives with much more features (sandboxes, extensions, line_offset
and comment_offset
and what not) in hopefully a subsequent PR but I'm open to adding it in this one.
So, I added a few tests that I felt seemed absolutely necessary and made sure that the function works as expected. Let me know if you all have any more test cases in mind. |
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 looks good to me. Aside from design choices for which I'm not the right person.
env, | ||
reinterpret_cast<const char*>(cached_data->data), | ||
cached_data->length); | ||
fun->Set(env->cached_data_string(), buf.ToLocalChecked()); |
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.
In that case it would be reasonable to not introduce it here in the first place :)
src/node_contextify.cc
Outdated
Local<Value> val = params_buf->Get(context, n).ToLocalChecked(); | ||
if (val->IsString()) { | ||
params[n] = val.As<String>(); | ||
} else { |
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.
we shouldn't be doing the type checks in c++, just assume they're all strings at this point. (CHECK(val->IsString())
if you must)
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.
I could do this, but I'm not entirely convinced that we shouldn't do any error checking here. Perhaps something on the JS level?
src/node_contextify.cc
Outdated
return; | ||
} | ||
} | ||
} else { |
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 condition shouldn't be needed, cjs should be a normal consumer of this function
CHECK(args[1]->IsString()); | ||
Local<String> filename = args[1].As<String>(); | ||
|
||
// Argument 3: line offset |
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.
i don't think we really need offsets
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.
I think we’d probably want this for parity with New()
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.
+1 to what @addaleax said. Added the additional args for parity.
src/node_contextify.cc
Outdated
|
||
// Read params from params buffer | ||
size_t params_len; | ||
Local<String> *params; |
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.
node pointers hang left
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.
Will fix, didn't notice.
src/node_contextify.cc
Outdated
Local<String> *params; | ||
if (!params_buf.IsEmpty()) { | ||
params_len = params_buf->Length(); | ||
params = new Local<String>[params_len]; |
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.
don't forget to free this
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.
Good catch! Will do.
it might be a good idea to open this pr on the node repo to get more feedback |
src/node_contextify.cc
Outdated
|
||
// Read params from params buffer | ||
size_t params_len; | ||
Local<String> *params; |
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.
I think it might be nicer to use a std::vector<Local<String>>
– right now, this looks like a memory leak because params
is not being deleted anywhere?
(Otherwise, style-nit: left-leaning pointers :))
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.
@addaleax I had been tempted to the that too, but the function needs an array and size value, so why bother putting stuff in a vector just to decompose it later?
Re:delete, it was a oversight and I will delete params
appropriately 😅
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.
Because std::vector
is basically a cleaner way of what new
/delete
does, namely it avoids this exact kind of memory leak and is a bit more flexible in general? You can feel free to not do it, but I’d be 90 % sure somebody else would ask for it in the public PR then
src/node_contextify.cc
Outdated
params[1] = env->module_parameter_require(); | ||
params[2] = env->module_parameter_module(); | ||
params[3] = env->module_parameter_filename(); | ||
params[4] = env->module_parameter_dirname(); |
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.
I still think the default should be an empty array
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.
@devsnek (#1 (comment)) and @addaleax I thought so at first too, but chose otherwise because I thought eternals would be faster?
Anyway, if you're still both +1 to defaulting to an empty array instead, then I think I'm okay with it.
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.
I thought eternals would be faster?
I don’t think it makes much of a difference. If you have an empty default parameter list, you don’t have any extra native streams, that’s also a nice thing.
But more importantly, this sets the API right to be self-contained rather than something with the specific purpose of supporting the module wrapper
lib/vm.js
Outdated
@@ -294,6 +299,8 @@ module.exports = { | |||
runInNewContext, | |||
runInThisContext, | |||
isContext, | |||
getWrappedFunction, | |||
getWrappedFunctionGeneric, |
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.
I think we only want to have one export of this kind? Maybe this is already implied in the WIP
tag here, just want to make sure it doesn’t get lost :)
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.
wanted to expose the generic version in case someone needs it. The getWrappedFunction
is a smaller variant with only 2 args and default values.
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.
That said, an options object with defaults sounds better, so I'll probably do that instead.
lib/vm.js
Outdated
@@ -286,6 +287,10 @@ function runInThisContext(code, options) { | |||
return createScript(code, options).runInThisContext(options); | |||
} | |||
|
|||
function getWrappedFunction(code, filename) { | |||
return getWrappedFunctionGeneric(code, filename, 0, 0, undefined, false); | |||
} |
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.
I would suggest as the public API:
vm.compileFunction(code, params = [], {
filename,
columnOffset,
lineOffset,
cachedData,
produceCachedData
} = {})
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.
Looks good, Will do.
lib/internal/modules/cjs/loader.js
Outdated
lineOffset: 0, | ||
displayErrors: true | ||
}); | ||
const compiledWrapper = vm.getWrappedFunction(content, filename); |
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.
Would there be a way to have the cake and eat it to? As is the removal of Module.wrap
use is a no-go for me since CJS tools rely on it. If there is a way to get the benefit + allow Module.wrap
tie-ins that would be rad.
This could be done in a variety of ways. For example using the Module.wrapper[0]
and Module.wrapper[1]
to be used to compile something internally (waves hands as I'm not familiar with V8 internals). Or having setters on Module.wrapper
, Module.wrapper[0]
, and Module.wrapper[1]
to trigger the old non-vm.getWrappedFunction
use.
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.
@jdalton I didn't remove Module.wrap, nor do I intend to (atleast not in this PR). This PR just changes module._compile to not use it internally, technically intended as a semver-major (because new bindings).
If in case somebody does decide to remove
Module.wrap
, it will have to go through the standard deprecation process that @devsnek pointed out, thus you could be assured that it won't be going anywhere any soon. Plus we won't do anything that hurts the community, would we? ;)
This is PR addresses a minor inconvenience that has existed since Node's creation so I'm not OK dropping any existing CJS tie-ins here. Module.wrap
and Module.wrapper
have been used by tooling to customize CJS module construction so I'd be wary of removing their use here. CJS is essentially frozen so I'd urge you to reconsider.
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.
@jdalton Proper syntax error messages that don’t get obfuscated by the added function code are important as well.
If there are specific use cases you’re thinking of, it would be good to know what public API would address those (and possibly whether they can also be addressed by monkey-patching the newly introduced vm
method)
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.
@jdalton what specifically makes Module.wrap
special to an extent that CJS tools "rely" on it? I'd love to see code that works with Module.wrap
but breaks on what we have right now. Aiming for a semver-minor
here, I'll be doing whatever I can to make sure no userland code breaks (and technically, it shouldn't, even right now).
I mean, you very well know at this point about all problems that the original function causes and how this will be an improvement, but again, I'd be making sure that nothing breaks in the process and if something does, let me know.
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.
Or having setters on Module.wrapper, Module.wrapper[0], and Module.wrapper[1] to trigger the old non-vm.getWrappedFunction use.
if we must keep using wrapper, this sounds like the best way. i would fire a deprecation warning too
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.
@jdalton again, I'm removing neither Module.wrap
nor Module.wrapper
here.
If you could point out which CJS modules/tools broke while changing Module._compile
internally, I could make sure it wouldn't.
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.
I think what John is referring to isn’t that Module.wrap
or Module.wrapper
don’t work anymore, it’s that replacing/monkey-patching them doesn’t have the effect of actually changing Node’s behaviour anymore?
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.
Wait, CJS modules are monkey-patching the Module
object and we're holding up PRs because it won't allow them to monkey-patch a core module anymore!?
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.
Wait, CJS modules are monkey-patching the Module object and we're holding up PRs because it won't allow them to monkey-patch a core module anymore!?
Yes, it’s the sensible thing to do for us. We have Node’s past lack of proper hook APIs to blame for this, not users who need to get things to work…
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.
CJS is very monkey-patchable. This particular API and functionality has existed since Jan 2011 (so pretty old). Losing the ability to monkey patch in this way is why I'm raising the concern.
Oh, also: The addition of a new |
@addaleax no tests fail, and I hope no CITGM runs would fail as well. Why not |
@ryzokuken It’s |
Btw, one thing that we could do is to implement |
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 is basically already an in-depth review, with these points addressed I think this would be good to go
Given the most recent bits of discussion I’d recommend splitting this into two PRs, first taking care of everything except the modules change, so that you can focus on the technical side of things there
lib/vm.js
Outdated
@@ -26,6 +26,7 @@ const { | |||
kParsingContext, | |||
makeContext, | |||
isContext: _isContext, | |||
getWrappedFunction |
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.
nit: s/getWrappedFunction
/compileFunction
/
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.
umm, do you mean I should rename the C++ binding and well? The C++ binding is named getWrappedFunction
//GetWrappedFunction
while the public API function is called vm.compileFunction
.
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.
Yes, that’s what I mean :)
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.
Sure! Will do.
src/node_contextify.cc
Outdated
|
||
// Read params from params buffer | ||
size_t params_len; | ||
Local<String>* params; |
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.
I’d still really encourage you to use something better than a raw pointer here. There’s a couple options…
std::unique_ptr<Local<String>[]>
. If you want to stick with custom allocation, this is what you want – You use it almost the same, but it automatically takes care of de-allocation.std::vector<Local<String>>
. This also avoids dealing with raw pointers, and is probably the most idiomatic thing C++-wise.MaybeStackBuffer<Local<String>, N>
(where N is something like 10 or so). This is a Node.js-specific thing and lacks a lot of the flexibility of built-in container types, but it has the small advantage of avoiding a heap allocation for the common case.
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.
In that case, I'll switch to a vector
.
src/node_contextify.cc
Outdated
|
||
for (int32_t n = 0; n < params_len; n++) { | ||
Local<Value> val = params_buf->Get(context, n).ToLocalChecked(); | ||
CHECK(val->IsString()); |
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.
Sorry, Github cut off review here because my connection was flaky :/
For one, we don’t currently do any checking that val
is actually a string in JS land, so right now passing in an array with non-string elements would crash the process (as far as I can tell)
Then, params_buf->Get(…)
can fail if the array element is defined via a getter, so the .ToLocalChecked()
may crash too – you probably want something like if (!params_buf->Get(context, n).ToLocal(&val)) return;
(but just as a heads up, that would leak memory unless you go with an RAII option for managing params
like the ones suggested above)
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.
Yes, this had been troubling me too, and the check was quite different originally. Will do this once I make the switch to vectors.
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.
i'd rather we did the argument handling in jsland and passed just raw arguments like ContextifyScript::New
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.
@devsnek totally doable. Plus then we could make it throw
descriptive errors instead of just crashing.
} | ||
fun->Set( | ||
env->cached_data_produced_string(), | ||
Boolean::New(isolate, cached_data_produced)); |
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.
Both of these should use the non-deprecated overloads of Set()
(and ideally also do error handling for these cases)
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.
I didn't check those out, will do this ASAP.
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.
@addaleax I suppose that by non-deprecated you mean ones that take context, key, val
instead of plain key, val
? How do I know which functions are deprecated?
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.
They are marked V8_DEPRECATE_SOON
or V8_DEPRECATED
in v8.h :)
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.
Got it, thanks.
std::vector<Local<String>> params; | ||
if (!params_buf.IsEmpty()) { | ||
for (uint32_t n = 0; n < params_buf->Length(); n++) { | ||
Local<Value> val = params_buf->Get(context, n).ToLocalChecked(); |
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.
The earlier comment here about ToLocalChecked still stands, btw
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.
Umm, we're checking that each item in params is a string, so that's covered. ToLocalChecked
can fail, so I guess we could return if it does. I hope there's no scope of a memory leak anymore, right?
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.
Yes, we tested that it’s a string (although a sufficiently evil getter could also return a string while typechecking and then later return something else)
What I meant was that if it’s a getter, it can always fail, so we should return back to JS if it does
I hope there's no scope of a memory leak anymore, right?
I don’t think so, no. :)
@addaleax I guess this does it? |
Reverting this enables us to provide slower, but longer-lasting replacements for the deprecated APIs. Original commit message: Put back deleted V8_DEPRECATE_SOON methods This partially reverts https://chromium-review.googlesource.com/c/v8/v8/+/1177861, which deleted many V8_DEPRECATE_SOON methods rather than moving them to V8_DEPRECATED first. This puts them back and marks them V8_DEPRECATED. Note V8_DEPRECATED that were deleted in the same CL stay deleted. NOTRY=true NOPRESUBMIT=true NOTREECHECKS=true Bug: v8:7786, v8:8240 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: I00330036d957f98dab403465b25e30d8382aac22 Reviewed-on: https://chromium-review.googlesource.com/1251422 Commit-Queue: Dan Elphick <[email protected]> Reviewed-by: Yang Guo <[email protected]> Reviewed-by: Michael Hablich <[email protected]> Cr-Commit-Position: refs/branch-heads/7.0@{nodejs#49} Cr-Branched-From: 6e2adae6f7f8e891cfd01f3280482b20590427a6-refs/heads/7.0.276@{#1} Cr-Branched-From: bc08a8624cbbea7a2d30071472bc73ad9544eadf-refs/heads/master@{nodejs#55424} Refs: v8/v8@9136dd8 Refs: nodejs#23122 PR-URL: nodejs#23158 Reviewed-By: Yang Guo <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
/cc @hashseed