blob: d703051423ed10de9d4813d34adf9b560666b737 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 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 "v8.h"
32
Ben Murdochb8e0da22011-05-16 14:20:40 +010033#include "heap.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "zone.h"
35#include "zone-inl.h"
36
37namespace v8 {
38namespace internal {
39
Ben Murdochb8e0da22011-05-16 14:20:40 +010040struct Register;
41
42class SafepointEntry BASE_EMBEDDED {
43 public:
44 SafepointEntry() : info_(0), bits_(NULL) {}
45
46 SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) {
47 ASSERT(is_valid());
48 }
49
50 bool is_valid() const { return bits_ != NULL; }
51
52 bool Equals(const SafepointEntry& other) const {
53 return info_ == other.info_ && bits_ == other.bits_;
54 }
55
56 void Reset() {
57 info_ = 0;
58 bits_ = NULL;
59 }
60
61 int deoptimization_index() const {
62 ASSERT(is_valid());
63 return DeoptimizationIndexField::decode(info_);
64 }
65
66 int gap_code_size() const {
67 ASSERT(is_valid());
68 return GapCodeSizeField::decode(info_);
69 }
70
71 int argument_count() const {
72 ASSERT(is_valid());
73 return ArgumentsField::decode(info_);
74 }
75
76 bool has_doubles() const {
77 ASSERT(is_valid());
78 return SaveDoublesField::decode(info_);
79 }
80
81 uint8_t* bits() {
82 ASSERT(is_valid());
83 return bits_;
84 }
85
86 bool HasRegisters() const;
87 bool HasRegisterAt(int reg_index) const;
88
89 // Reserve 13 bits for the gap code size. On ARM a constant pool can be
90 // emitted when generating the gap code. The size of the const pool is less
91 // than what can be represented in 12 bits, so 13 bits gives room for having
92 // instructions before potentially emitting a constant pool.
93 static const int kGapCodeSizeBits = 13;
94 static const int kArgumentsFieldBits = 3;
95 static const int kSaveDoublesFieldBits = 1;
96 static const int kDeoptIndexBits =
97 32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits;
98 class GapCodeSizeField: public BitField<unsigned, 0, kGapCodeSizeBits> {};
99 class DeoptimizationIndexField: public BitField<int,
100 kGapCodeSizeBits,
101 kDeoptIndexBits> {}; // NOLINT
102 class ArgumentsField: public BitField<unsigned,
103 kGapCodeSizeBits + kDeoptIndexBits,
104 kArgumentsFieldBits> {}; // NOLINT
105 class SaveDoublesField: public BitField<bool,
106 kGapCodeSizeBits + kDeoptIndexBits +
107 kArgumentsFieldBits,
108 kSaveDoublesFieldBits> { }; // NOLINT
109
110 private:
111 unsigned info_;
112 uint8_t* bits_;
113};
114
115
Ben Murdochb0fe1622011-05-05 13:52:32 +0100116class SafepointTable BASE_EMBEDDED {
117 public:
118 explicit SafepointTable(Code* code);
119
120 int size() const {
121 return kHeaderSize +
122 (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); }
123 unsigned length() const { return length_; }
124 unsigned entry_size() const { return entry_size_; }
125
126 unsigned GetPcOffset(unsigned index) const {
127 ASSERT(index < length_);
128 return Memory::uint32_at(GetPcOffsetLocation(index));
129 }
130
Ben Murdochb8e0da22011-05-16 14:20:40 +0100131 SafepointEntry GetEntry(unsigned index) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100132 ASSERT(index < length_);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100133 unsigned info = Memory::uint32_at(GetInfoLocation(index));
134 uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
135 return SafepointEntry(info, bits);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100136 }
137
Ben Murdochb8e0da22011-05-16 14:20:40 +0100138 // Returns the entry for the given pc.
139 SafepointEntry FindEntry(Address pc) const;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100140
141 void PrintEntry(unsigned index) const;
142
143 private:
144 static const uint8_t kNoRegisters = 0xFF;
145
146 static const int kLengthOffset = 0;
147 static const int kEntrySizeOffset = kLengthOffset + kIntSize;
148 static const int kHeaderSize = kEntrySizeOffset + kIntSize;
149
150 static const int kPcSize = kIntSize;
151 static const int kDeoptimizationIndexSize = kIntSize;
152 static const int kPcAndDeoptimizationIndexSize =
153 kPcSize + kDeoptimizationIndexSize;
154
155 Address GetPcOffsetLocation(unsigned index) const {
156 return pc_and_deoptimization_indexes_ +
157 (index * kPcAndDeoptimizationIndexSize);
158 }
159
Ben Murdochb8e0da22011-05-16 14:20:40 +0100160 Address GetInfoLocation(unsigned index) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100161 return GetPcOffsetLocation(index) + kPcSize;
162 }
163
164 static void PrintBits(uint8_t byte, int digits);
165
166 AssertNoAllocation no_allocation_;
167 Code* code_;
168 unsigned length_;
169 unsigned entry_size_;
170
171 Address pc_and_deoptimization_indexes_;
172 Address entries_;
173
174 friend class SafepointTableBuilder;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100175 friend class SafepointEntry;
176
177 DISALLOW_COPY_AND_ASSIGN(SafepointTable);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100178};
179
180
181class Safepoint BASE_EMBEDDED {
182 public:
Ben Murdochb8e0da22011-05-16 14:20:40 +0100183 static const int kNoDeoptimizationIndex =
184 (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100185
186 void DefinePointerSlot(int index) { indexes_->Add(index); }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100187 void DefinePointerRegister(Register reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100188
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 indexes_(32),
204 registers_(32),
205 emitted_(false) { }
206
207 // Get the offset of the emitted safepoint table in the code.
208 unsigned GetCodeOffset() const;
209
210 // Define a new safepoint for the current position in the body.
211 Safepoint DefineSafepoint(
212 Assembler* assembler,
213 int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
214
215 // Define a new safepoint with registers on the stack for the
216 // current position in the body and take the number of arguments on
217 // top of the registers into account.
218 Safepoint DefineSafepointWithRegisters(
219 Assembler* assembler,
220 int arguments,
221 int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
222
Ben Murdochb8e0da22011-05-16 14:20:40 +0100223 // Define a new safepoint with all double registers and the normal
224 // registers on the stack for the current position in the body and
225 // take the number of arguments on top of the registers into account.
226 // TODO(1043) Rewrite the three SafepointTableBuilder::DefineSafepoint
227 // methods to one method that uses template arguments.
228 Safepoint DefineSafepointWithRegistersAndDoubles(
229 Assembler* assembler,
230 int arguments,
231 int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
232
Ben Murdochb0fe1622011-05-05 13:52:32 +0100233 // Update the last safepoint with the size of the code generated for the gap
234 // following it.
235 void SetPcAfterGap(int pc) {
236 ASSERT(!deoptimization_info_.is_empty());
237 int index = deoptimization_info_.length() - 1;
238 deoptimization_info_[index].pc_after_gap = pc;
239 }
240
241 // Emit the safepoint table after the body. The number of bits per
242 // entry must be enough to hold all the pointer indexes.
243 void Emit(Assembler* assembler, int bits_per_entry);
244
245 private:
246 struct DeoptimizationInfo {
247 unsigned pc;
248 unsigned deoptimization_index;
249 unsigned pc_after_gap;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100250 unsigned arguments;
251 bool has_doubles;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100252 };
253
Ben Murdochb8e0da22011-05-16 14:20:40 +0100254 uint32_t EncodeExceptPC(const DeoptimizationInfo& info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100255
256 ZoneList<DeoptimizationInfo> deoptimization_info_;
257 ZoneList<ZoneList<int>*> indexes_;
258 ZoneList<ZoneList<int>*> registers_;
259
260 bool emitted_;
261 unsigned offset_;
262
263 DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
264};
265
266} } // namespace v8::internal
267
268#endif // V8_SAFEPOINT_TABLE_H_