[snapshot] extend code caching support to CompileFunctionInContext.
R=leszeks@chromium.org, mythria@chromium.org Bug: v8:7554 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: I3eb29d67dfa64887fb52ac706d069e15dd2d0e85 Reviewed-on: https://chromium-review.googlesource.com/980944 Reviewed-by: Mythri Alle <mythria@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#52299}
This commit is contained in:
parent
9a29c90277
commit
e71055211c
13
include/v8.h
13
include/v8.h
@ -1569,7 +1569,9 @@ class V8_EXPORT ScriptCompiler {
|
||||
static V8_WARN_UNUSED_RESULT MaybeLocal<Function> CompileFunctionInContext(
|
||||
Local<Context> context, Source* source, size_t arguments_count,
|
||||
Local<String> arguments[], size_t context_extension_count,
|
||||
Local<Object> context_extensions[]);
|
||||
Local<Object> context_extensions[],
|
||||
CompileOptions options = kNoCompileOptions,
|
||||
NoCacheReason no_cache_reason = kNoCacheNoReason);
|
||||
|
||||
/**
|
||||
* Creates and returns code cache for the specified unbound_script.
|
||||
@ -1579,6 +1581,15 @@ class V8_EXPORT ScriptCompiler {
|
||||
static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script,
|
||||
Local<String> source);
|
||||
|
||||
/**
|
||||
* Creates and returns code cache for the specified function that was
|
||||
* previously produced by CompileFunctionInContext.
|
||||
* This will return nullptr if the script cannot be serialized. The
|
||||
* CachedData returned by this function should be owned by the caller.
|
||||
*/
|
||||
static CachedData* CreateCodeCacheForFunction(Local<Function> function,
|
||||
Local<String> source);
|
||||
|
||||
private:
|
||||
static V8_WARN_UNUSED_RESULT MaybeLocal<UnboundScript> CompileUnboundInternal(
|
||||
Isolate* isolate, Source* source, CompileOptions options,
|
||||
|
94
src/api.cc
94
src/api.cc
@ -2398,22 +2398,14 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
|
||||
source->host_defined_options);
|
||||
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
|
||||
i::Compiler::GetSharedFunctionInfoForScript(
|
||||
str, script_details, source->resource_options, nullptr, &script_data,
|
||||
str, script_details, source->resource_options, nullptr, script_data,
|
||||
options, no_cache_reason, i::NOT_NATIVES_CODE);
|
||||
has_pending_exception = !maybe_function_info.ToHandle(&result);
|
||||
if (has_pending_exception && script_data != nullptr) {
|
||||
// This case won't happen during normal operation; we have compiled
|
||||
// successfully and produced cached data, and but the second compilation
|
||||
// of the same source code fails.
|
||||
delete script_data;
|
||||
script_data = nullptr;
|
||||
}
|
||||
RETURN_ON_FAILED_EXECUTION(UnboundScript);
|
||||
|
||||
if (options == kConsumeCodeCache) {
|
||||
source->cached_data->rejected = script_data->rejected();
|
||||
}
|
||||
delete script_data;
|
||||
has_pending_exception = !maybe_function_info.ToHandle(&result);
|
||||
RETURN_ON_FAILED_EXECUTION(UnboundScript);
|
||||
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
|
||||
}
|
||||
|
||||
@ -2498,15 +2490,19 @@ class IsIdentifierHelper {
|
||||
DISALLOW_COPY_AND_ASSIGN(IsIdentifierHelper);
|
||||
};
|
||||
|
||||
|
||||
MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
|
||||
Local<Context> v8_context, Source* source, size_t arguments_count,
|
||||
Local<String> arguments[], size_t context_extension_count,
|
||||
Local<Object> context_extensions[]) {
|
||||
Local<Object> context_extensions[], CompileOptions options,
|
||||
NoCacheReason no_cache_reason) {
|
||||
PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext,
|
||||
Function);
|
||||
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
|
||||
|
||||
DCHECK(options == CompileOptions::kConsumeCodeCache ||
|
||||
options == CompileOptions::kEagerCompile ||
|
||||
options == CompileOptions::kNoCompileOptions);
|
||||
|
||||
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
|
||||
i::Handle<i::SharedFunctionInfo> outer_info(context->closure()->shared(),
|
||||
isolate);
|
||||
@ -2535,25 +2531,30 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
|
||||
extension);
|
||||
}
|
||||
|
||||
i::Handle<i::Object> name_obj;
|
||||
int line_offset = 0;
|
||||
int column_offset = 0;
|
||||
if (!source->resource_name.IsEmpty()) {
|
||||
name_obj = Utils::OpenHandle(*(source->resource_name));
|
||||
}
|
||||
if (!source->resource_line_offset.IsEmpty()) {
|
||||
line_offset = static_cast<int>(source->resource_line_offset->Value());
|
||||
}
|
||||
if (!source->resource_column_offset.IsEmpty()) {
|
||||
column_offset = static_cast<int>(source->resource_column_offset->Value());
|
||||
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> result;
|
||||
has_pending_exception =
|
||||
!i::Compiler::GetWrappedFunction(
|
||||
Utils::OpenHandle(*source->source_string), arguments_list, context,
|
||||
line_offset, column_offset, name_obj, source->resource_options)
|
||||
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));
|
||||
}
|
||||
@ -2627,37 +2628,18 @@ ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCache(
|
||||
i::Handle<i::SharedFunctionInfo> shared =
|
||||
i::Handle<i::SharedFunctionInfo>::cast(
|
||||
Utils::OpenHandle(*unbound_script));
|
||||
i::Isolate* isolate = shared->GetIsolate();
|
||||
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
|
||||
base::ElapsedTimer timer;
|
||||
if (i::FLAG_profile_deserialization) {
|
||||
timer.Start();
|
||||
}
|
||||
i::HistogramTimerScope histogram_timer(
|
||||
isolate->counters()->compile_serialize());
|
||||
i::RuntimeCallTimerScope runtimeTimer(
|
||||
isolate, i::RuntimeCallCounterId::kCompileSerialize);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileSerialize");
|
||||
|
||||
i::Handle<i::String> source_str = Utils::OpenHandle(*source);
|
||||
DCHECK(shared->is_toplevel());
|
||||
i::Handle<i::Script> script(i::Script::cast(shared->script()));
|
||||
// TODO(7110): Enable serialization of Asm modules once the AsmWasmData is
|
||||
// context independent.
|
||||
if (script->ContainsAsmModule()) return nullptr;
|
||||
if (isolate->debug()->is_loaded()) return nullptr;
|
||||
return i::CodeSerializer::Serialize(shared, source_str);
|
||||
}
|
||||
|
||||
i::ScriptData* script_data =
|
||||
i::CodeSerializer::Serialize(isolate, shared, Utils::OpenHandle(*source));
|
||||
CachedData* result = new CachedData(
|
||||
script_data->data(), script_data->length(), CachedData::BufferOwned);
|
||||
script_data->ReleaseDataOwnership();
|
||||
delete script_data;
|
||||
|
||||
if (i::FLAG_profile_deserialization) {
|
||||
i::PrintF("[Serializing took %0.3f ms]\n",
|
||||
timer.Elapsed().InMillisecondsF());
|
||||
}
|
||||
return result;
|
||||
ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCacheForFunction(
|
||||
Local<Function> function, Local<String> source) {
|
||||
i::Handle<i::SharedFunctionInfo> shared(
|
||||
i::Handle<i::JSFunction>::cast(Utils::OpenHandle(*function))->shared());
|
||||
i::Handle<i::String> source_str = Utils::OpenHandle(*source);
|
||||
CHECK(shared->is_wrapped());
|
||||
return i::CodeSerializer::Serialize(shared, source_str);
|
||||
}
|
||||
|
||||
MaybeLocal<Script> Script::Compile(Local<Context> context, Local<String> source,
|
||||
@ -9603,15 +9585,15 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
|
||||
Local<String> source) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, UnboundScript);
|
||||
i::ScriptData* script_data = nullptr;
|
||||
i::Handle<i::String> str = Utils::OpenHandle(*source);
|
||||
i::Handle<i::SharedFunctionInfo> result;
|
||||
{
|
||||
ScriptOriginOptions origin_options;
|
||||
i::ScriptData* script_data = nullptr;
|
||||
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
|
||||
i::Compiler::GetSharedFunctionInfoForScript(
|
||||
str, i::Compiler::ScriptDetails(), origin_options, nullptr,
|
||||
&script_data, ScriptCompiler::kNoCompileOptions,
|
||||
script_data, ScriptCompiler::kNoCompileOptions,
|
||||
ScriptCompiler::kNoCacheBecauseInspector,
|
||||
i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE
|
||||
: i::INSPECTOR_CODE);
|
||||
|
148
src/compiler.cc
148
src/compiler.cc
@ -1001,6 +1001,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
|
||||
DCHECK(!shared_info->is_compiled());
|
||||
|
||||
Isolate* isolate = shared_info->GetIsolate();
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
DCHECK(!shared_info->HasBytecodeArray());
|
||||
@ -1072,7 +1073,6 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
|
||||
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<SharedFunctionInfo> shared_info = handle(function->shared());
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
|
||||
// Ensure shared function info is compiled.
|
||||
if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false;
|
||||
@ -1301,56 +1301,6 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
|
||||
return result;
|
||||
}
|
||||
|
||||
MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
|
||||
Handle<String> source, Handle<FixedArray> arguments,
|
||||
Handle<Context> context, int line_offset, int column_offset,
|
||||
Handle<Object> script_name, ScriptOriginOptions options) {
|
||||
Isolate* isolate = source->GetIsolate();
|
||||
int source_length = source->length();
|
||||
isolate->counters()->total_compile_size()->Increment(source_length);
|
||||
|
||||
Handle<Script> script = isolate->factory()->NewScript(source);
|
||||
if (isolate->NeedsSourcePositionsForProfiling()) {
|
||||
Script::InitLineEnds(script);
|
||||
}
|
||||
if (!script_name.is_null()) {
|
||||
script->set_name(*script_name);
|
||||
script->set_line_offset(line_offset);
|
||||
script->set_column_offset(column_offset);
|
||||
}
|
||||
script->set_wrapped_arguments(*arguments);
|
||||
script->set_origin_options(options);
|
||||
|
||||
ParseInfo parse_info(script);
|
||||
parse_info.set_eval(); // Use an eval scope as declaration scope.
|
||||
parse_info.set_wrapped_as_function();
|
||||
if (!context->IsNativeContext()) {
|
||||
parse_info.set_outer_scope_info(handle(context->scope_info()));
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> top_level;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level,
|
||||
CompileToplevel(&parse_info, isolate), JSFunction);
|
||||
|
||||
Handle<SharedFunctionInfo> wrapped;
|
||||
SharedFunctionInfo::ScriptIterator infos(script);
|
||||
while (SharedFunctionInfo* info = infos.Next()) {
|
||||
if (info->is_wrapped()) {
|
||||
wrapped = Handle<SharedFunctionInfo>(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCHECK(!wrapped.is_null());
|
||||
|
||||
Handle<JSFunction> function =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(wrapped, context,
|
||||
NOT_TENURED);
|
||||
// OnAfterCompile has to be called after we create the JSFunction, which we
|
||||
// may require to recompile the eval for debugging, if we find a function
|
||||
// that contains break points in the eval script.
|
||||
isolate->debug()->OnAfterCompile(script);
|
||||
return function;
|
||||
}
|
||||
|
||||
bool Compiler::CodeGenerationFromStringsAllowed(Isolate* isolate,
|
||||
Handle<Context> context,
|
||||
@ -1631,17 +1581,17 @@ Handle<Script> NewScript(Isolate* isolate, Handle<String> source,
|
||||
MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
|
||||
Handle<String> source, const Compiler::ScriptDetails& script_details,
|
||||
ScriptOriginOptions origin_options, v8::Extension* extension,
|
||||
ScriptData** cached_data, ScriptCompiler::CompileOptions compile_options,
|
||||
ScriptData* cached_data, ScriptCompiler::CompileOptions compile_options,
|
||||
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
|
||||
Isolate* isolate = source->GetIsolate();
|
||||
ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
|
||||
|
||||
if (compile_options == ScriptCompiler::kNoCompileOptions ||
|
||||
compile_options == ScriptCompiler::kEagerCompile) {
|
||||
cached_data = nullptr;
|
||||
DCHECK_NULL(cached_data);
|
||||
} else {
|
||||
DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
|
||||
DCHECK(cached_data && *cached_data);
|
||||
DCHECK(cached_data);
|
||||
DCHECK_NULL(extension);
|
||||
}
|
||||
int source_length = source->length();
|
||||
@ -1677,16 +1627,13 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.CompileDeserialize");
|
||||
Handle<SharedFunctionInfo> inner_result;
|
||||
if (CodeSerializer::Deserialize(isolate, *cached_data, source)
|
||||
if (CodeSerializer::Deserialize(isolate, cached_data, source)
|
||||
.ToHandle(&inner_result)) {
|
||||
// Promote to per-isolate compilation cache.
|
||||
DCHECK(inner_result->is_compiled());
|
||||
compilation_cache->PutScript(source, isolate->native_context(),
|
||||
language_mode, inner_result);
|
||||
Handle<Script> script(Script::cast(inner_result->script()), isolate);
|
||||
if (isolate->NeedsSourcePositionsForProfiling()) {
|
||||
Script::InitLineEnds(script);
|
||||
}
|
||||
maybe_result = inner_result;
|
||||
} else {
|
||||
// Deserializer failed. Fall through to compile.
|
||||
@ -1730,6 +1677,91 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
|
||||
return maybe_result;
|
||||
}
|
||||
|
||||
MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
|
||||
Handle<String> source, Handle<FixedArray> arguments,
|
||||
Handle<Context> context, const Compiler::ScriptDetails& script_details,
|
||||
ScriptOriginOptions origin_options, ScriptData* cached_data,
|
||||
v8::ScriptCompiler::CompileOptions compile_options,
|
||||
v8::ScriptCompiler::NoCacheReason no_cache_reason) {
|
||||
Isolate* isolate = source->GetIsolate();
|
||||
ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
|
||||
|
||||
if (compile_options == ScriptCompiler::kNoCompileOptions ||
|
||||
compile_options == ScriptCompiler::kEagerCompile) {
|
||||
DCHECK_NULL(cached_data);
|
||||
} else {
|
||||
DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
|
||||
DCHECK(cached_data);
|
||||
}
|
||||
|
||||
int source_length = source->length();
|
||||
isolate->counters()->total_compile_size()->Increment(source_length);
|
||||
|
||||
LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
|
||||
|
||||
MaybeHandle<SharedFunctionInfo> maybe_result;
|
||||
bool can_consume_code_cache =
|
||||
compile_options == ScriptCompiler::kConsumeCodeCache &&
|
||||
!isolate->debug()->is_loaded();
|
||||
if (can_consume_code_cache) {
|
||||
compile_timer.set_consuming_code_cache();
|
||||
// Then check cached code provided by embedder.
|
||||
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
|
||||
RuntimeCallTimerScope runtimeTimer(
|
||||
isolate, RuntimeCallCounterId::kCompileDeserialize);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.CompileDeserialize");
|
||||
maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source);
|
||||
if (maybe_result.is_null()) {
|
||||
// Deserializer failed. Fall through to compile.
|
||||
compile_timer.set_consuming_code_cache_failed();
|
||||
}
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> wrapped;
|
||||
Handle<Script> script;
|
||||
if (!maybe_result.ToHandle(&wrapped)) {
|
||||
script = NewScript(isolate, source, script_details, origin_options,
|
||||
NOT_NATIVES_CODE);
|
||||
script->set_wrapped_arguments(*arguments);
|
||||
|
||||
ParseInfo parse_info(script);
|
||||
parse_info.set_eval(); // Use an eval scope as declaration scope.
|
||||
parse_info.set_wrapped_as_function();
|
||||
// parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
|
||||
if (!context->IsNativeContext()) {
|
||||
parse_info.set_outer_scope_info(handle(context->scope_info()));
|
||||
}
|
||||
parse_info.set_language_mode(
|
||||
stricter_language_mode(parse_info.language_mode(), language_mode));
|
||||
|
||||
Handle<SharedFunctionInfo> top_level;
|
||||
maybe_result = CompileToplevel(&parse_info, isolate);
|
||||
if (maybe_result.is_null()) isolate->ReportPendingMessages();
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level, maybe_result, JSFunction);
|
||||
|
||||
SharedFunctionInfo::ScriptIterator infos(script);
|
||||
while (SharedFunctionInfo* info = infos.Next()) {
|
||||
if (info->is_wrapped()) {
|
||||
wrapped = Handle<SharedFunctionInfo>(info, isolate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCHECK(!wrapped.is_null());
|
||||
} else {
|
||||
script = Handle<Script>(Script::cast(wrapped->script()), isolate);
|
||||
}
|
||||
|
||||
Handle<JSFunction> function =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(wrapped, context,
|
||||
NOT_TENURED);
|
||||
// OnAfterCompile has to be called after we create the JSFunction, which we
|
||||
// may require to recompile the eval for debugging, if we find a function
|
||||
// that contains break points in the eval script.
|
||||
isolate->debug()->OnAfterCompile(script);
|
||||
return function;
|
||||
}
|
||||
|
||||
ScriptCompiler::ScriptStreamingTask* Compiler::NewBackgroundCompileTask(
|
||||
ScriptStreamingData* source, Isolate* isolate) {
|
||||
return new BackgroundCompileTask(source, isolate);
|
||||
|
@ -96,25 +96,6 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
|
||||
int column_offset = 0, Handle<Object> script_name = Handle<Object>(),
|
||||
ScriptOriginOptions options = ScriptOriginOptions());
|
||||
|
||||
// Create a function that results from wrapping |source| in a function,
|
||||
// with |arguments| being a list of parameters for that function.
|
||||
MUST_USE_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
|
||||
Handle<String> source, Handle<FixedArray> arguments,
|
||||
Handle<Context> context, int line_offset = 0, int column_offset = 0,
|
||||
Handle<Object> script_name = Handle<Object>(),
|
||||
ScriptOriginOptions options = ScriptOriginOptions());
|
||||
|
||||
// Returns true if the embedder permits compiling the given source string in
|
||||
// the given context.
|
||||
static bool CodeGenerationFromStringsAllowed(Isolate* isolate,
|
||||
Handle<Context> context,
|
||||
Handle<String> source);
|
||||
|
||||
// Create a (bound) function for a String source within a context for eval.
|
||||
MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
|
||||
Handle<Context> context, Handle<String> source,
|
||||
ParseRestriction restriction, int parameters_end_pos);
|
||||
|
||||
struct ScriptDetails {
|
||||
ScriptDetails() : line_offset(0), column_offset(0) {}
|
||||
explicit ScriptDetails(Handle<Object> script_name)
|
||||
@ -127,11 +108,32 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
|
||||
i::MaybeHandle<i::FixedArray> host_defined_options;
|
||||
};
|
||||
|
||||
// Create a function that results from wrapping |source| in a function,
|
||||
// with |arguments| being a list of parameters for that function.
|
||||
MUST_USE_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
|
||||
Handle<String> source, Handle<FixedArray> arguments,
|
||||
Handle<Context> context, const ScriptDetails& script_details,
|
||||
ScriptOriginOptions origin_options, ScriptData* cached_data,
|
||||
v8::ScriptCompiler::CompileOptions compile_options,
|
||||
v8::ScriptCompiler::NoCacheReason no_cache_reason);
|
||||
|
||||
// Returns true if the embedder permits compiling the given source string in
|
||||
// the given context.
|
||||
static bool CodeGenerationFromStringsAllowed(Isolate* isolate,
|
||||
Handle<Context> context,
|
||||
Handle<String> source);
|
||||
|
||||
// Create a (bound) function for a String source within a context for eval.
|
||||
MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
|
||||
Handle<Context> context, Handle<String> source,
|
||||
ParseRestriction restriction, int parameters_end_pos);
|
||||
|
||||
|
||||
// Create a shared function info object for a String source.
|
||||
static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
|
||||
Handle<String> source, const ScriptDetails& script_details,
|
||||
ScriptOriginOptions origin_options, v8::Extension* extension,
|
||||
ScriptData** cached_data, ScriptCompiler::CompileOptions compile_options,
|
||||
ScriptData* cached_data, ScriptCompiler::CompileOptions compile_options,
|
||||
ScriptCompiler::NoCacheReason no_cache_reason,
|
||||
NativesFlag is_natives_code);
|
||||
|
||||
|
@ -30,31 +30,49 @@ ScriptData::ScriptData(const byte* data, int length)
|
||||
}
|
||||
}
|
||||
|
||||
ScriptData* CodeSerializer::Serialize(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> info,
|
||||
Handle<String> source) {
|
||||
// static
|
||||
ScriptCompiler::CachedData* CodeSerializer::Serialize(
|
||||
Handle<SharedFunctionInfo> info, Handle<String> source) {
|
||||
Isolate* isolate = info->GetIsolate();
|
||||
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
|
||||
HistogramTimerScope histogram_timer(isolate->counters()->compile_serialize());
|
||||
RuntimeCallTimerScope runtimeTimer(isolate,
|
||||
RuntimeCallCounterId::kCompileSerialize);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileSerialize");
|
||||
|
||||
base::ElapsedTimer timer;
|
||||
if (FLAG_profile_deserialization) timer.Start();
|
||||
Handle<Script> script(Script::cast(info->script()), isolate);
|
||||
if (FLAG_trace_serializer) {
|
||||
PrintF("[Serializing from");
|
||||
Object* script = info->script();
|
||||
if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
|
||||
Script::cast(script)->name()->ShortPrint();
|
||||
PrintF("]\n");
|
||||
}
|
||||
// TODO(7110): Enable serialization of Asm modules once the AsmWasmData is
|
||||
// context independent.
|
||||
if (script->ContainsAsmModule()) return nullptr;
|
||||
if (isolate->debug()->is_loaded()) return nullptr;
|
||||
|
||||
// Serialize code object.
|
||||
CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source));
|
||||
DisallowHeapAllocation no_gc;
|
||||
cs.reference_map()->AddAttachedReference(*source);
|
||||
ScriptData* ret = cs.Serialize(info);
|
||||
ScriptData* script_data = cs.Serialize(info);
|
||||
|
||||
if (FLAG_profile_deserialization) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
int length = ret->length();
|
||||
int length = script_data->length();
|
||||
PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
ScriptCompiler::CachedData* result =
|
||||
new ScriptCompiler::CachedData(script_data->data(), script_data->length(),
|
||||
ScriptCompiler::CachedData::BufferOwned);
|
||||
script_data->ReleaseDataOwnership();
|
||||
delete script_data;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ScriptData* CodeSerializer::Serialize(Handle<HeapObject> obj) {
|
||||
@ -247,6 +265,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
||||
PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG,
|
||||
result->abstract_code(), *result, name));
|
||||
}
|
||||
|
||||
if (isolate->NeedsSourcePositionsForProfiling()) {
|
||||
Handle<Script> script(Script::cast(result->script()), isolate);
|
||||
Script::InitLineEnds(script);
|
||||
}
|
||||
return scope.CloseAndEscape(result);
|
||||
}
|
||||
|
||||
|
@ -45,9 +45,8 @@ class ScriptData {
|
||||
|
||||
class CodeSerializer : public Serializer<> {
|
||||
public:
|
||||
static ScriptData* Serialize(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> info,
|
||||
Handle<String> source);
|
||||
static ScriptCompiler::CachedData* Serialize(Handle<SharedFunctionInfo> info,
|
||||
Handle<String> source);
|
||||
|
||||
ScriptData* Serialize(Handle<HeapObject> obj);
|
||||
|
||||
|
@ -1220,10 +1220,9 @@ int CountBuiltins() {
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
static Handle<SharedFunctionInfo> CompileScript(
|
||||
Isolate* isolate, Handle<String> source, Handle<String> name,
|
||||
ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) {
|
||||
ScriptData* cached_data, v8::ScriptCompiler::CompileOptions options) {
|
||||
return Compiler::GetSharedFunctionInfoForScript(
|
||||
source, Compiler::ScriptDetails(name), v8::ScriptOriginOptions(),
|
||||
nullptr, cached_data, options, ScriptCompiler::kNoCacheNoReason,
|
||||
@ -1279,7 +1278,7 @@ TEST(CodeSerializerOnePlusOne) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, copy_source, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
|
||||
@ -1317,7 +1316,7 @@ TEST(CodeSerializerPromotedToCompilationCache) {
|
||||
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
Handle<SharedFunctionInfo> copy = CompileScript(
|
||||
isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache);
|
||||
isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
|
||||
|
||||
MaybeHandle<SharedFunctionInfo> shared =
|
||||
isolate->compilation_cache()->LookupScript(
|
||||
@ -1365,7 +1364,7 @@ TEST(CodeSerializerInternalizedString) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, copy_source, Handle<String>(), &script_data,
|
||||
copy = CompileScript(isolate, copy_source, Handle<String>(), script_data,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1418,7 +1417,7 @@ TEST(CodeSerializerLargeCodeObject) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1492,7 +1491,7 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1545,7 +1544,7 @@ TEST(CodeSerializerLargeStrings) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1613,7 +1612,7 @@ TEST(CodeSerializerThreeBigStrings) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1731,7 +1730,7 @@ TEST(CodeSerializerExternalString) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_string, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_string, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1788,7 +1787,7 @@ TEST(CodeSerializerLargeExternalString) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), &cache,
|
||||
copy = CompileScript(isolate, source_str, Handle<String>(), cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -1837,7 +1836,7 @@ TEST(CodeSerializerExternalScriptName) {
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = CompileScript(isolate, source_string, name, &cache,
|
||||
copy = CompileScript(isolate, source_string, name, cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
@ -2218,8 +2217,9 @@ TEST(Regress503552) {
|
||||
|
||||
heap::SimulateIncrementalMarking(isolate->heap());
|
||||
|
||||
script_data = CodeSerializer::Serialize(isolate, shared, source);
|
||||
delete script_data;
|
||||
v8::ScriptCompiler::CachedData* cache_data =
|
||||
CodeSerializer::Serialize(shared, source);
|
||||
delete cache_data;
|
||||
}
|
||||
|
||||
TEST(SnapshotCreatorMultipleContexts) {
|
||||
@ -3420,7 +3420,7 @@ TEST(WeakArraySerializationInCodeCache) {
|
||||
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
Handle<SharedFunctionInfo> copy = CompileScript(
|
||||
isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache);
|
||||
isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
|
||||
|
||||
// Verify that the pointers in shared_function_infos are weak.
|
||||
WeakFixedArray* sfis = Script::cast(copy->script())->shared_function_infos();
|
||||
@ -3429,5 +3429,42 @@ TEST(WeakArraySerializationInCodeCache) {
|
||||
delete cache;
|
||||
}
|
||||
|
||||
TEST(CachedCompileFunctionInContext) {
|
||||
DisableAlwaysOpt();
|
||||
LocalContext env;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
|
||||
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
v8::Local<v8::String> source = v8_str("return x*x;");
|
||||
v8::Local<v8::String> arg_str = v8_str("x");
|
||||
ScriptCompiler::CachedData* cache;
|
||||
{
|
||||
v8::ScriptCompiler::Source script_source(source);
|
||||
v8::Local<v8::Function> fun =
|
||||
v8::ScriptCompiler::CompileFunctionInContext(
|
||||
env.local(), &script_source, 1, &arg_str, 0, nullptr,
|
||||
v8::ScriptCompiler::kEagerCompile)
|
||||
.ToLocalChecked();
|
||||
cache = v8::ScriptCompiler::CreateCodeCacheForFunction(fun, source);
|
||||
}
|
||||
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
v8::ScriptCompiler::Source script_source(source, cache);
|
||||
v8::Local<v8::Function> fun =
|
||||
v8::ScriptCompiler::CompileFunctionInContext(
|
||||
env.local(), &script_source, 1, &arg_str, 0, nullptr,
|
||||
v8::ScriptCompiler::kConsumeCodeCache)
|
||||
.ToLocalChecked();
|
||||
v8::Local<v8::Value> arg = v8_num(3);
|
||||
v8::Local<v8::Value> result =
|
||||
fun->Call(env.local(), v8::Undefined(CcTest::isolate()), 1, &arg)
|
||||
.ToLocalChecked();
|
||||
CHECK_EQ(9, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user