[api] Get ScriptOrModule from CompileFunctionInContext
Adds a new out param which allows accessing the ScriptOrModule of a function, which allows an embedder such as Node.js to use the function's i::Script lifetime. Refs: https://github.com/nodejs/node-v8/issues/111 Change-Id: I34346d94d76e8f9b8377c97d948673f4b95eb9d5 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1699698 Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#62830}
This commit is contained in:
parent
9c766330e0
commit
b33af60dd9
@ -1699,7 +1699,8 @@ class V8_EXPORT ScriptCompiler {
|
|||||||
Local<String> arguments[], size_t context_extension_count,
|
Local<String> arguments[], size_t context_extension_count,
|
||||||
Local<Object> context_extensions[],
|
Local<Object> context_extensions[],
|
||||||
CompileOptions options = kNoCompileOptions,
|
CompileOptions options = kNoCompileOptions,
|
||||||
NoCacheReason no_cache_reason = kNoCacheNoReason);
|
NoCacheReason no_cache_reason = kNoCacheNoReason,
|
||||||
|
Local<ScriptOrModule>* script_or_module_out = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns code cache for the specified unbound_script.
|
* Creates and returns code cache for the specified unbound_script.
|
||||||
|
125
src/api/api.cc
125
src/api/api.cc
@ -2496,70 +2496,83 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
|
|||||||
Local<Context> v8_context, Source* source, size_t arguments_count,
|
Local<Context> v8_context, Source* source, size_t arguments_count,
|
||||||
Local<String> arguments[], size_t context_extension_count,
|
Local<String> arguments[], size_t context_extension_count,
|
||||||
Local<Object> context_extensions[], CompileOptions options,
|
Local<Object> context_extensions[], CompileOptions options,
|
||||||
NoCacheReason no_cache_reason) {
|
NoCacheReason no_cache_reason,
|
||||||
PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext,
|
Local<ScriptOrModule>* script_or_module_out) {
|
||||||
Function);
|
Local<Function> result;
|
||||||
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
|
|
||||||
|
|
||||||
DCHECK(options == CompileOptions::kConsumeCodeCache ||
|
{
|
||||||
options == CompileOptions::kEagerCompile ||
|
PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext,
|
||||||
options == CompileOptions::kNoCompileOptions);
|
Function);
|
||||||
|
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
|
||||||
|
|
||||||
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
|
DCHECK(options == CompileOptions::kConsumeCodeCache ||
|
||||||
|
options == CompileOptions::kEagerCompile ||
|
||||||
|
options == CompileOptions::kNoCompileOptions);
|
||||||
|
|
||||||
DCHECK(context->IsNativeContext());
|
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
|
||||||
i::Handle<i::SharedFunctionInfo> outer_info(
|
|
||||||
context->empty_function().shared(), isolate);
|
|
||||||
|
|
||||||
i::Handle<i::JSFunction> fun;
|
DCHECK(context->IsNativeContext());
|
||||||
i::Handle<i::FixedArray> arguments_list =
|
|
||||||
isolate->factory()->NewFixedArray(static_cast<int>(arguments_count));
|
i::Handle<i::FixedArray> arguments_list =
|
||||||
for (int i = 0; i < static_cast<int>(arguments_count); i++) {
|
isolate->factory()->NewFixedArray(static_cast<int>(arguments_count));
|
||||||
i::Handle<i::String> argument = Utils::OpenHandle(*arguments[i]);
|
for (int i = 0; i < static_cast<int>(arguments_count); i++) {
|
||||||
if (!IsIdentifier(isolate, argument)) return Local<Function>();
|
i::Handle<i::String> argument = Utils::OpenHandle(*arguments[i]);
|
||||||
arguments_list->set(i, *argument);
|
if (!IsIdentifier(isolate, argument)) return Local<Function>();
|
||||||
|
arguments_list->set(i, *argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < context_extension_count; ++i) {
|
||||||
|
i::Handle<i::JSReceiver> extension =
|
||||||
|
Utils::OpenHandle(*context_extensions[i]);
|
||||||
|
if (!extension->IsJSObject()) return Local<Function>();
|
||||||
|
context = isolate->factory()->NewWithContext(
|
||||||
|
context,
|
||||||
|
i::ScopeInfo::CreateForWithScope(
|
||||||
|
isolate,
|
||||||
|
context->IsNativeContext()
|
||||||
|
? i::Handle<i::ScopeInfo>::null()
|
||||||
|
: i::Handle<i::ScopeInfo>(context->scope_info(), isolate)),
|
||||||
|
extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
i::Compiler::ScriptDetails script_details = GetScriptDetails(
|
||||||
|
isolate, source->resource_name, source->resource_line_offset,
|
||||||
|
source->resource_column_offset, source->source_map_url,
|
||||||
|
source->host_defined_options);
|
||||||
|
|
||||||
|
i::ScriptData* script_data = nullptr;
|
||||||
|
if (options == kConsumeCodeCache) {
|
||||||
|
DCHECK(source->cached_data);
|
||||||
|
// ScriptData takes care of pointer-aligning the data.
|
||||||
|
script_data = new i::ScriptData(source->cached_data->data,
|
||||||
|
source->cached_data->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
i::Handle<i::JSFunction> scoped_result;
|
||||||
|
has_pending_exception =
|
||||||
|
!i::Compiler::GetWrappedFunction(
|
||||||
|
Utils::OpenHandle(*source->source_string), arguments_list, context,
|
||||||
|
script_details, source->resource_options, script_data, options,
|
||||||
|
no_cache_reason)
|
||||||
|
.ToHandle(&scoped_result);
|
||||||
|
if (options == kConsumeCodeCache) {
|
||||||
|
source->cached_data->rejected = script_data->rejected();
|
||||||
|
}
|
||||||
|
delete script_data;
|
||||||
|
RETURN_ON_FAILED_EXECUTION(Function);
|
||||||
|
result = handle_scope.Escape(Utils::CallableToLocal(scoped_result));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < context_extension_count; ++i) {
|
if (script_or_module_out != nullptr) {
|
||||||
i::Handle<i::JSReceiver> extension =
|
i::Handle<i::JSFunction> function =
|
||||||
Utils::OpenHandle(*context_extensions[i]);
|
i::Handle<i::JSFunction>::cast(Utils::OpenHandle(*result));
|
||||||
if (!extension->IsJSObject()) return Local<Function>();
|
i::Isolate* isolate = function->GetIsolate();
|
||||||
context = isolate->factory()->NewWithContext(
|
i::Handle<i::SharedFunctionInfo> shared(function->shared(), isolate);
|
||||||
context,
|
i::Handle<i::Script> script(i::Script::cast(shared->script()), isolate);
|
||||||
i::ScopeInfo::CreateForWithScope(
|
*script_or_module_out = v8::Utils::ScriptOrModuleToLocal(script);
|
||||||
isolate,
|
|
||||||
context->IsNativeContext()
|
|
||||||
? i::Handle<i::ScopeInfo>::null()
|
|
||||||
: i::Handle<i::ScopeInfo>(context->scope_info(), isolate)),
|
|
||||||
extension);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i::Compiler::ScriptDetails script_details = GetScriptDetails(
|
return result;
|
||||||
isolate, source->resource_name, source->resource_line_offset,
|
|
||||||
source->resource_column_offset, source->source_map_url,
|
|
||||||
source->host_defined_options);
|
|
||||||
|
|
||||||
i::ScriptData* script_data = nullptr;
|
|
||||||
if (options == kConsumeCodeCache) {
|
|
||||||
DCHECK(source->cached_data);
|
|
||||||
// ScriptData takes care of pointer-aligning the data.
|
|
||||||
script_data = new i::ScriptData(source->cached_data->data,
|
|
||||||
source->cached_data->length);
|
|
||||||
}
|
|
||||||
|
|
||||||
i::Handle<i::JSFunction> result;
|
|
||||||
has_pending_exception =
|
|
||||||
!i::Compiler::GetWrappedFunction(
|
|
||||||
Utils::OpenHandle(*source->source_string), arguments_list, context,
|
|
||||||
script_details, source->resource_options, script_data, options,
|
|
||||||
no_cache_reason)
|
|
||||||
.ToHandle(&result);
|
|
||||||
if (options == kConsumeCodeCache) {
|
|
||||||
source->cached_data->rejected = script_data->rejected();
|
|
||||||
}
|
|
||||||
delete script_data;
|
|
||||||
RETURN_ON_FAILED_EXECUTION(Function);
|
|
||||||
RETURN_ESCAPED(Utils::CallableToLocal(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCompiler::ScriptStreamingTask::Run() { data_->task->Run(); }
|
void ScriptCompiler::ScriptStreamingTask::Run() { data_->task->Run(); }
|
||||||
|
@ -650,11 +650,16 @@ TEST(CompileFunctionInContextScriptOrigin) {
|
|||||||
v8::Integer::New(CcTest::isolate(), 22),
|
v8::Integer::New(CcTest::isolate(), 22),
|
||||||
v8::Integer::New(CcTest::isolate(), 41));
|
v8::Integer::New(CcTest::isolate(), 41));
|
||||||
v8::ScriptCompiler::Source script_source(v8_str("throw new Error()"), origin);
|
v8::ScriptCompiler::Source script_source(v8_str("throw new Error()"), origin);
|
||||||
|
Local<ScriptOrModule> script;
|
||||||
v8::Local<v8::Function> fun =
|
v8::Local<v8::Function> fun =
|
||||||
v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source,
|
v8::ScriptCompiler::CompileFunctionInContext(
|
||||||
0, nullptr, 0, nullptr)
|
env.local(), &script_source, 0, nullptr, 0, nullptr,
|
||||||
|
v8::ScriptCompiler::CompileOptions::kNoCompileOptions,
|
||||||
|
v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script)
|
||||||
.ToLocalChecked();
|
.ToLocalChecked();
|
||||||
CHECK(!fun.IsEmpty());
|
CHECK(!fun.IsEmpty());
|
||||||
|
CHECK(!script.IsEmpty());
|
||||||
|
CHECK(script->GetResourceName()->StrictEquals(v8_str("test")));
|
||||||
v8::TryCatch try_catch(CcTest::isolate());
|
v8::TryCatch try_catch(CcTest::isolate());
|
||||||
CcTest::isolate()->SetCaptureStackTraceForUncaughtExceptions(true);
|
CcTest::isolate()->SetCaptureStackTraceForUncaughtExceptions(true);
|
||||||
CHECK(fun->Call(env.local(), env->Global(), 0, nullptr).IsEmpty());
|
CHECK(fun->Call(env.local(), env->Global(), 0, nullptr).IsEmpty());
|
||||||
|
Loading…
Reference in New Issue
Block a user