1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_SAFEPOINT_TABLE_H_
29#define V8_SAFEPOINT_TABLE_H_
30
31#include "heap.h"
32#include "v8memory.h"
33#include "zone.h"
34
35namespace v8 {
36namespace internal {
37
38struct Register;
39
40class SafepointEntry BASE_EMBEDDED {
41 public:
42  SafepointEntry() : info_(0), bits_(NULL) {}
43
44  SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) {
45    ASSERT(is_valid());
46  }
47
48  bool is_valid() const { return bits_ != NULL; }
49
50  bool Equals(const SafepointEntry& other) const {
51    return info_ == other.info_ && bits_ == other.bits_;
52  }
53
54  void Reset() {
55    info_ = 0;
56    bits_ = NULL;
57  }
58
59  int deoptimization_index() const {
60    ASSERT(is_valid());
61    return DeoptimizationIndexField::decode(info_);
62  }
63
64  int gap_code_size() const {
65    ASSERT(is_valid());
66    return GapCodeSizeField::decode(info_);
67  }
68
69  int argument_count() const {
70    ASSERT(is_valid());
71    return ArgumentsField::decode(info_);
72  }
73
74  bool has_doubles() const {
75    ASSERT(is_valid());
76    return SaveDoublesField::decode(info_);
77  }
78
79  uint8_t* bits() {
80    ASSERT(is_valid());
81    return bits_;
82  }
83
84  bool HasRegisters() const;
85  bool HasRegisterAt(int reg_index) const;
86
87  // Reserve 13 bits for the gap code size. On ARM a constant pool can be
88  // emitted when generating the gap code. The size of the const pool is less
89  // than what can be represented in 12 bits, so 13 bits gives room for having
90  // instructions before potentially emitting a constant pool.
91  static const int kGapCodeSizeBits = 13;
92  static const int kArgumentsFieldBits = 3;
93  static const int kSaveDoublesFieldBits = 1;
94  static const int kDeoptIndexBits =
95      32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits;
96  class GapCodeSizeField: public BitField<unsigned, 0, kGapCodeSizeBits> {};
97  class DeoptimizationIndexField: public BitField<int,
98                                                  kGapCodeSizeBits,
99                                                  kDeoptIndexBits> {};  // NOLINT
100  class ArgumentsField: public BitField<unsigned,
101                                        kGapCodeSizeBits + kDeoptIndexBits,
102                                        kArgumentsFieldBits> {};  // NOLINT
103  class SaveDoublesField: public BitField<bool,
104                                          kGapCodeSizeBits + kDeoptIndexBits +
105                                          kArgumentsFieldBits,
106                                          kSaveDoublesFieldBits> { }; // NOLINT
107
108 private:
109  unsigned info_;
110  uint8_t* bits_;
111};
112
113
114class SafepointTable BASE_EMBEDDED {
115 public:
116  explicit SafepointTable(Code* code);
117
118  int size() const {
119    return kHeaderSize +
120           (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); }
121  unsigned length() const { return length_; }
122  unsigned entry_size() const { return entry_size_; }
123
124  unsigned GetPcOffset(unsigned index) const {
125    ASSERT(index < length_);
126    return Memory::uint32_at(GetPcOffsetLocation(index));
127  }
128
129  SafepointEntry GetEntry(unsigned index) const {
130    ASSERT(index < length_);
131    unsigned info = Memory::uint32_at(GetInfoLocation(index));
132    uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
133    return SafepointEntry(info, bits);
134  }
135
136  // Returns the entry for the given pc.
137  SafepointEntry FindEntry(Address pc) const;
138
139  void PrintEntry(unsigned index) const;
140
141 private:
142  static const uint8_t kNoRegisters = 0xFF;
143
144  static const int kLengthOffset = 0;
145  static const int kEntrySizeOffset = kLengthOffset + kIntSize;
146  static const int kHeaderSize = kEntrySizeOffset + kIntSize;
147
148  static const int kPcSize = kIntSize;
149  static const int kDeoptimizationIndexSize = kIntSize;
150  static const int kPcAndDeoptimizationIndexSize =
151      kPcSize + kDeoptimizationIndexSize;
152
153  Address GetPcOffsetLocation(unsigned index) const {
154    return pc_and_deoptimization_indexes_ +
155           (index * kPcAndDeoptimizationIndexSize);
156  }
157
158  Address GetInfoLocation(unsigned index) const {
159    return GetPcOffsetLocation(index) + kPcSize;
160  }
161
162  static void PrintBits(uint8_t byte, int digits);
163
164  AssertNoAllocation no_allocation_;
165  Code* code_;
166  unsigned length_;
167  unsigned entry_size_;
168
169  Address pc_and_deoptimization_indexes_;
170  Address entries_;
171
172  friend class SafepointTableBuilder;
173  friend class SafepointEntry;
174
175  DISALLOW_COPY_AND_ASSIGN(SafepointTable);
176};
177
178
179class Safepoint BASE_EMBEDDED {
180 public:
181  typedef enum {
182    kSimple = 0,
183    kWithRegisters = 1 << 0,
184    kWithDoubles = 1 << 1,
185    kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
186  } Kind;
187
188  static const int kNoDeoptimizationIndex =
189      (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
190
191  void DefinePointerSlot(int index) { indexes_->Add(index); }
192  void DefinePointerRegister(Register reg);
193
194 private:
195  Safepoint(ZoneList<int>* indexes, ZoneList<int>* registers) :
196      indexes_(indexes), registers_(registers) { }
197  ZoneList<int>* indexes_;
198  ZoneList<int>* registers_;
199
200  friend class SafepointTableBuilder;
201};
202
203
204class SafepointTableBuilder BASE_EMBEDDED {
205 public:
206  SafepointTableBuilder()
207      : deoptimization_info_(32),
208        indexes_(32),
209        registers_(32),
210        emitted_(false) { }
211
212  // Get the offset of the emitted safepoint table in the code.
213  unsigned GetCodeOffset() const;
214
215  // Define a new safepoint for the current position in the body.
216  Safepoint DefineSafepoint(Assembler* assembler,
217                            Safepoint::Kind kind,
218                            int arguments,
219                            int deoptimization_index);
220
221  // Update the last safepoint with the size of the code generated until the
222  // end of the gap following it.
223  void SetPcAfterGap(int pc) {
224    ASSERT(!deoptimization_info_.is_empty());
225    int index = deoptimization_info_.length() - 1;
226    deoptimization_info_[index].pc_after_gap = pc;
227  }
228
229  // Get the end pc offset of the last safepoint, including the code generated
230  // until the end of the gap following it.
231  unsigned GetPcAfterGap() {
232    int index = deoptimization_info_.length();
233    if (index == 0) return 0;
234    return deoptimization_info_[index - 1].pc_after_gap;
235  }
236
237  // Emit the safepoint table after the body. The number of bits per
238  // entry must be enough to hold all the pointer indexes.
239  void Emit(Assembler* assembler, int bits_per_entry);
240
241  // Count the number of deoptimization points where the next
242  // following deoptimization point comes less than limit bytes
243  // after the end of this point's gap.
244  int CountShortDeoptimizationIntervals(unsigned limit);
245
246 private:
247  struct DeoptimizationInfo {
248    unsigned pc;
249    unsigned deoptimization_index;
250    unsigned pc_after_gap;
251    unsigned arguments;
252    bool has_doubles;
253  };
254
255  uint32_t EncodeExceptPC(const DeoptimizationInfo& info);
256
257  ZoneList<DeoptimizationInfo> deoptimization_info_;
258  ZoneList<ZoneList<int>*> indexes_;
259  ZoneList<ZoneList<int>*> registers_;
260
261  unsigned offset_;
262  bool emitted_;
263
264  DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
265};
266
267} }  // namespace v8::internal
268
269#endif  // V8_SAFEPOINT_TABLE_H_
270