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