• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Writer(Vector<byte> buffer)34   explicit Writer(Vector<byte> buffer)
35       : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
36 
bytes_written() const37   size_t bytes_written() const { return pos_ - start_; }
current_location() const38   byte* current_location() const { return pos_; }
current_size() const39   size_t current_size() const { return end_ - pos_; }
current_buffer() const40   Vector<byte> current_buffer() const {
41     return {current_location(), current_size()};
42   }
43 
44   template <typename T>
Write(const T & value)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 
WriteVector(const Vector<const byte> v)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 
Skip(size_t size)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:
Reader(Vector<const byte> buffer)77   explicit Reader(Vector<const byte> buffer)
78       : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
79 
bytes_read() const80   size_t bytes_read() const { return pos_ - start_; }
current_location() const81   const byte* current_location() const { return pos_; }
current_size() const82   size_t current_size() const { return end_ - pos_; }
current_buffer() const83   Vector<const byte> current_buffer() const {
84     return {current_location(), current_size()};
85   }
86 
87   template <typename T>
Read()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 
ReadVector(Vector<byte> v)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 
Skip(size_t size)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 
WriteVersion(Isolate * isolate,Writer * writer)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 
IsSupportedVersion(Isolate * isolate,const Vector<const byte> version)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.
SetWasmCalleeTag(RelocInfo * rinfo,uint32_t tag)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 
GetWasmCalleeTag(RelocInfo * rinfo)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 
NativeModuleSerializer(Isolate * isolate,const NativeModule * module,Vector<WasmCode * const> code_table)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 
MeasureCode(const WasmCode * code) const261 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 
Measure() const270 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 
WriteHeader(Writer * writer)278 void NativeModuleSerializer::WriteHeader(Writer* writer) {
279   writer->Write(native_module_->num_functions());
280   writer->Write(native_module_->num_imported_functions());
281 }
282 
WriteCode(const WasmCode * code,Writer * writer)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 
Write(Writer * writer)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 
WasmSerializer(Isolate * isolate,NativeModule * native_module)385 WasmSerializer::WasmSerializer(Isolate* isolate, NativeModule* native_module)
386     : isolate_(isolate),
387       native_module_(native_module),
388       code_table_(native_module->SnapshotCodeTable()) {}
389 
GetSerializedNativeModuleSize() const390 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 
SerializeNativeModule(Vector<byte> buffer) const396 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 
NativeModuleDeserializer(Isolate * isolate,NativeModule * native_module)428 NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate,
429                                                    NativeModule* native_module)
430     : isolate_(isolate), native_module_(native_module), read_called_(false) {}
431 
Read(Reader * reader)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 
ReadHeader(Reader * reader)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 
ReadCode(uint32_t fn_index,Reader * reader)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 
DeserializeNativeModule(Isolate * isolate,Vector<const byte> data,Vector<const byte> wire_bytes)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