Revert "Add support to produce code cache after execute."
This reverts commit 5d4a090377
.
Reason for revert: Speculative revert due to timeouts on testing with
--isolates:
https://build.chromium.org/p/client.v8/builders/V8%20Linux/builds/21889
https://build.chromium.org/p/client.v8/builders/V8%20Linux%20-%20debug/builds/18138
Original change's description:
> Add support to produce code cache after execute.
>
> Adds new API function to request code cache. Earlier code cache was
> produced along with compile requests. This new API allows us to request
> code cache after executing. Also adds support in the code serializer to
> serialize after executing the script.
>
> Bug: chromium:783124
> Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
> Change-Id: Id7b972a2b4c8dcf7a6d9f5ea210890ae968320bd
> Reviewed-on: https://chromium-review.googlesource.com/781767
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Commit-Queue: Mythri Alle <mythria@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49717}
TBR=ulan@chromium.org,rmcilroy@chromium.org,yangguo@chromium.org,mythria@chromium.org
Change-Id: Id9e0285e73bbc3ea3908b4b7bbf6599e4f7cd76e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:783124
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/796870
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49722}
This commit is contained in:
parent
27fd921a28
commit
5ff7af939e
@ -1576,14 +1576,6 @@ 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[]);
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and returns code cache for the specified unbound_script.
|
|
||||||
* This will return nullptr if the script cannot be serialized. The
|
|
||||||
* CachedData returned by this function should be owned by the caller.
|
|
||||||
*/
|
|
||||||
static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script,
|
|
||||||
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,
|
||||||
|
20
src/api.cc
20
src/api.cc
@ -2660,26 +2660,6 @@ uint32_t ScriptCompiler::CachedDataVersionTag() {
|
|||||||
static_cast<uint32_t>(internal::CpuFeatures::SupportedFeatures())));
|
static_cast<uint32_t>(internal::CpuFeatures::SupportedFeatures())));
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptCompiler::CachedData* ScriptCompiler::CreateCodeCache(
|
|
||||||
Local<UnboundScript> unbound_script, Local<String> source) {
|
|
||||||
i::Handle<i::SharedFunctionInfo> shared =
|
|
||||||
i::Handle<i::SharedFunctionInfo>::cast(
|
|
||||||
Utils::OpenHandle(*unbound_script));
|
|
||||||
DCHECK(shared->is_toplevel());
|
|
||||||
i::Handle<i::Script> script(i::Script::cast(shared->script()));
|
|
||||||
i::Isolate* isolate = shared->GetIsolate();
|
|
||||||
// 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;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeLocal<Script> Script::Compile(Local<Context> context, Local<String> source,
|
MaybeLocal<Script> Script::Compile(Local<Context> context, Local<String> source,
|
||||||
ScriptOrigin* origin) {
|
ScriptOrigin* origin) {
|
||||||
|
@ -1176,6 +1176,15 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
bool ContainsAsmModule(Handle<Script> script) {
|
||||||
|
DisallowHeapAllocation no_gc;
|
||||||
|
SharedFunctionInfo::ScriptIterator iter(script);
|
||||||
|
while (SharedFunctionInfo* info = iter.Next()) {
|
||||||
|
if (info->HasAsmWasmData()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldProduceCodeCache(ScriptCompiler::CompileOptions options) {
|
bool ShouldProduceCodeCache(ScriptCompiler::CompileOptions options) {
|
||||||
return options == ScriptCompiler::kProduceCodeCache ||
|
return options == ScriptCompiler::kProduceCodeCache ||
|
||||||
options == ScriptCompiler::kProduceFullCodeCache;
|
options == ScriptCompiler::kProduceFullCodeCache;
|
||||||
@ -1563,7 +1572,7 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
|
|||||||
compilation_cache->PutScript(source, context, language_mode, result,
|
compilation_cache->PutScript(source, context, language_mode, result,
|
||||||
vector);
|
vector);
|
||||||
if (ShouldProduceCodeCache(compile_options) &&
|
if (ShouldProduceCodeCache(compile_options) &&
|
||||||
!script->ContainsAsmModule()) {
|
!ContainsAsmModule(script)) {
|
||||||
compile_timer.set_producing_code_cache();
|
compile_timer.set_producing_code_cache();
|
||||||
|
|
||||||
HistogramTimerScope histogram_timer(
|
HistogramTimerScope histogram_timer(
|
||||||
|
199
src/d8.cc
199
src/d8.cc
@ -506,8 +506,6 @@ std::vector<Worker*> Shell::workers_;
|
|||||||
std::vector<ExternalizedContents> Shell::externalized_contents_;
|
std::vector<ExternalizedContents> Shell::externalized_contents_;
|
||||||
base::LazyMutex Shell::isolate_status_lock_;
|
base::LazyMutex Shell::isolate_status_lock_;
|
||||||
std::map<v8::Isolate*, bool> Shell::isolate_status_;
|
std::map<v8::Isolate*, bool> Shell::isolate_status_;
|
||||||
std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
|
|
||||||
Shell::cached_code_map_;
|
|
||||||
|
|
||||||
Global<Context> Shell::evaluation_context_;
|
Global<Context> Shell::evaluation_context_;
|
||||||
ArrayBuffer::Allocator* Shell::array_buffer_allocator;
|
ArrayBuffer::Allocator* Shell::array_buffer_allocator;
|
||||||
@ -568,37 +566,95 @@ class BackgroundCompileThread : public base::Thread {
|
|||||||
std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task_;
|
std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task_;
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptCompiler::CachedData* Shell::LookupCodeCache(Isolate* isolate,
|
ScriptCompiler::CachedData* CompileForCachedData(
|
||||||
Local<Value> name) {
|
Local<String> source, Local<Value> name,
|
||||||
CHECK(name->IsString());
|
ScriptCompiler::CompileOptions compile_options) {
|
||||||
v8::String::Utf8Value key(isolate, name);
|
int source_length = source->Length();
|
||||||
DCHECK(*key);
|
uint16_t* source_buffer = new uint16_t[source_length];
|
||||||
auto entry = cached_code_map_.find(*key);
|
source->Write(source_buffer, 0, source_length);
|
||||||
if (entry != cached_code_map_.end() && entry->second) {
|
int name_length = 0;
|
||||||
int length = entry->second->length;
|
uint16_t* name_buffer = nullptr;
|
||||||
uint8_t* cache = new uint8_t[length];
|
if (name->IsString()) {
|
||||||
memcpy(cache, entry->second->data, length);
|
Local<String> name_string = Local<String>::Cast(name);
|
||||||
ScriptCompiler::CachedData* cached_data = new ScriptCompiler::CachedData(
|
name_length = name_string->Length();
|
||||||
cache, length, ScriptCompiler::CachedData::BufferOwned);
|
name_buffer = new uint16_t[name_length];
|
||||||
return cached_data;
|
name_string->Write(name_buffer, 0, name_length);
|
||||||
}
|
}
|
||||||
return nullptr;
|
Isolate::CreateParams create_params;
|
||||||
|
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
|
||||||
|
i::FLAG_hash_seed ^= 1337; // Use a different hash seed.
|
||||||
|
Isolate* temp_isolate = Isolate::New(create_params);
|
||||||
|
i::FLAG_hash_seed ^= 1337; // Restore old hash seed.
|
||||||
|
temp_isolate->SetHostImportModuleDynamicallyCallback(
|
||||||
|
Shell::HostImportModuleDynamically);
|
||||||
|
temp_isolate->SetHostInitializeImportMetaObjectCallback(
|
||||||
|
Shell::HostInitializeImportMetaObject);
|
||||||
|
ScriptCompiler::CachedData* result = nullptr;
|
||||||
|
{
|
||||||
|
Isolate::Scope isolate_scope(temp_isolate);
|
||||||
|
HandleScope handle_scope(temp_isolate);
|
||||||
|
Context::Scope context_scope(Context::New(temp_isolate));
|
||||||
|
Local<String> source_copy =
|
||||||
|
v8::String::NewFromTwoByte(temp_isolate, source_buffer,
|
||||||
|
v8::NewStringType::kNormal, source_length)
|
||||||
|
.ToLocalChecked();
|
||||||
|
Local<Value> name_copy;
|
||||||
|
if (name_buffer) {
|
||||||
|
name_copy =
|
||||||
|
v8::String::NewFromTwoByte(temp_isolate, name_buffer,
|
||||||
|
v8::NewStringType::kNormal, name_length)
|
||||||
|
.ToLocalChecked();
|
||||||
|
} else {
|
||||||
|
name_copy = v8::Undefined(temp_isolate);
|
||||||
|
}
|
||||||
|
ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
|
||||||
|
if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
|
||||||
|
compile_options)
|
||||||
|
.IsEmpty() &&
|
||||||
|
script_source.GetCachedData()) {
|
||||||
|
int length = script_source.GetCachedData()->length;
|
||||||
|
uint8_t* cache = new uint8_t[length];
|
||||||
|
memcpy(cache, script_source.GetCachedData()->data, length);
|
||||||
|
result = new ScriptCompiler::CachedData(
|
||||||
|
cache, length, ScriptCompiler::CachedData::BufferOwned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp_isolate->Dispose();
|
||||||
|
delete[] source_buffer;
|
||||||
|
delete[] name_buffer;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::StoreInCodeCache(Isolate* isolate, Local<Value> name,
|
|
||||||
const ScriptCompiler::CachedData* cache_data) {
|
// Compile a string within the current v8 context.
|
||||||
CHECK(name->IsString());
|
MaybeLocal<Script> Shell::CompileString(
|
||||||
if (cache_data == nullptr) return;
|
Isolate* isolate, Local<String> source, Local<Value> name,
|
||||||
v8::String::Utf8Value key(isolate, name);
|
ScriptCompiler::CompileOptions compile_options) {
|
||||||
DCHECK(*key);
|
Local<Context> context(isolate->GetCurrentContext());
|
||||||
int length = cache_data->length;
|
ScriptOrigin origin(name);
|
||||||
uint8_t* cache = new uint8_t[length];
|
if (compile_options == ScriptCompiler::kNoCompileOptions) {
|
||||||
memcpy(cache, cache_data->data, length);
|
ScriptCompiler::Source script_source(source, origin);
|
||||||
cached_code_map_[*key] = std::unique_ptr<ScriptCompiler::CachedData>(
|
return ScriptCompiler::Compile(context, &script_source, compile_options);
|
||||||
new ScriptCompiler::CachedData(cache, length,
|
}
|
||||||
ScriptCompiler::CachedData::BufferOwned));
|
|
||||||
|
ScriptCompiler::CachedData* data =
|
||||||
|
CompileForCachedData(source, name, compile_options);
|
||||||
|
ScriptCompiler::Source cached_source(source, origin, data);
|
||||||
|
if (compile_options == ScriptCompiler::kProduceCodeCache) {
|
||||||
|
compile_options = ScriptCompiler::kConsumeCodeCache;
|
||||||
|
} else if (compile_options == ScriptCompiler::kProduceParserCache) {
|
||||||
|
compile_options = ScriptCompiler::kConsumeParserCache;
|
||||||
|
} else {
|
||||||
|
DCHECK(false); // A new compile option?
|
||||||
|
}
|
||||||
|
if (data == nullptr) compile_options = ScriptCompiler::kNoCompileOptions;
|
||||||
|
MaybeLocal<Script> result =
|
||||||
|
ScriptCompiler::Compile(context, &cached_source, compile_options);
|
||||||
|
CHECK(data == nullptr || !data->rejected);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Executes a string within the current v8 context.
|
// Executes a string within the current v8 context.
|
||||||
bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
||||||
Local<Value> name, bool print_result,
|
Local<Value> name, bool print_result,
|
||||||
@ -615,22 +671,7 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
|||||||
Local<Context>::New(isolate, data->realms_[data->realm_current_]);
|
Local<Context>::New(isolate, data->realms_[data->realm_current_]);
|
||||||
Context::Scope context_scope(realm);
|
Context::Scope context_scope(realm);
|
||||||
MaybeLocal<Script> maybe_script;
|
MaybeLocal<Script> maybe_script;
|
||||||
Local<Context> context(isolate->GetCurrentContext());
|
if (options.stress_background_compile) {
|
||||||
ScriptOrigin origin(name);
|
|
||||||
|
|
||||||
if (options.compile_options == ScriptCompiler::kConsumeCodeCache) {
|
|
||||||
ScriptCompiler::CachedData* cached_code = LookupCodeCache(isolate, name);
|
|
||||||
if (cached_code != nullptr) {
|
|
||||||
ScriptCompiler::Source script_source(source, origin, cached_code);
|
|
||||||
maybe_script = ScriptCompiler::Compile(context, &script_source,
|
|
||||||
options.compile_options);
|
|
||||||
CHECK(!cached_code->rejected);
|
|
||||||
} else {
|
|
||||||
ScriptCompiler::Source script_source(source, origin);
|
|
||||||
maybe_script = ScriptCompiler::Compile(
|
|
||||||
context, &script_source, ScriptCompiler::kNoCompileOptions);
|
|
||||||
}
|
|
||||||
} else if (options.stress_background_compile) {
|
|
||||||
// Start a background thread compiling the script.
|
// Start a background thread compiling the script.
|
||||||
BackgroundCompileThread background_compile_thread(isolate, source);
|
BackgroundCompileThread background_compile_thread(isolate, source);
|
||||||
background_compile_thread.Start();
|
background_compile_thread.Start();
|
||||||
@ -638,26 +679,18 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
|||||||
// In parallel, compile on the main thread to flush out any data races.
|
// In parallel, compile on the main thread to flush out any data races.
|
||||||
{
|
{
|
||||||
TryCatch ignore_try_catch(isolate);
|
TryCatch ignore_try_catch(isolate);
|
||||||
ScriptCompiler::Source script_source(source, origin);
|
Shell::CompileString(isolate, source, name, options.compile_options);
|
||||||
USE(ScriptCompiler::Compile(context, &script_source,
|
|
||||||
ScriptCompiler::kNoCompileOptions));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join with background thread and finalize compilation.
|
// Join with background thread and finalize compilation.
|
||||||
background_compile_thread.Join();
|
background_compile_thread.Join();
|
||||||
|
ScriptOrigin origin(name);
|
||||||
maybe_script = v8::ScriptCompiler::Compile(
|
maybe_script = v8::ScriptCompiler::Compile(
|
||||||
context, background_compile_thread.streamed_source(), source, origin);
|
isolate->GetCurrentContext(),
|
||||||
|
background_compile_thread.streamed_source(), source, origin);
|
||||||
} else {
|
} else {
|
||||||
ScriptCompiler::Source script_source(source, origin);
|
|
||||||
ScriptCompiler::CompileOptions compile_options =
|
|
||||||
options.cache_code_after_execute ? ScriptCompiler::kNoCompileOptions
|
|
||||||
: options.compile_options;
|
|
||||||
maybe_script =
|
maybe_script =
|
||||||
ScriptCompiler::Compile(context, &script_source, compile_options);
|
Shell::CompileString(isolate, source, name, options.compile_options);
|
||||||
if (compile_options == ScriptCompiler::kProduceCodeCache ||
|
|
||||||
compile_options == ScriptCompiler::kProduceParserCache) {
|
|
||||||
StoreInCodeCache(isolate, name, script_source.GetCachedData());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Script> script;
|
Local<Script> script;
|
||||||
@ -668,14 +701,6 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybe_result = script->Run(realm);
|
maybe_result = script->Run(realm);
|
||||||
if (options.compile_options == ScriptCompiler::kProduceCodeCache &&
|
|
||||||
options.cache_code_after_execute) {
|
|
||||||
// Serialize and store it in memory for the next execution.
|
|
||||||
ScriptCompiler::CachedData* cached_data =
|
|
||||||
ScriptCompiler::CreateCodeCache(script->GetUnboundScript(), source);
|
|
||||||
StoreInCodeCache(isolate, name, cached_data);
|
|
||||||
delete cached_data;
|
|
||||||
}
|
|
||||||
if (!EmptyMessageQueues(isolate)) success = false;
|
if (!EmptyMessageQueues(isolate)) success = false;
|
||||||
data->realm_current_ = data->realm_switch_;
|
data->realm_current_ = data->realm_switch_;
|
||||||
}
|
}
|
||||||
@ -2843,9 +2868,6 @@ bool Shell::SetOptions(int argc, char* argv[]) {
|
|||||||
options.compile_options = v8::ScriptCompiler::kProduceParserCache;
|
options.compile_options = v8::ScriptCompiler::kProduceParserCache;
|
||||||
} else if (strncmp(value, "=none", 6) == 0) {
|
} else if (strncmp(value, "=none", 6) == 0) {
|
||||||
options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
|
options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
|
||||||
} else if (strncmp(value, "=after-execute", 10) == 0) {
|
|
||||||
options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
|
|
||||||
options.cache_code_after_execute = true;
|
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown option to --cache.\n");
|
printf("Unknown option to --cache.\n");
|
||||||
return false;
|
return false;
|
||||||
@ -3391,47 +3413,6 @@ int Shell::Main(int argc, char* argv[]) {
|
|||||||
bool last_run = i == options.stress_runs - 1;
|
bool last_run = i == options.stress_runs - 1;
|
||||||
result = RunMain(isolate, argc, argv, last_run);
|
result = RunMain(isolate, argc, argv, last_run);
|
||||||
}
|
}
|
||||||
} else if (options.compile_options ==
|
|
||||||
v8::ScriptCompiler::kProduceCodeCache ||
|
|
||||||
options.compile_options ==
|
|
||||||
v8::ScriptCompiler::kProduceParserCache) {
|
|
||||||
printf("============ Run: Produce code cache ============\n");
|
|
||||||
// First run to produce the cache
|
|
||||||
result = RunMain(isolate, argc, argv, false);
|
|
||||||
|
|
||||||
// Change the options to consume cache
|
|
||||||
if (options.compile_options == v8::ScriptCompiler::kProduceCodeCache) {
|
|
||||||
options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
|
|
||||||
} else if (options.compile_options ==
|
|
||||||
v8::ScriptCompiler::kProduceParserCache) {
|
|
||||||
options.compile_options = v8::ScriptCompiler::kConsumeParserCache;
|
|
||||||
} else {
|
|
||||||
// We only expect ProduceCodeCache or ProduceParserCache here.
|
|
||||||
// compile_options cannot be NoCompileOptions.
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("============ Run: Consume code cache ============\n");
|
|
||||||
// Second run to consume the cache in new isolate
|
|
||||||
Isolate::CreateParams create_params;
|
|
||||||
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
|
|
||||||
i::FLAG_hash_seed ^= 1337; // Use a different hash seed.
|
|
||||||
Isolate* isolate2 = Isolate::New(create_params);
|
|
||||||
i::FLAG_hash_seed ^= 1337; // Restore old hash seed.
|
|
||||||
isolate2->SetHostImportModuleDynamicallyCallback(
|
|
||||||
Shell::HostImportModuleDynamically);
|
|
||||||
isolate2->SetHostInitializeImportMetaObjectCallback(
|
|
||||||
Shell::HostInitializeImportMetaObject);
|
|
||||||
{
|
|
||||||
D8Console console(isolate2);
|
|
||||||
debug::SetConsoleDelegate(isolate2, &console);
|
|
||||||
PerIsolateData data(isolate2);
|
|
||||||
Isolate::Scope isolate_scope(isolate2);
|
|
||||||
|
|
||||||
result = RunMain(isolate2, argc, argv, false);
|
|
||||||
}
|
|
||||||
cached_code_map_.clear();
|
|
||||||
isolate2->Dispose();
|
|
||||||
} else {
|
} else {
|
||||||
bool last_run = true;
|
bool last_run = true;
|
||||||
result = RunMain(isolate, argc, argv, last_run);
|
result = RunMain(isolate, argc, argv, last_run);
|
||||||
|
11
src/d8.h
11
src/d8.h
@ -296,7 +296,6 @@ class ShellOptions {
|
|||||||
num_isolates(1),
|
num_isolates(1),
|
||||||
compile_options(v8::ScriptCompiler::kNoCompileOptions),
|
compile_options(v8::ScriptCompiler::kNoCompileOptions),
|
||||||
stress_background_compile(false),
|
stress_background_compile(false),
|
||||||
cache_code_after_execute(false),
|
|
||||||
isolate_sources(nullptr),
|
isolate_sources(nullptr),
|
||||||
icu_data_file(nullptr),
|
icu_data_file(nullptr),
|
||||||
natives_blob(nullptr),
|
natives_blob(nullptr),
|
||||||
@ -330,7 +329,6 @@ class ShellOptions {
|
|||||||
int num_isolates;
|
int num_isolates;
|
||||||
v8::ScriptCompiler::CompileOptions compile_options;
|
v8::ScriptCompiler::CompileOptions compile_options;
|
||||||
bool stress_background_compile;
|
bool stress_background_compile;
|
||||||
bool cache_code_after_execute;
|
|
||||||
SourceGroup* isolate_sources;
|
SourceGroup* isolate_sources;
|
||||||
const char* icu_data_file;
|
const char* icu_data_file;
|
||||||
const char* natives_blob;
|
const char* natives_blob;
|
||||||
@ -346,6 +344,9 @@ class ShellOptions {
|
|||||||
|
|
||||||
class Shell : public i::AllStatic {
|
class Shell : public i::AllStatic {
|
||||||
public:
|
public:
|
||||||
|
static MaybeLocal<Script> CompileString(
|
||||||
|
Isolate* isolate, Local<String> source, Local<Value> name,
|
||||||
|
v8::ScriptCompiler::CompileOptions compile_options);
|
||||||
static bool ExecuteString(Isolate* isolate, Local<String> source,
|
static bool ExecuteString(Isolate* isolate, Local<String> source,
|
||||||
Local<Value> name, bool print_result,
|
Local<Value> name, bool print_result,
|
||||||
bool report_exceptions);
|
bool report_exceptions);
|
||||||
@ -503,16 +504,10 @@ class Shell : public i::AllStatic {
|
|||||||
int index);
|
int index);
|
||||||
static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
|
static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
|
||||||
const std::string& file_name);
|
const std::string& file_name);
|
||||||
static ScriptCompiler::CachedData* LookupCodeCache(Isolate* isolate,
|
|
||||||
Local<Value> name);
|
|
||||||
static void StoreInCodeCache(Isolate* isolate, Local<Value> name,
|
|
||||||
const ScriptCompiler::CachedData* data);
|
|
||||||
// We may have multiple isolates running concurrently, so the access to
|
// We may have multiple isolates running concurrently, so the access to
|
||||||
// the isolate_status_ needs to be concurrency-safe.
|
// the isolate_status_ needs to be concurrency-safe.
|
||||||
static base::LazyMutex isolate_status_lock_;
|
static base::LazyMutex isolate_status_lock_;
|
||||||
static std::map<Isolate*, bool> isolate_status_;
|
static std::map<Isolate*, bool> isolate_status_;
|
||||||
static std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
|
|
||||||
cached_code_map_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -13263,15 +13263,6 @@ bool Script::GetPositionInfo(Handle<Script> script, int position,
|
|||||||
|
|
||||||
bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
|
bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
|
||||||
|
|
||||||
bool Script::ContainsAsmModule() {
|
|
||||||
DisallowHeapAllocation no_gc;
|
|
||||||
SharedFunctionInfo::ScriptIterator iter(Handle<Script>(this));
|
|
||||||
while (SharedFunctionInfo* info = iter.Next()) {
|
|
||||||
if (info->HasAsmWasmData()) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool GetPositionInfoSlow(const Script* script, int position,
|
bool GetPositionInfoSlow(const Script* script, int position,
|
||||||
Script::PositionInfo* info) {
|
Script::PositionInfo* info) {
|
||||||
|
@ -635,14 +635,6 @@ ByteArray* BytecodeArray::SourcePositionTable() {
|
|||||||
->source_position_table();
|
->source_position_table();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeArray::ClearFrameCacheFromSourcePositionTable() {
|
|
||||||
Object* maybe_table = source_position_table();
|
|
||||||
if (maybe_table->IsByteArray()) return;
|
|
||||||
DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
|
|
||||||
set_source_position_table(SourcePositionTableWithFrameCache::cast(maybe_table)
|
|
||||||
->source_position_table());
|
|
||||||
}
|
|
||||||
|
|
||||||
int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); }
|
int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); }
|
||||||
|
|
||||||
int BytecodeArray::SizeIncludingMetadata() {
|
int BytecodeArray::SizeIncludingMetadata() {
|
||||||
|
@ -790,7 +790,6 @@ class BytecodeArray : public FixedArrayBase {
|
|||||||
DECL_ACCESSORS(source_position_table, Object)
|
DECL_ACCESSORS(source_position_table, Object)
|
||||||
|
|
||||||
inline ByteArray* SourcePositionTable();
|
inline ByteArray* SourcePositionTable();
|
||||||
inline void ClearFrameCacheFromSourcePositionTable();
|
|
||||||
|
|
||||||
DECL_CAST(BytecodeArray)
|
DECL_CAST(BytecodeArray)
|
||||||
|
|
||||||
|
@ -118,9 +118,6 @@ class Script : public Struct {
|
|||||||
// Retrieve source position from where eval was called.
|
// Retrieve source position from where eval was called.
|
||||||
int GetEvalPosition();
|
int GetEvalPosition();
|
||||||
|
|
||||||
// Check if the script contains any Asm modules.
|
|
||||||
bool ContainsAsmModule();
|
|
||||||
|
|
||||||
// Init line_ends array with source code positions of line ends.
|
// Init line_ends array with source code positions of line ends.
|
||||||
static void InitLineEnds(Handle<Script> script);
|
static void InitLineEnds(Handle<Script> script);
|
||||||
|
|
||||||
|
@ -106,37 +106,12 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj->IsScript()) {
|
if (obj->IsScript()) {
|
||||||
Script* script_obj = Script::cast(obj);
|
|
||||||
DCHECK_NE(script_obj->compilation_type(), Script::COMPILATION_TYPE_EVAL);
|
|
||||||
// Wrapper object is a context-dependent JSValue. Reset it here.
|
// Wrapper object is a context-dependent JSValue. Reset it here.
|
||||||
script_obj->set_wrapper(isolate()->heap()->undefined_value());
|
Script::cast(obj)->set_wrapper(isolate()->heap()->undefined_value());
|
||||||
// We want to differentiate between undefined and uninitialized_symbol for
|
|
||||||
// context_data for now. It is hack to allow debugging for scripts that are
|
|
||||||
// included as a part of custom snapshot. (see debug::Script::IsEmbedded())
|
|
||||||
Object* context_data = script_obj->context_data();
|
|
||||||
if (context_data != isolate()->heap()->undefined_value() &&
|
|
||||||
context_data != isolate()->heap()->uninitialized_symbol()) {
|
|
||||||
script_obj->set_context_data(isolate()->heap()->undefined_value());
|
|
||||||
}
|
|
||||||
// We don't want to serialize host options to avoid serializing unnecessary
|
|
||||||
// object graph.
|
|
||||||
FixedArray* host_options = script_obj->host_defined_options();
|
|
||||||
script_obj->set_host_defined_options(
|
|
||||||
isolate()->heap()->empty_fixed_array());
|
|
||||||
SerializeGeneric(obj, how_to_code, where_to_point);
|
|
||||||
script_obj->set_host_defined_options(host_options);
|
|
||||||
script_obj->set_context_data(context_data);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->IsSharedFunctionInfo()) {
|
if (obj->IsSharedFunctionInfo()) {
|
||||||
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
|
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
|
||||||
// TODO(7110): Enable serializing of Asm modules once the AsmWasmData
|
|
||||||
// is context independent.
|
|
||||||
DCHECK(!sfi->IsApiFunction() && !sfi->HasAsmWasmData());
|
|
||||||
// Do not serialize when a debugger is active.
|
|
||||||
DCHECK(sfi->debug_info()->IsSmi());
|
|
||||||
|
|
||||||
// Mark SFI to indicate whether the code is cached.
|
// Mark SFI to indicate whether the code is cached.
|
||||||
bool was_deserialized = sfi->deserialized();
|
bool was_deserialized = sfi->deserialized();
|
||||||
sfi->set_deserialized(sfi->is_compiled());
|
sfi->set_deserialized(sfi->is_compiled());
|
||||||
@ -145,11 +120,6 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->IsBytecodeArray()) {
|
|
||||||
// Clear the stack frame cache if present
|
|
||||||
BytecodeArray::cast(obj)->ClearFrameCacheFromSourcePositionTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Past this point we should not see any (context-specific) maps anymore.
|
// Past this point we should not see any (context-specific) maps anymore.
|
||||||
CHECK(!obj->IsMap());
|
CHECK(!obj->IsMap());
|
||||||
// There should be no references to the global object embedded.
|
// There should be no references to the global object embedded.
|
||||||
|
@ -234,13 +234,6 @@ HeapObject* Deserializer<AllocatorT>::PostProcessNewObject(HeapObject* obj,
|
|||||||
void* backing_store = off_heap_backing_stores_[store_index->value()];
|
void* backing_store = off_heap_backing_stores_[store_index->value()];
|
||||||
fta->set_external_pointer(backing_store);
|
fta->set_external_pointer(backing_store);
|
||||||
}
|
}
|
||||||
} else if (obj->IsBytecodeArray()) {
|
|
||||||
// TODO(mythria): Remove these once we store the default values for these
|
|
||||||
// fields in the serializer.
|
|
||||||
BytecodeArray* bytecode_array = BytecodeArray::cast(obj);
|
|
||||||
bytecode_array->set_interrupt_budget(
|
|
||||||
interpreter::Interpreter::kInterruptBudget);
|
|
||||||
bytecode_array->set_osr_loop_nesting_level(0);
|
|
||||||
}
|
}
|
||||||
// Check alignment.
|
// Check alignment.
|
||||||
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
|
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
|
||||||
|
@ -57,8 +57,6 @@
|
|||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
enum CodeCacheType { kLazy, kEager, kAfterExecute };
|
|
||||||
|
|
||||||
void DisableLazyDeserialization() {
|
void DisableLazyDeserialization() {
|
||||||
// UNINITIALIZED tests do not set up the isolate sufficiently for lazy
|
// UNINITIALIZED tests do not set up the isolate sufficiently for lazy
|
||||||
// deserialization to work.
|
// deserialization to work.
|
||||||
@ -1840,8 +1838,8 @@ static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::ScriptCompiler::CachedData* ProduceCache(
|
v8::ScriptCompiler::CachedData* ProduceCache(const char* source,
|
||||||
const char* source, CodeCacheType cacheType = CodeCacheType::kLazy) {
|
bool eager = false) {
|
||||||
v8::ScriptCompiler::CachedData* cache;
|
v8::ScriptCompiler::CachedData* cache;
|
||||||
v8::Isolate::CreateParams create_params;
|
v8::Isolate::CreateParams create_params;
|
||||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||||
@ -1855,23 +1853,19 @@ v8::ScriptCompiler::CachedData* ProduceCache(
|
|||||||
v8::Local<v8::String> source_str = v8_str(source);
|
v8::Local<v8::String> source_str = v8_str(source);
|
||||||
v8::ScriptOrigin origin(v8_str("test"));
|
v8::ScriptOrigin origin(v8_str("test"));
|
||||||
v8::ScriptCompiler::Source source(source_str, origin);
|
v8::ScriptCompiler::Source source(source_str, origin);
|
||||||
v8::ScriptCompiler::CompileOptions options;
|
v8::ScriptCompiler::CompileOptions options =
|
||||||
switch (cacheType) {
|
eager ? v8::ScriptCompiler::kProduceFullCodeCache
|
||||||
case CodeCacheType::kLazy:
|
: v8::ScriptCompiler::kProduceCodeCache;
|
||||||
options = v8::ScriptCompiler::kProduceCodeCache;
|
|
||||||
break;
|
|
||||||
case CodeCacheType::kEager:
|
|
||||||
options = v8::ScriptCompiler::kProduceFullCodeCache;
|
|
||||||
break;
|
|
||||||
case CodeCacheType::kAfterExecute:
|
|
||||||
options = v8::ScriptCompiler::kNoCompileOptions;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
v8::Local<v8::UnboundScript> script =
|
v8::Local<v8::UnboundScript> script =
|
||||||
v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
|
v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
|
||||||
.ToLocalChecked();
|
.ToLocalChecked();
|
||||||
|
const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
|
||||||
|
CHECK(data);
|
||||||
|
// Persist cached data.
|
||||||
|
uint8_t* buffer = NewArray<uint8_t>(data->length);
|
||||||
|
MemCopy(buffer, data->data, data->length);
|
||||||
|
cache = new v8::ScriptCompiler::CachedData(
|
||||||
|
buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
|
||||||
|
|
||||||
v8::Local<v8::Value> result = script->BindToCurrentContext()
|
v8::Local<v8::Value> result = script->BindToCurrentContext()
|
||||||
->Run(isolate1->GetCurrentContext())
|
->Run(isolate1->GetCurrentContext())
|
||||||
@ -1880,18 +1874,6 @@ v8::ScriptCompiler::CachedData* ProduceCache(
|
|||||||
result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
|
result->ToString(isolate1->GetCurrentContext()).ToLocalChecked();
|
||||||
CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
|
CHECK(result_string->Equals(isolate1->GetCurrentContext(), v8_str("abcdef"))
|
||||||
.FromJust());
|
.FromJust());
|
||||||
|
|
||||||
if (cacheType == CodeCacheType::kAfterExecute) {
|
|
||||||
cache = ScriptCompiler::CreateCodeCache(script, source_str);
|
|
||||||
} else {
|
|
||||||
const ScriptCompiler::CachedData* data = source.GetCachedData();
|
|
||||||
CHECK(data);
|
|
||||||
uint8_t* buffer = NewArray<uint8_t>(data->length);
|
|
||||||
MemCopy(buffer, data->data, data->length);
|
|
||||||
cache = new v8::ScriptCompiler::CachedData(
|
|
||||||
buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
|
|
||||||
}
|
|
||||||
CHECK(cache);
|
|
||||||
}
|
}
|
||||||
isolate1->Dispose();
|
isolate1->Dispose();
|
||||||
return cache;
|
return cache;
|
||||||
@ -1954,8 +1936,7 @@ TEST(CodeSerializerIsolatesEager) {
|
|||||||
" }"
|
" }"
|
||||||
"}"
|
"}"
|
||||||
"f()() + 'def'";
|
"f()() + 'def'";
|
||||||
v8::ScriptCompiler::CachedData* cache =
|
v8::ScriptCompiler::CachedData* cache = ProduceCache(source, true);
|
||||||
ProduceCache(source, CodeCacheType::kEager);
|
|
||||||
|
|
||||||
v8::Isolate::CreateParams create_params;
|
v8::Isolate::CreateParams create_params;
|
||||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||||
@ -1993,68 +1974,6 @@ TEST(CodeSerializerIsolatesEager) {
|
|||||||
isolate2->Dispose();
|
isolate2->Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CodeSerializerAfterExecute) {
|
|
||||||
// We test that no compilations happen when running this code. Forcing
|
|
||||||
// to always optimize breaks this test.
|
|
||||||
bool prev_opt_value = FLAG_opt;
|
|
||||||
bool prev_always_opt_value = FLAG_always_opt;
|
|
||||||
FLAG_always_opt = false;
|
|
||||||
FLAG_opt = false;
|
|
||||||
const char* source = "function f() { return 'abc'; }; f() + 'def'";
|
|
||||||
v8::ScriptCompiler::CachedData* cache =
|
|
||||||
ProduceCache(source, CodeCacheType::kAfterExecute);
|
|
||||||
|
|
||||||
v8::Isolate::CreateParams create_params;
|
|
||||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
||||||
v8::Isolate* isolate2 = v8::Isolate::New(create_params);
|
|
||||||
|
|
||||||
{
|
|
||||||
v8::Isolate::Scope iscope(isolate2);
|
|
||||||
v8::HandleScope scope(isolate2);
|
|
||||||
v8::Local<v8::Context> context = v8::Context::New(isolate2);
|
|
||||||
v8::Context::Scope context_scope(context);
|
|
||||||
|
|
||||||
v8::Local<v8::String> source_str = v8_str(source);
|
|
||||||
v8::ScriptOrigin origin(v8_str("test"));
|
|
||||||
v8::ScriptCompiler::Source source(source_str, origin, cache);
|
|
||||||
v8::Local<v8::UnboundScript> script;
|
|
||||||
{
|
|
||||||
DisallowCompilation no_compile_expected(
|
|
||||||
reinterpret_cast<Isolate*>(isolate2));
|
|
||||||
script = v8::ScriptCompiler::CompileUnboundScript(
|
|
||||||
isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache)
|
|
||||||
.ToLocalChecked();
|
|
||||||
}
|
|
||||||
CHECK(!cache->rejected);
|
|
||||||
CheckDeserializedFlag(script);
|
|
||||||
|
|
||||||
Handle<SharedFunctionInfo> sfi = v8::Utils::OpenHandle(*script);
|
|
||||||
CHECK(sfi->HasBytecodeArray());
|
|
||||||
BytecodeArray* bytecode = sfi->bytecode_array();
|
|
||||||
CHECK_EQ(bytecode->interrupt_budget(),
|
|
||||||
interpreter::Interpreter::kInterruptBudget);
|
|
||||||
CHECK_EQ(bytecode->osr_loop_nesting_level(), 0);
|
|
||||||
|
|
||||||
{
|
|
||||||
DisallowCompilation no_compile_expected(
|
|
||||||
reinterpret_cast<Isolate*>(isolate2));
|
|
||||||
v8::Local<v8::Value> result = script->BindToCurrentContext()
|
|
||||||
->Run(isolate2->GetCurrentContext())
|
|
||||||
.ToLocalChecked();
|
|
||||||
v8::Local<v8::String> result_string =
|
|
||||||
result->ToString(isolate2->GetCurrentContext()).ToLocalChecked();
|
|
||||||
CHECK(
|
|
||||||
result_string->Equals(isolate2->GetCurrentContext(), v8_str("abcdef"))
|
|
||||||
.FromJust());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isolate2->Dispose();
|
|
||||||
|
|
||||||
// Restore the flags.
|
|
||||||
FLAG_always_opt = prev_always_opt_value;
|
|
||||||
FLAG_opt = prev_opt_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CodeSerializerFlagChange) {
|
TEST(CodeSerializerFlagChange) {
|
||||||
const char* source = "function f() { return 'abc'; }; f() + 'def'";
|
const char* source = "function f() { return 'abc'; }; f() + 'def'";
|
||||||
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
|
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// Flags: --cache=after-execute
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
function h() {
|
|
||||||
function k() { return 0; };
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
return h();
|
|
||||||
}
|
|
||||||
|
|
||||||
g();
|
|
Loading…
Reference in New Issue
Block a user