Commit 0c7ee927 authored by mtrofin's avatar mtrofin Committed by Commit bot

[wasm] Complete separation of compilation and instantiation

Support for serializing/deserializing the compiled wasm module.

We want to reuse the javascript snapshotting mechanics, at least in the
short term, when we still use the JS heap for the compiled wasm code.
Given that a module may be compiled in one v8 instance and then
instantiated later, in a different instance, whatever information we need
at instantiation time must also be serializable.

We currently hold on to the un-decoded wasm bytes, for enabling
debugging scenarios. This imposes a ~20% penalty on the memory
requirements of the wasm compiled code. We do not need this data
otherwise, for runtime, and it is sensible to consider eventually loading it
on demand. Therefore, I intentionally avoided relying on it and re-
decoding the wasm module data, and instead saved the information
necessary to support instantiation.

Given how whatever we need to persist must be serializable, the CL
uses a structure made out of serializable objects (fixed arrays mostly)
for storing this information. I preferred going this route rather than
adding more wasm-specific support to the serializer, given that we want
to eventually move off the JS heap, and therefore the serializer.

Additionally, it turns out this extra information is relatively not complex:
minimal structure, little nesting depth, mostly simple data like numbers
or byte blobs, or opaque data like compiled functions.

This CL also moves export compilation ahead of instantiation time.

This change added a helper getter to FixedArray, to make typed retrieval
of elements easier.

BUG=

Review-Url: https://codereview.chromium.org/2094563002
Cr-Commit-Position: refs/heads/master@{#37348}
parent f99f6333
...@@ -2955,29 +2955,31 @@ void WasmGraphBuilder::SetSourcePosition(Node* node, ...@@ -2955,29 +2955,31 @@ void WasmGraphBuilder::SetSourcePosition(Node* node,
} }
static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
CompilationInfo* info, Isolate* isolate, Handle<Code> code,
const char* message, uint32_t index, const char* message, uint32_t index,
wasm::WasmName func_name) { const wasm::WasmName& module_name,
Isolate* isolate = info->isolate(); const wasm::WasmName& func_name) {
if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { DCHECK(isolate->logger()->is_logging_code_events() ||
ScopedVector<char> buffer(128); isolate->is_profiling());
SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length(),
func_name.start()); ScopedVector<char> buffer(128);
Handle<String> name_str = SNPrintF(buffer, "%s#%d:%.*s:%.*s", message, index, module_name.length(),
isolate->factory()->NewStringFromAsciiChecked(buffer.start()); module_name.start(), func_name.length(), func_name.start());
Handle<String> script_str = Handle<String> name_str =
isolate->factory()->NewStringFromAsciiChecked("(WASM)"); isolate->factory()->NewStringFromAsciiChecked(buffer.start());
Handle<Code> code = info->code(); Handle<String> script_str =
Handle<SharedFunctionInfo> shared = isolate->factory()->NewStringFromAsciiChecked("(WASM)");
isolate->factory()->NewSharedFunctionInfo(name_str, code, false); Handle<SharedFunctionInfo> shared =
PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared, isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
*script_str, 0, 0)); PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
} *script_str, 0, 0));
} }
Handle<JSFunction> CompileJSToWasmWrapper( Handle<JSFunction> CompileJSToWasmWrapper(Isolate* isolate,
Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name, wasm::ModuleEnv* module,
Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) { Handle<String> name,
Handle<Code> wasm_code,
uint32_t index) {
const wasm::WasmFunction* func = &module->module->functions[index]; const wasm::WasmFunction* func = &module->module->functions[index];
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -2990,7 +2992,6 @@ Handle<JSFunction> CompileJSToWasmWrapper( ...@@ -2990,7 +2992,6 @@ Handle<JSFunction> CompileJSToWasmWrapper(
shared->set_internal_formal_parameter_count(params); shared->set_internal_formal_parameter_count(params);
Handle<JSFunction> function = isolate->factory()->NewFunction( Handle<JSFunction> function = isolate->factory()->NewFunction(
isolate->wasm_function_map(), name, MaybeHandle<Code>()); isolate->wasm_function_map(), name, MaybeHandle<Code>());
function->SetInternalField(0, *module_object);
function->set_shared(*shared); function->set_shared(*shared);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -3056,9 +3057,13 @@ Handle<JSFunction> CompileJSToWasmWrapper( ...@@ -3056,9 +3057,13 @@ Handle<JSFunction> CompileJSToWasmWrapper(
buffer.Dispose(); buffer.Dispose();
} }
RecordFunctionCompilation( if (isolate->logger()->is_logging_code_events() ||
CodeEventListener::FUNCTION_TAG, &info, "js-to-wasm", index, isolate->is_profiling()) {
module->module->GetName(func->name_offset, func->name_length)); RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate, code, "js-to-wasm", index,
wasm::WasmName("export"),
module->module->GetName(func->name_offset, func->name_length));
}
// Set the JSFunction's machine code. // Set the JSFunction's machine code.
function->set_code(*code); function->set_code(*code);
} }
...@@ -3067,9 +3072,9 @@ Handle<JSFunction> CompileJSToWasmWrapper( ...@@ -3067,9 +3072,9 @@ Handle<JSFunction> CompileJSToWasmWrapper(
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<Code> CompileWasmToJSWrapper(Isolate* isolate,
Handle<JSFunction> function, Handle<JSFunction> function,
wasm::FunctionSig* sig, wasm::FunctionSig* sig, uint32_t index,
wasm::WasmName module_name, Handle<String> import_module,
wasm::WasmName function_name) { MaybeHandle<String> import_function) {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Create the Graph // Create the Graph
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -3128,10 +3133,21 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, ...@@ -3128,10 +3133,21 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate,
if (debugging) { if (debugging) {
buffer.Dispose(); buffer.Dispose();
} }
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info,
"wasm-to-js", 0, module_name);
} }
if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
const char* function_name = nullptr;
int function_name_size = 0;
if (!import_function.is_null()) {
Handle<String> handle = import_function.ToHandleChecked();
function_name = handle->ToCString().get();
function_name_size = handle->length();
}
RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index,
{import_module->ToCString().get(), import_module->length()},
{function_name, function_name_size});
}
return code; return code;
} }
...@@ -3294,11 +3310,14 @@ Handle<Code> WasmCompilationUnit::FinishCompilation() { ...@@ -3294,11 +3310,14 @@ Handle<Code> WasmCompilationUnit::FinishCompilation() {
Handle<Code> code = info_.code(); Handle<Code> code = info_.code();
DCHECK(!code.is_null()); DCHECK(!code.is_null());
RecordFunctionCompilation( if (isolate_->logger()->is_logging_code_events() ||
CodeEventListener::FUNCTION_TAG, &info_, "WASM_function", isolate_->is_profiling()) {
function_->func_index, RecordFunctionCompilation(
module_env_->module->GetName(function_->name_offset, CodeEventListener::FUNCTION_TAG, isolate_, code, "WASM_function",
function_->name_length)); function_->func_index, wasm::WasmName("module"),
module_env_->module->GetName(function_->name_offset,
function_->name_length));
}
if (FLAG_trace_wasm_decode_time) { if (FLAG_trace_wasm_decode_time) {
double compile_ms = compile_timer.Elapsed().InMillisecondsF(); double compile_ms = compile_timer.Elapsed().InMillisecondsF();
......
...@@ -79,15 +79,17 @@ class WasmCompilationUnit final { ...@@ -79,15 +79,17 @@ class WasmCompilationUnit final {
// Wraps a JS function, producing a code object that can be called from WASM. // Wraps a JS function, producing a code object that can be called from WASM.
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<Code> CompileWasmToJSWrapper(Isolate* isolate,
Handle<JSFunction> function, Handle<JSFunction> function,
wasm::FunctionSig* sig, wasm::FunctionSig* sig, uint32_t index,
wasm::WasmName module_name, Handle<String> import_module,
wasm::WasmName function_name); MaybeHandle<String> import_function);
// Wraps a given wasm code object, producing a JSFunction that can be called // Wraps a given wasm code object, producing a JSFunction that can be called
// from JavaScript. // from JavaScript.
Handle<JSFunction> CompileJSToWasmWrapper( Handle<JSFunction> CompileJSToWasmWrapper(Isolate* isolate,
Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name, wasm::ModuleEnv* module,
Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index); Handle<String> name,
Handle<Code> wasm_code,
uint32_t index);
// Abstracts details of building TurboFan graph nodes for WASM to separate // Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan. // the WASM decoder from the internal details of TurboFan.
......
...@@ -2306,12 +2306,24 @@ Handle<Object> FixedArray::get(FixedArray* array, int index, Isolate* isolate) { ...@@ -2306,12 +2306,24 @@ Handle<Object> FixedArray::get(FixedArray* array, int index, Isolate* isolate) {
return handle(array->get(index), isolate); return handle(array->get(index), isolate);
} }
template <class T>
MaybeHandle<T> FixedArray::GetValue(int index) const {
Object* obj = get(index);
if (obj->IsUndefined(GetIsolate())) return MaybeHandle<T>();
return Handle<T>(T::cast(obj));
}
template <class T>
Handle<T> FixedArray::GetValueChecked(int index) const {
Object* obj = get(index);
CHECK(!obj->IsUndefined(GetIsolate()));
return Handle<T>(T::cast(obj));
}
bool FixedArray::is_the_hole(int index) { bool FixedArray::is_the_hole(int index) {
return get(index) == GetHeap()->the_hole_value(); return get(index) == GetHeap()->the_hole_value();
} }
void FixedArray::set(int index, Smi* value) { void FixedArray::set(int index, Smi* value) {
DCHECK(map() != GetHeap()->fixed_cow_array_map()); DCHECK(map() != GetHeap()->fixed_cow_array_map());
DCHECK(index >= 0 && index < this->length()); DCHECK(index >= 0 && index < this->length());
...@@ -3981,6 +3993,9 @@ byte ByteArray::get(int index) { ...@@ -3981,6 +3993,9 @@ byte ByteArray::get(int index) {
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
} }
const byte* ByteArray::data() const {
return reinterpret_cast<const byte*>(FIELD_ADDR_CONST(this, kHeaderSize));
}
void ByteArray::set(int index, byte value) { void ByteArray::set(int index, byte value) {
DCHECK(index >= 0 && index < this->length()); DCHECK(index >= 0 && index < this->length());
......
...@@ -2644,6 +2644,12 @@ class FixedArray: public FixedArrayBase { ...@@ -2644,6 +2644,12 @@ class FixedArray: public FixedArrayBase {
inline Object* get(int index) const; inline Object* get(int index) const;
static inline Handle<Object> get(FixedArray* array, int index, static inline Handle<Object> get(FixedArray* array, int index,
Isolate* isolate); Isolate* isolate);
template <class T>
MaybeHandle<T> GetValue(int index) const;
template <class T>
Handle<T> GetValueChecked(int index) const;
// Setter that uses write barrier. // Setter that uses write barrier.
inline void set(int index, Object* value); inline void set(int index, Object* value);
inline bool is_the_hole(int index); inline bool is_the_hole(int index);
...@@ -4420,6 +4426,7 @@ class ByteArray: public FixedArrayBase { ...@@ -4420,6 +4426,7 @@ class ByteArray: public FixedArrayBase {
// Setter and getter. // Setter and getter.
inline byte get(int index); inline byte get(int index);
inline void set(int index, byte value); inline void set(int index, byte value);
inline const byte* data() const;
// Copy in / copy out whole byte slices. // Copy in / copy out whole byte slices.
inline void copy_out(int index, byte* buffer, int length); inline void copy_out(int index, byte* buffer, int length);
......
...@@ -14,7 +14,7 @@ namespace internal { ...@@ -14,7 +14,7 @@ namespace internal {
template <typename T> template <typename T>
class Signature : public ZoneObject { class Signature : public ZoneObject {
public: public:
Signature(size_t return_count, size_t parameter_count, T* reps) Signature(size_t return_count, size_t parameter_count, const T* reps)
: return_count_(return_count), : return_count_(return_count),
parameter_count_(parameter_count), parameter_count_(parameter_count),
reps_(reps) {} reps_(reps) {}
...@@ -32,6 +32,8 @@ class Signature : public ZoneObject { ...@@ -32,6 +32,8 @@ class Signature : public ZoneObject {
return reps_[index]; return reps_[index];
} }
const T* raw_data() const { return reps_; }
// For incrementally building signatures. // For incrementally building signatures.
class Builder { class Builder {
public: public:
...@@ -71,7 +73,7 @@ class Signature : public ZoneObject { ...@@ -71,7 +73,7 @@ class Signature : public ZoneObject {
protected: protected:
size_t return_count_; size_t return_count_;
size_t parameter_count_; size_t parameter_count_;
T* reps_; const T* reps_;
}; };
} // namespace internal } // namespace internal
......
...@@ -192,9 +192,14 @@ i::MaybeHandle<i::JSObject> InstantiateModuleCommon( ...@@ -192,9 +192,14 @@ i::MaybeHandle<i::JSObject> InstantiateModuleCommon(
memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj)); memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
} }
object = result.val->Instantiate(isolate, ffi, memory); i::MaybeHandle<i::FixedArray> compiled_module =
if (!object.is_null()) { result.val->CompileFunctions(isolate);
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked())); if (!compiled_module.is_null()) {
object = i::wasm::WasmModule::Instantiate(
isolate, compiled_module.ToHandleChecked(), ffi, memory);
if (!object.is_null()) {
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
}
} }
} }
......
This diff is collapsed.
...@@ -224,10 +224,12 @@ struct WasmModule { ...@@ -224,10 +224,12 @@ struct WasmModule {
} }
// Creates a new instantiation of the module in the given isolate. // Creates a new instantiation of the module in the given isolate.
MaybeHandle<JSObject> Instantiate(Isolate* isolate, Handle<JSReceiver> ffi, static MaybeHandle<JSObject> Instantiate(Isolate* isolate,
Handle<JSArrayBuffer> memory) const; Handle<FixedArray> compiled_module,
Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory);
Handle<FixedArray> CompileFunctions(Isolate* isolate) const; MaybeHandle<FixedArray> CompileFunctions(Isolate* isolate) const;
uint32_t FunctionTableSize() const { uint32_t FunctionTableSize() const {
if (indirect_table_size > 0) { if (indirect_table_size > 0) {
......
...@@ -186,10 +186,9 @@ class TestingModule : public ModuleEnv { ...@@ -186,10 +186,9 @@ class TestingModule : public ModuleEnv {
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source)))); *v8::Local<v8::Function>::Cast(CompileRun(source))));
uint32_t index = AddFunction(sig, Handle<Code>::null()); uint32_t index = AddFunction(sig, Handle<Code>::null());
WasmName module_name = ArrayVector("test"); Handle<Code> code =
WasmName function_name; CompileWasmToJSWrapper(isolate_, jsfunc, sig, index,
Handle<Code> code = CompileWasmToJSWrapper(isolate_, jsfunc, sig, Handle<String>::null(), Handle<String>::null());
module_name, function_name);
instance->function_code[index] = code; instance->function_code[index] = code;
return index; return index;
} }
...@@ -200,8 +199,10 @@ class TestingModule : public ModuleEnv { ...@@ -200,8 +199,10 @@ class TestingModule : public ModuleEnv {
Handle<JSObject> module_object = Handle<JSObject>(0, isolate_); Handle<JSObject> module_object = Handle<JSObject>(0, isolate_);
Handle<Code> code = instance->function_code[index]; Handle<Code> code = instance->function_code[index];
WasmJs::InstallWasmFunctionMap(isolate_, isolate_->native_context()); WasmJs::InstallWasmFunctionMap(isolate_, isolate_->native_context());
return compiler::CompileJSToWasmWrapper(isolate_, this, name, code, Handle<JSFunction> ret =
module_object, index); compiler::CompileJSToWasmWrapper(isolate_, this, name, code, index);
ret->SetInternalField(0, *module_object);
return ret;
} }
void SetFunctionCode(uint32_t index, Handle<Code> code) { void SetFunctionCode(uint32_t index, Handle<Code> code) {
......
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