• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_CODEGEN_SAFEPOINT_TABLE_H_
6 #define V8_CODEGEN_SAFEPOINT_TABLE_H_
7 
8 #include "src/base/memory.h"
9 #include "src/common/assert-scope.h"
10 #include "src/utils/allocation.h"
11 #include "src/utils/utils.h"
12 #include "src/zone/zone-chunk-list.h"
13 #include "src/zone/zone.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 namespace wasm {
19 class WasmCode;
20 }  // namespace wasm
21 
22 class SafepointEntry {
23  public:
SafepointEntry()24   SafepointEntry() : deopt_index_(0), bits_(nullptr), trampoline_pc_(-1) {}
25 
SafepointEntry(unsigned deopt_index,uint8_t * bits,int trampoline_pc)26   SafepointEntry(unsigned deopt_index, uint8_t* bits, int trampoline_pc)
27       : deopt_index_(deopt_index), bits_(bits), trampoline_pc_(trampoline_pc) {
28     DCHECK(is_valid());
29   }
30 
is_valid()31   bool is_valid() const { return bits_ != nullptr; }
32 
Equals(const SafepointEntry & other)33   bool Equals(const SafepointEntry& other) const {
34     return deopt_index_ == other.deopt_index_ && bits_ == other.bits_;
35   }
36 
Reset()37   void Reset() {
38     deopt_index_ = 0;
39     bits_ = nullptr;
40   }
41 
trampoline_pc()42   int trampoline_pc() { return trampoline_pc_; }
43 
44   static const unsigned kNoDeoptIndex = kMaxUInt32;
45 
deoptimization_index()46   int deoptimization_index() const {
47     DCHECK(is_valid() && has_deoptimization_index());
48     return deopt_index_;
49   }
50 
has_deoptimization_index()51   bool has_deoptimization_index() const {
52     DCHECK(is_valid());
53     return deopt_index_ != kNoDeoptIndex;
54   }
55 
bits()56   uint8_t* bits() {
57     DCHECK(is_valid());
58     return bits_;
59   }
60 
61  private:
62   unsigned deopt_index_;
63   uint8_t* bits_;
64   // It needs to be an integer as it is -1 for eager deoptimizations.
65   int trampoline_pc_;
66 };
67 
68 class SafepointTable {
69  public:
70   explicit SafepointTable(Code code);
71   explicit SafepointTable(const wasm::WasmCode* code);
72 
size()73   int size() const {
74     return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_));
75   }
length()76   unsigned length() const { return length_; }
entry_size()77   unsigned entry_size() const { return entry_size_; }
78 
GetPcOffset(unsigned index)79   unsigned GetPcOffset(unsigned index) const {
80     DCHECK(index < length_);
81     return base::Memory<uint32_t>(GetPcOffsetLocation(index));
82   }
83 
GetTrampolinePcOffset(unsigned index)84   int GetTrampolinePcOffset(unsigned index) const {
85     DCHECK(index < length_);
86     return base::Memory<int>(GetTrampolineLocation(index));
87   }
88 
89   unsigned find_return_pc(unsigned pc_offset);
90 
GetEntry(unsigned index)91   SafepointEntry GetEntry(unsigned index) const {
92     DCHECK(index < length_);
93     unsigned deopt_index =
94         base::Memory<uint32_t>(GetEncodedInfoLocation(index));
95     uint8_t* bits = &base::Memory<uint8_t>(entries() + (index * entry_size_));
96     int trampoline_pc =
97         has_deopt_ ? base::Memory<int>(GetTrampolineLocation(index)) : -1;
98     return SafepointEntry(deopt_index, bits, trampoline_pc);
99   }
100 
101   // Returns the entry for the given pc.
102   SafepointEntry FindEntry(Address pc) const;
103 
104   void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
105 
106  private:
107   SafepointTable(Address instruction_start, Address safepoint_table_address,
108                  uint32_t stack_slots, bool has_deopt);
109 
110   static const uint8_t kNoRegisters = 0xFF;
111 
112   // Layout information.
113   static const int kLengthOffset = 0;
114   static const int kEntrySizeOffset = kLengthOffset + kIntSize;
115   static const int kHeaderSize = kEntrySizeOffset + kIntSize;
116   static const int kPcOffset = 0;
117   static const int kEncodedInfoOffset = kPcOffset + kIntSize;
118   static const int kTrampolinePcOffset = kEncodedInfoOffset + kIntSize;
119   static const int kFixedEntrySize = kTrampolinePcOffset + kIntSize;
120 
ReadLength(Address table)121   static uint32_t ReadLength(Address table) {
122     return base::Memory<uint32_t>(table + kLengthOffset);
123   }
ReadEntrySize(Address table)124   static uint32_t ReadEntrySize(Address table) {
125     return base::Memory<uint32_t>(table + kEntrySizeOffset);
126   }
pc_and_deoptimization_indexes()127   Address pc_and_deoptimization_indexes() const {
128     return safepoint_table_address_ + kHeaderSize;
129   }
entries()130   Address entries() const {
131     return safepoint_table_address_ + kHeaderSize + (length_ * kFixedEntrySize);
132   }
133 
GetPcOffsetLocation(unsigned index)134   Address GetPcOffsetLocation(unsigned index) const {
135     return pc_and_deoptimization_indexes() + (index * kFixedEntrySize);
136   }
137 
GetEncodedInfoLocation(unsigned index)138   Address GetEncodedInfoLocation(unsigned index) const {
139     return GetPcOffsetLocation(index) + kEncodedInfoOffset;
140   }
141 
GetTrampolineLocation(unsigned index)142   Address GetTrampolineLocation(unsigned index) const {
143     return GetPcOffsetLocation(index) + kTrampolinePcOffset;
144   }
145 
146   static void PrintBits(std::ostream& os, uint8_t byte, int digits);
147 
148   DISALLOW_HEAP_ALLOCATION(no_allocation_)
149 
150   const Address instruction_start_;
151   const uint32_t stack_slots_;
152   const bool has_deopt_;
153 
154   // Safepoint table layout.
155   const Address safepoint_table_address_;
156   const uint32_t length_;
157   const uint32_t entry_size_;
158 
159   friend class SafepointTableBuilder;
160   friend class SafepointEntry;
161 
162   DISALLOW_COPY_AND_ASSIGN(SafepointTable);
163 };
164 
165 class Safepoint {
166  public:
167   enum DeoptMode { kNoLazyDeopt, kLazyDeopt };
168 
169   static const int kNoDeoptimizationIndex = SafepointEntry::kNoDeoptIndex;
170 
DefinePointerSlot(int index)171   void DefinePointerSlot(int index) { indexes_->push_back(index); }
172 
173  private:
Safepoint(ZoneChunkList<int> * indexes)174   explicit Safepoint(ZoneChunkList<int>* indexes) : indexes_(indexes) {}
175   ZoneChunkList<int>* const indexes_;
176 
177   friend class SafepointTableBuilder;
178 };
179 
180 class SafepointTableBuilder {
181  public:
SafepointTableBuilder(Zone * zone)182   explicit SafepointTableBuilder(Zone* zone)
183       : deoptimization_info_(zone),
184         emitted_(false),
185         zone_(zone) {}
186 
187   // Get the offset of the emitted safepoint table in the code.
188   unsigned GetCodeOffset() const;
189 
190   // Define a new safepoint for the current position in the body.
191   Safepoint DefineSafepoint(Assembler* assembler, Safepoint::DeoptMode mode);
192 
193   // Emit the safepoint table after the body. The number of bits per
194   // entry must be enough to hold all the pointer indexes.
195   V8_EXPORT_PRIVATE void Emit(Assembler* assembler, int bits_per_entry);
196 
197   // Find the Deoptimization Info with pc offset {pc} and update its
198   // trampoline field. Calling this function ensures that the safepoint
199   // table contains the trampoline PC {trampoline} that replaced the
200   // return PC {pc} on the stack.
201   int UpdateDeoptimizationInfo(int pc, int trampoline, int start,
202                                unsigned deopt_index);
203 
204  private:
205   struct DeoptimizationInfo {
206     unsigned pc;
207     unsigned deopt_index;
208     int trampoline;
209     ZoneChunkList<int>* indexes;
DeoptimizationInfoDeoptimizationInfo210     DeoptimizationInfo(Zone* zone, unsigned pc)
211         : pc(pc),
212           deopt_index(Safepoint::kNoDeoptimizationIndex),
213           trampoline(-1),
214           indexes(zone->New<ZoneChunkList<int>>(
215               zone, ZoneChunkList<int>::StartMode::kSmall)) {}
216   };
217 
218   // Compares all fields of a {DeoptimizationInfo} except {pc} and {trampoline}.
219   bool IsIdenticalExceptForPc(const DeoptimizationInfo&,
220                               const DeoptimizationInfo&) const;
221 
222   // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
223   void RemoveDuplicates();
224 
225   ZoneChunkList<DeoptimizationInfo> deoptimization_info_;
226 
227   unsigned offset_;
228   bool emitted_;
229 
230   Zone* zone_;
231 
232   DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
233 };
234 
235 }  // namespace internal
236 }  // namespace v8
237 
238 #endif  // V8_CODEGEN_SAFEPOINT_TABLE_H_
239