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