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