Commit 3c897883 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Skip serialization of breakpoints and certion stubs

Breakpoints are always re-set by the embedder after compilation, so we
don't want to store the corresponding breakpoint objects.
Also don't serialize WASM_INTERPRETER_ENTRY stubs as they are replaced
by ordinary WASM_FUNCTION code at instantiation anyway, and skip
WASM_TO_JS wrappers which are recompiled on each instantiation.
Instead, we serialize the Illegal builtin, and also use that one
instead of the placeholder when compiling the wasm code initially.

R=titzer@chromium.org, yangguo@chromium.org
BUG=v8:5822

Review-Url: https://codereview.chromium.org/2629853004
Cr-Commit-Position: refs/heads/master@{#42451}
parent 4f91cee3
......@@ -229,14 +229,20 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return scope.CloseAndEscape(result);
}
WasmCompiledModuleSerializer::WasmCompiledModuleSerializer(
Isolate* isolate, uint32_t source_hash, Handle<Context> native_context,
Handle<SeqOneByteString> module_bytes)
: CodeSerializer(isolate, source_hash) {
reference_map()->AddAttachedReference(*isolate->native_context());
reference_map()->AddAttachedReference(*module_bytes);
}
std::unique_ptr<ScriptData> WasmCompiledModuleSerializer::SerializeWasmModule(
Isolate* isolate, Handle<FixedArray> input) {
Handle<WasmCompiledModule> compiled_module =
Handle<WasmCompiledModule>::cast(input);
WasmCompiledModuleSerializer wasm_cs(isolate, 0);
wasm_cs.reference_map()->AddAttachedReference(*isolate->native_context());
wasm_cs.reference_map()->AddAttachedReference(
compiled_module->module_bytes());
WasmCompiledModuleSerializer wasm_cs(isolate, 0, isolate->native_context(),
handle(compiled_module->module_bytes()));
ScriptData* data = wasm_cs.Serialize(compiled_module);
return std::unique_ptr<ScriptData>(data);
}
......@@ -277,11 +283,35 @@ MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule(
Handle<WasmCompiledModule> compiled_module(
static_cast<WasmCompiledModule*>(*obj.ToHandleChecked()), isolate);
WasmCompiledModule::RecreateModuleWrapper(isolate, compiled_module);
WasmCompiledModule::ReinitializeAfterDeserialization(isolate,
compiled_module);
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
return compiled_module;
}
void WasmCompiledModuleSerializer::SerializeCodeObject(
Code* code_object, HowToCode how_to_code, WhereToPoint where_to_point) {
Code::Kind kind = code_object->kind();
switch (kind) {
case Code::WASM_FUNCTION:
case Code::JS_TO_WASM_FUNCTION:
// Just serialize the code_object.
break;
case Code::WASM_TO_JS_FUNCTION:
// Serialize the illegal builtin instead. On instantiation of a
// deserialized module, these will be replaced again.
code_object = *isolate()->builtins()->Illegal();
break;
default:
UNREACHABLE();
}
SerializeGeneric(code_object, how_to_code, where_to_point);
}
bool WasmCompiledModuleSerializer::ElideObject(Object* obj) {
return obj->IsWeakCell() || obj->IsForeign() || obj->IsBreakPointInfo();
}
class Checksum {
public:
explicit Checksum(Vector<const byte> payload) {
......
......@@ -64,23 +64,13 @@ class WasmCompiledModuleSerializer : public CodeSerializer {
protected:
void SerializeCodeObject(Code* code_object, HowToCode how_to_code,
WhereToPoint where_to_point) override {
Code::Kind kind = code_object->kind();
if (kind == Code::WASM_FUNCTION || kind == Code::WASM_TO_JS_FUNCTION ||
kind == Code::JS_TO_WASM_FUNCTION) {
SerializeGeneric(code_object, how_to_code, where_to_point);
} else {
UNREACHABLE();
}
}
bool ElideObject(Object* obj) override {
return obj->IsWeakCell() || obj->IsForeign();
};
WhereToPoint where_to_point) override;
bool ElideObject(Object* obj) override;
private:
WasmCompiledModuleSerializer(Isolate* isolate, uint32_t source_hash)
: CodeSerializer(isolate, source_hash) {}
WasmCompiledModuleSerializer(Isolate* isolate, uint32_t source_hash,
Handle<Context> native_context,
Handle<SeqOneByteString> module_bytes);
DISALLOW_COPY_AND_ASSIGN(WasmCompiledModuleSerializer);
};
......
......@@ -160,14 +160,6 @@ void RelocateTableSizeReferences(Handle<FixedArray> code_table,
}
}
Handle<Code> CreatePlaceholder(Factory* factory, Code::Kind kind) {
byte buffer[] = {0, 0, 0, 0}; // fake instructions.
CodeDesc desc = {
buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr};
return factory->NewCode(desc, Code::KindField::encode(kind),
Handle<Object>::null());
}
void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
for (int i = 0; i < code_table->length(); ++i) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
......@@ -412,7 +404,7 @@ void CompileSequentially(Isolate* isolate, ModuleBytesEnv* module_env,
str.start());
break;
}
// Install the code into the linker table.
// Install the code into the linker table.
functions[i] = code;
}
}
......@@ -469,6 +461,15 @@ void PatchDirectCallsAndContext(Handle<FixedArray> new_functions,
wasm::Decoder decoder(nullptr, nullptr);
int num_wasm_functions = static_cast<int>(wasm_functions->size());
int func_index = start;
// We patch WASM_FUNCTION and WASM_TO_JS_FUNCTION during re-instantiation,
// and illegal builtins initially and after deserialization.
auto is_at_wasm_call = [](RelocIterator& it) {
Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
return code->kind() == Code::WASM_FUNCTION ||
code->kind() == Code::WASM_TO_JS_FUNCTION ||
code->builtin_index() == Builtins::kIllegal;
};
// Patch all wasm functions.
for (; func_index < num_wasm_functions; ++func_index) {
Code* wasm_function = Code::cast(new_functions->get(func_index));
......@@ -489,10 +490,7 @@ void PatchDirectCallsAndContext(Handle<FixedArray> new_functions,
continue;
}
DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
Code::Kind kind =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind();
if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION)
continue;
if (!is_at_wasm_call(it)) continue;
size_t offset = it.rinfo()->pc() - wasm_function->instruction_start();
int byte_pos =
AdvanceSourcePositionTableIterator(source_pos_iterator, offset);
......@@ -516,10 +514,7 @@ void PatchDirectCallsAndContext(Handle<FixedArray> new_functions,
continue;
}
DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
Code::Kind kind =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind();
if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION)
continue;
if (!is_at_wasm_call(it)) continue;
++num_wasm_calls;
Code* new_code = Code::cast(new_functions->get(exp.index));
DCHECK(new_code->kind() == Code::WASM_FUNCTION ||
......@@ -926,28 +921,21 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
Handle<FixedArray> code_table =
factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
// Initialize the code table with placeholders.
Handle<Code> code_placeholder =
CreatePlaceholder(factory, Code::WASM_FUNCTION);
// Initialize the code table with the illegal builtin. All call sites will be
// patched at instantiation.
Handle<Code> illegal_builtin = isolate->builtins()->Illegal();
for (uint32_t i = 0; i < functions.size(); ++i) {
code_table->set(static_cast<int>(i), *code_placeholder);
temp_instance.function_code[i] = code_placeholder;
code_table->set(static_cast<int>(i), *illegal_builtin);
temp_instance.function_code[i] = illegal_builtin;
}
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
// Avoid a race condition by collecting results into a second vector.
std::vector<Handle<Code>> results;
results.reserve(temp_instance.function_code.size());
for (size_t i = 0; i < temp_instance.function_code.size(); ++i) {
results.push_back(temp_instance.function_code[i]);
}
std::vector<Handle<Code>> results(temp_instance.function_code);
CompileInParallel(isolate, &module_env, results, thrower);
for (size_t i = 0; i < results.size(); ++i) {
temp_instance.function_code[i] = results[i];
}
temp_instance.function_code.swap(results);
} else {
CompileSequentially(isolate, &module_env, temp_instance.function_code,
thrower);
......
......@@ -570,9 +570,19 @@ bool WasmSharedModuleData::is_asm_js() {
return asm_js;
}
void WasmSharedModuleData::RecreateModuleWrapper(
void WasmSharedModuleData::ReinitializeAfterDeserialization(
Isolate* isolate, Handle<WasmSharedModuleData> shared) {
DCHECK(shared->get(kModuleWrapper)->IsUndefined(isolate));
#ifdef DEBUG
// No BreakpointInfo objects should survive deserialization.
if (shared->has_breakpoint_infos()) {
for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) {
DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate));
}
}
#endif
shared->set(kBreakPointInfos, isolate->heap()->undefined_value());
WasmModule* module = nullptr;
{
......@@ -795,7 +805,7 @@ void WasmCompiledModule::PrintInstancesChain() {
#endif
}
void WasmCompiledModule::RecreateModuleWrapper(
void WasmCompiledModule::ReinitializeAfterDeserialization(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
// This method must only be called immediately after deserialization.
// At this point, no module wrapper exists, so the shared module data is
......@@ -804,7 +814,7 @@ void WasmCompiledModule::RecreateModuleWrapper(
static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
isolate);
DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
WasmSharedModuleData::RecreateModuleWrapper(isolate, shared);
WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
}
......
......@@ -184,8 +184,8 @@ class WasmSharedModuleData : public FixedArray {
// Check whether this module was generated from asm.js source.
bool is_asm_js();
// Recreate the ModuleWrapper from the module bytes after deserialization.
static void RecreateModuleWrapper(Isolate*, Handle<WasmSharedModuleData>);
static void ReinitializeAfterDeserialization(Isolate*,
Handle<WasmSharedModuleData>);
static void AddBreakpoint(Handle<WasmSharedModuleData>, int position,
Handle<Object> break_point_object);
......@@ -323,9 +323,8 @@ class WasmCompiledModule : public FixedArray {
void PrintInstancesChain();
// Recreate the ModuleWrapper from the module bytes after deserialization.
static void RecreateModuleWrapper(Isolate* isolate,
Handle<WasmCompiledModule> compiled_module);
static void ReinitializeAfterDeserialization(Isolate*,
Handle<WasmCompiledModule>);
// Get the function name of the function identified by the given index.
// Returns a null handle if the function is unnamed or the name is not a valid
......
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