diff options
author | Ujjwal Sharma <usharma1998@gmail.com> | 2018-06-28 12:05:19 +0530 |
---|---|---|
committer | Michaƫl Zasso <targos@protonmail.com> | 2018-09-06 08:53:57 +0200 |
commit | a0bab897620d9bd8150d68ba5eb22be47aa55087 (patch) | |
tree | 4a33941402c4913f1be9c26b072c530e62be79bb /src/node_contextify.cc | |
parent | ca2dd8cbb0a8fbc688b7c4a27740530e819e36c9 (diff) | |
download | node-new-a0bab897620d9bd8150d68ba5eb22be47aa55087.tar.gz |
vm: add bindings for v8::CompileFunctionInContext
Adds a method compileFunction to the vm module, which serves as a
binding for v8::CompileFunctionInContext with appropriate args for
specifying the details, and provide params for the wrapper.
Eventually, we would be changing Module._compile to use this internally
over the standard Module.wrap
PR-URL: https://github.com/nodejs/node/pull/21571
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src/node_contextify.cc')
-rw-r--r-- | src/node_contextify.cc | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 01c607fd74..e490f60cf0 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -206,6 +206,7 @@ void ContextifyContext::Init(Environment* env, Local<Object> target) { env->SetMethod(target, "makeContext", MakeContext); env->SetMethod(target, "isContext", IsContext); + env->SetMethod(target, "compileFunction", CompileFunction); } @@ -948,6 +949,144 @@ 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: context extensions (optional) + Local<Array> context_extensions_buf; + if (!args[7]->IsUndefined()) { + CHECK(args[7]->IsArray()); + context_extensions_buf = args[7].As<Array>(); + } + + // Argument 9: params for the function (optional) + Local<Array> params_buf; + if (!args[8]->IsUndefined()) { + CHECK(args[8]->IsArray()); + params_buf = args[8].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()); + } + + 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 context extensions from buffer + std::vector<Local<Object>> context_extensions; + if (!context_extensions_buf.IsEmpty()) { + for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) { + Local<Value> val; + if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return; + CHECK(val->IsObject()); + context_extensions.push_back(val.As<Object>()); + } + } + + // 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; + if (!params_buf->Get(context, n).ToLocal(&val)) return; + CHECK(val->IsString()); + params.push_back(val.As<String>()); + } + } + + MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext( + context, &source, params.size(), params.data(), + context_extensions.size(), context_extensions.data(), 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 std::unique_ptr<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); + if (fun->Set( + parsing_context, + env->cached_data_string(), + buf.ToLocalChecked()).IsNothing()) return; + } + if (fun->Set( + parsing_context, + env->cached_data_produced_string(), + Boolean::New(isolate, cached_data_produced)).IsNothing()) return; + } + + args.GetReturnValue().Set(fun); +} + + void Initialize(Local<Object> target, Local<Value> unused, Local<Context> context) { |