1 // Copyright 2011 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 #ifndef V8_SAFEPOINT_TABLE_H_ 6 #define V8_SAFEPOINT_TABLE_H_ 7 8 #include "src/allocation.h" 9 #include "src/assert-scope.h" 10 #include "src/utils.h" 11 #include "src/v8memory.h" 12 #include "src/zone/zone-chunk-list.h" 13 #include "src/zone/zone.h" 14 15 namespace v8 { 16 namespace internal { 17 18 class Register; 19 20 class SafepointEntry BASE_EMBEDDED { 21 public: SafepointEntry()22 SafepointEntry() : info_(0), bits_(nullptr), trampoline_pc_(-1) {} 23 SafepointEntry(unsigned info,uint8_t * bits,int trampoline_pc)24 SafepointEntry(unsigned info, uint8_t* bits, int trampoline_pc) 25 : info_(info), bits_(bits), trampoline_pc_(trampoline_pc) { 26 DCHECK(is_valid()); 27 } 28 is_valid()29 bool is_valid() const { return bits_ != nullptr; } 30 Equals(const SafepointEntry & other)31 bool Equals(const SafepointEntry& other) const { 32 return info_ == other.info_ && bits_ == other.bits_; 33 } 34 Reset()35 void Reset() { 36 info_ = 0; 37 bits_ = nullptr; 38 } 39 deoptimization_index()40 int deoptimization_index() const { 41 DCHECK(is_valid()); 42 return DeoptimizationIndexField::decode(info_); 43 } 44 trampoline_pc()45 int trampoline_pc() { return trampoline_pc_; } 46 set_trampoline_pc(int trampoline_pc)47 void set_trampoline_pc(int trampoline_pc) { trampoline_pc_ = trampoline_pc; } 48 49 static const int kArgumentsFieldBits = 3; 50 static const int kSaveDoublesFieldBits = 1; 51 static const int kDeoptIndexBits = 52 32 - kArgumentsFieldBits - kSaveDoublesFieldBits; 53 54 class DeoptimizationIndexField: 55 public BitField<int, 0, kDeoptIndexBits> {}; // NOLINT 56 class ArgumentsField: 57 public BitField<unsigned, 58 kDeoptIndexBits, 59 kArgumentsFieldBits> {}; // NOLINT 60 class SaveDoublesField: 61 public BitField<bool, 62 kDeoptIndexBits + kArgumentsFieldBits, 63 kSaveDoublesFieldBits> { }; // NOLINT 64 argument_count()65 int argument_count() const { 66 DCHECK(is_valid()); 67 return ArgumentsField::decode(info_); 68 } 69 has_doubles()70 bool has_doubles() const { 71 DCHECK(is_valid()); 72 return SaveDoublesField::decode(info_); 73 } 74 bits()75 uint8_t* bits() { 76 DCHECK(is_valid()); 77 return bits_; 78 } 79 80 bool HasRegisters() const; 81 bool HasRegisterAt(int reg_index) const; 82 83 private: 84 unsigned info_; 85 uint8_t* bits_; 86 // It needs to be an integer as it is -1 for eager deoptimizations. 87 int trampoline_pc_; 88 }; 89 90 91 class SafepointTable BASE_EMBEDDED { 92 public: 93 explicit SafepointTable(Code* code); 94 explicit SafepointTable(Address instruction_start, 95 size_t safepoint_table_offset, uint32_t stack_slots, 96 bool has_deopt = false); 97 size()98 int size() const { 99 return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_)); 100 } length()101 unsigned length() const { return length_; } entry_size()102 unsigned entry_size() const { return entry_size_; } 103 GetPcOffset(unsigned index)104 unsigned GetPcOffset(unsigned index) const { 105 DCHECK(index < length_); 106 return Memory<uint32_t>(GetPcOffsetLocation(index)); 107 } 108 GetTrampolinePcOffset(unsigned index)109 int GetTrampolinePcOffset(unsigned index) const { 110 DCHECK(index < length_); 111 return Memory<int>(GetTrampolineLocation(index)); 112 } 113 114 unsigned find_return_pc(unsigned pc_offset); 115 GetEntry(unsigned index)116 SafepointEntry GetEntry(unsigned index) const { 117 DCHECK(index < length_); 118 unsigned info = Memory<uint32_t>(GetInfoLocation(index)); 119 uint8_t* bits = &Memory<uint8_t>(entries_ + (index * entry_size_)); 120 int trampoline_pc = 121 has_deopt_ ? Memory<int>(GetTrampolineLocation(index)) : -1; 122 return SafepointEntry(info, bits, trampoline_pc); 123 } 124 125 // Returns the entry for the given pc. 126 SafepointEntry FindEntry(Address pc) const; 127 128 void PrintEntry(unsigned index, std::ostream& os) const; // NOLINT 129 130 private: 131 static const uint8_t kNoRegisters = 0xFF; 132 133 // Layout information 134 static const int kLengthOffset = 0; 135 static const int kEntrySizeOffset = kLengthOffset + kIntSize; 136 static const int kHeaderSize = kEntrySizeOffset + kIntSize; 137 static const int kPcOffset = 0; 138 static const int kDeoptimizationIndexOffset = kPcOffset + kIntSize; 139 static const int kTrampolinePcOffset = kDeoptimizationIndexOffset + kIntSize; 140 static const int kFixedEntrySize = kTrampolinePcOffset + kIntSize; 141 GetPcOffsetLocation(unsigned index)142 Address GetPcOffsetLocation(unsigned index) const { 143 return pc_and_deoptimization_indexes_ + (index * kFixedEntrySize); 144 } 145 146 // TODO(juliana): rename this to GetDeoptimizationIndexLocation GetInfoLocation(unsigned index)147 Address GetInfoLocation(unsigned index) const { 148 return GetPcOffsetLocation(index) + kDeoptimizationIndexOffset; 149 } 150 GetTrampolineLocation(unsigned index)151 Address GetTrampolineLocation(unsigned index) const { 152 return GetPcOffsetLocation(index) + kTrampolinePcOffset; 153 } 154 155 static void PrintBits(std::ostream& os, // NOLINT 156 uint8_t byte, int digits); 157 158 DisallowHeapAllocation no_allocation_; 159 Address instruction_start_; 160 uint32_t stack_slots_; 161 unsigned length_; 162 unsigned entry_size_; 163 164 Address pc_and_deoptimization_indexes_; 165 Address entries_; 166 bool has_deopt_; 167 168 friend class SafepointTableBuilder; 169 friend class SafepointEntry; 170 171 DISALLOW_COPY_AND_ASSIGN(SafepointTable); 172 }; 173 174 175 class Safepoint BASE_EMBEDDED { 176 public: 177 typedef enum { 178 kSimple = 0, 179 kWithRegisters = 1 << 0, 180 kWithDoubles = 1 << 1, 181 kWithRegistersAndDoubles = kWithRegisters | kWithDoubles 182 } Kind; 183 184 enum DeoptMode { 185 kNoLazyDeopt, 186 kLazyDeopt 187 }; 188 189 static const int kNoDeoptimizationIndex = 190 (1 << (SafepointEntry::kDeoptIndexBits)) - 1; 191 DefinePointerSlot(int index)192 void DefinePointerSlot(int index) { indexes_->push_back(index); } 193 void DefinePointerRegister(Register reg); 194 195 private: Safepoint(ZoneChunkList<int> * indexes,ZoneChunkList<int> * registers)196 Safepoint(ZoneChunkList<int>* indexes, ZoneChunkList<int>* registers) 197 : indexes_(indexes), registers_(registers) {} 198 ZoneChunkList<int>* const indexes_; 199 ZoneChunkList<int>* const registers_; 200 201 friend class SafepointTableBuilder; 202 }; 203 204 205 class SafepointTableBuilder BASE_EMBEDDED { 206 public: SafepointTableBuilder(Zone * zone)207 explicit SafepointTableBuilder(Zone* zone) 208 : deoptimization_info_(zone), 209 emitted_(false), 210 last_lazy_safepoint_(0), 211 zone_(zone) {} 212 213 // Get the offset of the emitted safepoint table in the code. 214 unsigned GetCodeOffset() const; 215 216 // Define a new safepoint for the current position in the body. 217 Safepoint DefineSafepoint(Assembler* assembler, 218 Safepoint::Kind kind, 219 int arguments, 220 Safepoint::DeoptMode mode); 221 222 // Record deoptimization index for lazy deoptimization for the last 223 // outstanding safepoints. 224 void RecordLazyDeoptimizationIndex(int index); BumpLastLazySafepointIndex()225 void BumpLastLazySafepointIndex() { 226 last_lazy_safepoint_ = deoptimization_info_.size(); 227 } 228 229 // Emit the safepoint table after the body. The number of bits per 230 // entry must be enough to hold all the pointer indexes. 231 void Emit(Assembler* assembler, int bits_per_entry); 232 233 // Find the Deoptimization Info with pc offset {pc} and update its 234 // trampoline field. Calling this function ensures that the safepoint 235 // table contains the trampoline PC (trampoline} that replaced the 236 // return PC {pc} on the stack. 237 int UpdateDeoptimizationInfo(int pc, int trampoline, int start); 238 239 private: 240 struct DeoptimizationInfo { 241 unsigned pc; 242 unsigned arguments; 243 bool has_doubles; 244 int trampoline; 245 ZoneChunkList<int>* indexes; 246 ZoneChunkList<int>* registers; 247 unsigned deopt_index; DeoptimizationInfoDeoptimizationInfo248 DeoptimizationInfo(Zone* zone, unsigned pc, unsigned arguments, 249 Safepoint::Kind kind) 250 : pc(pc), 251 arguments(arguments), 252 has_doubles(kind & Safepoint::kWithDoubles), 253 trampoline(-1), 254 indexes(new (zone) ZoneChunkList<int>( 255 zone, ZoneChunkList<int>::StartMode::kSmall)), 256 registers(kind & Safepoint::kWithRegisters 257 ? new (zone) ZoneChunkList<int>( 258 zone, ZoneChunkList<int>::StartMode::kSmall) 259 : nullptr), 260 deopt_index(Safepoint::kNoDeoptimizationIndex) {} 261 }; 262 263 uint32_t EncodeExceptPC(const DeoptimizationInfo&); 264 265 bool IsIdenticalExceptForPc(const DeoptimizationInfo&, 266 const DeoptimizationInfo&) const; 267 // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32. 268 void RemoveDuplicates(); 269 270 ZoneChunkList<DeoptimizationInfo> deoptimization_info_; 271 272 unsigned offset_; 273 bool emitted_; 274 size_t last_lazy_safepoint_; 275 276 Zone* zone_; 277 278 DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder); 279 }; 280 281 } // namespace internal 282 } // namespace v8 283 284 #endif // V8_SAFEPOINT_TABLE_H_ 285