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 35 namespace v8 { 36 namespace internal { 37 38 struct Register; 39 40 class 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 114 class 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 179 class 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 204 class 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