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