diff --git a/include/v8.h b/include/v8.h index e7317e4d2a..caf56656ae 100644 --- a/include/v8.h +++ b/include/v8.h @@ -3915,7 +3915,8 @@ class V8_EXPORT WasmCompiledModule : public Object { private: static MaybeLocal Deserialize( - Isolate* isolate, const CallerOwnedBuffer& serialized_module); + Isolate* isolate, const CallerOwnedBuffer& serialized_module, + const CallerOwnedBuffer& wire_bytes); static MaybeLocal Compile(Isolate* isolate, const uint8_t* start, size_t length); diff --git a/src/api.cc b/src/api.cc index 22615e0274..c13aa6258b 100644 --- a/src/api.cc +++ b/src/api.cc @@ -7224,12 +7224,15 @@ WasmCompiledModule::SerializedModule WasmCompiledModule::Serialize() { MaybeLocal WasmCompiledModule::Deserialize( Isolate* isolate, - const WasmCompiledModule::CallerOwnedBuffer& serialized_module) { + const WasmCompiledModule::CallerOwnedBuffer& serialized_module, + const WasmCompiledModule::CallerOwnedBuffer& wire_bytes) { int size = static_cast(serialized_module.second); i::ScriptData sc(serialized_module.first, size); i::Isolate* i_isolate = reinterpret_cast(isolate); i::MaybeHandle maybe_compiled_part = - i::WasmCompiledModuleSerializer::DeserializeWasmModule(i_isolate, &sc); + i::WasmCompiledModuleSerializer::DeserializeWasmModule( + i_isolate, &sc, + {wire_bytes.first, static_cast(wire_bytes.second)}); i::Handle compiled_part; if (!maybe_compiled_part.ToHandle(&compiled_part)) { return MaybeLocal(); @@ -7245,24 +7248,9 @@ MaybeLocal WasmCompiledModule::DeserializeOrCompile( Isolate* isolate, const WasmCompiledModule::CallerOwnedBuffer& serialized_module, const WasmCompiledModule::CallerOwnedBuffer& wire_bytes) { - MaybeLocal ret = Deserialize(isolate, serialized_module); + MaybeLocal ret = + Deserialize(isolate, serialized_module, wire_bytes); if (!ret.IsEmpty()) { - // TODO(mtrofin): once we stop taking a dependency on Deserialize, - // clean this up to avoid the back and forth between internal - // and external representations. - i::Isolate* i_isolate = reinterpret_cast(isolate); - i::Vector str(wire_bytes.first, - static_cast(wire_bytes.second)); - i::Handle wire_bytes_as_string( - i::SeqOneByteString::cast( - *i_isolate->factory()->NewStringFromOneByte(str).ToHandleChecked()), - i_isolate); - - i::Handle obj = - i::Handle::cast(Utils::OpenHandle(*ret.ToLocalChecked())); - i::Handle compiled_part = - i::handle(i::wasm::WasmCompiledModule::cast(obj->GetInternalField(0))); - compiled_part->set_module_bytes(wire_bytes_as_string); return ret; } return Compile(isolate, wire_bytes.first, wire_bytes.second); diff --git a/src/heap/heap.h b/src/heap/heap.h index 84bbe89725..eee7d28a69 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -1442,6 +1442,10 @@ class Heap { // ArrayBuffer tracking. ===================================================== // =========================================================================== + // TODO(gc): API usability: encapsulate mutation of JSArrayBuffer::is_external + // in the registration/unregistration APIs. Consider dropping the "New" from + // "RegisterNewArrayBuffer" because one can re-register a previously + // unregistered buffer, too, and the name is confusing. void RegisterNewArrayBuffer(JSArrayBuffer* buffer); void UnregisterArrayBuffer(JSArrayBuffer* buffer); diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc index 1f6efa168f..943e126556 100644 --- a/src/runtime/runtime-test.cc +++ b/src/runtime/runtime-test.cc @@ -754,15 +754,31 @@ RUNTIME_FUNCTION(Runtime_SerializeWasmModule) { // Return undefined if unsuccessful. RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) { HandleScope shs(isolate); - DCHECK(args.length() == 1); + DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, wire_bytes, 1); Address mem_start = static_cast
(buffer->backing_store()); int mem_size = static_cast(buffer->byte_length()->Number()); + // DeserializeWasmModule will allocate. We assume JSArrayBuffer doesn't + // get relocated. ScriptData sc(mem_start, mem_size); + bool already_external = wire_bytes->is_external(); + if (!already_external) { + wire_bytes->set_is_external(true); + isolate->heap()->UnregisterArrayBuffer(*wire_bytes); + } MaybeHandle maybe_compiled_module = - WasmCompiledModuleSerializer::DeserializeWasmModule(isolate, &sc); + WasmCompiledModuleSerializer::DeserializeWasmModule( + isolate, &sc, + Vector( + reinterpret_cast(wire_bytes->backing_store()), + static_cast(wire_bytes->byte_length()->Number()))); + if (!already_external) { + wire_bytes->set_is_external(false); + isolate->heap()->RegisterNewArrayBuffer(*wire_bytes); + } Handle compiled_module; if (!maybe_compiled_module.ToHandle(&compiled_module)) { return isolate->heap()->undefined_value(); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4cb2b9863f..76b2e008ac 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -897,7 +897,7 @@ namespace internal { F(HasFixedUint8ClampedElements, 1, 1) \ F(SpeciesProtector, 0, 1) \ F(SerializeWasmModule, 1, 1) \ - F(DeserializeWasmModule, 1, 1) \ + F(DeserializeWasmModule, 2, 1) \ F(IsAsmWasmCode, 1, 1) \ F(IsNotAsmWasmCode, 1, 1) \ F(ValidateWasmInstancesChain, 2, 1) \ diff --git a/src/snapshot/code-serializer.cc b/src/snapshot/code-serializer.cc index 74ccf5f260..7e1e545759 100644 --- a/src/snapshot/code-serializer.cc +++ b/src/snapshot/code-serializer.cc @@ -223,12 +223,14 @@ std::unique_ptr WasmCompiledModuleSerializer::SerializeWasmModule( Handle::cast(input); WasmCompiledModuleSerializer wasm_cs(isolate, 0); wasm_cs.reference_map()->AddAttachedReference(*isolate->native_context()); + wasm_cs.reference_map()->AddAttachedReference( + *compiled_module->module_bytes()); ScriptData* data = wasm_cs.Serialize(compiled_module); return std::unique_ptr(data); } MaybeHandle WasmCompiledModuleSerializer::DeserializeWasmModule( - Isolate* isolate, ScriptData* data) { + Isolate* isolate, ScriptData* data, Vector wire_bytes) { SerializedCodeData::SanityCheckResult sanity_check_result = SerializedCodeData::CHECK_SUCCESS; MaybeHandle nothing; @@ -242,6 +244,15 @@ MaybeHandle WasmCompiledModuleSerializer::DeserializeWasmModule( Deserializer deserializer(&scd, true); deserializer.AddAttachedObject(isolate->native_context()); + MaybeHandle maybe_wire_bytes_as_string = + isolate->factory()->NewStringFromOneByte(wire_bytes, TENURED); + Handle wire_bytes_as_string; + if (!maybe_wire_bytes_as_string.ToHandle(&wire_bytes_as_string)) { + return nothing; + } + deserializer.AddAttachedObject( + handle(SeqOneByteString::cast(*wire_bytes_as_string))); + Vector stub_keys = scd.CodeStubKeys(); for (int i = 0; i < stub_keys.length(); ++i) { deserializer.AddAttachedObject( @@ -250,8 +261,9 @@ MaybeHandle WasmCompiledModuleSerializer::DeserializeWasmModule( MaybeHandle obj = deserializer.DeserializeObject(isolate); if (obj.is_null() || !obj.ToHandleChecked()->IsFixedArray()) return nothing; - Handle compiled_module = - Handle::cast(obj.ToHandleChecked()); + Handle compiled_module = + Handle::cast(obj.ToHandleChecked()); + wasm::WasmCompiledModule::RecreateModuleWrapper(isolate, compiled_module); return compiled_module; } diff --git a/src/snapshot/code-serializer.h b/src/snapshot/code-serializer.h index 61780ec0f8..15757379f0 100644 --- a/src/snapshot/code-serializer.h +++ b/src/snapshot/code-serializer.h @@ -59,8 +59,8 @@ class WasmCompiledModuleSerializer : public CodeSerializer { public: static std::unique_ptr SerializeWasmModule( Isolate* isolate, Handle compiled_module); - static MaybeHandle DeserializeWasmModule(Isolate* isolate, - ScriptData* data); + static MaybeHandle DeserializeWasmModule( + Isolate* isolate, ScriptData* data, Vector wire_bytes); protected: void SerializeCodeObject(Code* code_object, HowToCode how_to_code, diff --git a/test/mjsunit/wasm/compiled-module-serialization.js b/test/mjsunit/wasm/compiled-module-serialization.js index 96ebd8ab63..b5c25e0a01 100644 --- a/test/mjsunit/wasm/compiled-module-serialization.js +++ b/test/mjsunit/wasm/compiled-module-serialization.js @@ -35,12 +35,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); kExprCallFunction, 1]); builder.appendToTable([2, 3]); - - var module = new WebAssembly.Module(builder.toBuffer()); + var wire_bytes = builder.toBuffer(); + var module = new WebAssembly.Module(wire_bytes); var buff = %SerializeWasmModule(module); module = null; gc(); - module = %DeserializeWasmModule(buff); + module = %DeserializeWasmModule(buff, wire_bytes); var mem_1 = new ArrayBuffer(4); var view_1 = new Int32Array(mem_1); @@ -59,7 +59,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); (function DeserializeInvalidObject() { var invalid_buffer = new ArrayBuffer(10); - module = %DeserializeWasmModule(invalid_buffer); + module = %DeserializeWasmModule(invalid_buffer, invalid_buffer); assertEquals(module, undefined); })(); @@ -69,9 +69,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); .addBody([kExprI8Const, 42]) .exportFunc(); - var compiled_module = new WebAssembly.Module(builder.toBuffer()); + var wire_bytes = builder.toBuffer(); + var compiled_module = new WebAssembly.Module(wire_bytes); var serialized = %SerializeWasmModule(compiled_module); - var clone = %DeserializeWasmModule(serialized); + var clone = %DeserializeWasmModule(serialized, wire_bytes); assertNotNull(clone); assertFalse(clone == undefined); @@ -85,11 +86,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); .addBody([kExprI8Const, 42]) .exportFunc(); - var compiled_module = new WebAssembly.Module(builder.toBuffer()); + var wire_bytes = builder.toBuffer() + var compiled_module = new WebAssembly.Module(wire_bytes); var instance1 = new WebAssembly.Instance(compiled_module); var instance2 = new WebAssembly.Instance(compiled_module); var serialized = %SerializeWasmModule(compiled_module); - var clone = %DeserializeWasmModule(serialized); + var clone = %DeserializeWasmModule(serialized, wire_bytes); assertNotNull(clone); assertFalse(clone == undefined);