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