LCOV - code coverage report
Current view: top level - src/wasm - wasm-serialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 187 195 95.9 %
Date: 2019-04-17 Functions: 27 29 93.1 %

          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

Generated by: LCOV version 1.10