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/heap/heap.h"
10#include "src/v8memory.h"
11#include "src/zone.h"
12
13namespace v8 {
14namespace internal {
15
16struct Register;
17
18class SafepointEntry BASE_EMBEDDED {
19 public:
20  SafepointEntry() : info_(0), bits_(NULL) {}
21
22  SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) {
23    DCHECK(is_valid());
24  }
25
26  bool is_valid() const { return bits_ != NULL; }
27
28  bool Equals(const SafepointEntry& other) const {
29    return info_ == other.info_ && bits_ == other.bits_;
30  }
31
32  void Reset() {
33    info_ = 0;
34    bits_ = NULL;
35  }
36
37  int deoptimization_index() const {
38    DCHECK(is_valid());
39    return DeoptimizationIndexField::decode(info_);
40  }
41
42  static const int kArgumentsFieldBits = 3;
43  static const int kSaveDoublesFieldBits = 1;
44  static const int kDeoptIndexBits =
45      32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
46  class DeoptimizationIndexField:
47    public BitField<int, 0, kDeoptIndexBits> {};  // NOLINT
48  class ArgumentsField:
49    public BitField<unsigned,
50                    kDeoptIndexBits,
51                    kArgumentsFieldBits> {};  // NOLINT
52  class SaveDoublesField:
53    public BitField<bool,
54                    kDeoptIndexBits + kArgumentsFieldBits,
55                    kSaveDoublesFieldBits> { }; // NOLINT
56
57  int argument_count() const {
58    DCHECK(is_valid());
59    return ArgumentsField::decode(info_);
60  }
61
62  bool has_doubles() const {
63    DCHECK(is_valid());
64    return SaveDoublesField::decode(info_);
65  }
66
67  uint8_t* bits() {
68    DCHECK(is_valid());
69    return bits_;
70  }
71
72  bool HasRegisters() const;
73  bool HasRegisterAt(int reg_index) const;
74
75 private:
76  unsigned info_;
77  uint8_t* bits_;
78};
79
80
81class SafepointTable BASE_EMBEDDED {
82 public:
83  explicit SafepointTable(Code* code);
84
85  int size() const {
86    return kHeaderSize +
87           (length_ * (kPcAndDeoptimizationIndexSize + entry_size_));
88  }
89  unsigned length() const { return length_; }
90  unsigned entry_size() const { return entry_size_; }
91
92  unsigned GetPcOffset(unsigned index) const {
93    DCHECK(index < length_);
94    return Memory::uint32_at(GetPcOffsetLocation(index));
95  }
96
97  SafepointEntry GetEntry(unsigned index) const {
98    DCHECK(index < length_);
99    unsigned info = Memory::uint32_at(GetInfoLocation(index));
100    uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
101    return SafepointEntry(info, bits);
102  }
103
104  // Returns the entry for the given pc.
105  SafepointEntry FindEntry(Address pc) const;
106
107  void PrintEntry(unsigned index, OStream& os) const;  // NOLINT
108
109 private:
110  static const uint8_t kNoRegisters = 0xFF;
111
112  static const int kLengthOffset = 0;
113  static const int kEntrySizeOffset = kLengthOffset + kIntSize;
114  static const int kHeaderSize = kEntrySizeOffset + kIntSize;
115
116  static const int kPcSize = kIntSize;
117  static const int kDeoptimizationIndexSize = kIntSize;
118  static const int kPcAndDeoptimizationIndexSize =
119      kPcSize + kDeoptimizationIndexSize;
120
121  Address GetPcOffsetLocation(unsigned index) const {
122    return pc_and_deoptimization_indexes_ +
123           (index * kPcAndDeoptimizationIndexSize);
124  }
125
126  Address GetInfoLocation(unsigned index) const {
127    return GetPcOffsetLocation(index) + kPcSize;
128  }
129
130  static void PrintBits(OStream& os,  // NOLINT
131                        uint8_t byte, int digits);
132
133  DisallowHeapAllocation no_allocation_;
134  Code* code_;
135  unsigned length_;
136  unsigned entry_size_;
137
138  Address pc_and_deoptimization_indexes_;
139  Address entries_;
140
141  friend class SafepointTableBuilder;
142  friend class SafepointEntry;
143
144  DISALLOW_COPY_AND_ASSIGN(SafepointTable);
145};
146
147
148class Safepoint BASE_EMBEDDED {
149 public:
150  typedef enum {
151    kSimple = 0,
152    kWithRegisters = 1 << 0,
153    kWithDoubles = 1 << 1,
154    kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
155  } Kind;
156
157  enum DeoptMode {
158    kNoLazyDeopt,
159    kLazyDeopt
160  };
161
162  static const int kNoDeoptimizationIndex =
163      (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
164
165  void DefinePointerSlot(int index, Zone* zone) { indexes_->Add(index, zone); }
166  void DefinePointerRegister(Register reg, Zone* zone);
167
168 private:
169  Safepoint(ZoneList<int>* indexes, ZoneList<int>* registers)
170      : indexes_(indexes), registers_(registers) {}
171  ZoneList<int>* indexes_;
172  ZoneList<int>* registers_;
173
174  friend class SafepointTableBuilder;
175};
176
177
178class SafepointTableBuilder BASE_EMBEDDED {
179 public:
180  explicit SafepointTableBuilder(Zone* zone)
181      : deoptimization_info_(32, zone),
182        deopt_index_list_(32, zone),
183        indexes_(32, zone),
184        registers_(32, zone),
185        emitted_(false),
186        last_lazy_safepoint_(0),
187        zone_(zone) { }
188
189  // Get the offset of the emitted safepoint table in the code.
190  unsigned GetCodeOffset() const;
191
192  // Define a new safepoint for the current position in the body.
193  Safepoint DefineSafepoint(Assembler* assembler,
194                            Safepoint::Kind kind,
195                            int arguments,
196                            Safepoint::DeoptMode mode);
197
198  // Record deoptimization index for lazy deoptimization for the last
199  // outstanding safepoints.
200  void RecordLazyDeoptimizationIndex(int index);
201  void BumpLastLazySafepointIndex() {
202    last_lazy_safepoint_ = deopt_index_list_.length();
203  }
204
205  // Emit the safepoint table after the body. The number of bits per
206  // entry must be enough to hold all the pointer indexes.
207  void Emit(Assembler* assembler, int bits_per_entry);
208
209
210 private:
211  struct DeoptimizationInfo {
212    unsigned pc;
213    unsigned arguments;
214    bool has_doubles;
215  };
216
217  uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index);
218
219  ZoneList<DeoptimizationInfo> deoptimization_info_;
220  ZoneList<unsigned> deopt_index_list_;
221  ZoneList<ZoneList<int>*> indexes_;
222  ZoneList<ZoneList<int>*> registers_;
223
224  unsigned offset_;
225  bool emitted_;
226  int last_lazy_safepoint_;
227
228  Zone* zone_;
229
230  DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
231};
232
233} }  // namespace v8::internal
234
235#endif  // V8_SAFEPOINT_TABLE_H_
236