11cb0ef41Sopenharmony_ci// Copyright 2011 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_CODEGEN_SAFEPOINT_TABLE_H_
61cb0ef41Sopenharmony_ci#define V8_CODEGEN_SAFEPOINT_TABLE_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/bit-field.h"
91cb0ef41Sopenharmony_ci#include "src/base/iterator.h"
101cb0ef41Sopenharmony_ci#include "src/base/memory.h"
111cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
121cb0ef41Sopenharmony_ci#include "src/utils/allocation.h"
131cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h"
141cb0ef41Sopenharmony_ci#include "src/utils/utils.h"
151cb0ef41Sopenharmony_ci#include "src/zone/zone-chunk-list.h"
161cb0ef41Sopenharmony_ci#include "src/zone/zone.h"
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace v8 {
191cb0ef41Sopenharmony_cinamespace internal {
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cinamespace wasm {
221cb0ef41Sopenharmony_ciclass WasmCode;
231cb0ef41Sopenharmony_ci}  // namespace wasm
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciclass SafepointEntry {
261cb0ef41Sopenharmony_ci public:
271cb0ef41Sopenharmony_ci  static constexpr int kNoDeoptIndex = -1;
281cb0ef41Sopenharmony_ci  static constexpr int kNoTrampolinePC = -1;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  SafepointEntry() = default;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  SafepointEntry(int pc, int deopt_index, uint32_t tagged_register_indexes,
331cb0ef41Sopenharmony_ci                 base::Vector<uint8_t> tagged_slots, int trampoline_pc)
341cb0ef41Sopenharmony_ci      : pc_(pc),
351cb0ef41Sopenharmony_ci        deopt_index_(deopt_index),
361cb0ef41Sopenharmony_ci        tagged_register_indexes_(tagged_register_indexes),
371cb0ef41Sopenharmony_ci        tagged_slots_(tagged_slots),
381cb0ef41Sopenharmony_ci        trampoline_pc_(trampoline_pc) {
391cb0ef41Sopenharmony_ci    DCHECK(is_initialized());
401cb0ef41Sopenharmony_ci  }
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  bool is_initialized() const { return tagged_slots_.begin() != nullptr; }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  bool operator==(const SafepointEntry& other) const {
451cb0ef41Sopenharmony_ci    return pc_ == other.pc_ && deopt_index_ == other.deopt_index_ &&
461cb0ef41Sopenharmony_ci           tagged_register_indexes_ == other.tagged_register_indexes_ &&
471cb0ef41Sopenharmony_ci           tagged_slots_ == other.tagged_slots_ &&
481cb0ef41Sopenharmony_ci           trampoline_pc_ == other.trampoline_pc_;
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  void Reset() {
521cb0ef41Sopenharmony_ci    *this = SafepointEntry{};
531cb0ef41Sopenharmony_ci    DCHECK(!is_initialized());
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  int pc() const { return pc_; }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  int trampoline_pc() const { return trampoline_pc_; }
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  bool has_deoptimization_index() const {
611cb0ef41Sopenharmony_ci    DCHECK(is_initialized());
621cb0ef41Sopenharmony_ci    return deopt_index_ != kNoDeoptIndex;
631cb0ef41Sopenharmony_ci  }
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  int deoptimization_index() const {
661cb0ef41Sopenharmony_ci    DCHECK(is_initialized() && has_deoptimization_index());
671cb0ef41Sopenharmony_ci    return deopt_index_;
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  uint32_t tagged_register_indexes() const {
711cb0ef41Sopenharmony_ci    DCHECK(is_initialized());
721cb0ef41Sopenharmony_ci    return tagged_register_indexes_;
731cb0ef41Sopenharmony_ci  }
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  base::Vector<const uint8_t> tagged_slots() const {
761cb0ef41Sopenharmony_ci    DCHECK(is_initialized());
771cb0ef41Sopenharmony_ci    return tagged_slots_;
781cb0ef41Sopenharmony_ci  }
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci private:
811cb0ef41Sopenharmony_ci  int pc_ = -1;
821cb0ef41Sopenharmony_ci  int deopt_index_ = kNoDeoptIndex;
831cb0ef41Sopenharmony_ci  uint32_t tagged_register_indexes_ = 0;
841cb0ef41Sopenharmony_ci  base::Vector<uint8_t> tagged_slots_;
851cb0ef41Sopenharmony_ci  int trampoline_pc_ = kNoTrampolinePC;
861cb0ef41Sopenharmony_ci};
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci// A wrapper class for accessing the safepoint table embedded into the Code
891cb0ef41Sopenharmony_ci// object.
901cb0ef41Sopenharmony_ciclass SafepointTable {
911cb0ef41Sopenharmony_ci public:
921cb0ef41Sopenharmony_ci  // The isolate and pc arguments are used for figuring out whether pc
931cb0ef41Sopenharmony_ci  // belongs to the embedded or un-embedded code blob.
941cb0ef41Sopenharmony_ci  explicit SafepointTable(Isolate* isolate, Address pc, Code code);
951cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
961cb0ef41Sopenharmony_ci  explicit SafepointTable(const wasm::WasmCode* code);
971cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  SafepointTable(const SafepointTable&) = delete;
1001cb0ef41Sopenharmony_ci  SafepointTable& operator=(const SafepointTable&) = delete;
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  int length() const { return length_; }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  int byte_size() const {
1051cb0ef41Sopenharmony_ci    return kHeaderSize + length_ * (entry_size() + tagged_slots_bytes());
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  int find_return_pc(int pc_offset);
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  SafepointEntry GetEntry(int index) const {
1111cb0ef41Sopenharmony_ci    DCHECK_GT(length_, index);
1121cb0ef41Sopenharmony_ci    Address entry_ptr =
1131cb0ef41Sopenharmony_ci        safepoint_table_address_ + kHeaderSize + index * entry_size();
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    int pc = read_bytes(&entry_ptr, pc_size());
1161cb0ef41Sopenharmony_ci    int deopt_index = SafepointEntry::kNoDeoptIndex;
1171cb0ef41Sopenharmony_ci    int trampoline_pc = SafepointEntry::kNoTrampolinePC;
1181cb0ef41Sopenharmony_ci    if (has_deopt_data()) {
1191cb0ef41Sopenharmony_ci      STATIC_ASSERT(SafepointEntry::kNoDeoptIndex == -1);
1201cb0ef41Sopenharmony_ci      STATIC_ASSERT(SafepointEntry::kNoTrampolinePC == -1);
1211cb0ef41Sopenharmony_ci      // `-1` to restore the original value, see also
1221cb0ef41Sopenharmony_ci      // SafepointTableBuilder::Emit.
1231cb0ef41Sopenharmony_ci      deopt_index = read_bytes(&entry_ptr, deopt_index_size()) - 1;
1241cb0ef41Sopenharmony_ci      trampoline_pc = read_bytes(&entry_ptr, pc_size()) - 1;
1251cb0ef41Sopenharmony_ci      DCHECK(deopt_index >= 0 || deopt_index == SafepointEntry::kNoDeoptIndex);
1261cb0ef41Sopenharmony_ci      DCHECK(trampoline_pc >= 0 ||
1271cb0ef41Sopenharmony_ci             trampoline_pc == SafepointEntry::kNoTrampolinePC);
1281cb0ef41Sopenharmony_ci    }
1291cb0ef41Sopenharmony_ci    int tagged_register_indexes =
1301cb0ef41Sopenharmony_ci        read_bytes(&entry_ptr, register_indexes_size());
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci    // Entry bits start after the the vector of entries (thus the pc offset of
1331cb0ef41Sopenharmony_ci    // the non-existing entry after the last one).
1341cb0ef41Sopenharmony_ci    uint8_t* tagged_slots_start = reinterpret_cast<uint8_t*>(
1351cb0ef41Sopenharmony_ci        safepoint_table_address_ + kHeaderSize + length_ * entry_size());
1361cb0ef41Sopenharmony_ci    base::Vector<uint8_t> tagged_slots(
1371cb0ef41Sopenharmony_ci        tagged_slots_start + index * tagged_slots_bytes(),
1381cb0ef41Sopenharmony_ci        tagged_slots_bytes());
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci    return SafepointEntry(pc, deopt_index, tagged_register_indexes,
1411cb0ef41Sopenharmony_ci                          tagged_slots, trampoline_pc);
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  // Returns the entry for the given pc.
1451cb0ef41Sopenharmony_ci  SafepointEntry FindEntry(Address pc) const;
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  void Print(std::ostream&) const;
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci private:
1501cb0ef41Sopenharmony_ci  // Layout information.
1511cb0ef41Sopenharmony_ci  static constexpr int kLengthOffset = 0;
1521cb0ef41Sopenharmony_ci  static constexpr int kEntryConfigurationOffset = kLengthOffset + kIntSize;
1531cb0ef41Sopenharmony_ci  static constexpr int kHeaderSize = kEntryConfigurationOffset + kUInt32Size;
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  using HasDeoptDataField = base::BitField<bool, 0, 1>;
1561cb0ef41Sopenharmony_ci  using RegisterIndexesSizeField = HasDeoptDataField::Next<int, 3>;
1571cb0ef41Sopenharmony_ci  using PcSizeField = RegisterIndexesSizeField::Next<int, 3>;
1581cb0ef41Sopenharmony_ci  using DeoptIndexSizeField = PcSizeField::Next<int, 3>;
1591cb0ef41Sopenharmony_ci  // In 22 bits, we can encode up to 4M bytes, corresponding to 32M frame slots,
1601cb0ef41Sopenharmony_ci  // which is 128MB on 32-bit and 256MB on 64-bit systems. The stack size is
1611cb0ef41Sopenharmony_ci  // limited to a bit below 1MB anyway (see FLAG_stack_size).
1621cb0ef41Sopenharmony_ci  using TaggedSlotsBytesField = DeoptIndexSizeField::Next<int, 22>;
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  SafepointTable(Address instruction_start, Address safepoint_table_address);
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  int entry_size() const {
1671cb0ef41Sopenharmony_ci    int deopt_data_size = has_deopt_data() ? pc_size() + deopt_index_size() : 0;
1681cb0ef41Sopenharmony_ci    return pc_size() + deopt_data_size + register_indexes_size();
1691cb0ef41Sopenharmony_ci  }
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  int tagged_slots_bytes() const {
1721cb0ef41Sopenharmony_ci    return TaggedSlotsBytesField::decode(entry_configuration_);
1731cb0ef41Sopenharmony_ci  }
1741cb0ef41Sopenharmony_ci  bool has_deopt_data() const {
1751cb0ef41Sopenharmony_ci    return HasDeoptDataField::decode(entry_configuration_);
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci  int pc_size() const { return PcSizeField::decode(entry_configuration_); }
1781cb0ef41Sopenharmony_ci  int deopt_index_size() const {
1791cb0ef41Sopenharmony_ci    return DeoptIndexSizeField::decode(entry_configuration_);
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci  int register_indexes_size() const {
1821cb0ef41Sopenharmony_ci    return RegisterIndexesSizeField::decode(entry_configuration_);
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  static int read_bytes(Address* ptr, int bytes) {
1861cb0ef41Sopenharmony_ci    uint32_t result = 0;
1871cb0ef41Sopenharmony_ci    for (int b = 0; b < bytes; ++b, ++*ptr) {
1881cb0ef41Sopenharmony_ci      result |= uint32_t{*reinterpret_cast<uint8_t*>(*ptr)} << (8 * b);
1891cb0ef41Sopenharmony_ci    }
1901cb0ef41Sopenharmony_ci    return static_cast<int>(result);
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  DISALLOW_GARBAGE_COLLECTION(no_gc_)
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  const Address instruction_start_;
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  // Safepoint table layout.
1981cb0ef41Sopenharmony_ci  const Address safepoint_table_address_;
1991cb0ef41Sopenharmony_ci  const int length_;
2001cb0ef41Sopenharmony_ci  const uint32_t entry_configuration_;
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  friend class SafepointTableBuilder;
2031cb0ef41Sopenharmony_ci  friend class SafepointEntry;
2041cb0ef41Sopenharmony_ci};
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ciclass SafepointTableBuilder {
2071cb0ef41Sopenharmony_ci private:
2081cb0ef41Sopenharmony_ci  struct EntryBuilder {
2091cb0ef41Sopenharmony_ci    int pc;
2101cb0ef41Sopenharmony_ci    int deopt_index = SafepointEntry::kNoDeoptIndex;
2111cb0ef41Sopenharmony_ci    int trampoline = SafepointEntry::kNoTrampolinePC;
2121cb0ef41Sopenharmony_ci    GrowableBitVector* stack_indexes;
2131cb0ef41Sopenharmony_ci    uint32_t register_indexes = 0;
2141cb0ef41Sopenharmony_ci    EntryBuilder(Zone* zone, int pc)
2151cb0ef41Sopenharmony_ci        : pc(pc), stack_indexes(zone->New<GrowableBitVector>()) {}
2161cb0ef41Sopenharmony_ci  };
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci public:
2191cb0ef41Sopenharmony_ci  explicit SafepointTableBuilder(Zone* zone) : entries_(zone), zone_(zone) {}
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  SafepointTableBuilder(const SafepointTableBuilder&) = delete;
2221cb0ef41Sopenharmony_ci  SafepointTableBuilder& operator=(const SafepointTableBuilder&) = delete;
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  bool emitted() const {
2251cb0ef41Sopenharmony_ci    return safepoint_table_offset_ != kNoSafepointTableOffset;
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  int safepoint_table_offset() const {
2291cb0ef41Sopenharmony_ci    DCHECK(emitted());
2301cb0ef41Sopenharmony_ci    return safepoint_table_offset_;
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  class Safepoint {
2341cb0ef41Sopenharmony_ci   public:
2351cb0ef41Sopenharmony_ci    void DefineTaggedStackSlot(int index) {
2361cb0ef41Sopenharmony_ci      // Note it is only valid to specify stack slots here that are *not* in
2371cb0ef41Sopenharmony_ci      // the fixed part of the frame (e.g. argc, target, context, stored rbp,
2381cb0ef41Sopenharmony_ci      // return address). Frame iteration handles the fixed part of the frame
2391cb0ef41Sopenharmony_ci      // with custom code, see CommonFrame::IterateCompiledFrame.
2401cb0ef41Sopenharmony_ci      entry_->stack_indexes->Add(index, table_->zone_);
2411cb0ef41Sopenharmony_ci      table_->UpdateMinMaxStackIndex(index);
2421cb0ef41Sopenharmony_ci    }
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci    void DefineTaggedRegister(int reg_code) {
2451cb0ef41Sopenharmony_ci      DCHECK_LT(reg_code,
2461cb0ef41Sopenharmony_ci                kBitsPerByte * sizeof(EntryBuilder::register_indexes));
2471cb0ef41Sopenharmony_ci      entry_->register_indexes |= 1u << reg_code;
2481cb0ef41Sopenharmony_ci    }
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci   private:
2511cb0ef41Sopenharmony_ci    friend class SafepointTableBuilder;
2521cb0ef41Sopenharmony_ci    Safepoint(EntryBuilder* entry, SafepointTableBuilder* table)
2531cb0ef41Sopenharmony_ci        : entry_(entry), table_(table) {}
2541cb0ef41Sopenharmony_ci    EntryBuilder* const entry_;
2551cb0ef41Sopenharmony_ci    SafepointTableBuilder* const table_;
2561cb0ef41Sopenharmony_ci  };
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci  // Define a new safepoint for the current position in the body.
2591cb0ef41Sopenharmony_ci  Safepoint DefineSafepoint(Assembler* assembler);
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  // Emit the safepoint table after the body. The number of bits per
2621cb0ef41Sopenharmony_ci  // entry must be enough to hold all the pointer indexes.
2631cb0ef41Sopenharmony_ci  V8_EXPORT_PRIVATE void Emit(Assembler* assembler, int bits_per_entry);
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci  // Find the Deoptimization Info with pc offset {pc} and update its
2661cb0ef41Sopenharmony_ci  // trampoline field. Calling this function ensures that the safepoint
2671cb0ef41Sopenharmony_ci  // table contains the trampoline PC {trampoline} that replaced the
2681cb0ef41Sopenharmony_ci  // return PC {pc} on the stack.
2691cb0ef41Sopenharmony_ci  int UpdateDeoptimizationInfo(int pc, int trampoline, int start,
2701cb0ef41Sopenharmony_ci                               int deopt_index);
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci private:
2731cb0ef41Sopenharmony_ci  // Remove consecutive identical entries.
2741cb0ef41Sopenharmony_ci  void RemoveDuplicates();
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci  void UpdateMinMaxStackIndex(int index) {
2771cb0ef41Sopenharmony_ci#ifdef DEBUG
2781cb0ef41Sopenharmony_ci    max_stack_index_ = std::max(max_stack_index_, index);
2791cb0ef41Sopenharmony_ci#endif  // DEBUG
2801cb0ef41Sopenharmony_ci    min_stack_index_ = std::min(min_stack_index_, index);
2811cb0ef41Sopenharmony_ci  }
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci  int min_stack_index() const {
2841cb0ef41Sopenharmony_ci    return min_stack_index_ == std::numeric_limits<int>::max()
2851cb0ef41Sopenharmony_ci               ? 0
2861cb0ef41Sopenharmony_ci               : min_stack_index_;
2871cb0ef41Sopenharmony_ci  }
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  static constexpr int kNoSafepointTableOffset = -1;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  // Tracks the min/max stack slot index over all entries. We need the minimum
2921cb0ef41Sopenharmony_ci  // index when encoding the actual table since we shift all unused lower
2931cb0ef41Sopenharmony_ci  // indices out of the encoding. Tracking the indices during safepoint
2941cb0ef41Sopenharmony_ci  // construction means we don't have to iterate again later.
2951cb0ef41Sopenharmony_ci#ifdef DEBUG
2961cb0ef41Sopenharmony_ci  int max_stack_index_ = 0;
2971cb0ef41Sopenharmony_ci#endif  // DEBUG
2981cb0ef41Sopenharmony_ci  int min_stack_index_ = std::numeric_limits<int>::max();
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  ZoneChunkList<EntryBuilder> entries_;
3011cb0ef41Sopenharmony_ci  int safepoint_table_offset_ = kNoSafepointTableOffset;
3021cb0ef41Sopenharmony_ci  Zone* const zone_;
3031cb0ef41Sopenharmony_ci};
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci}  // namespace internal
3061cb0ef41Sopenharmony_ci}  // namespace v8
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci#endif  // V8_CODEGEN_SAFEPOINT_TABLE_H_
309