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