• 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_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