Home | History | Annotate | Download | only in wasm
      1 // Copyright 2017 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/wasm/wasm-serialization.h"
      6 
      7 #include "src/assembler-inl.h"
      8 #include "src/external-reference-table.h"
      9 #include "src/objects-inl.h"
     10 #include "src/objects.h"
     11 #include "src/snapshot/code-serializer.h"
     12 #include "src/snapshot/serializer-common.h"
     13 #include "src/utils.h"
     14 #include "src/version.h"
     15 #include "src/wasm/function-compiler.h"
     16 #include "src/wasm/module-compiler.h"
     17 #include "src/wasm/module-decoder.h"
     18 #include "src/wasm/wasm-code-manager.h"
     19 #include "src/wasm/wasm-module.h"
     20 #include "src/wasm/wasm-objects-inl.h"
     21 #include "src/wasm/wasm-objects.h"
     22 #include "src/wasm/wasm-result.h"
     23 
     24 namespace v8 {
     25 namespace internal {
     26 namespace wasm {
     27 
     28 namespace {
     29 
     30 // TODO(bbudge) Try to unify the various implementations of readers and writers
     31 // in WASM, e.g. StreamProcessor and ZoneBuffer, with these.
     32 class Writer {
     33  public:
     34   explicit Writer(Vector<byte> buffer)
     35       : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
     36 
     37   size_t bytes_written() const { return pos_ - start_; }
     38   byte* current_location() const { return pos_; }
     39   size_t current_size() const { return end_ - pos_; }
     40   Vector<byte> current_buffer() const {
     41     return {current_location(), current_size()};
     42   }
     43 
     44   template <typename T>
     45   void Write(const T& value) {
     46     DCHECK_GE(current_size(), sizeof(T));
     47     WriteUnalignedValue(reinterpret_cast<Address>(current_location()), value);
     48     pos_ += sizeof(T);
     49     if (FLAG_wasm_trace_serialization) {
     50       StdoutStream{} << "wrote: " << (size_t)value << " sized: " << sizeof(T)
     51                      << std::endl;
     52     }
     53   }
     54 
     55   void WriteVector(const Vector<const byte> v) {
     56     DCHECK_GE(current_size(), v.size());
     57     if (v.size() > 0) {
     58       memcpy(current_location(), v.start(), v.size());
     59       pos_ += v.size();
     60     }
     61     if (FLAG_wasm_trace_serialization) {
     62       StdoutStream{} << "wrote vector of " << v.size() << " elements"
     63                      << std::endl;
     64     }
     65   }
     66 
     67   void Skip(size_t size) { pos_ += size; }
     68 
     69  private:
     70   byte* const start_;
     71   byte* const end_;
     72   byte* pos_;
     73 };
     74 
     75 class Reader {
     76  public:
     77   explicit Reader(Vector<const byte> buffer)
     78       : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
     79 
     80   size_t bytes_read() const { return pos_ - start_; }
     81   const byte* current_location() const { return pos_; }
     82   size_t current_size() const { return end_ - pos_; }
     83   Vector<const byte> current_buffer() const {
     84     return {current_location(), current_size()};
     85   }
     86 
     87   template <typename T>
     88   T Read() {
     89     DCHECK_GE(current_size(), sizeof(T));
     90     T value =
     91         ReadUnalignedValue<T>(reinterpret_cast<Address>(current_location()));
     92     pos_ += sizeof(T);
     93     if (FLAG_wasm_trace_serialization) {
     94       StdoutStream{} << "read: " << (size_t)value << " sized: " << sizeof(T)
     95                      << std::endl;
     96     }
     97     return value;
     98   }
     99 
    100   void ReadVector(Vector<byte> v) {
    101     if (v.size() > 0) {
    102       DCHECK_GE(current_size(), v.size());
    103       memcpy(v.start(), current_location(), v.size());
    104       pos_ += v.size();
    105     }
    106     if (FLAG_wasm_trace_serialization) {
    107       StdoutStream{} << "read vector of " << v.size() << " elements"
    108                      << std::endl;
    109     }
    110   }
    111 
    112   void Skip(size_t size) { pos_ += size; }
    113 
    114  private:
    115   const byte* const start_;
    116   const byte* const end_;
    117   const byte* pos_;
    118 };
    119 
    120 constexpr size_t kVersionSize = 4 * sizeof(uint32_t);
    121 
    122 void WriteVersion(Isolate* isolate, Writer* writer) {
    123   writer->Write(SerializedData::ComputeMagicNumber(
    124       isolate->heap()->external_reference_table()));
    125   writer->Write(Version::Hash());
    126   writer->Write(static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
    127   writer->Write(FlagList::Hash());
    128 }
    129 
    130 bool IsSupportedVersion(Isolate* isolate, const Vector<const byte> version) {
    131   if (version.size() < kVersionSize) return false;
    132   byte current_version[kVersionSize];
    133   Writer writer({current_version, kVersionSize});
    134   WriteVersion(isolate, &writer);
    135   return memcmp(version.start(), current_version, kVersionSize) == 0;
    136 }
    137 
    138 // On Intel, call sites are encoded as a displacement. For linking and for
    139 // serialization/deserialization, we want to store/retrieve a tag (the function
    140 // index). On Intel, that means accessing the raw displacement.
    141 // On ARM64, call sites are encoded as either a literal load or a direct branch.
    142 // Other platforms simply require accessing the target address.
    143 void SetWasmCalleeTag(RelocInfo* rinfo, uint32_t tag) {
    144 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
    145   *(reinterpret_cast<uint32_t*>(rinfo->target_address_address())) = tag;
    146 #elif V8_TARGET_ARCH_ARM64
    147   Instruction* instr = reinterpret_cast<Instruction*>(rinfo->pc());
    148   if (instr->IsLdrLiteralX()) {
    149     Memory<Address>(rinfo->constant_pool_entry_address()) =
    150         static_cast<Address>(tag);
    151   } else {
    152     DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
    153     instr->SetBranchImmTarget(
    154         reinterpret_cast<Instruction*>(rinfo->pc() + tag * kInstrSize));
    155   }
    156 #else
    157   Address addr = static_cast<Address>(tag);
    158   if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
    159     rinfo->set_target_external_reference(addr, SKIP_ICACHE_FLUSH);
    160   } else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
    161     rinfo->set_wasm_stub_call_address(addr, SKIP_ICACHE_FLUSH);
    162   } else {
    163     rinfo->set_target_address(addr, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
    164   }
    165 #endif
    166 }
    167 
    168 uint32_t GetWasmCalleeTag(RelocInfo* rinfo) {
    169 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
    170   return *(reinterpret_cast<uint32_t*>(rinfo->target_address_address()));
    171 #elif V8_TARGET_ARCH_ARM64
    172   Instruction* instr = reinterpret_cast<Instruction*>(rinfo->pc());
    173   if (instr->IsLdrLiteralX()) {
    174     return static_cast<uint32_t>(
    175         Memory<Address>(rinfo->constant_pool_entry_address()));
    176   } else {
    177     DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
    178     return static_cast<uint32_t>(instr->ImmPCOffset() / kInstrSize);
    179   }
    180 #else
    181   Address addr;
    182   if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
    183     addr = rinfo->target_external_reference();
    184   } else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
    185     addr = rinfo->wasm_stub_call_address();
    186   } else {
    187     addr = rinfo->target_address();
    188   }
    189   return static_cast<uint32_t>(addr);
    190 #endif
    191 }
    192 
    193 constexpr size_t kHeaderSize =
    194     sizeof(uint32_t) +  // total wasm function count
    195     sizeof(uint32_t);   // imported functions (index of first wasm function)
    196 
    197 constexpr size_t kCodeHeaderSize =
    198     sizeof(size_t) +         // size of code section
    199     sizeof(size_t) +         // offset of constant pool
    200     sizeof(size_t) +         // offset of safepoint table
    201     sizeof(size_t) +         // offset of handler table
    202     sizeof(uint32_t) +       // stack slots
    203     sizeof(size_t) +         // code size
    204     sizeof(size_t) +         // reloc size
    205     sizeof(size_t) +         // source positions size
    206     sizeof(size_t) +         // protected instructions size
    207     sizeof(WasmCode::Tier);  // tier
    208 
    209 }  // namespace
    210 
    211 class V8_EXPORT_PRIVATE NativeModuleSerializer {
    212  public:
    213   NativeModuleSerializer() = delete;
    214   NativeModuleSerializer(Isolate*, const NativeModule*,
    215                          Vector<WasmCode* const>);
    216 
    217   size_t Measure() const;
    218   bool Write(Writer* writer);
    219 
    220  private:
    221   size_t MeasureCode(const WasmCode*) const;
    222   void WriteHeader(Writer* writer);
    223   void WriteCode(const WasmCode*, Writer* writer);
    224 
    225   Isolate* const isolate_;
    226   const NativeModule* const native_module_;
    227   Vector<WasmCode* const> code_table_;
    228   bool write_called_;
    229 
    230   // Reverse lookup tables for embedded addresses.
    231   std::map<Address, uint32_t> wasm_stub_targets_lookup_;
    232   std::map<Address, uint32_t> reference_table_lookup_;
    233 
    234   DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer);
    235 };
    236 
    237 NativeModuleSerializer::NativeModuleSerializer(
    238     Isolate* isolate, const NativeModule* module,
    239     Vector<WasmCode* const> code_table)
    240     : isolate_(isolate),
    241       native_module_(module),
    242       code_table_(code_table),
    243       write_called_(false) {
    244   DCHECK_NOT_NULL(isolate_);
    245   DCHECK_NOT_NULL(native_module_);
    246   // TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist
    247   // the unique ones, i.e. the cache.
    248   for (uint32_t i = 0; i < WasmCode::kRuntimeStubCount; ++i) {
    249     Address addr =
    250         native_module_->runtime_stub(static_cast<WasmCode::RuntimeStubId>(i))
    251             ->instruction_start();
    252     wasm_stub_targets_lookup_.insert(std::make_pair(addr, i));
    253   }
    254   ExternalReferenceTable* table = isolate_->heap()->external_reference_table();
    255   for (uint32_t i = 0; i < table->size(); ++i) {
    256     Address addr = table->address(i);
    257     reference_table_lookup_.insert(std::make_pair(addr, i));
    258   }
    259 }
    260 
    261 size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const {
    262   if (code == nullptr) return sizeof(size_t);
    263   DCHECK_EQ(WasmCode::kFunction, code->kind());
    264   return kCodeHeaderSize + code->instructions().size() +
    265          code->reloc_info().size() + code->source_positions().size() +
    266          code->protected_instructions().size() *
    267              sizeof(trap_handler::ProtectedInstructionData);
    268 }
    269 
    270 size_t NativeModuleSerializer::Measure() const {
    271   size_t size = kHeaderSize;
    272   for (WasmCode* code : code_table_) {
    273     size += MeasureCode(code);
    274   }
    275   return size;
    276 }
    277 
    278 void NativeModuleSerializer::WriteHeader(Writer* writer) {
    279   writer->Write(native_module_->num_functions());
    280   writer->Write(native_module_->num_imported_functions());
    281 }
    282 
    283 void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
    284   if (code == nullptr) {
    285     writer->Write(size_t{0});
    286     return;
    287   }
    288   DCHECK_EQ(WasmCode::kFunction, code->kind());
    289   // Write the size of the entire code section, followed by the code header.
    290   writer->Write(MeasureCode(code));
    291   writer->Write(code->constant_pool_offset());
    292   writer->Write(code->safepoint_table_offset());
    293   writer->Write(code->handler_table_offset());
    294   writer->Write(code->stack_slots());
    295   writer->Write(code->instructions().size());
    296   writer->Write(code->reloc_info().size());
    297   writer->Write(code->source_positions().size());
    298   writer->Write(code->protected_instructions().size());
    299   writer->Write(code->tier());
    300 
    301   // Get a pointer to the destination buffer, to hold relocated code.
    302   byte* serialized_code_start = writer->current_buffer().start();
    303   byte* code_start = serialized_code_start;
    304   size_t code_size = code->instructions().size();
    305   writer->Skip(code_size);
    306   // Write the reloc info, source positions, and protected code.
    307   writer->WriteVector(code->reloc_info());
    308   writer->WriteVector(code->source_positions());
    309   writer->WriteVector(Vector<byte>::cast(code->protected_instructions()));
    310 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM
    311   // On platforms that don't support misaligned word stores, copy to an aligned
    312   // buffer if necessary so we can relocate the serialized code.
    313   std::unique_ptr<byte[]> aligned_buffer;
    314   if (!IsAligned(reinterpret_cast<Address>(serialized_code_start),
    315                  kInt32Size)) {
    316     aligned_buffer.reset(new byte[code_size]);
    317     code_start = aligned_buffer.get();
    318   }
    319 #endif
    320   memcpy(code_start, code->instructions().start(), code_size);
    321   // Relocate the code.
    322   int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
    323              RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
    324              RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
    325              RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
    326              RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
    327   RelocIterator orig_iter(code->instructions(), code->reloc_info(),
    328                           code->constant_pool(), mask);
    329   for (RelocIterator iter(
    330            {code_start, code->instructions().size()}, code->reloc_info(),
    331            reinterpret_cast<Address>(code_start) + code->constant_pool_offset(),
    332            mask);
    333        !iter.done(); iter.next(), orig_iter.next()) {
    334     RelocInfo::Mode mode = orig_iter.rinfo()->rmode();
    335     switch (mode) {
    336       case RelocInfo::WASM_CALL: {
    337         Address orig_target = orig_iter.rinfo()->wasm_call_address();
    338         uint32_t tag =
    339             native_module_->GetFunctionIndexFromJumpTableSlot(orig_target);
    340         SetWasmCalleeTag(iter.rinfo(), tag);
    341       } break;
    342       case RelocInfo::WASM_STUB_CALL: {
    343         Address orig_target = orig_iter.rinfo()->wasm_stub_call_address();
    344         auto stub_iter = wasm_stub_targets_lookup_.find(orig_target);
    345         DCHECK(stub_iter != wasm_stub_targets_lookup_.end());
    346         uint32_t tag = stub_iter->second;
    347         SetWasmCalleeTag(iter.rinfo(), tag);
    348       } break;
    349       case RelocInfo::EXTERNAL_REFERENCE: {
    350         Address orig_target = orig_iter.rinfo()->target_external_reference();
    351         auto ref_iter = reference_table_lookup_.find(orig_target);
    352         DCHECK(ref_iter != reference_table_lookup_.end());
    353         uint32_t tag = ref_iter->second;
    354         SetWasmCalleeTag(iter.rinfo(), tag);
    355       } break;
    356       case RelocInfo::INTERNAL_REFERENCE:
    357       case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
    358         Address orig_target = orig_iter.rinfo()->target_internal_reference();
    359         Address offset = orig_target - code->instruction_start();
    360         Assembler::deserialization_set_target_internal_reference_at(
    361             iter.rinfo()->pc(), offset, mode);
    362       } break;
    363       default:
    364         UNREACHABLE();
    365     }
    366   }
    367   // If we copied to an aligned buffer, copy code into serialized buffer.
    368   if (code_start != serialized_code_start) {
    369     memcpy(serialized_code_start, code_start, code_size);
    370   }
    371 }
    372 
    373 bool NativeModuleSerializer::Write(Writer* writer) {
    374   DCHECK(!write_called_);
    375   write_called_ = true;
    376 
    377   WriteHeader(writer);
    378 
    379   for (WasmCode* code : code_table_) {
    380     WriteCode(code, writer);
    381   }
    382   return true;
    383 }
    384 
    385 WasmSerializer::WasmSerializer(Isolate* isolate, NativeModule* native_module)
    386     : isolate_(isolate),
    387       native_module_(native_module),
    388       code_table_(native_module->SnapshotCodeTable()) {}
    389 
    390 size_t WasmSerializer::GetSerializedNativeModuleSize() const {
    391   Vector<WasmCode* const> code_table(code_table_.data(), code_table_.size());
    392   NativeModuleSerializer serializer(isolate_, native_module_, code_table);
    393   return kVersionSize + serializer.Measure();
    394 }
    395 
    396 bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
    397   Vector<WasmCode* const> code_table(code_table_.data(), code_table_.size());
    398   NativeModuleSerializer serializer(isolate_, native_module_, code_table);
    399   size_t measured_size = kVersionSize + serializer.Measure();
    400   if (buffer.size() < measured_size) return false;
    401 
    402   Writer writer(buffer);
    403   WriteVersion(isolate_, &writer);
    404 
    405   if (!serializer.Write(&writer)) return false;
    406   DCHECK_EQ(measured_size, writer.bytes_written());
    407   return true;
    408 }
    409 
    410 class V8_EXPORT_PRIVATE NativeModuleDeserializer {
    411  public:
    412   NativeModuleDeserializer() = delete;
    413   NativeModuleDeserializer(Isolate*, NativeModule*);
    414 
    415   bool Read(Reader* reader);
    416 
    417  private:
    418   bool ReadHeader(Reader* reader);
    419   bool ReadCode(uint32_t fn_index, Reader* reader);
    420 
    421   Isolate* const isolate_;
    422   NativeModule* const native_module_;
    423   bool read_called_;
    424 
    425   DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer);
    426 };
    427 
    428 NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate,
    429                                                    NativeModule* native_module)
    430     : isolate_(isolate), native_module_(native_module), read_called_(false) {}
    431 
    432 bool NativeModuleDeserializer::Read(Reader* reader) {
    433   DCHECK(!read_called_);
    434   read_called_ = true;
    435 
    436   if (!ReadHeader(reader)) return false;
    437   uint32_t total_fns = native_module_->num_functions();
    438   uint32_t first_wasm_fn = native_module_->num_imported_functions();
    439   for (uint32_t i = first_wasm_fn; i < total_fns; ++i) {
    440     if (!ReadCode(i, reader)) return false;
    441   }
    442   return reader->current_size() == 0;
    443 }
    444 
    445 bool NativeModuleDeserializer::ReadHeader(Reader* reader) {
    446   size_t functions = reader->Read<uint32_t>();
    447   size_t imports = reader->Read<uint32_t>();
    448   return functions == native_module_->num_functions() &&
    449          imports == native_module_->num_imported_functions();
    450 }
    451 
    452 bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
    453   size_t code_section_size = reader->Read<size_t>();
    454   if (code_section_size == 0) return true;
    455   size_t constant_pool_offset = reader->Read<size_t>();
    456   size_t safepoint_table_offset = reader->Read<size_t>();
    457   size_t handler_table_offset = reader->Read<size_t>();
    458   uint32_t stack_slot_count = reader->Read<uint32_t>();
    459   size_t code_size = reader->Read<size_t>();
    460   size_t reloc_size = reader->Read<size_t>();
    461   size_t source_position_size = reader->Read<size_t>();
    462   size_t protected_instructions_size = reader->Read<size_t>();
    463   WasmCode::Tier tier = reader->Read<WasmCode::Tier>();
    464 
    465   Vector<const byte> code_buffer = {reader->current_location(), code_size};
    466   reader->Skip(code_size);
    467 
    468   OwnedVector<byte> reloc_info = OwnedVector<byte>::New(reloc_size);
    469   reader->ReadVector(reloc_info.as_vector());
    470   OwnedVector<byte> source_pos = OwnedVector<byte>::New(source_position_size);
    471   reader->ReadVector(source_pos.as_vector());
    472   auto protected_instructions =
    473       OwnedVector<trap_handler::ProtectedInstructionData>::New(
    474           protected_instructions_size);
    475   reader->ReadVector(Vector<byte>::cast(protected_instructions.as_vector()));
    476 
    477   WasmCode* code = native_module_->AddDeserializedCode(
    478       fn_index, code_buffer, stack_slot_count, safepoint_table_offset,
    479       handler_table_offset, constant_pool_offset,
    480       std::move(protected_instructions), std::move(reloc_info),
    481       std::move(source_pos), tier);
    482 
    483   // Relocate the code.
    484   int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
    485              RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
    486              RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
    487              RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
    488              RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
    489   for (RelocIterator iter(code->instructions(), code->reloc_info(),
    490                           code->constant_pool(), mask);
    491        !iter.done(); iter.next()) {
    492     RelocInfo::Mode mode = iter.rinfo()->rmode();
    493     switch (mode) {
    494       case RelocInfo::WASM_CALL: {
    495         uint32_t tag = GetWasmCalleeTag(iter.rinfo());
    496         Address target = native_module_->GetCallTargetForFunction(tag);
    497         iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
    498         break;
    499       }
    500       case RelocInfo::WASM_STUB_CALL: {
    501         uint32_t tag = GetWasmCalleeTag(iter.rinfo());
    502         DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
    503         Address target =
    504             native_module_
    505                 ->runtime_stub(static_cast<WasmCode::RuntimeStubId>(tag))
    506                 ->instruction_start();
    507         iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
    508         break;
    509       }
    510       case RelocInfo::EXTERNAL_REFERENCE: {
    511         uint32_t tag = GetWasmCalleeTag(iter.rinfo());
    512         Address address =
    513             isolate_->heap()->external_reference_table()->address(tag);
    514         iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH);
    515         break;
    516       }
    517       case RelocInfo::INTERNAL_REFERENCE:
    518       case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
    519         Address offset = iter.rinfo()->target_internal_reference();
    520         Address target = code->instruction_start() + offset;
    521         Assembler::deserialization_set_target_internal_reference_at(
    522             iter.rinfo()->pc(), target, mode);
    523         break;
    524       }
    525       default:
    526         UNREACHABLE();
    527     }
    528   }
    529 
    530   if (FLAG_print_code || FLAG_print_wasm_code) code->Print();
    531   code->Validate();
    532 
    533   // Finally, flush the icache for that code.
    534   Assembler::FlushICache(code->instructions().start(),
    535                          code->instructions().size());
    536 
    537   return true;
    538 }
    539 
    540 MaybeHandle<WasmModuleObject> DeserializeNativeModule(
    541     Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes) {
    542   if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
    543     return {};
    544   }
    545   if (!IsSupportedVersion(isolate, data)) {
    546     return {};
    547   }
    548   // TODO(titzer): module features should be part of the serialization format.
    549   WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
    550   ModuleResult decode_result = DecodeWasmModule(
    551       enabled_features, wire_bytes.start(), wire_bytes.end(), false,
    552       i::wasm::kWasmOrigin, isolate->counters(), isolate->allocator());
    553   if (!decode_result.ok()) return {};
    554   CHECK_NOT_NULL(decode_result.val);
    555   WasmModule* module = decode_result.val.get();
    556   Handle<Script> script = CreateWasmScript(isolate, wire_bytes);
    557 
    558   // TODO(eholk): We need to properly preserve the flag whether the trap
    559   // handler was used or not when serializing.
    560   UseTrapHandler use_trap_handler =
    561       trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler;
    562   ModuleEnv env(module, use_trap_handler,
    563                 RuntimeExceptionSupport::kRuntimeExceptionSupport);
    564 
    565   OwnedVector<uint8_t> wire_bytes_copy = OwnedVector<uint8_t>::Of(wire_bytes);
    566 
    567   Handle<WasmModuleObject> module_object = WasmModuleObject::New(
    568       isolate, enabled_features, std::move(decode_result.val), env,
    569       std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
    570   NativeModule* native_module = module_object->native_module();
    571 
    572   if (FLAG_wasm_lazy_compilation) {
    573     native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
    574   }
    575   NativeModuleDeserializer deserializer(isolate, native_module);
    576 
    577   Reader reader(data + kVersionSize);
    578   if (!deserializer.Read(&reader)) return {};
    579 
    580   // TODO(6792): Wrappers below might be cloned using {Factory::CopyCode}. This
    581   // requires unlocking the code space here. This should eventually be moved
    582   // into the allocator.
    583   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
    584   CompileJsToWasmWrappers(isolate, module_object);
    585 
    586   // Log the code within the generated module for profiling.
    587   native_module->LogWasmCodes(isolate);
    588 
    589   return module_object;
    590 }
    591 
    592 }  // namespace wasm
    593 }  // namespace internal
    594 }  // namespace v8
    595