5 #include "src/wasm/wasm-serialization.h" 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" 34 explicit Writer(Vector<byte> buffer)
35 : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
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()};
45 void Write(
const T& value) {
46 DCHECK_GE(current_size(),
sizeof(T));
47 WriteUnalignedValue(reinterpret_cast<Address>(current_location()), value);
49 if (FLAG_trace_wasm_serialization) {
50 StdoutStream{} <<
"wrote: " <<
static_cast<size_t>(value)
51 <<
" sized: " <<
sizeof(T) << std::endl;
55 void WriteVector(
const Vector<const byte> v) {
56 DCHECK_GE(current_size(), v.size());
58 memcpy(current_location(), v.start(), v.size());
61 if (FLAG_trace_wasm_serialization) {
62 StdoutStream{} <<
"wrote vector of " << v.size() <<
" elements" 67 void Skip(
size_t size) { pos_ += size; }
77 explicit Reader(Vector<const byte> buffer)
78 : start_(buffer.start()), end_(buffer.end()), pos_(buffer.start()) {}
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()};
89 DCHECK_GE(current_size(),
sizeof(T));
91 ReadUnalignedValue<T>(
reinterpret_cast<Address
>(current_location()));
93 if (FLAG_trace_wasm_serialization) {
94 StdoutStream{} <<
"read: " <<
static_cast<size_t>(value)
95 <<
" sized: " <<
sizeof(T) << std::endl;
100 void ReadVector(Vector<byte> v) {
102 DCHECK_GE(current_size(), v.size());
103 memcpy(v.start(), current_location(), v.size());
106 if (FLAG_trace_wasm_serialization) {
107 StdoutStream{} <<
"read vector of " << v.size() <<
" elements" 112 void Skip(
size_t size) { pos_ += size; }
115 const byte*
const start_;
116 const byte*
const end_;
120 constexpr
size_t kVersionSize = 4 *
sizeof(
uint32_t);
122 void WriteVersion(Isolate* isolate, Writer* writer) {
124 SerializedData::ComputeMagicNumber(isolate->external_reference_table()));
125 writer->Write(Version::Hash());
126 writer->Write(static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
127 writer->Write(FlagList::Hash());
135 void SetWasmCalleeTag(RelocInfo* rinfo,
uint32_t tag) {
136 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 137 *(
reinterpret_cast<uint32_t*
>(rinfo->target_address_address())) = tag;
138 #elif V8_TARGET_ARCH_ARM64 139 Instruction* instr =
reinterpret_cast<Instruction*
>(rinfo->pc());
140 if (instr->IsLdrLiteralX()) {
141 Memory<Address>(rinfo->constant_pool_entry_address()) =
142 static_cast<Address>(tag);
144 DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
145 instr->SetBranchImmTarget(
146 reinterpret_cast<Instruction*>(rinfo->pc() + tag * kInstrSize));
149 Address addr =
static_cast<Address
>(tag);
150 if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
151 rinfo->set_target_external_reference(addr, SKIP_ICACHE_FLUSH);
152 }
else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
153 rinfo->set_wasm_stub_call_address(addr, SKIP_ICACHE_FLUSH);
155 rinfo->set_target_address(addr, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
160 uint32_t GetWasmCalleeTag(RelocInfo* rinfo) {
161 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 162 return *(
reinterpret_cast<uint32_t*
>(rinfo->target_address_address()));
163 #elif V8_TARGET_ARCH_ARM64 164 Instruction* instr =
reinterpret_cast<Instruction*
>(rinfo->pc());
165 if (instr->IsLdrLiteralX()) {
167 Memory<Address>(rinfo->constant_pool_entry_address()));
169 DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
170 return static_cast<uint32_t>(instr->ImmPCOffset() / kInstrSize);
174 if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
175 addr = rinfo->target_external_reference();
176 }
else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
177 addr = rinfo->wasm_stub_call_address();
179 addr = rinfo->target_address();
185 constexpr
size_t kHeaderSize =
189 constexpr
size_t kCodeHeaderSize =
199 sizeof(WasmCode::Tier);
209 size_t Measure()
const;
210 bool Write(Writer* writer);
213 size_t MeasureCode(
const WasmCode*)
const;
214 void WriteHeader(Writer* writer);
215 void WriteCode(
const WasmCode*, Writer* writer);
223 std::map<Address, uint32_t> wasm_stub_targets_lookup_;
224 std::map<Address, uint32_t> reference_table_lookup_;
229 NativeModuleSerializer::NativeModuleSerializer(
233 native_module_(module),
234 code_table_(code_table),
235 write_called_(false) {
236 DCHECK_NOT_NULL(isolate_);
237 DCHECK_NOT_NULL(native_module_);
240 for (
uint32_t i = 0;
i < WasmCode::kRuntimeStubCount; ++
i) {
242 native_module_->runtime_stub(static_cast<WasmCode::RuntimeStubId>(
i))
243 ->instruction_start();
244 wasm_stub_targets_lookup_.insert(std::make_pair(addr,
i));
248 Address addr = table->address(
i);
249 reference_table_lookup_.insert(std::make_pair(addr,
i));
253 size_t NativeModuleSerializer::MeasureCode(
const WasmCode* code)
const {
254 if (code ==
nullptr)
return sizeof(
size_t);
255 DCHECK_EQ(WasmCode::kFunction, code->kind());
256 return kCodeHeaderSize + code->instructions().size() +
257 code->reloc_info().size() + code->source_positions().size() +
258 code->protected_instructions().size() *
259 sizeof(trap_handler::ProtectedInstructionData);
262 size_t NativeModuleSerializer::Measure()
const {
263 size_t size = kHeaderSize;
264 for (WasmCode* code : code_table_) {
265 size += MeasureCode(code);
270 void NativeModuleSerializer::WriteHeader(Writer* writer) {
274 writer->Write(native_module_->num_functions());
275 writer->Write(native_module_->num_imported_functions());
278 void NativeModuleSerializer::WriteCode(
const WasmCode* code, Writer* writer) {
279 if (code ==
nullptr) {
280 writer->Write(
size_t{0});
283 DCHECK_EQ(WasmCode::kFunction, code->kind());
285 writer->Write(MeasureCode(code));
286 writer->Write(code->constant_pool_offset());
287 writer->Write(code->safepoint_table_offset());
288 writer->Write(code->handler_table_offset());
289 writer->Write(code->stack_slots());
290 writer->Write(code->instructions().size());
291 writer->Write(code->reloc_info().size());
292 writer->Write(code->source_positions().size());
293 writer->Write(code->protected_instructions().size());
294 writer->Write(code->tier());
297 byte* serialized_code_start = writer->current_buffer().start();
298 byte* code_start = serialized_code_start;
299 size_t code_size = code->instructions().size();
300 writer->Skip(code_size);
302 writer->WriteVector(code->reloc_info());
303 writer->WriteVector(code->source_positions());
304 writer->WriteVector(Vector<byte>::cast(code->protected_instructions()));
305 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM 308 std::unique_ptr<byte[]> aligned_buffer;
309 if (!IsAligned(reinterpret_cast<Address>(serialized_code_start),
311 aligned_buffer.reset(
new byte[code_size]);
312 code_start = aligned_buffer.get();
315 memcpy(code_start, code->instructions().start(), code_size);
317 int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
318 RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
319 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
320 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
321 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
322 RelocIterator orig_iter(code->instructions(), code->reloc_info(),
323 code->constant_pool(), mask);
324 for (RelocIterator iter(
325 {code_start, code->instructions().size()}, code->reloc_info(),
326 reinterpret_cast<Address
>(code_start) + code->constant_pool_offset(),
328 !iter.done(); iter.next(), orig_iter.next()) {
329 RelocInfo::Mode mode = orig_iter.rinfo()->rmode();
331 case RelocInfo::WASM_CALL: {
332 Address orig_target = orig_iter.rinfo()->wasm_call_address();
334 native_module_->GetFunctionIndexFromJumpTableSlot(orig_target);
335 SetWasmCalleeTag(iter.rinfo(), tag);
337 case RelocInfo::WASM_STUB_CALL: {
338 Address orig_target = orig_iter.rinfo()->wasm_stub_call_address();
339 auto stub_iter = wasm_stub_targets_lookup_.find(orig_target);
340 DCHECK(stub_iter != wasm_stub_targets_lookup_.end());
342 SetWasmCalleeTag(iter.rinfo(), tag);
344 case RelocInfo::EXTERNAL_REFERENCE: {
345 Address orig_target = orig_iter.rinfo()->target_external_reference();
346 auto ref_iter = reference_table_lookup_.find(orig_target);
347 DCHECK(ref_iter != reference_table_lookup_.end());
349 SetWasmCalleeTag(iter.rinfo(), tag);
351 case RelocInfo::INTERNAL_REFERENCE:
352 case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
353 Address orig_target = orig_iter.rinfo()->target_internal_reference();
354 Address offset = orig_target - code->instruction_start();
355 Assembler::deserialization_set_target_internal_reference_at(
356 iter.rinfo()->pc(), offset, mode);
363 if (code_start != serialized_code_start) {
364 memcpy(serialized_code_start, code_start, code_size);
368 bool NativeModuleSerializer::Write(Writer* writer) {
369 DCHECK(!write_called_);
370 write_called_ =
true;
374 for (WasmCode* code : code_table_) {
375 WriteCode(code, writer);
380 WasmSerializer::WasmSerializer(Isolate* isolate, NativeModule* native_module)
382 native_module_(native_module),
383 code_table_(native_module->SnapshotCodeTable()) {}
385 size_t WasmSerializer::GetSerializedNativeModuleSize()
const {
386 NativeModuleSerializer serializer(isolate_, native_module_,
387 VectorOf(code_table_));
388 return kVersionSize + serializer.Measure();
391 bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer)
const {
392 NativeModuleSerializer serializer(isolate_, native_module_,
393 VectorOf(code_table_));
394 size_t measured_size = kVersionSize + serializer.Measure();
395 if (buffer.size() < measured_size)
return false;
397 Writer writer(buffer);
398 WriteVersion(isolate_, &writer);
400 if (!serializer.Write(&writer))
return false;
401 DCHECK_EQ(measured_size, writer.bytes_written());
410 bool Read(Reader* reader);
413 bool ReadHeader(Reader* reader);
414 bool ReadCode(
uint32_t fn_index, Reader* reader);
423 NativeModuleDeserializer::NativeModuleDeserializer(
Isolate* isolate,
425 : isolate_(isolate), native_module_(native_module), read_called_(false) {}
427 bool NativeModuleDeserializer::Read(Reader* reader) {
428 DCHECK(!read_called_);
431 if (!ReadHeader(reader))
return false;
432 uint32_t total_fns = native_module_->num_functions();
433 uint32_t first_wasm_fn = native_module_->num_imported_functions();
434 for (
uint32_t i = first_wasm_fn;
i < total_fns; ++
i) {
435 if (!ReadCode(
i, reader))
return false;
437 return reader->current_size() == 0;
440 bool NativeModuleDeserializer::ReadHeader(Reader* reader) {
441 size_t functions = reader->Read<
uint32_t>();
442 size_t imports = reader->Read<
uint32_t>();
443 return functions == native_module_->num_functions() &&
444 imports == native_module_->num_imported_functions();
447 bool NativeModuleDeserializer::ReadCode(
uint32_t fn_index, Reader* reader) {
448 size_t code_section_size = reader->Read<
size_t>();
449 if (code_section_size == 0)
return true;
450 size_t constant_pool_offset = reader->Read<
size_t>();
451 size_t safepoint_table_offset = reader->Read<
size_t>();
452 size_t handler_table_offset = reader->Read<
size_t>();
454 size_t code_size = reader->Read<
size_t>();
455 size_t reloc_size = reader->Read<
size_t>();
456 size_t source_position_size = reader->Read<
size_t>();
457 size_t protected_instructions_size = reader->Read<
size_t>();
458 WasmCode::Tier tier = reader->Read<WasmCode::Tier>();
460 Vector<const byte> code_buffer = {reader->current_location(), code_size};
461 reader->Skip(code_size);
463 OwnedVector<byte> reloc_info = OwnedVector<byte>::New(reloc_size);
464 reader->ReadVector(reloc_info.as_vector());
465 OwnedVector<byte> source_pos = OwnedVector<byte>::New(source_position_size);
466 reader->ReadVector(source_pos.as_vector());
467 auto protected_instructions =
468 OwnedVector<trap_handler::ProtectedInstructionData>::New(
469 protected_instructions_size);
470 reader->ReadVector(Vector<byte>::cast(protected_instructions.as_vector()));
472 WasmCode* code = native_module_->AddDeserializedCode(
473 fn_index, code_buffer, stack_slot_count, safepoint_table_offset,
474 handler_table_offset, constant_pool_offset,
475 std::move(protected_instructions), std::move(reloc_info),
476 std::move(source_pos), tier);
479 int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
480 RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
481 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
482 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
483 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
484 for (RelocIterator iter(code->instructions(), code->reloc_info(),
485 code->constant_pool(), mask);
486 !iter.done(); iter.next()) {
487 RelocInfo::Mode mode = iter.rinfo()->rmode();
489 case RelocInfo::WASM_CALL: {
490 uint32_t tag = GetWasmCalleeTag(iter.rinfo());
491 Address target = native_module_->GetCallTargetForFunction(tag);
492 iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
495 case RelocInfo::WASM_STUB_CALL: {
496 uint32_t tag = GetWasmCalleeTag(iter.rinfo());
497 DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
500 ->runtime_stub(static_cast<WasmCode::RuntimeStubId>(tag))
501 ->instruction_start();
502 iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
505 case RelocInfo::EXTERNAL_REFERENCE: {
506 uint32_t tag = GetWasmCalleeTag(iter.rinfo());
507 Address address = isolate_->external_reference_table()->address(tag);
508 iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH);
511 case RelocInfo::INTERNAL_REFERENCE:
512 case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
513 Address offset = iter.rinfo()->target_internal_reference();
514 Address target = code->instruction_start() + offset;
515 Assembler::deserialization_set_target_internal_reference_at(
516 iter.rinfo()->pc(), target, mode);
524 if (FLAG_print_code || FLAG_print_wasm_code) code->Print();
528 Assembler::FlushICache(code->instructions().start(),
529 code->instructions().size());
534 bool IsSupportedVersion(Isolate* isolate, Vector<const byte> version) {
535 if (version.size() < kVersionSize)
return false;
536 byte current_version[kVersionSize];
537 Writer writer({current_version, kVersionSize});
538 WriteVersion(isolate, &writer);
539 return memcmp(version.start(), current_version, kVersionSize) == 0;
542 MaybeHandle<WasmModuleObject> DeserializeNativeModule(
543 Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes) {
544 if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
547 if (!IsSupportedVersion(isolate, data)) {
551 WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
552 ModuleResult decode_result = DecodeWasmModule(
553 enabled_features, wire_bytes.start(), wire_bytes.end(),
false,
554 i::wasm::kWasmOrigin, isolate->counters(), isolate->allocator());
555 if (decode_result.failed())
return {};
556 CHECK_NOT_NULL(decode_result.value());
557 WasmModule* module = decode_result.value().get();
558 Handle<Script> script =
559 CreateWasmScript(isolate, wire_bytes, module->source_map_url);
561 OwnedVector<uint8_t> wire_bytes_copy = OwnedVector<uint8_t>::Of(wire_bytes);
563 Handle<WasmModuleObject> module_object = WasmModuleObject::New(
564 isolate, enabled_features, std::move(decode_result).value(),
565 std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
566 NativeModule* native_module = module_object->native_module();
568 if (FLAG_wasm_lazy_compilation) {
569 native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
571 NativeModuleDeserializer deserializer(isolate, native_module);
573 Reader reader(data + kVersionSize);
574 if (!deserializer.Read(&reader))
return {};
576 CompileJsToWasmWrappers(isolate, native_module,
577 handle(module_object->export_wrappers(), isolate));
580 native_module->LogWasmCodes(isolate);
582 return module_object;