Index: src/value-serializer.cc |
diff --git a/src/value-serializer.cc b/src/value-serializer.cc |
index c3328f1bcade58ff0a69970226af8331f393af87..86c96dac16b430ab7a5bc433a1a8f607d52267da 100644 |
--- a/src/value-serializer.cc |
+++ b/src/value-serializer.cc |
@@ -9,11 +9,15 @@ |
#include "src/base/logging.h" |
#include "src/conversions.h" |
#include "src/factory.h" |
+#include "src/flags.h" |
#include "src/handles-inl.h" |
#include "src/isolate.h" |
#include "src/objects-inl.h" |
#include "src/objects.h" |
+#include "src/snapshot/code-serializer.h" |
#include "src/transitions.h" |
+#include "src/wasm/wasm-module.h" |
+#include "src/wasm/wasm-result.h" |
namespace v8 { |
namespace internal { |
@@ -107,6 +111,11 @@ enum class SerializationTag : uint8_t { |
kArrayBufferView = 'V', |
// Shared array buffer (transferred). transferID:uint32_t |
kSharedArrayBufferTransfer = 'u', |
+ // Compiled WebAssembly module. encodingType:(one-byte tag). |
+ // If encodingType == 'y' (raw bytes): |
+ // wasmWireByteLength:uint32_t, then raw data |
+ // compiledDataLength:uint32_t, then raw data |
+ kWasmModule = 'W', |
}; |
namespace { |
@@ -124,6 +133,10 @@ enum class ArrayBufferViewTag : uint8_t { |
kDataView = '?', |
}; |
+enum class WasmEncodingTag : uint8_t { |
+ kRawBytes = 'y', |
+}; |
+ |
} // namespace |
ValueSerializer::ValueSerializer(Isolate* isolate, |
@@ -365,8 +378,16 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { |
case JS_OBJECT_TYPE: |
case JS_API_OBJECT_TYPE: { |
Handle<JSObject> js_object = Handle<JSObject>::cast(receiver); |
- return js_object->GetInternalFieldCount() ? WriteHostObject(js_object) |
- : WriteJSObject(js_object); |
+ Map* map = js_object->map(); |
+ if (FLAG_expose_wasm && |
+ map->GetConstructor() == |
+ isolate_->native_context()->wasm_module_constructor()) { |
+ return WriteWasmModule(js_object); |
+ } else if (JSObject::GetInternalFieldCount(map)) { |
+ return WriteHostObject(js_object); |
+ } else { |
+ return WriteJSObject(js_object); |
+ } |
} |
case JS_SPECIAL_API_OBJECT_TYPE: |
return WriteHostObject(Handle<JSObject>::cast(receiver)); |
@@ -717,6 +738,29 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) { |
return Just(true); |
} |
+Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) { |
+ Handle<wasm::WasmCompiledModule> compiled_part( |
+ wasm::WasmCompiledModule::cast(object->GetInternalField(0)), isolate_); |
+ WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes; |
+ WriteTag(SerializationTag::kWasmModule); |
+ WriteRawBytes(&encoding_tag, sizeof(encoding_tag)); |
+ |
+ Handle<String> wire_bytes = compiled_part->module_bytes(); |
+ int wire_bytes_length = wire_bytes->length(); |
+ WriteVarint<uint32_t>(wire_bytes_length); |
+ uint8_t* destination = ReserveRawBytes(wire_bytes_length); |
+ String::WriteToFlat(*wire_bytes, destination, 0, wire_bytes_length); |
+ |
+ std::unique_ptr<ScriptData> script_data = |
+ WasmCompiledModuleSerializer::SerializeWasmModule(isolate_, |
+ compiled_part); |
+ int script_data_length = script_data->length(); |
+ WriteVarint<uint32_t>(script_data_length); |
+ WriteRawBytes(script_data->data(), script_data_length); |
+ |
+ return Just(true); |
+} |
+ |
Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) { |
if (!delegate_) { |
isolate_->Throw(*isolate_->factory()->NewError( |
@@ -1027,6 +1071,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() { |
const bool is_shared = true; |
return ReadTransferredJSArrayBuffer(is_shared); |
} |
+ case SerializationTag::kWasmModule: |
+ return ReadWasmModule(); |
default: |
// TODO(jbroman): Introduce an explicit tag for host objects to avoid |
// having to treat every unknown tag as a potential host object. |
@@ -1429,6 +1475,52 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( |
return typed_array; |
} |
+MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() { |
+ if (!FLAG_expose_wasm) return MaybeHandle<JSObject>(); |
+ |
+ Vector<const uint8_t> encoding_tag; |
+ if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) || |
+ encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) { |
+ return MaybeHandle<JSObject>(); |
+ } |
+ |
+ // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled |
+ // script data. |
+ static_assert(sizeof(int) <= sizeof(uint32_t), |
+ "max int must fit in uint32_t"); |
+ const uint32_t max_valid_size = std::numeric_limits<int>::max(); |
+ uint32_t wire_bytes_length = 0; |
+ Vector<const uint8_t> wire_bytes; |
+ uint32_t compiled_bytes_length = 0; |
+ Vector<const uint8_t> compiled_bytes; |
+ if (!ReadVarint<uint32_t>().To(&wire_bytes_length) || |
+ wire_bytes_length > max_valid_size || |
+ !ReadRawBytes(wire_bytes_length).To(&wire_bytes) || |
+ !ReadVarint<uint32_t>().To(&compiled_bytes_length) || |
+ compiled_bytes_length > max_valid_size || |
+ !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) { |
+ return MaybeHandle<JSObject>(); |
+ } |
+ |
+ // Try to deserialize the compiled module first. |
+ ScriptData script_data(compiled_bytes.start(), compiled_bytes.length()); |
+ Handle<FixedArray> compiled_part; |
+ if (WasmCompiledModuleSerializer::DeserializeWasmModule( |
+ isolate_, &script_data, wire_bytes) |
+ .ToHandle(&compiled_part)) { |
+ return wasm::CreateWasmModuleObject( |
+ isolate_, Handle<wasm::WasmCompiledModule>::cast(compiled_part), |
+ wasm::ModuleOrigin::kWasmOrigin); |
+ } |
+ |
+ // If that fails, recompile. |
+ wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule"); |
+ return wasm::CreateModuleObjectFromBytes( |
+ isolate_, wire_bytes.begin(), wire_bytes.end(), &thrower, |
+ wasm::ModuleOrigin::kWasmOrigin, Handle<Script>::null(), nullptr, |
+ nullptr); |
+} |
+ |
MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { |
if (!delegate_) return MaybeHandle<JSObject>(); |
STACK_CHECK(isolate_, MaybeHandle<JSObject>()); |