wasm-serialization.cc 24.6 KB
Newer Older
1 2 3 4 5 6
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/wasm/wasm-serialization.h"

7
#include "src/codegen/assembler-inl.h"
8
#include "src/codegen/external-reference-table.h"
9 10
#include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
11
#include "src/runtime/runtime.h"
12
#include "src/snapshot/code-serializer.h"
13
#include "src/snapshot/serializer-common.h"
14 15 16
#include "src/utils/ostreams.h"
#include "src/utils/utils.h"
#include "src/utils/version.h"
17
#include "src/wasm/function-compiler.h"
18 19
#include "src/wasm/module-compiler.h"
#include "src/wasm/module-decoder.h"
20
#include "src/wasm/wasm-code-manager.h"
21 22 23 24 25 26 27 28
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-result.h"

namespace v8 {
namespace internal {
namespace wasm {
29

30 31
namespace {

32 33
// TODO(bbudge) Try to unify the various implementations of readers and writers
// in WASM, e.g. StreamProcessor and ZoneBuffer, with these.
34 35
class Writer {
 public:
36
  explicit Writer(Vector<byte> buffer)
37
      : start_(buffer.begin()), end_(buffer.end()), pos_(buffer.begin()) {}
38 39 40 41 42 43 44 45

  size_t bytes_written() const { return pos_ - start_; }
  byte* current_location() const { return pos_; }
  size_t current_size() const { return end_ - pos_; }
  Vector<byte> current_buffer() const {
    return {current_location(), current_size()};
  }

46 47
  template <typename T>
  void Write(const T& value) {
48 49 50
    DCHECK_GE(current_size(), sizeof(T));
    WriteUnalignedValue(reinterpret_cast<Address>(current_location()), value);
    pos_ += sizeof(T);
51
    if (FLAG_trace_wasm_serialization) {
52 53
      StdoutStream{} << "wrote: " << static_cast<size_t>(value)
                     << " sized: " << sizeof(T) << std::endl;
54 55 56
    }
  }

57 58 59
  void WriteVector(const Vector<const byte> v) {
    DCHECK_GE(current_size(), v.size());
    if (v.size() > 0) {
60
      memcpy(current_location(), v.begin(), v.size());
61
      pos_ += v.size();
62
    }
63
    if (FLAG_trace_wasm_serialization) {
64 65
      StdoutStream{} << "wrote vector of " << v.size() << " elements"
                     << std::endl;
66 67 68
    }
  }

69
  void Skip(size_t size) { pos_ += size; }
70

71
 private:
72
  byte* const start_;
73 74
  byte* const end_;
  byte* pos_;
75 76 77 78
};

class Reader {
 public:
79
  explicit Reader(Vector<const byte> buffer)
80
      : start_(buffer.begin()), end_(buffer.end()), pos_(buffer.begin()) {}
81 82 83 84 85 86 87 88

  size_t bytes_read() const { return pos_ - start_; }
  const byte* current_location() const { return pos_; }
  size_t current_size() const { return end_ - pos_; }
  Vector<const byte> current_buffer() const {
    return {current_location(), current_size()};
  }

89 90
  template <typename T>
  T Read() {
91 92 93 94
    DCHECK_GE(current_size(), sizeof(T));
    T value =
        ReadUnalignedValue<T>(reinterpret_cast<Address>(current_location()));
    pos_ += sizeof(T);
95
    if (FLAG_trace_wasm_serialization) {
96 97
      StdoutStream{} << "read: " << static_cast<size_t>(value)
                     << " sized: " << sizeof(T) << std::endl;
98
    }
99
    return value;
100 101
  }

102 103 104
  void ReadVector(Vector<byte> v) {
    if (v.size() > 0) {
      DCHECK_GE(current_size(), v.size());
105
      memcpy(v.begin(), current_location(), v.size());
106
      pos_ += v.size();
107
    }
108
    if (FLAG_trace_wasm_serialization) {
109 110
      StdoutStream{} << "read vector of " << v.size() << " elements"
                     << std::endl;
111 112 113
    }
  }

114
  void Skip(size_t size) { pos_ += size; }
115

116
 private:
117
  const byte* const start_;
118 119
  const byte* const end_;
  const byte* pos_;
120 121
};

122
void WriteHeader(Writer* writer) {
123
  writer->Write(SerializedData::kMagicNumber);
124 125 126
  writer->Write(Version::Hash());
  writer->Write(static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
  writer->Write(FlagList::Hash());
127
  DCHECK_EQ(WasmSerializer::kHeaderSize, writer->bytes_written());
128 129
}

130 131
// On Intel, call sites are encoded as a displacement. For linking and for
// serialization/deserialization, we want to store/retrieve a tag (the function
132 133 134
// index). On Intel, that means accessing the raw displacement.
// On ARM64, call sites are encoded as either a literal load or a direct branch.
// Other platforms simply require accessing the target address.
135 136
void SetWasmCalleeTag(RelocInfo* rinfo, uint32_t tag) {
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
137
  DCHECK(rinfo->HasTargetAddressAddress());
138
  DCHECK(!RelocInfo::IsCompressedEmbeddedObject(rinfo->rmode()));
139
  WriteUnalignedValue(rinfo->target_address_address(), tag);
140 141 142
#elif V8_TARGET_ARCH_ARM64
  Instruction* instr = reinterpret_cast<Instruction*>(rinfo->pc());
  if (instr->IsLdrLiteralX()) {
143 144
    WriteUnalignedValue(rinfo->constant_pool_entry_address(),
                        static_cast<Address>(tag));
145 146 147
  } else {
    DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
    instr->SetBranchImmTarget(
148
        reinterpret_cast<Instruction*>(rinfo->pc() + tag * kInstrSize));
149
  }
150
#else
151
  Address addr = static_cast<Address>(tag);
152 153
  if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
    rinfo->set_target_external_reference(addr, SKIP_ICACHE_FLUSH);
154 155
  } else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
    rinfo->set_wasm_stub_call_address(addr, SKIP_ICACHE_FLUSH);
156 157 158
  } else {
    rinfo->set_target_address(addr, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
  }
159 160 161 162 163
#endif
}

uint32_t GetWasmCalleeTag(RelocInfo* rinfo) {
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
164
  DCHECK(!RelocInfo::IsCompressedEmbeddedObject(rinfo->rmode()));
165
  return ReadUnalignedValue<uint32_t>(rinfo->target_address_address());
166 167 168
#elif V8_TARGET_ARCH_ARM64
  Instruction* instr = reinterpret_cast<Instruction*>(rinfo->pc());
  if (instr->IsLdrLiteralX()) {
169
    return ReadUnalignedValue<uint32_t>(rinfo->constant_pool_entry_address());
170 171
  } else {
    DCHECK(instr->IsBranchAndLink() || instr->IsUnconditionalBranch());
172
    return static_cast<uint32_t>(instr->ImmPCOffset() / kInstrSize);
173
  }
174
#else
175 176 177 178 179 180 181 182
  Address addr;
  if (rinfo->rmode() == RelocInfo::EXTERNAL_REFERENCE) {
    addr = rinfo->target_external_reference();
  } else if (rinfo->rmode() == RelocInfo::WASM_STUB_CALL) {
    addr = rinfo->wasm_stub_call_address();
  } else {
    addr = rinfo->target_address();
  }
183
  return static_cast<uint32_t>(addr);
184 185 186
#endif
}

187 188
constexpr size_t kHeaderSize =
    sizeof(uint32_t) +  // total wasm function count
189
    sizeof(uint32_t);   // imported functions (index of first wasm function)
190 191

constexpr size_t kCodeHeaderSize =
192 193 194 195 196 197 198 199 200 201 202 203 204
    sizeof(size_t) +          // size of code section
    sizeof(size_t) +          // offset of constant pool
    sizeof(size_t) +          // offset of safepoint table
    sizeof(size_t) +          // offset of handler table
    sizeof(size_t) +          // offset of code comments
    sizeof(size_t) +          // unpadded binary size
    sizeof(uint32_t) +        // stack slots
    sizeof(uint32_t) +        // tagged parameter slots
    sizeof(size_t) +          // code size
    sizeof(size_t) +          // reloc size
    sizeof(size_t) +          // source positions size
    sizeof(size_t) +          // protected instructions size
    sizeof(WasmCode::Kind) +  // code kind
205
    sizeof(ExecutionTier);    // tier
206

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
// A List of all isolate-independent external references. This is used to create
// a tag from the Address of an external reference and vice versa.
class ExternalReferenceList {
 public:
  uint32_t tag_from_address(Address ext_ref_address) const {
    auto tag_addr_less_than = [this](uint32_t tag, Address searched_addr) {
      return external_reference_by_tag_[tag] < searched_addr;
    };
    auto it = std::lower_bound(std::begin(tags_ordered_by_address_),
                               std::end(tags_ordered_by_address_),
                               ext_ref_address, tag_addr_less_than);
    DCHECK_NE(std::end(tags_ordered_by_address_), it);
    uint32_t tag = *it;
    DCHECK_EQ(address_from_tag(tag), ext_ref_address);
    return tag;
  }

  Address address_from_tag(uint32_t tag) const {
    DCHECK_GT(kNumExternalReferences, tag);
    return external_reference_by_tag_[tag];
  }

  static const ExternalReferenceList& Get() {
    static ExternalReferenceList list;  // Lazily initialized.
    return list;
  }

 private:
  // Private constructor. There will only be a single instance of this object.
  ExternalReferenceList() {
    for (uint32_t i = 0; i < kNumExternalReferences; ++i) {
      tags_ordered_by_address_[i] = i;
    }
    auto addr_by_tag_less_than = [this](uint32_t a, uint32_t b) {
      return external_reference_by_tag_[a] < external_reference_by_tag_[b];
    };
    std::sort(std::begin(tags_ordered_by_address_),
              std::end(tags_ordered_by_address_), addr_by_tag_less_than);
  }

247 248
#define COUNT_EXTERNAL_REFERENCE(name, ...) +1
  static constexpr uint32_t kNumExternalReferencesList =
249
      EXTERNAL_REFERENCE_LIST(COUNT_EXTERNAL_REFERENCE);
250 251 252 253
  static constexpr uint32_t kNumExternalReferencesIntrinsics =
      FOR_EACH_INTRINSIC(COUNT_EXTERNAL_REFERENCE);
  static constexpr uint32_t kNumExternalReferences =
      kNumExternalReferencesList + kNumExternalReferencesIntrinsics;
254 255 256
#undef COUNT_EXTERNAL_REFERENCE

  Address external_reference_by_tag_[kNumExternalReferences] = {
257 258
#define EXT_REF_ADDR(name, desc) ExternalReference::name().address(),
      EXTERNAL_REFERENCE_LIST(EXT_REF_ADDR)
259
#undef EXT_REF_ADDR
260 261 262 263 264
#define RUNTIME_ADDR(name, ...) \
  ExternalReference::Create(Runtime::k##name).address(),
          FOR_EACH_INTRINSIC(RUNTIME_ADDR)
#undef RUNTIME_ADDR
  };
265 266 267 268 269 270 271
  uint32_t tags_ordered_by_address_[kNumExternalReferences];
  DISALLOW_COPY_AND_ASSIGN(ExternalReferenceList);
};

static_assert(std::is_trivially_destructible<ExternalReferenceList>::value,
              "static destructors not allowed");

272
}  // namespace
273 274 275

class V8_EXPORT_PRIVATE NativeModuleSerializer {
 public:
276
  NativeModuleSerializer() = delete;
277
  NativeModuleSerializer(const NativeModule*, Vector<WasmCode* const>);
278

279
  size_t Measure() const;
280
  bool Write(Writer* writer);
281 282

 private:
283 284 285
  size_t MeasureCode(const WasmCode*) const;
  void WriteHeader(Writer* writer);
  void WriteCode(const WasmCode*, Writer* writer);
286

287
  const NativeModule* const native_module_;
288
  Vector<WasmCode* const> code_table_;
289 290 291
  bool write_called_;

  DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer);
292 293
};

294
NativeModuleSerializer::NativeModuleSerializer(
295 296
    const NativeModule* module, Vector<WasmCode* const> code_table)
    : native_module_(module), code_table_(code_table), write_called_(false) {
297 298 299 300 301 302
  DCHECK_NOT_NULL(native_module_);
  // TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist
  // the unique ones, i.e. the cache.
}

size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const {
303
  if (code == nullptr) return sizeof(size_t);
304 305
  DCHECK(code->kind() == WasmCode::kFunction ||
         code->kind() == WasmCode::kInterpreterEntry);
306 307
  return kCodeHeaderSize + code->instructions().size() +
         code->reloc_info().size() + code->source_positions().size() +
308
         code->protected_instructions().size() *
309 310 311 312
             sizeof(trap_handler::ProtectedInstructionData);
}

size_t NativeModuleSerializer::Measure() const {
313
  size_t size = kHeaderSize;
314
  for (WasmCode* code : code_table_) {
315
    size += MeasureCode(code);
316
  }
317
  return size;
318 319
}

320
void NativeModuleSerializer::WriteHeader(Writer* writer) {
321 322 323
  // TODO(eholk): We need to properly preserve the flag whether the trap
  // handler was used or not when serializing.

324
  writer->Write(native_module_->num_functions());
325
  writer->Write(native_module_->num_imported_functions());
326 327
}

328
void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
329
  if (code == nullptr) {
330 331 332
    writer->Write(size_t{0});
    return;
  }
333 334
  DCHECK(code->kind() == WasmCode::kFunction ||
         code->kind() == WasmCode::kInterpreterEntry);
335 336 337 338 339
  // Write the size of the entire code section, followed by the code header.
  writer->Write(MeasureCode(code));
  writer->Write(code->constant_pool_offset());
  writer->Write(code->safepoint_table_offset());
  writer->Write(code->handler_table_offset());
340 341
  writer->Write(code->code_comments_offset());
  writer->Write(code->unpadded_binary_size());
342
  writer->Write(code->stack_slots());
343
  writer->Write(code->tagged_parameter_slots());
344 345 346 347
  writer->Write(code->instructions().size());
  writer->Write(code->reloc_info().size());
  writer->Write(code->source_positions().size());
  writer->Write(code->protected_instructions().size());
348
  writer->Write(code->kind());
349
  writer->Write(code->tier());
350 351

  // Get a pointer to the destination buffer, to hold relocated code.
352
  byte* serialized_code_start = writer->current_buffer().begin();
353 354 355 356
  byte* code_start = serialized_code_start;
  size_t code_size = code->instructions().size();
  writer->Skip(code_size);
  // Write the reloc info, source positions, and protected code.
357 358
  writer->WriteVector(code->reloc_info());
  writer->WriteVector(code->source_positions());
359
  writer->WriteVector(Vector<byte>::cast(code->protected_instructions()));
360
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM || \
361
    V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390X
362 363 364 365 366 367 368 369 370
  // On platforms that don't support misaligned word stores, copy to an aligned
  // buffer if necessary so we can relocate the serialized code.
  std::unique_ptr<byte[]> aligned_buffer;
  if (!IsAligned(reinterpret_cast<Address>(serialized_code_start),
                 kInt32Size)) {
    aligned_buffer.reset(new byte[code_size]);
    code_start = aligned_buffer.get();
  }
#endif
371
  memcpy(code_start, code->instructions().begin(), code_size);
372
  // Relocate the code.
373
  int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
374
             RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
375 376 377
             RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
378 379
  RelocIterator orig_iter(code->instructions(), code->reloc_info(),
                          code->constant_pool(), mask);
380 381
  for (RelocIterator iter(
           {code_start, code->instructions().size()}, code->reloc_info(),
382
           reinterpret_cast<Address>(code_start) + code->constant_pool_offset(),
383
           mask);
384 385 386 387 388
       !iter.done(); iter.next(), orig_iter.next()) {
    RelocInfo::Mode mode = orig_iter.rinfo()->rmode();
    switch (mode) {
      case RelocInfo::WASM_CALL: {
        Address orig_target = orig_iter.rinfo()->wasm_call_address();
389 390
        uint32_t tag =
            native_module_->GetFunctionIndexFromJumpTableSlot(orig_target);
391
        SetWasmCalleeTag(iter.rinfo(), tag);
392
      } break;
393
      case RelocInfo::WASM_STUB_CALL: {
394 395 396
        Address target = orig_iter.rinfo()->wasm_stub_call_address();
        uint32_t tag = native_module_->GetRuntimeStubId(target);
        DCHECK_GT(WasmCode::kRuntimeStubCount, tag);
397 398
        SetWasmCalleeTag(iter.rinfo(), tag);
      } break;
399 400
      case RelocInfo::EXTERNAL_REFERENCE: {
        Address orig_target = orig_iter.rinfo()->target_external_reference();
401 402 403
        uint32_t ext_ref_tag =
            ExternalReferenceList::Get().tag_from_address(orig_target);
        SetWasmCalleeTag(iter.rinfo(), ext_ref_tag);
404
      } break;
405 406 407 408 409 410 411
      case RelocInfo::INTERNAL_REFERENCE:
      case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
        Address orig_target = orig_iter.rinfo()->target_internal_reference();
        Address offset = orig_target - code->instruction_start();
        Assembler::deserialization_set_target_internal_reference_at(
            iter.rinfo()->pc(), offset, mode);
      } break;
412 413 414 415
      default:
        UNREACHABLE();
    }
  }
416 417 418 419
  // If we copied to an aligned buffer, copy code into serialized buffer.
  if (code_start != serialized_code_start) {
    memcpy(serialized_code_start, code_start, code_size);
  }
420 421
}

422 423 424 425 426 427
bool NativeModuleSerializer::Write(Writer* writer) {
  DCHECK(!write_called_);
  write_called_ = true;

  WriteHeader(writer);

428
  for (WasmCode* code : code_table_) {
429
    WriteCode(code, writer);
430
  }
431
  return true;
432 433
}

434 435
WasmSerializer::WasmSerializer(NativeModule* native_module)
    : native_module_(native_module),
436 437 438
      code_table_(native_module->SnapshotCodeTable()) {}

size_t WasmSerializer::GetSerializedNativeModuleSize() const {
439
  NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
440
  return kHeaderSize + serializer.Measure();
441
}
442

443
bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
444
  NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
445
  size_t measured_size = kHeaderSize + serializer.Measure();
446
  if (buffer.size() < measured_size) return false;
447

448
  Writer writer(buffer);
449
  WriteHeader(&writer);
450

451 452 453
  if (!serializer.Write(&writer)) return false;
  DCHECK_EQ(measured_size, writer.bytes_written());
  return true;
454 455
}

456 457 458
class V8_EXPORT_PRIVATE NativeModuleDeserializer {
 public:
  NativeModuleDeserializer() = delete;
459
  explicit NativeModuleDeserializer(NativeModule*);
460

461 462 463 464 465 466 467 468 469 470 471 472
  bool Read(Reader* reader);

 private:
  bool ReadHeader(Reader* reader);
  bool ReadCode(uint32_t fn_index, Reader* reader);

  NativeModule* const native_module_;
  bool read_called_;

  DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer);
};

473 474
NativeModuleDeserializer::NativeModuleDeserializer(NativeModule* native_module)
    : native_module_(native_module), read_called_(false) {}
475 476 477 478 479 480

bool NativeModuleDeserializer::Read(Reader* reader) {
  DCHECK(!read_called_);
  read_called_ = true;

  if (!ReadHeader(reader)) return false;
481
  uint32_t total_fns = native_module_->num_functions();
482 483 484
  uint32_t first_wasm_fn = native_module_->num_imported_functions();
  for (uint32_t i = first_wasm_fn; i < total_fns; ++i) {
    if (!ReadCode(i, reader)) return false;
485
  }
486
  return reader->current_size() == 0;
487 488
}

489 490 491
bool NativeModuleDeserializer::ReadHeader(Reader* reader) {
  size_t functions = reader->Read<uint32_t>();
  size_t imports = reader->Read<uint32_t>();
492
  return functions == native_module_->num_functions() &&
493
         imports == native_module_->num_imported_functions();
494 495
}

496 497
bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
  size_t code_section_size = reader->Read<size_t>();
498 499
  if (code_section_size == 0) {
    DCHECK(FLAG_wasm_lazy_compilation ||
500
           native_module_->enabled_features().has_compilation_hints());
501 502 503
    native_module_->UseLazyStub(fn_index);
    return true;
  }
504 505 506
  size_t constant_pool_offset = reader->Read<size_t>();
  size_t safepoint_table_offset = reader->Read<size_t>();
  size_t handler_table_offset = reader->Read<size_t>();
507 508
  size_t code_comment_offset = reader->Read<size_t>();
  size_t unpadded_binary_size = reader->Read<size_t>();
509
  uint32_t stack_slot_count = reader->Read<uint32_t>();
510
  uint32_t tagged_parameter_slots = reader->Read<uint32_t>();
511 512 513 514
  size_t code_size = reader->Read<size_t>();
  size_t reloc_size = reader->Read<size_t>();
  size_t source_position_size = reader->Read<size_t>();
  size_t protected_instructions_size = reader->Read<size_t>();
515
  WasmCode::Kind kind = reader->Read<WasmCode::Kind>();
516
  ExecutionTier tier = reader->Read<ExecutionTier>();
517

518 519 520
  Vector<const byte> code_buffer = {reader->current_location(), code_size};
  reader->Skip(code_size);

521 522 523 524
  OwnedVector<byte> reloc_info = OwnedVector<byte>::New(reloc_size);
  reader->ReadVector(reloc_info.as_vector());
  OwnedVector<byte> source_pos = OwnedVector<byte>::New(source_position_size);
  reader->ReadVector(source_pos.as_vector());
525 526 527 528
  auto protected_instructions =
      OwnedVector<trap_handler::ProtectedInstructionData>::New(
          protected_instructions_size);
  reader->ReadVector(Vector<byte>::cast(protected_instructions.as_vector()));
529 530

  WasmCode* code = native_module_->AddDeserializedCode(
531 532 533 534
      fn_index, code_buffer, stack_slot_count, tagged_parameter_slots,
      safepoint_table_offset, handler_table_offset, constant_pool_offset,
      code_comment_offset, unpadded_binary_size,
      std::move(protected_instructions), std::move(reloc_info),
535
      std::move(source_pos), kind, tier);
536

537
  // Relocate the code.
538 539
  int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
             RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
540 541 542
             RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
543 544
  auto jump_tables_ref =
      native_module_->FindJumpTablesForCode(code->instruction_start());
545 546
  for (RelocIterator iter(code->instructions(), code->reloc_info(),
                          code->constant_pool(), mask);
547 548 549
       !iter.done(); iter.next()) {
    RelocInfo::Mode mode = iter.rinfo()->rmode();
    switch (mode) {
550 551
      case RelocInfo::WASM_CALL: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
552 553
        Address target =
            native_module_->GetNearCallTargetForFunction(tag, jump_tables_ref);
554 555 556
        iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
        break;
      }
557 558 559
      case RelocInfo::WASM_STUB_CALL: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
        DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
560
        Address target = native_module_->GetNearRuntimeStubEntry(
561
            static_cast<WasmCode::RuntimeStubId>(tag), jump_tables_ref);
562 563 564
        iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
        break;
      }
565 566
      case RelocInfo::EXTERNAL_REFERENCE: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
567
        Address address = ExternalReferenceList::Get().address_from_tag(tag);
568
        iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH);
569
        break;
570
      }
571 572 573 574 575 576 577 578
      case RelocInfo::INTERNAL_REFERENCE:
      case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
        Address offset = iter.rinfo()->target_internal_reference();
        Address target = code->instruction_start() + offset;
        Assembler::deserialization_set_target_internal_reference_at(
            iter.rinfo()->pc(), target, mode);
        break;
      }
579 580
      default:
        UNREACHABLE();
581 582
    }
  }
583

584
  code->MaybePrint();
585 586 587
  code->Validate();

  // Finally, flush the icache for that code.
588
  FlushInstructionCache(code->instructions().begin(),
589
                        code->instructions().size());
590

591 592 593
  return true;
}

594 595 596 597 598 599 600
bool IsSupportedVersion(Vector<const byte> header) {
  if (header.size() < WasmSerializer::kHeaderSize) return false;
  byte current_version[WasmSerializer::kHeaderSize];
  Writer writer({current_version, WasmSerializer::kHeaderSize});
  WriteHeader(&writer);
  return memcmp(header.begin(), current_version, WasmSerializer::kHeaderSize) ==
         0;
601 602
}

603
MaybeHandle<WasmModuleObject> DeserializeNativeModule(
604
    Isolate* isolate, Vector<const byte> data,
605
    Vector<const byte> wire_bytes_vec, Vector<const char> source_url) {
606 607 608
  if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) return {};
  if (!IsSupportedVersion(data)) return {};

609
  ModuleWireBytes wire_bytes(wire_bytes_vec);
610
  // TODO(titzer): module features should be part of the serialization format.
611
  WasmEngine* wasm_engine = isolate->wasm_engine();
612
  WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
613 614 615
  ModuleResult decode_result = DecodeWasmModule(
      enabled_features, wire_bytes.start(), wire_bytes.end(), false,
      i::wasm::kWasmOrigin, isolate->counters(), wasm_engine->allocator());
616
  if (decode_result.failed()) return {};
617 618
  std::shared_ptr<WasmModule> module = std::move(decode_result.value());
  CHECK_NOT_NULL(module);
619 620 621
  Handle<Script> script =
      CreateWasmScript(isolate, wire_bytes, VectorOf(module->source_map_url),
                       module->name, source_url);
622

623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
  auto shared_native_module =
      wasm_engine->MaybeGetNativeModule(module->origin, wire_bytes_vec);
  if (shared_native_module == nullptr) {
    const bool kIncludeLiftoff = false;
    size_t code_size_estimate =
        wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get(),
                                                            kIncludeLiftoff);
    shared_native_module = wasm_engine->NewNativeModule(
        isolate, enabled_features, std::move(module), code_size_estimate);
    shared_native_module->SetWireBytes(
        OwnedVector<uint8_t>::Of(wire_bytes_vec));

    NativeModuleDeserializer deserializer(shared_native_module.get());
    WasmCodeRefScope wasm_code_ref_scope;

638
    Reader reader(data + WasmSerializer::kHeaderSize);
639 640 641 642 643 644 645
    bool error = !deserializer.Read(&reader);
    wasm_engine->UpdateNativeModuleCache(shared_native_module, error);
    if (error) return {};
  }

  // Log the code within the generated module for profiling.
  shared_native_module->LogWasmCodes(isolate);
646 647 648 649

  Handle<FixedArray> export_wrappers;
  CompileJsToWasmWrappers(isolate, shared_native_module->module(),
                          &export_wrappers);
650

651
  Handle<WasmModuleObject> module_object = WasmModuleObject::New(
652
      isolate, std::move(shared_native_module), script, export_wrappers);
653

654 655
  // Finish the Wasm script now and make it public to the debugger.
  isolate->debug()->OnAfterCompile(script);
656
  return module_object;
657 658 659 660 661
}

}  // namespace wasm
}  // namespace internal
}  // namespace v8