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