diff options
Diffstat (limited to 'deps/v8/src/wasm/wasm-serialization.cc')
-rw-r--r-- | deps/v8/src/wasm/wasm-serialization.cc | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc new file mode 100644 index 0000000000..337692b595 --- /dev/null +++ b/deps/v8/src/wasm/wasm-serialization.cc @@ -0,0 +1,687 @@ +// 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. + +#include "src/wasm/wasm-serialization.h" + +#include "src/assembler-inl.h" +#include "src/code-stubs.h" +#include "src/external-reference-table.h" +#include "src/objects-inl.h" +#include "src/objects.h" +#include "src/snapshot/serializer-common.h" +#include "src/version.h" +#include "src/wasm/module-compiler.h" +#include "src/wasm/module-decoder.h" +#include "src/wasm/wasm-module.h" +#include "src/wasm/wasm-objects-inl.h" +#include "src/wasm/wasm-objects.h" +#include "src/wasm/wasm-result.h" + +namespace v8 { +namespace internal { +namespace wasm { + +namespace { +void SetRawTargetData(RelocInfo* rinfo, uint32_t value) { + if (rinfo->target_address_size() == sizeof(uint32_t)) { + *(reinterpret_cast<uint32_t*>(rinfo->target_address_address())) = value; + return; + } else { + DCHECK_EQ(rinfo->target_address_size(), sizeof(intptr_t)); + DCHECK_EQ(rinfo->target_address_size(), 8); + *(reinterpret_cast<intptr_t*>(rinfo->target_address_address())) = + static_cast<intptr_t>(value); + return; + } +} + +class Writer { + public: + explicit Writer(Vector<byte> buffer) : buffer_(buffer) {} + template <typename T> + void Write(const T& value) { + if (FLAG_wasm_trace_serialization) { + OFStream os(stdout); + os << "wrote: " << (size_t)value << " sized: " << sizeof(T) << std::endl; + } + DCHECK_GE(buffer_.size(), sizeof(T)); + memcpy(buffer_.start(), reinterpret_cast<const byte*>(&value), sizeof(T)); + buffer_ = buffer_ + sizeof(T); + } + + void WriteVector(const Vector<const byte> data) { + DCHECK_GE(buffer_.size(), data.size()); + if (data.size() > 0) { + memcpy(buffer_.start(), data.start(), data.size()); + buffer_ = buffer_ + data.size(); + } + if (FLAG_wasm_trace_serialization) { + OFStream os(stdout); + os << "wrote vector of " << data.size() << " elements" << std::endl; + } + } + Vector<byte> current_buffer() const { return buffer_; } + + private: + Vector<byte> buffer_; +}; + +class Reader { + public: + explicit Reader(Vector<const byte> buffer) : buffer_(buffer) {} + + template <typename T> + T Read() { + DCHECK_GE(buffer_.size(), sizeof(T)); + T ret; + memcpy(reinterpret_cast<byte*>(&ret), buffer_.start(), sizeof(T)); + buffer_ = buffer_ + sizeof(T); + if (FLAG_wasm_trace_serialization) { + OFStream os(stdout); + os << "read: " << (size_t)ret << " sized: " << sizeof(T) << std::endl; + } + return ret; + } + + Vector<const byte> GetSubvector(size_t size) { + Vector<const byte> ret = {buffer_.start(), size}; + buffer_ = buffer_ + size; + return ret; + } + + void ReadIntoVector(const Vector<byte> data) { + if (data.size() > 0) { + DCHECK_GE(buffer_.size(), data.size()); + memcpy(data.start(), buffer_.start(), data.size()); + buffer_ = buffer_ + data.size(); + } + if (FLAG_wasm_trace_serialization) { + OFStream os(stdout); + os << "read vector of " << data.size() << " elements" << std::endl; + } + } + + Vector<const byte> current_buffer() const { return buffer_; } + + private: + Vector<const byte> buffer_; +}; + +} // namespace + +size_t WasmSerializedFormatVersion::GetVersionSize() { return kVersionSize; } + +bool WasmSerializedFormatVersion::WriteVersion(Isolate* isolate, + Vector<byte> buffer) { + if (buffer.size() < GetVersionSize()) return false; + Writer writer(buffer); + writer.Write(SerializedData::ComputeMagicNumber( + ExternalReferenceTable::instance(isolate))); + writer.Write(Version::Hash()); + writer.Write(static_cast<uint32_t>(CpuFeatures::SupportedFeatures())); + writer.Write(FlagList::Hash()); + return true; +} + +bool WasmSerializedFormatVersion::IsSupportedVersion( + Isolate* isolate, const Vector<const byte> buffer) { + if (buffer.size() < kVersionSize) return false; + byte version[kVersionSize]; + CHECK(WriteVersion(isolate, {version, kVersionSize})); + if (memcmp(buffer.start(), version, kVersionSize) == 0) return true; + return false; +} + +NativeModuleSerializer::NativeModuleSerializer(Isolate* isolate, + const NativeModule* module) + : isolate_(isolate), native_module_(module) { + DCHECK_NOT_NULL(isolate_); + DCHECK_NOT_NULL(native_module_); + DCHECK_NULL(native_module_->lazy_builtin_); + // TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist + // the unique ones, i.e. the cache. + ExternalReferenceTable* table = ExternalReferenceTable::instance(isolate_); + for (uint32_t i = 0; i < table->size(); ++i) { + Address addr = table->address(i); + reference_table_lookup_.insert(std::make_pair(addr, i)); + } + // defer populating the stub_lookup_ to when we buffer the stubs + for (auto pair : native_module_->trampolines_) { + v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first); + int builtin_index = code->builtin_index(); + if (builtin_index >= 0) { + uint32_t tag = static_cast<uint32_t>(builtin_index); + builtin_lookup_.insert(std::make_pair(pair.second, tag)); + } + } + BufferHeader(); + state_ = Metadata; +} + +size_t NativeModuleSerializer::MeasureHeader() const { + return sizeof(uint32_t) + // total wasm fct count + sizeof( + uint32_t) + // imported fcts - i.e. index of first wasm function + sizeof(uint32_t) + // table count + native_module_->specialization_data_.function_tables.size() * + 2 // 2 same-sized tables, containing pointers + * sizeof(GlobalHandleAddress); +} + +void NativeModuleSerializer::BufferHeader() { + size_t metadata_size = MeasureHeader(); + scratch_.resize(metadata_size); + remaining_ = {scratch_.data(), metadata_size}; + Writer writer(remaining_); + writer.Write(native_module_->FunctionCount()); + writer.Write(native_module_->num_imported_functions()); + writer.Write(static_cast<uint32_t>( + native_module_->specialization_data_.function_tables.size())); + for (size_t i = 0, + e = native_module_->specialization_data_.function_tables.size(); + i < e; ++i) { + writer.Write(native_module_->specialization_data_.function_tables[i]); + writer.Write(native_module_->specialization_data_.signature_tables[i]); + } +} + +size_t NativeModuleSerializer::GetCodeHeaderSize() { + return sizeof(size_t) + // size of this section + sizeof(size_t) + // offset of constant pool + sizeof(size_t) + // offset of safepoint table + sizeof(uint32_t) + // stack slots + sizeof(size_t) + // code size + sizeof(size_t) + // reloc size + sizeof(uint32_t) + // handler size + sizeof(uint32_t) + // source positions size + sizeof(size_t) + // protected instructions size + sizeof(bool); // is_liftoff +} + +size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const { + FixedArray* handler_table = GetHandlerTable(code); + ByteArray* source_positions = GetSourcePositions(code); + return GetCodeHeaderSize() + code->instructions().size() + // code + code->reloc_info().size() + // reloc info + (handler_table == nullptr + ? 0 + : static_cast<uint32_t>( + handler_table->length())) + // handler table + (source_positions == nullptr + ? 0 + : static_cast<uint32_t>( + source_positions->length())) + // source positions + code->protected_instructions().size() * + sizeof(trap_handler::ProtectedInstructionData); +} + +size_t NativeModuleSerializer::Measure() const { + size_t ret = MeasureHeader() + MeasureCopiedStubs(); + for (uint32_t i = native_module_->num_imported_functions(), + e = native_module_->FunctionCount(); + i < e; ++i) { + ret += MeasureCode(native_module_->GetCode(i)); + } + return ret; +} + +size_t NativeModuleSerializer::DrainBuffer(Vector<byte> dest) { + size_t to_write = std::min(dest.size(), remaining_.size()); + memcpy(dest.start(), remaining_.start(), to_write); + DCHECK_GE(remaining_.size(), to_write); + remaining_ = remaining_ + to_write; + return to_write; +} + +size_t NativeModuleSerializer::MeasureCopiedStubs() const { + size_t ret = sizeof(uint32_t) + // number of stubs + native_module_->stubs_.size() * sizeof(uint32_t); // stub keys + for (auto pair : native_module_->trampolines_) { + v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first); + int builtin_index = code->builtin_index(); + if (builtin_index < 0) ret += sizeof(uint32_t); + } + return ret; +} + +void NativeModuleSerializer::BufferCopiedStubs() { + // We buffer all the stubs together, because they are very likely + // few and small. Each stub is buffered like a WasmCode would, + // and in addition prefaced by its stub key. The whole section is prefaced + // by the number of stubs. + size_t buff_size = MeasureCopiedStubs(); + scratch_.resize(buff_size); + remaining_ = {scratch_.data(), buff_size}; + Writer writer(remaining_); + writer.Write( + static_cast<uint32_t>((buff_size - sizeof(uint32_t)) / sizeof(uint32_t))); + uint32_t stub_id = 0; + + for (auto pair : native_module_->stubs_) { + uint32_t key = pair.first; + writer.Write(key); + stub_lookup_.insert( + std::make_pair(pair.second->instructions().start(), stub_id)); + ++stub_id; + } + + for (auto pair : native_module_->trampolines_) { + v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first); + int builtin_index = code->builtin_index(); + if (builtin_index < 0) { + stub_lookup_.insert(std::make_pair(pair.second, stub_id)); + writer.Write(code->stub_key()); + ++stub_id; + } + } +} + +FixedArray* NativeModuleSerializer::GetHandlerTable( + const WasmCode* code) const { + if (code->kind() != WasmCode::Function) return nullptr; + uint32_t index = code->index(); + // We write the address, the size, and then copy the code as-is, followed + // by reloc info, followed by handler table and source positions. + Object* handler_table_entry = + native_module_->compiled_module()->handler_table()->get( + static_cast<int>(index)); + if (handler_table_entry->IsFixedArray()) { + return FixedArray::cast(handler_table_entry); + } + return nullptr; +} + +ByteArray* NativeModuleSerializer::GetSourcePositions( + const WasmCode* code) const { + if (code->kind() != WasmCode::Function) return nullptr; + uint32_t index = code->index(); + Object* source_positions_entry = + native_module_->compiled_module()->source_positions()->get( + static_cast<int>(index)); + if (source_positions_entry->IsByteArray()) { + return ByteArray::cast(source_positions_entry); + } + return nullptr; +} + +void NativeModuleSerializer::BufferCurrentWasmCode() { + const WasmCode* code = native_module_->GetCode(index_); + size_t size = MeasureCode(code); + scratch_.resize(size); + remaining_ = {scratch_.data(), size}; + BufferCodeInAllocatedScratch(code); +} + +void NativeModuleSerializer::BufferCodeInAllocatedScratch( + const WasmCode* code) { + // We write the address, the size, and then copy the code as-is, followed + // by reloc info, followed by handler table and source positions. + FixedArray* handler_table_entry = GetHandlerTable(code); + uint32_t handler_table_size = 0; + Address handler_table = nullptr; + if (handler_table_entry != nullptr) { + handler_table_size = static_cast<uint32_t>(handler_table_entry->length()); + handler_table = reinterpret_cast<Address>( + handler_table_entry->GetFirstElementAddress()); + } + ByteArray* source_positions_entry = GetSourcePositions(code); + Address source_positions = nullptr; + uint32_t source_positions_size = 0; + if (source_positions_entry != nullptr) { + source_positions = source_positions_entry->GetDataStartAddress(); + source_positions_size = + static_cast<uint32_t>(source_positions_entry->length()); + } + Writer writer(remaining_); + // write the header + writer.Write(MeasureCode(code)); + writer.Write(code->constant_pool_offset()); + writer.Write(code->safepoint_table_offset()); + writer.Write(code->stack_slots()); + writer.Write(code->instructions().size()); + writer.Write(code->reloc_info().size()); + writer.Write(handler_table_size); + writer.Write(source_positions_size); + writer.Write(code->protected_instructions().size()); + writer.Write(code->is_liftoff()); + // next is the code, which we have to reloc. + Address serialized_code_start = writer.current_buffer().start(); + // write the code and everything else + writer.WriteVector(code->instructions()); + writer.WriteVector(code->reloc_info()); + writer.WriteVector({handler_table, handler_table_size}); + writer.WriteVector({source_positions, source_positions_size}); + writer.WriteVector( + {reinterpret_cast<const byte*>(code->protected_instructions().data()), + sizeof(trap_handler::ProtectedInstructionData) * + code->protected_instructions().size()}); + // now relocate the code + int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | + RelocInfo::ModeMask(RelocInfo::WASM_CALL) | + RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY); + RelocIterator orig_iter(code->instructions(), code->reloc_info(), + code->constant_pool(), mask); + for (RelocIterator + iter({serialized_code_start, code->instructions().size()}, + code->reloc_info(), + serialized_code_start + code->constant_pool_offset(), mask); + !iter.done(); iter.next(), orig_iter.next()) { + RelocInfo::Mode mode = orig_iter.rinfo()->rmode(); + switch (mode) { + case RelocInfo::CODE_TARGET: { + Address orig_target = orig_iter.rinfo()->target_address(); + uint32_t tag = EncodeBuiltinOrStub(orig_target); + SetRawTargetData(iter.rinfo(), tag); + } break; + case RelocInfo::WASM_CALL: { + Address orig_target = orig_iter.rinfo()->wasm_call_address(); + uint32_t tag = wasm_targets_lookup_[orig_target]; + SetRawTargetData(iter.rinfo(), tag); + } break; + case RelocInfo::RUNTIME_ENTRY: { + Address orig_target = orig_iter.rinfo()->target_address(); + uint32_t tag = reference_table_lookup_[orig_target]; + SetRawTargetData(iter.rinfo(), tag); + } break; + default: + UNREACHABLE(); + } + } +} + +uint32_t NativeModuleSerializer::EncodeBuiltinOrStub(Address address) { + auto builtin_iter = builtin_lookup_.find(address); + uint32_t tag = 0; + if (builtin_iter != builtin_lookup_.end()) { + uint32_t id = builtin_iter->second; + DCHECK_LT(id, std::numeric_limits<uint16_t>::max()); + tag = id << 16; + } else { + auto stub_iter = stub_lookup_.find(address); + DCHECK(stub_iter != stub_lookup_.end()); + uint32_t id = stub_iter->second; + DCHECK_LT(id, std::numeric_limits<uint16_t>::max()); + tag = id & 0x0000ffff; + } + return tag; +} + +size_t NativeModuleSerializer::Write(Vector<byte> dest) { + Vector<byte> original = dest; + while (dest.size() > 0) { + switch (state_) { + case Metadata: { + dest = dest + DrainBuffer(dest); + if (remaining_.size() == 0) { + BufferCopiedStubs(); + state_ = Stubs; + } + break; + } + case Stubs: { + dest = dest + DrainBuffer(dest); + if (remaining_.size() == 0) { + index_ = native_module_->num_imported_functions(); + BufferCurrentWasmCode(); + state_ = CodeSection; + } + break; + } + case CodeSection: { + dest = dest + DrainBuffer(dest); + if (remaining_.size() == 0) { + if (++index_ < native_module_->FunctionCount()) { + BufferCurrentWasmCode(); + } else { + state_ = Done; + } + } + break; + } + default: + UNREACHABLE(); + } + } + DCHECK_GE(original.size(), dest.size()); + return original.size() - dest.size(); +} + +// static +std::pair<std::unique_ptr<byte[]>, size_t> +NativeModuleSerializer::SerializeWholeModule( + Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { + NativeModule* native_module = compiled_module->GetNativeModule(); + NativeModuleSerializer serializer(isolate, native_module); + size_t version_size = WasmSerializedFormatVersion::GetVersionSize(); + size_t buff_size = serializer.Measure() + version_size; + std::unique_ptr<byte[]> ret(new byte[buff_size]); + if (!WasmSerializedFormatVersion::WriteVersion(isolate, + {ret.get(), buff_size})) { + return {}; + } + + size_t written = + serializer.Write({ret.get() + version_size, buff_size - version_size}); + if (written != buff_size - version_size) return {}; + + return {std::move(ret), buff_size}; +} + +NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate, + NativeModule* native_module) + : isolate_(isolate), native_module_(native_module) {} + +void NativeModuleDeserializer::Expect(size_t size) { + scratch_.resize(size); + current_expectation_ = size; + unread_ = {scratch_.data(), size}; +} + +bool NativeModuleDeserializer::Read(Vector<const byte> data) { + unread_ = data; + if (!ReadHeader()) return false; + if (!ReadStubs()) return false; + index_ = native_module_->num_imported_functions(); + for (; index_ < native_module_->FunctionCount(); ++index_) { + if (!ReadCode()) return false; + } + native_module_->LinkAll(); + return data.size() - unread_.size(); +} + +bool NativeModuleDeserializer::ReadHeader() { + size_t start_size = unread_.size(); + Reader reader(unread_); + size_t functions = reader.Read<uint32_t>(); + size_t imports = reader.Read<uint32_t>(); + bool ok = functions == native_module_->FunctionCount() && + imports == native_module_->num_imported_functions(); + if (!ok) return false; + size_t table_count = reader.Read<uint32_t>(); + + std::vector<GlobalHandleAddress> sigs(table_count); + std::vector<GlobalHandleAddress> funcs(table_count); + for (size_t i = 0; i < table_count; ++i) { + funcs[i] = reader.Read<GlobalHandleAddress>(); + sigs[i] = reader.Read<GlobalHandleAddress>(); + } + native_module_->signature_tables() = sigs; + native_module_->function_tables() = funcs; + // resize, so that from here on the native module can be + // asked about num_function_tables(). + native_module_->empty_function_tables().resize(table_count); + native_module_->empty_signature_tables().resize(table_count); + + unread_ = unread_ + (start_size - reader.current_buffer().size()); + return true; +} + +bool NativeModuleDeserializer::ReadStubs() { + size_t start_size = unread_.size(); + Reader reader(unread_); + size_t nr_stubs = reader.Read<uint32_t>(); + stubs_.reserve(nr_stubs); + for (size_t i = 0; i < nr_stubs; ++i) { + uint32_t key = reader.Read<uint32_t>(); + v8::internal::Code* stub = + *(v8::internal::CodeStub::GetCode(isolate_, key).ToHandleChecked()); + stubs_.push_back(native_module_->GetLocalAddressFor(handle(stub))); + } + unread_ = unread_ + (start_size - reader.current_buffer().size()); + return true; +} + +bool NativeModuleDeserializer::ReadCode() { + size_t start_size = unread_.size(); + Reader reader(unread_); + size_t code_section_size = reader.Read<size_t>(); + USE(code_section_size); + size_t constant_pool_offset = reader.Read<size_t>(); + size_t safepoint_table_offset = reader.Read<size_t>(); + uint32_t stack_slot_count = reader.Read<uint32_t>(); + size_t code_size = reader.Read<size_t>(); + size_t reloc_size = reader.Read<size_t>(); + uint32_t handler_size = reader.Read<uint32_t>(); + uint32_t source_position_size = reader.Read<uint32_t>(); + size_t protected_instructions_size = reader.Read<size_t>(); + bool is_liftoff = reader.Read<bool>(); + std::shared_ptr<ProtectedInstructions> protected_instructions( + new ProtectedInstructions(protected_instructions_size)); + DCHECK_EQ(protected_instructions_size, protected_instructions->size()); + + Vector<const byte> code_buffer = reader.GetSubvector(code_size); + std::unique_ptr<byte[]> reloc_info; + if (reloc_size > 0) { + reloc_info.reset(new byte[reloc_size]); + reader.ReadIntoVector({reloc_info.get(), reloc_size}); + } + WasmCode* ret = native_module_->AddOwnedCode( + code_buffer, std::move(reloc_info), reloc_size, Just(index_), + WasmCode::Function, constant_pool_offset, stack_slot_count, + safepoint_table_offset, protected_instructions, is_liftoff); + if (ret == nullptr) return false; + native_module_->SetCodeTable(index_, ret); + + // now relocate the code + int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | + RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | + RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY); + for (RelocIterator iter(ret->instructions(), ret->reloc_info(), + ret->constant_pool(), mask); + !iter.done(); iter.next()) { + RelocInfo::Mode mode = iter.rinfo()->rmode(); + switch (mode) { + case RelocInfo::EMBEDDED_OBJECT: { + // We only expect {undefined}. We check for that when we add code. + iter.rinfo()->set_target_object(isolate_->heap()->undefined_value(), + SKIP_WRITE_BARRIER); + } + case RelocInfo::CODE_TARGET: { + uint32_t tag = *(reinterpret_cast<uint32_t*>( + iter.rinfo()->target_address_address())); + Address target = GetTrampolineOrStubFromTag(tag); + iter.rinfo()->set_target_address(nullptr, target, SKIP_WRITE_BARRIER, + SKIP_ICACHE_FLUSH); + } break; + case RelocInfo::RUNTIME_ENTRY: { + uint32_t orig_target = static_cast<uint32_t>( + reinterpret_cast<intptr_t>(iter.rinfo()->target_address())); + Address address = + ExternalReferenceTable::instance(isolate_)->address(orig_target); + iter.rinfo()->set_target_runtime_entry( + nullptr, address, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH); + } break; + default: + break; + } + } + if (handler_size > 0) { + Handle<FixedArray> handler_table = isolate_->factory()->NewFixedArray( + static_cast<int>(handler_size), TENURED); + reader.ReadIntoVector( + {reinterpret_cast<Address>(handler_table->GetFirstElementAddress()), + handler_size}); + native_module_->compiled_module()->handler_table()->set( + static_cast<int>(index_), *handler_table); + } + if (source_position_size > 0) { + Handle<ByteArray> source_positions = isolate_->factory()->NewByteArray( + static_cast<int>(source_position_size), TENURED); + reader.ReadIntoVector( + {source_positions->GetDataStartAddress(), source_position_size}); + native_module_->compiled_module()->source_positions()->set( + static_cast<int>(index_), *source_positions); + } + if (protected_instructions_size > 0) { + reader.ReadIntoVector( + {reinterpret_cast<byte*>(protected_instructions->data()), + sizeof(trap_handler::ProtectedInstructionData) * + protected_instructions->size()}); + } + unread_ = unread_ + (start_size - reader.current_buffer().size()); + return true; +} + +Address NativeModuleDeserializer::GetTrampolineOrStubFromTag(uint32_t tag) { + if ((tag & 0x0000ffff) == 0) { + int builtin_id = static_cast<int>(tag >> 16); + v8::internal::Code* builtin = isolate_->builtins()->builtin(builtin_id); + return native_module_->GetLocalAddressFor(handle(builtin)); + } else { + DCHECK_EQ(tag & 0xffff0000, 0); + return stubs_[tag]; + } +} + +MaybeHandle<WasmCompiledModule> NativeModuleDeserializer::DeserializeFullBuffer( + Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes) { + if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) { + return {}; + } + if (!WasmSerializedFormatVersion::IsSupportedVersion(isolate, data)) { + return {}; + } + data = data + WasmSerializedFormatVersion::GetVersionSize(); + ModuleResult decode_result = + SyncDecodeWasmModule(isolate, wire_bytes.start(), wire_bytes.end(), false, + i::wasm::kWasmOrigin); + if (!decode_result.ok()) return {}; + CHECK_NOT_NULL(decode_result.val); + Handle<String> module_bytes = + isolate->factory() + ->NewStringFromOneByte( + {wire_bytes.start(), static_cast<size_t>(wire_bytes.length())}, + TENURED) + .ToHandleChecked(); + DCHECK(module_bytes->IsSeqOneByteString()); + // The {module_wrapper} will take ownership of the {WasmModule} object, + // and it will be destroyed when the GC reclaims the wrapper object. + Handle<WasmModuleWrapper> module_wrapper = + WasmModuleWrapper::From(isolate, decode_result.val.release()); + Handle<Script> script = CreateWasmScript(isolate, wire_bytes); + Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New( + isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes), + script, Handle<ByteArray>::null()); + int export_wrappers_size = + static_cast<int>(shared->module()->num_exported_functions); + Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray( + static_cast<int>(export_wrappers_size), TENURED); + + Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New( + isolate, shared->module(), isolate->factory()->NewFixedArray(0, TENURED), + export_wrappers, {}, {}); + compiled_module->OnWasmModuleDecodingComplete(shared); + NativeModuleDeserializer deserializer(isolate, + compiled_module->GetNativeModule()); + if (!deserializer.Read(data)) return {}; + + CompileJsToWasmWrappers(isolate, compiled_module, isolate->counters()); + WasmCompiledModule::ReinitializeAfterDeserialization(isolate, + compiled_module); + return compiled_module; +} + +} // namespace wasm +} // namespace internal +} // namespace v8 |