wasm-serialization.cc 24.5 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 14 15
#include "src/utils/ostreams.h"
#include "src/utils/utils.h"
#include "src/utils/version.h"
16
#include "src/wasm/function-compiler.h"
17 18
#include "src/wasm/module-compiler.h"
#include "src/wasm/module-decoder.h"
19
#include "src/wasm/wasm-code-manager.h"
20 21 22 23 24 25 26 27
#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 {
28

29 30
namespace {

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

  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()};
  }

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

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

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

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

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

  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()};
  }

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

101 102 103 104 105
  template <typename T>
  Vector<const T> ReadVector(size_t size) {
    DCHECK_GE(current_size(), size);
    Vector<const byte> bytes{pos_, size * sizeof(T)};
    pos_ += size * sizeof(T);
106
    if (FLAG_trace_wasm_serialization) {
107 108
      StdoutStream{} << "read vector of " << size << " elements of size "
                     << sizeof(T) << " (total size " << size * sizeof(T) << ")"
109
                     << std::endl;
110
    }
111
    return Vector<const T>::cast(bytes);
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 192 193 194 195 196 197 198 199 200 201 202 203 204
constexpr size_t kCodeHeaderSize = sizeof(bool) +  // whether code is present
                                   sizeof(int) +   // offset of constant pool
                                   sizeof(int) +   // offset of safepoint table
                                   sizeof(int) +   // offset of handler table
                                   sizeof(int) +   // offset of code comments
                                   sizeof(int) +   // unpadded binary size
                                   sizeof(int) +   // stack slots
                                   sizeof(int) +   // tagged parameter slots
                                   sizeof(int) +   // code size
                                   sizeof(int) +   // reloc size
                                   sizeof(int) +   // source positions size
                                   sizeof(int) +  // protected instructions size
                                   sizeof(WasmCode::Kind) +  // code kind
                                   sizeof(ExecutionTier);    // tier
205

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
// 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);
  }

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

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

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

271
}  // namespace
272 273 274

class V8_EXPORT_PRIVATE NativeModuleSerializer {
 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 283 284
  size_t MeasureCode(const WasmCode*) const;
  void WriteHeader(Writer* writer);
  void WriteCode(const WasmCode*, Writer* writer);
285

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

  DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer);
291 292
};

293
NativeModuleSerializer::NativeModuleSerializer(
294 295
    const NativeModule* module, Vector<WasmCode* const> code_table)
    : native_module_(module), code_table_(code_table), write_called_(false) {
296 297 298 299 300 301
  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 {
302
  if (code == nullptr) return sizeof(bool);
303
  DCHECK_EQ(WasmCode::kFunction, code->kind());
304 305
  return kCodeHeaderSize + code->instructions().size() +
         code->reloc_info().size() + code->source_positions().size() +
306
         code->protected_instructions_data().size();
307 308 309
}

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

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

321
  writer->Write(native_module_->num_functions());
322
  writer->Write(native_module_->num_imported_functions());
323 324
}

325
void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
326
  if (code == nullptr) {
327
    writer->Write(false);
328 329
    return;
  }
330
  writer->Write(true);
331
  DCHECK_EQ(WasmCode::kFunction, code->kind());
332 333 334 335
  // Write the size of the entire code section, followed by the code header.
  writer->Write(code->constant_pool_offset());
  writer->Write(code->safepoint_table_offset());
  writer->Write(code->handler_table_offset());
336 337
  writer->Write(code->code_comments_offset());
  writer->Write(code->unpadded_binary_size());
338
  writer->Write(code->stack_slots());
339
  writer->Write(code->tagged_parameter_slots());
340 341 342
  writer->Write(code->instructions().length());
  writer->Write(code->reloc_info().length());
  writer->Write(code->source_positions().length());
343
  writer->Write(code->protected_instructions_data().length());
344
  writer->Write(code->kind());
345
  writer->Write(code->tier());
346 347

  // Get a pointer to the destination buffer, to hold relocated code.
348
  byte* serialized_code_start = writer->current_buffer().begin();
349 350 351 352
  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.
353 354
  writer->WriteVector(code->reloc_info());
  writer->WriteVector(code->source_positions());
355
  writer->WriteVector(code->protected_instructions_data());
356
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM || \
357
    V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X
358 359 360 361
  // 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),
362 363 364
                 kSystemPointerSize)) {
    // 'byte' does not guarantee an alignment but seems to work well enough in
    // practice.
365 366 367 368
    aligned_buffer.reset(new byte[code_size]);
    code_start = aligned_buffer.get();
  }
#endif
369
  memcpy(code_start, code->instructions().begin(), code_size);
370
  // Relocate the code.
371
  int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
372
             RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
373 374 375
             RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
376 377
  RelocIterator orig_iter(code->instructions(), code->reloc_info(),
                          code->constant_pool(), mask);
378 379
  for (RelocIterator iter(
           {code_start, code->instructions().size()}, code->reloc_info(),
380
           reinterpret_cast<Address>(code_start) + code->constant_pool_offset(),
381
           mask);
382 383 384 385 386
       !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();
387 388
        uint32_t tag =
            native_module_->GetFunctionIndexFromJumpTableSlot(orig_target);
389
        SetWasmCalleeTag(iter.rinfo(), tag);
390
      } break;
391
      case RelocInfo::WASM_STUB_CALL: {
392 393 394
        Address target = orig_iter.rinfo()->wasm_stub_call_address();
        uint32_t tag = native_module_->GetRuntimeStubId(target);
        DCHECK_GT(WasmCode::kRuntimeStubCount, tag);
395 396
        SetWasmCalleeTag(iter.rinfo(), tag);
      } break;
397 398
      case RelocInfo::EXTERNAL_REFERENCE: {
        Address orig_target = orig_iter.rinfo()->target_external_reference();
399 400 401
        uint32_t ext_ref_tag =
            ExternalReferenceList::Get().tag_from_address(orig_target);
        SetWasmCalleeTag(iter.rinfo(), ext_ref_tag);
402
      } break;
403 404 405 406 407 408 409
      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;
410 411 412 413
      default:
        UNREACHABLE();
    }
  }
414 415 416 417
  // 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);
  }
418 419
}

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

  WriteHeader(writer);

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

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

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

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

446
  Writer writer(buffer);
447
  WriteHeader(&writer);
448

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

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

459 460 461 462
  bool Read(Reader* reader);

 private:
  bool ReadHeader(Reader* reader);
463
  bool ReadCode(int fn_index, Reader* reader);
464 465 466 467 468 469 470

  NativeModule* const native_module_;
  bool read_called_;

  DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer);
};

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

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

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

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

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

517 518 519
  auto code_buffer = reader->ReadVector<byte>(code_size);
  auto reloc_info = reader->ReadVector<byte>(reloc_size);
  auto source_pos = reader->ReadVector<byte>(source_position_size);
520
  auto protected_instructions =
521
      reader->ReadVector<byte>(protected_instructions_size);
522 523

  WasmCode* code = native_module_->AddDeserializedCode(
524 525
      fn_index, code_buffer, stack_slot_count, tagged_parameter_slots,
      safepoint_table_offset, handler_table_offset, constant_pool_offset,
526 527
      code_comment_offset, unpadded_binary_size, protected_instructions,
      std::move(reloc_info), std::move(source_pos), kind, tier);
528

529
  // Relocate the code.
530 531
  int mask = RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
             RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL) |
532 533 534
             RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
             RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
535 536
  auto jump_tables_ref = native_module_->FindJumpTablesForRegion(
      base::AddressRegionOf(code->instructions()));
537 538
  for (RelocIterator iter(code->instructions(), code->reloc_info(),
                          code->constant_pool(), mask);
539 540 541
       !iter.done(); iter.next()) {
    RelocInfo::Mode mode = iter.rinfo()->rmode();
    switch (mode) {
542 543
      case RelocInfo::WASM_CALL: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
544 545
        Address target =
            native_module_->GetNearCallTargetForFunction(tag, jump_tables_ref);
546 547 548
        iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
        break;
      }
549 550 551
      case RelocInfo::WASM_STUB_CALL: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
        DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
552
        Address target = native_module_->GetNearRuntimeStubEntry(
553
            static_cast<WasmCode::RuntimeStubId>(tag), jump_tables_ref);
554 555 556
        iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
        break;
      }
557 558
      case RelocInfo::EXTERNAL_REFERENCE: {
        uint32_t tag = GetWasmCalleeTag(iter.rinfo());
559
        Address address = ExternalReferenceList::Get().address_from_tag(tag);
560
        iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH);
561
        break;
562
      }
563 564 565 566 567 568 569 570
      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;
      }
571 572
      default:
        UNREACHABLE();
573 574
    }
  }
575

576
  code->MaybePrint();
577 578 579
  code->Validate();

  // Finally, flush the icache for that code.
580
  FlushInstructionCache(code->instructions().begin(),
581
                        code->instructions().size());
582

583 584 585
  return true;
}

586 587 588 589 590 591 592
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;
593 594
}

595
MaybeHandle<WasmModuleObject> DeserializeNativeModule(
596
    Isolate* isolate, Vector<const byte> data,
597
    Vector<const byte> wire_bytes_vec, Vector<const char> source_url) {
598 599 600
  if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) return {};
  if (!IsSupportedVersion(data)) return {};

601
  ModuleWireBytes wire_bytes(wire_bytes_vec);
602
  // TODO(titzer): module features should be part of the serialization format.
603
  WasmEngine* wasm_engine = isolate->wasm_engine();
604
  WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
605 606 607
  ModuleResult decode_result = DecodeWasmModule(
      enabled_features, wire_bytes.start(), wire_bytes.end(), false,
      i::wasm::kWasmOrigin, isolate->counters(), wasm_engine->allocator());
608
  if (decode_result.failed()) return {};
609 610
  std::shared_ptr<WasmModule> module = std::move(decode_result.value());
  CHECK_NOT_NULL(module);
611

612 613
  auto shared_native_module = wasm_engine->MaybeGetNativeModule(
      module->origin, wire_bytes_vec, isolate);
614 615 616 617 618 619 620 621 622 623 624
  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());
625
    Reader reader(data + WasmSerializer::kHeaderSize);
626
    bool error = !deserializer.Read(&reader);
627
    wasm_engine->UpdateNativeModuleCache(error, &shared_native_module, isolate);
628 629 630 631 632
    if (error) return {};
  }

  // Log the code within the generated module for profiling.
  shared_native_module->LogWasmCodes(isolate);
633 634 635 636

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

638
  Handle<Script> script =
639
      wasm_engine->GetOrCreateScript(isolate, shared_native_module, source_url);
640
  Handle<WasmModuleObject> module_object = WasmModuleObject::New(
641
      isolate, std::move(shared_native_module), script, export_wrappers);
642

643 644
  // Finish the Wasm script now and make it public to the debugger.
  isolate->debug()->OnAfterCompile(script);
645
  return module_object;
646 647 648 649 650
}

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