From 1abbe0a2123e8333922894258389c2d5c1568472 Mon Sep 17 00:00:00 2001 From: Ujjwal Sharma Date: Thu, 28 Jun 2018 12:05:19 +0530 Subject: 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 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: John-David Dalton Reviewed-By: Gus Caplan Reviewed-By: James M Snell --- src/node_contextify.cc | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) (limited to 'src/node_contextify.cc') diff --git a/src/node_contextify.cc b/src/node_contextify.cc index ce9f5eb2f7..070c6bab60 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -209,6 +209,7 @@ void ContextifyContext::Init(Environment* env, Local target) { env->SetMethod(target, "makeContext", MakeContext); env->SetMethod(target, "isContext", IsContext); + env->SetMethod(target, "compileFunction", CompileFunction); } @@ -987,6 +988,144 @@ class ContextifyScript : public BaseObject { }; +void ContextifyContext::CompileFunction( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + Local context = env->context(); + + // Argument 1: source code + CHECK(args[0]->IsString()); + Local code = args[0].As(); + + // Argument 2: filename + CHECK(args[1]->IsString()); + Local filename = args[1].As(); + + // Argument 3: line offset + CHECK(args[2]->IsNumber()); + Local line_offset = args[2].As(); + + // Argument 4: column offset + CHECK(args[3]->IsNumber()); + Local column_offset = args[3].As(); + + // Argument 5: cached data (optional) + Local cached_data_buf; + if (!args[4]->IsUndefined()) { + CHECK(args[4]->IsUint8Array()); + cached_data_buf = args[4].As(); + } + + // Argument 6: produce cache data + CHECK(args[5]->IsBoolean()); + bool produce_cached_data = args[5]->IsTrue(); + + // Argument 7: parsing context (optional) + Local parsing_context; + if (!args[6]->IsUndefined()) { + CHECK(args[6]->IsObject()); + ContextifyContext* sandbox = + ContextifyContext::ContextFromContextifiedSandbox( + env, args[6].As()); + CHECK_NOT_NULL(sandbox); + parsing_context = sandbox->context(); + } else { + parsing_context = context; + } + + // Argument 8: context extensions (optional) + Local context_extensions_buf; + if (!args[7]->IsUndefined()) { + CHECK(args[7]->IsArray()); + context_extensions_buf = args[7].As(); + } + + // Argument 9: params for the function (optional) + Local params_buf; + if (!args[8]->IsUndefined()) { + CHECK(args[8]->IsArray()); + params_buf = args[8].As(); + } + + // 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(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> context_extensions; + if (!context_extensions_buf.IsEmpty()) { + for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) { + Local val; + if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return; + CHECK(val->IsObject()); + context_extensions.push_back(val.As()); + } + } + + // Read params from params buffer + std::vector> params; + if (!params_buf.IsEmpty()) { + for (uint32_t n = 0; n < params_buf->Length(); n++) { + Local val; + if (!params_buf->Get(context, n).ToLocal(&val)) return; + CHECK(val->IsString()); + params.push_back(val.As()); + } + } + + MaybeLocal maybe_fun = ScriptCompiler::CompileFunctionInContext( + context, &source, params.size(), params.data(), + context_extensions.size(), context_extensions.data(), options); + + Local 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 + cached_data(ScriptCompiler::CreateCodeCacheForFunction(fun, code)); + bool cached_data_produced = cached_data != nullptr; + if (cached_data_produced) { + MaybeLocal buf = Buffer::Copy( + env, + reinterpret_cast(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 target, Local unused, Local context) { -- cgit v1.2.3