Commit e7105521 authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

[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/980944Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52299}
parent 9a29c902
...@@ -1569,7 +1569,9 @@ class V8_EXPORT ScriptCompiler { ...@@ -1569,7 +1569,9 @@ class V8_EXPORT ScriptCompiler {
static V8_WARN_UNUSED_RESULT MaybeLocal<Function> CompileFunctionInContext( static V8_WARN_UNUSED_RESULT MaybeLocal<Function> CompileFunctionInContext(
Local<Context> context, Source* source, size_t arguments_count, Local<Context> 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[]); Local<Object> context_extensions[],
CompileOptions options = kNoCompileOptions,
NoCacheReason no_cache_reason = kNoCacheNoReason);
/** /**
* Creates and returns code cache for the specified unbound_script. * Creates and returns code cache for the specified unbound_script.
...@@ -1579,6 +1581,15 @@ class V8_EXPORT ScriptCompiler { ...@@ -1579,6 +1581,15 @@ class V8_EXPORT ScriptCompiler {
static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script, static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script,
Local<String> source); 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: private:
static V8_WARN_UNUSED_RESULT MaybeLocal<UnboundScript> CompileUnboundInternal( static V8_WARN_UNUSED_RESULT MaybeLocal<UnboundScript> CompileUnboundInternal(
Isolate* isolate, Source* source, CompileOptions options, Isolate* isolate, Source* source, CompileOptions options,
......
...@@ -2398,22 +2398,14 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( ...@@ -2398,22 +2398,14 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
source->host_defined_options); source->host_defined_options);
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info = i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript( 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); 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) { if (options == kConsumeCodeCache) {
source->cached_data->rejected = script_data->rejected(); source->cached_data->rejected = script_data->rejected();
} }
delete script_data; delete script_data;
has_pending_exception = !maybe_function_info.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(UnboundScript);
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
} }
...@@ -2498,15 +2490,19 @@ class IsIdentifierHelper { ...@@ -2498,15 +2490,19 @@ class IsIdentifierHelper {
DISALLOW_COPY_AND_ASSIGN(IsIdentifierHelper); DISALLOW_COPY_AND_ASSIGN(IsIdentifierHelper);
}; };
MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext( 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[]) { Local<Object> context_extensions[], CompileOptions options,
NoCacheReason no_cache_reason) {
PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext, PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext,
Function); Function);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler"); 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::Context> context = Utils::OpenHandle(*v8_context);
i::Handle<i::SharedFunctionInfo> outer_info(context->closure()->shared(), i::Handle<i::SharedFunctionInfo> outer_info(context->closure()->shared(),
isolate); isolate);
...@@ -2535,25 +2531,30 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext( ...@@ -2535,25 +2531,30 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
extension); extension);
} }
i::Handle<i::Object> name_obj; i::Compiler::ScriptDetails script_details = GetScriptDetails(
int line_offset = 0; isolate, source->resource_name, source->resource_line_offset,
int column_offset = 0; source->resource_column_offset, source->source_map_url,
if (!source->resource_name.IsEmpty()) { source->host_defined_options);
name_obj = Utils::OpenHandle(*(source->resource_name));
} i::ScriptData* script_data = nullptr;
if (!source->resource_line_offset.IsEmpty()) { if (options == kConsumeCodeCache) {
line_offset = static_cast<int>(source->resource_line_offset->Value()); DCHECK(source->cached_data);
} // ScriptData takes care of pointer-aligning the data.
if (!source->resource_column_offset.IsEmpty()) { script_data = new i::ScriptData(source->cached_data->data,
column_offset = static_cast<int>(source->resource_column_offset->Value()); source->cached_data->length);
} }
i::Handle<i::JSFunction> result; i::Handle<i::JSFunction> result;
has_pending_exception = has_pending_exception =
!i::Compiler::GetWrappedFunction( !i::Compiler::GetWrappedFunction(
Utils::OpenHandle(*source->source_string), arguments_list, context, 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); .ToHandle(&result);
if (options == kConsumeCodeCache) {
source->cached_data->rejected = script_data->rejected();
}
delete script_data;
RETURN_ON_FAILED_EXECUTION(Function); RETURN_ON_FAILED_EXECUTION(Function);
RETURN_ESCAPED(Utils::CallableToLocal(result)); RETURN_ESCAPED(Utils::CallableToLocal(result));
} }
...@@ -2627,37 +2628,18 @@ ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCache( ...@@ -2627,37 +2628,18 @@ ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCache(
i::Handle<i::SharedFunctionInfo> shared = i::Handle<i::SharedFunctionInfo> shared =
i::Handle<i::SharedFunctionInfo>::cast( i::Handle<i::SharedFunctionInfo>::cast(
Utils::OpenHandle(*unbound_script)); Utils::OpenHandle(*unbound_script));
i::Isolate* isolate = shared->GetIsolate(); i::Handle<i::String> source_str = Utils::OpenHandle(*source);
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");
DCHECK(shared->is_toplevel()); DCHECK(shared->is_toplevel());
i::Handle<i::Script> script(i::Script::cast(shared->script())); return i::CodeSerializer::Serialize(shared, source_str);
// 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;
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) { ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCacheForFunction(
i::PrintF("[Serializing took %0.3f ms]\n", Local<Function> function, Local<String> source) {
timer.Elapsed().InMillisecondsF()); i::Handle<i::SharedFunctionInfo> shared(
} i::Handle<i::JSFunction>::cast(Utils::OpenHandle(*function))->shared());
return result; 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, MaybeLocal<Script> Script::Compile(Local<Context> context, Local<String> source,
...@@ -9603,15 +9585,15 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate, ...@@ -9603,15 +9585,15 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
Local<String> source) { Local<String> source) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, UnboundScript); 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::String> str = Utils::OpenHandle(*source);
i::Handle<i::SharedFunctionInfo> result; i::Handle<i::SharedFunctionInfo> result;
{ {
ScriptOriginOptions origin_options; ScriptOriginOptions origin_options;
i::ScriptData* script_data = nullptr;
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info = i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript( i::Compiler::GetSharedFunctionInfoForScript(
str, i::Compiler::ScriptDetails(), origin_options, nullptr, str, i::Compiler::ScriptDetails(), origin_options, nullptr,
&script_data, ScriptCompiler::kNoCompileOptions, script_data, ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheBecauseInspector, ScriptCompiler::kNoCacheBecauseInspector,
i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE
: i::INSPECTOR_CODE); : i::INSPECTOR_CODE);
......
...@@ -1001,6 +1001,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, ...@@ -1001,6 +1001,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
DCHECK(!shared_info->is_compiled()); DCHECK(!shared_info->is_compiled());
Isolate* isolate = shared_info->GetIsolate(); Isolate* isolate = shared_info->GetIsolate();
DCHECK(AllowCompilation::IsAllowed(isolate));
DCHECK(ThreadId::Current().Equals(isolate->thread_id())); DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
DCHECK(!isolate->has_pending_exception()); DCHECK(!isolate->has_pending_exception());
DCHECK(!shared_info->HasBytecodeArray()); DCHECK(!shared_info->HasBytecodeArray());
...@@ -1072,7 +1073,6 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { ...@@ -1072,7 +1073,6 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
Isolate* isolate = function->GetIsolate(); Isolate* isolate = function->GetIsolate();
Handle<SharedFunctionInfo> shared_info = handle(function->shared()); Handle<SharedFunctionInfo> shared_info = handle(function->shared());
DCHECK(AllowCompilation::IsAllowed(isolate));
// Ensure shared function info is compiled. // Ensure shared function info is compiled.
if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false; if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false;
...@@ -1301,56 +1301,6 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( ...@@ -1301,56 +1301,6 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
return result; 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, bool Compiler::CodeGenerationFromStringsAllowed(Isolate* isolate,
Handle<Context> context, Handle<Context> context,
...@@ -1631,17 +1581,17 @@ Handle<Script> NewScript(Isolate* isolate, Handle<String> source, ...@@ -1631,17 +1581,17 @@ Handle<Script> NewScript(Isolate* isolate, Handle<String> source,
MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
Handle<String> source, const Compiler::ScriptDetails& script_details, Handle<String> source, const Compiler::ScriptDetails& script_details,
ScriptOriginOptions origin_options, v8::Extension* extension, 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) { ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
Isolate* isolate = source->GetIsolate(); Isolate* isolate = source->GetIsolate();
ScriptCompileTimerScope compile_timer(isolate, no_cache_reason); ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
if (compile_options == ScriptCompiler::kNoCompileOptions || if (compile_options == ScriptCompiler::kNoCompileOptions ||
compile_options == ScriptCompiler::kEagerCompile) { compile_options == ScriptCompiler::kEagerCompile) {
cached_data = nullptr; DCHECK_NULL(cached_data);
} else { } else {
DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache); DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
DCHECK(cached_data && *cached_data); DCHECK(cached_data);
DCHECK_NULL(extension); DCHECK_NULL(extension);
} }
int source_length = source->length(); int source_length = source->length();
...@@ -1677,16 +1627,13 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( ...@@ -1677,16 +1627,13 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileDeserialize"); "V8.CompileDeserialize");
Handle<SharedFunctionInfo> inner_result; Handle<SharedFunctionInfo> inner_result;
if (CodeSerializer::Deserialize(isolate, *cached_data, source) if (CodeSerializer::Deserialize(isolate, cached_data, source)
.ToHandle(&inner_result)) { .ToHandle(&inner_result)) {
// Promote to per-isolate compilation cache. // Promote to per-isolate compilation cache.
DCHECK(inner_result->is_compiled()); DCHECK(inner_result->is_compiled());
compilation_cache->PutScript(source, isolate->native_context(), compilation_cache->PutScript(source, isolate->native_context(),
language_mode, inner_result); language_mode, inner_result);
Handle<Script> script(Script::cast(inner_result->script()), isolate); Handle<Script> script(Script::cast(inner_result->script()), isolate);
if (isolate->NeedsSourcePositionsForProfiling()) {
Script::InitLineEnds(script);
}
maybe_result = inner_result; maybe_result = inner_result;
} else { } else {
// Deserializer failed. Fall through to compile. // Deserializer failed. Fall through to compile.
...@@ -1730,6 +1677,91 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( ...@@ -1730,6 +1677,91 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
return maybe_result; 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( ScriptCompiler::ScriptStreamingTask* Compiler::NewBackgroundCompileTask(
ScriptStreamingData* source, Isolate* isolate) { ScriptStreamingData* source, Isolate* isolate) {
return new BackgroundCompileTask(source, isolate); return new BackgroundCompileTask(source, isolate);
......
...@@ -96,13 +96,26 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -96,13 +96,26 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
int column_offset = 0, Handle<Object> script_name = Handle<Object>(), int column_offset = 0, Handle<Object> script_name = Handle<Object>(),
ScriptOriginOptions options = ScriptOriginOptions()); ScriptOriginOptions options = ScriptOriginOptions());
struct ScriptDetails {
ScriptDetails() : line_offset(0), column_offset(0) {}
explicit ScriptDetails(Handle<Object> script_name)
: line_offset(0), column_offset(0), name_obj(script_name) {}
int line_offset;
int column_offset;
i::MaybeHandle<i::Object> name_obj;
i::MaybeHandle<i::Object> source_map_url;
i::MaybeHandle<i::FixedArray> host_defined_options;
};
// Create a function that results from wrapping |source| in a function, // Create a function that results from wrapping |source| in a function,
// with |arguments| being a list of parameters for that function. // with |arguments| being a list of parameters for that function.
MUST_USE_RESULT static MaybeHandle<JSFunction> GetWrappedFunction( MUST_USE_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
Handle<String> source, Handle<FixedArray> arguments, Handle<String> source, Handle<FixedArray> arguments,
Handle<Context> context, int line_offset = 0, int column_offset = 0, Handle<Context> context, const ScriptDetails& script_details,
Handle<Object> script_name = Handle<Object>(), ScriptOriginOptions origin_options, ScriptData* cached_data,
ScriptOriginOptions options = ScriptOriginOptions()); v8::ScriptCompiler::CompileOptions compile_options,
v8::ScriptCompiler::NoCacheReason no_cache_reason);
// Returns true if the embedder permits compiling the given source string in // Returns true if the embedder permits compiling the given source string in
// the given context. // the given context.
...@@ -115,23 +128,12 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -115,23 +128,12 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
Handle<Context> context, Handle<String> source, Handle<Context> context, Handle<String> source,
ParseRestriction restriction, int parameters_end_pos); ParseRestriction restriction, int parameters_end_pos);
struct ScriptDetails {
ScriptDetails() : line_offset(0), column_offset(0) {}
explicit ScriptDetails(Handle<Object> script_name)
: line_offset(0), column_offset(0), name_obj(script_name) {}
int line_offset;
int column_offset;
i::MaybeHandle<i::Object> name_obj;
i::MaybeHandle<i::Object> source_map_url;
i::MaybeHandle<i::FixedArray> host_defined_options;
};
// Create a shared function info object for a String source. // Create a shared function info object for a String source.
static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript( static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
Handle<String> source, const ScriptDetails& script_details, Handle<String> source, const ScriptDetails& script_details,
ScriptOriginOptions origin_options, v8::Extension* extension, 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, ScriptCompiler::NoCacheReason no_cache_reason,
NativesFlag is_natives_code); NativesFlag is_natives_code);
......
...@@ -30,31 +30,49 @@ ScriptData::ScriptData(const byte* data, int length) ...@@ -30,31 +30,49 @@ ScriptData::ScriptData(const byte* data, int length)
} }
} }
ScriptData* CodeSerializer::Serialize(Isolate* isolate, // static
Handle<SharedFunctionInfo> info, ScriptCompiler::CachedData* CodeSerializer::Serialize(
Handle<String> source) { 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; base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start(); if (FLAG_profile_deserialization) timer.Start();
Handle<Script> script(Script::cast(info->script()), isolate);
if (FLAG_trace_serializer) { if (FLAG_trace_serializer) {
PrintF("[Serializing from"); PrintF("[Serializing from");
Object* script = info->script(); Object* script = info->script();
if (script->IsScript()) Script::cast(script)->name()->ShortPrint(); Script::cast(script)->name()->ShortPrint();
PrintF("]\n"); 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. // Serialize code object.
CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source)); CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source));
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
cs.reference_map()->AddAttachedReference(*source); cs.reference_map()->AddAttachedReference(*source);
ScriptData* ret = cs.Serialize(info); ScriptData* script_data = cs.Serialize(info);
if (FLAG_profile_deserialization) { if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF(); 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); 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) { ScriptData* CodeSerializer::Serialize(Handle<HeapObject> obj) {
...@@ -247,6 +265,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -247,6 +265,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG, PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG,
result->abstract_code(), *result, name)); result->abstract_code(), *result, name));
} }
if (isolate->NeedsSourcePositionsForProfiling()) {
Handle<Script> script(Script::cast(result->script()), isolate);
Script::InitLineEnds(script);
}
return scope.CloseAndEscape(result); return scope.CloseAndEscape(result);
} }
......
...@@ -45,8 +45,7 @@ class ScriptData { ...@@ -45,8 +45,7 @@ class ScriptData {
class CodeSerializer : public Serializer<> { class CodeSerializer : public Serializer<> {
public: public:
static ScriptData* Serialize(Isolate* isolate, static ScriptCompiler::CachedData* Serialize(Handle<SharedFunctionInfo> info,
Handle<SharedFunctionInfo> info,
Handle<String> source); Handle<String> source);
ScriptData* Serialize(Handle<HeapObject> obj); ScriptData* Serialize(Handle<HeapObject> obj);
......
...@@ -1220,10 +1220,9 @@ int CountBuiltins() { ...@@ -1220,10 +1220,9 @@ int CountBuiltins() {
return counter; return counter;
} }
static Handle<SharedFunctionInfo> CompileScript( static Handle<SharedFunctionInfo> CompileScript(
Isolate* isolate, Handle<String> source, Handle<String> name, 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( return Compiler::GetSharedFunctionInfoForScript(
source, Compiler::ScriptDetails(name), v8::ScriptOriginOptions(), source, Compiler::ScriptDetails(name), v8::ScriptOriginOptions(),
nullptr, cached_data, options, ScriptCompiler::kNoCacheNoReason, nullptr, cached_data, options, ScriptCompiler::kNoCacheNoReason,
...@@ -1279,7 +1278,7 @@ TEST(CodeSerializerOnePlusOne) { ...@@ -1279,7 +1278,7 @@ TEST(CodeSerializerOnePlusOne) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, copy_source, Handle<String>(), &cache, copy = CompileScript(isolate, copy_source, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
...@@ -1317,7 +1316,7 @@ TEST(CodeSerializerPromotedToCompilationCache) { ...@@ -1317,7 +1316,7 @@ TEST(CodeSerializerPromotedToCompilationCache) {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
Handle<SharedFunctionInfo> copy = CompileScript( Handle<SharedFunctionInfo> copy = CompileScript(
isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache); isolate, src, src, cache, v8::ScriptCompiler::kConsumeCodeCache);
MaybeHandle<SharedFunctionInfo> shared = MaybeHandle<SharedFunctionInfo> shared =
isolate->compilation_cache()->LookupScript( isolate->compilation_cache()->LookupScript(
...@@ -1365,7 +1364,7 @@ TEST(CodeSerializerInternalizedString) { ...@@ -1365,7 +1364,7 @@ TEST(CodeSerializerInternalizedString) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); 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); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1418,7 +1417,7 @@ TEST(CodeSerializerLargeCodeObject) { ...@@ -1418,7 +1417,7 @@ TEST(CodeSerializerLargeCodeObject) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_str, Handle<String>(), &cache, copy = CompileScript(isolate, source_str, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1492,7 +1491,7 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { ...@@ -1492,7 +1491,7 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_str, Handle<String>(), &cache, copy = CompileScript(isolate, source_str, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1545,7 +1544,7 @@ TEST(CodeSerializerLargeStrings) { ...@@ -1545,7 +1544,7 @@ TEST(CodeSerializerLargeStrings) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_str, Handle<String>(), &cache, copy = CompileScript(isolate, source_str, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1613,7 +1612,7 @@ TEST(CodeSerializerThreeBigStrings) { ...@@ -1613,7 +1612,7 @@ TEST(CodeSerializerThreeBigStrings) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_str, Handle<String>(), &cache, copy = CompileScript(isolate, source_str, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1731,7 +1730,7 @@ TEST(CodeSerializerExternalString) { ...@@ -1731,7 +1730,7 @@ TEST(CodeSerializerExternalString) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_string, Handle<String>(), &cache, copy = CompileScript(isolate, source_string, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1788,7 +1787,7 @@ TEST(CodeSerializerLargeExternalString) { ...@@ -1788,7 +1787,7 @@ TEST(CodeSerializerLargeExternalString) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_str, Handle<String>(), &cache, copy = CompileScript(isolate, source_str, Handle<String>(), cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -1837,7 +1836,7 @@ TEST(CodeSerializerExternalScriptName) { ...@@ -1837,7 +1836,7 @@ TEST(CodeSerializerExternalScriptName) {
Handle<SharedFunctionInfo> copy; Handle<SharedFunctionInfo> copy;
{ {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, source_string, name, &cache, copy = CompileScript(isolate, source_string, name, cache,
v8::ScriptCompiler::kConsumeCodeCache); v8::ScriptCompiler::kConsumeCodeCache);
} }
CHECK_NE(*orig, *copy); CHECK_NE(*orig, *copy);
...@@ -2218,8 +2217,9 @@ TEST(Regress503552) { ...@@ -2218,8 +2217,9 @@ TEST(Regress503552) {
heap::SimulateIncrementalMarking(isolate->heap()); heap::SimulateIncrementalMarking(isolate->heap());
script_data = CodeSerializer::Serialize(isolate, shared, source); v8::ScriptCompiler::CachedData* cache_data =
delete script_data; CodeSerializer::Serialize(shared, source);
delete cache_data;
} }
TEST(SnapshotCreatorMultipleContexts) { TEST(SnapshotCreatorMultipleContexts) {
...@@ -3420,7 +3420,7 @@ TEST(WeakArraySerializationInCodeCache) { ...@@ -3420,7 +3420,7 @@ TEST(WeakArraySerializationInCodeCache) {
DisallowCompilation no_compile_expected(isolate); DisallowCompilation no_compile_expected(isolate);
Handle<SharedFunctionInfo> copy = CompileScript( 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. // Verify that the pointers in shared_function_infos are weak.
WeakFixedArray* sfis = Script::cast(copy->script())->shared_function_infos(); WeakFixedArray* sfis = Script::cast(copy->script())->shared_function_infos();
...@@ -3429,5 +3429,42 @@ TEST(WeakArraySerializationInCodeCache) { ...@@ -3429,5 +3429,42 @@ TEST(WeakArraySerializationInCodeCache) {
delete cache; 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 internal
} // namespace v8 } // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment