-
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
Changes from all commits
ba9f1c8
ef24aaa
63b780d
1e22bcf
e9b1ba8
ac1000f
f5f6bb8
97e6bd4
46cc9be
b5c534e
0ac8d78
7521df0
19934f2
7c037d2
cedba7c
7603fed
d306efd
40c2296
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 |
---|---|---|
|
@@ -207,6 +207,7 @@ void ContextifyContext::Init(Environment* env, Local<Object> target) { | |
|
||
env->SetMethod(target, "makeContext", MakeContext); | ||
env->SetMethod(target, "isContext", IsContext); | ||
env->SetMethod(target, "compileFunction", CompileFunction); | ||
} | ||
|
||
|
||
|
@@ -951,6 +952,120 @@ class ContextifyScript : public BaseObject { | |
}; | ||
|
||
|
||
void ContextifyContext::CompileFunction( | ||
const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args); | ||
Isolate* isolate = env->isolate(); | ||
Local<Context> context = env->context(); | ||
|
||
// Argument 1: source code | ||
CHECK(args[0]->IsString()); | ||
Local<String> code = args[0].As<String>(); | ||
|
||
// Argument 2: filename | ||
CHECK(args[1]->IsString()); | ||
Local<String> filename = args[1].As<String>(); | ||
|
||
// Argument 3: line offset | ||
CHECK(args[2]->IsNumber()); | ||
Local<Integer> line_offset = args[2].As<Integer>(); | ||
|
||
// Argument 4: column offset | ||
CHECK(args[3]->IsNumber()); | ||
Local<Integer> column_offset = args[3].As<Integer>(); | ||
|
||
// Argument 5: cached data (optional) | ||
Local<Uint8Array> cached_data_buf; | ||
if (!args[4]->IsUndefined()) { | ||
CHECK(args[4]->IsUint8Array()); | ||
cached_data_buf = args[4].As<Uint8Array>(); | ||
} | ||
|
||
// Argument 6: produce cache data | ||
CHECK(args[5]->IsBoolean()); | ||
bool produce_cached_data = args[5]->IsTrue(); | ||
|
||
// Argument 7: parsing context (optional) | ||
Local<Context> parsing_context; | ||
if (!args[6]->IsUndefined()) { | ||
CHECK(args[6]->IsObject()); | ||
ContextifyContext* sandbox = | ||
ContextifyContext::ContextFromContextifiedSandbox( | ||
env, args[6].As<Object>()); | ||
CHECK_NOT_NULL(sandbox); | ||
parsing_context = sandbox->context(); | ||
} else { | ||
parsing_context = context; | ||
} | ||
|
||
// Argument 8: params for the function (optional) | ||
Local<Array> params_buf; | ||
if (!args[7]->IsUndefined()) { | ||
CHECK(args[7]->IsArray()); | ||
params_buf = args[7].As<Array>(); | ||
} | ||
|
||
// Read cache from cached data buffer | ||
ScriptCompiler::CachedData* cached_data = nullptr; | ||
if (!cached_data_buf.IsEmpty()) { | ||
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 commentThe 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 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 did it in this particular fashion to mimic what 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 see. In that case it's alright then. |
||
} | ||
|
||
ScriptOrigin origin(filename, line_offset, column_offset); | ||
ScriptCompiler::Source source(code, origin, cached_data); | ||
ScriptCompiler::CompileOptions options; | ||
if (source.GetCachedData() == nullptr) { | ||
options = ScriptCompiler::kNoCompileOptions; | ||
} else { | ||
options = ScriptCompiler::kConsumeCodeCache; | ||
} | ||
|
||
TryCatch try_catch(isolate); | ||
Context::Scope scope(parsing_context); | ||
|
||
// Read params from params buffer | ||
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 commentThe 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 commentThe 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. 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. 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 don’t think so, no. :) |
||
CHECK(val->IsString()); | ||
params.push_back(val.As<String>()); | ||
} | ||
} | ||
|
||
MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext( | ||
context, &source, params.size(), params.data(), 0, nullptr, options); | ||
|
||
Local<Function> fun; | ||
if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) { | ||
ContextifyScript::DecorateErrorStack(env, try_catch); | ||
try_catch.ReThrow(); | ||
return; | ||
} | ||
|
||
if (produce_cached_data) { | ||
const ScriptCompiler::CachedData* cached_data = | ||
ScriptCompiler::CreateCodeCacheForFunction(fun, code); | ||
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); | ||
fun->Set(env->cached_data_string(), buf.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. @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 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. 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 commentThe reason will be displayed to describe this comment to others. Learn more. @devsnek could you drop me a link to it? Currently it 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. 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. 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. 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 commentThe 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 :) |
||
} | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Both of these should use the non-deprecated overloads of 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 didn't check those out, will do this ASAP. 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. @addaleax I suppose that by non-deprecated you mean ones that take 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. They are marked 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. Got it, thanks. |
||
} | ||
|
||
args.GetReturnValue().Set(fun); | ||
} | ||
|
||
|
||
void Initialize(Local<Object> target, | ||
Local<Value> unused, | ||
Local<Context> context) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,3 +128,30 @@ const vm = require('vm'); | |
'Received type object' | ||
}); | ||
}); | ||
|
||
// vm.compileFunction | ||
{ | ||
assert.strictEqual( | ||
vm.compileFunction('console.log("Hello, World!")').toString(), | ||
'function () {\nconsole.log("Hello, World!")\n}' | ||
); | ||
|
||
assert.strictEqual( | ||
vm.compileFunction( | ||
'return p + q + r + s + t', | ||
['p', 'q', 'r', 's', 't'] | ||
)('ab', 'cd', 'ef', 'gh', 'ij'), | ||
'abcdefghij' | ||
); | ||
|
||
vm.compileFunction('return'); // Should not throw on 'return' | ||
|
||
common.expectsError(() => { | ||
vm.compileFunction( | ||
'});\n\n(function() {\nconsole.log(1);\n})();\n\n(function() {' | ||
); | ||
}, { | ||
type: SyntaxError, | ||
message: 'Unexpected token }' | ||
}); | ||
} | ||
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 thought you had more tests :) 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. 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 commentThe 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 commentThe 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.
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.