OLD | NEW |
(Empty) | |
| 1 // 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 #include "v8.h" |
| 29 |
| 30 #include "codegen-inl.h" |
| 31 #include "jump-target-inl.h" |
| 32 #include "register-allocator-inl.h" |
| 33 |
| 34 namespace v8 { |
| 35 namespace internal { |
| 36 |
| 37 |
| 38 void JumpTarget::Jump(Result* arg) { |
| 39 ASSERT(cgen()->has_valid_frame()); |
| 40 |
| 41 cgen()->frame()->Push(arg); |
| 42 DoJump(); |
| 43 } |
| 44 |
| 45 |
| 46 #ifdef DEBUG |
| 47 #define DECLARE_ARGCHECK_VARS(name) \ |
| 48 Result::Type name##_type = name->type(); \ |
| 49 Register name##_reg = name->is_register() ? name->reg() : no_reg |
| 50 |
| 51 #define ASSERT_ARGCHECK(name) \ |
| 52 ASSERT(name->type() == name##_type); \ |
| 53 ASSERT(!name->is_register() || name->reg().is(name##_reg)) |
| 54 |
| 55 #else |
| 56 #define DECLARE_ARGCHECK_VARS(name) do {} while (false) |
| 57 |
| 58 #define ASSERT_ARGCHECK(name) do {} while (false) |
| 59 #endif |
| 60 |
| 61 void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) { |
| 62 ASSERT(cgen()->has_valid_frame()); |
| 63 |
| 64 // We want to check that non-frame registers at the call site stay in |
| 65 // the same registers on the fall-through branch. |
| 66 DECLARE_ARGCHECK_VARS(arg); |
| 67 |
| 68 cgen()->frame()->Push(arg); |
| 69 DoBranch(cc, hint); |
| 70 *arg = cgen()->frame()->Pop(); |
| 71 |
| 72 ASSERT_ARGCHECK(arg); |
| 73 } |
| 74 |
| 75 |
| 76 void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) { |
| 77 ASSERT(cgen()->has_valid_frame()); |
| 78 |
| 79 int count = cgen()->frame()->height() - expected_height_; |
| 80 if (count > 0) { |
| 81 // We negate and branch here rather than using DoBranch's negate |
| 82 // and branch. This gives us a hook to remove statement state |
| 83 // from the frame. |
| 84 JumpTarget fall_through; |
| 85 // Branch to fall through will not negate, because it is a |
| 86 // forward-only target. |
| 87 fall_through.Branch(NegateCondition(cc), NegateHint(hint)); |
| 88 Jump(arg); // May emit merge code here. |
| 89 fall_through.Bind(); |
| 90 } else { |
| 91 DECLARE_ARGCHECK_VARS(arg); |
| 92 cgen()->frame()->Push(arg); |
| 93 DoBranch(cc, hint); |
| 94 *arg = cgen()->frame()->Pop(); |
| 95 ASSERT_ARGCHECK(arg); |
| 96 } |
| 97 } |
| 98 |
| 99 #undef DECLARE_ARGCHECK_VARS |
| 100 #undef ASSERT_ARGCHECK |
| 101 |
| 102 |
| 103 void JumpTarget::Bind(Result* arg) { |
| 104 if (cgen()->has_valid_frame()) { |
| 105 cgen()->frame()->Push(arg); |
| 106 } |
| 107 DoBind(); |
| 108 *arg = cgen()->frame()->Pop(); |
| 109 } |
| 110 |
| 111 |
| 112 void JumpTarget::ComputeEntryFrame() { |
| 113 // Given: a collection of frames reaching by forward CFG edges and |
| 114 // the directionality of the block. Compute: an entry frame for the |
| 115 // block. |
| 116 |
| 117 Counters::compute_entry_frame.Increment(); |
| 118 #ifdef DEBUG |
| 119 if (compiling_deferred_code_) { |
| 120 ASSERT(reaching_frames_.length() > 1); |
| 121 VirtualFrame* frame = reaching_frames_[0]; |
| 122 bool all_identical = true; |
| 123 for (int i = 1; i < reaching_frames_.length(); i++) { |
| 124 if (!frame->Equals(reaching_frames_[i])) { |
| 125 all_identical = false; |
| 126 break; |
| 127 } |
| 128 } |
| 129 ASSERT(!all_identical || all_identical); |
| 130 } |
| 131 #endif |
| 132 |
| 133 // Choose an initial frame. |
| 134 VirtualFrame* initial_frame = reaching_frames_[0]; |
| 135 |
| 136 // A list of pointers to frame elements in the entry frame. NULL |
| 137 // indicates that the element has not yet been determined. |
| 138 int length = initial_frame->element_count(); |
| 139 ZoneList<FrameElement*> elements(length); |
| 140 |
| 141 // Initially populate the list of elements based on the initial |
| 142 // frame. |
| 143 for (int i = 0; i < length; i++) { |
| 144 FrameElement element = initial_frame->elements_[i]; |
| 145 // We do not allow copies or constants in bidirectional frames. |
| 146 if (direction_ == BIDIRECTIONAL) { |
| 147 if (element.is_constant() || element.is_copy()) { |
| 148 elements.Add(NULL); |
| 149 continue; |
| 150 } |
| 151 } |
| 152 elements.Add(&initial_frame->elements_[i]); |
| 153 } |
| 154 |
| 155 // Compute elements based on the other reaching frames. |
| 156 if (reaching_frames_.length() > 1) { |
| 157 for (int i = 0; i < length; i++) { |
| 158 FrameElement* element = elements[i]; |
| 159 for (int j = 1; j < reaching_frames_.length(); j++) { |
| 160 // Element computation is monotonic: new information will not |
| 161 // change our decision about undetermined or invalid elements. |
| 162 if (element == NULL || !element->is_valid()) break; |
| 163 |
| 164 FrameElement* other = &reaching_frames_[j]->elements_[i]; |
| 165 element = element->Combine(other); |
| 166 if (element != NULL && !element->is_copy()) { |
| 167 ASSERT(other != NULL); |
| 168 // We overwrite the number information of one of the incoming frames. |
| 169 // This is safe because we only use the frame for emitting merge code. |
| 170 // The number information of incoming frames is not used anymore. |
| 171 element->set_number_info(NumberInfo::Combine(element->number_info(), |
| 172 other->number_info())); |
| 173 } |
| 174 } |
| 175 elements[i] = element; |
| 176 } |
| 177 } |
| 178 |
| 179 // Build the new frame. A freshly allocated frame has memory elements |
| 180 // for the parameters and some platform-dependent elements (e.g., |
| 181 // return address). Replace those first. |
| 182 entry_frame_ = new VirtualFrame(); |
| 183 int index = 0; |
| 184 for (; index < entry_frame_->element_count(); index++) { |
| 185 FrameElement* target = elements[index]; |
| 186 // If the element is determined, set it now. Count registers. Mark |
| 187 // elements as copied exactly when they have a copy. Undetermined |
| 188 // elements are initially recorded as if in memory. |
| 189 if (target != NULL) { |
| 190 entry_frame_->elements_[index] = *target; |
| 191 InitializeEntryElement(index, target); |
| 192 } |
| 193 } |
| 194 // Then fill in the rest of the frame with new elements. |
| 195 for (; index < length; index++) { |
| 196 FrameElement* target = elements[index]; |
| 197 if (target == NULL) { |
| 198 entry_frame_->elements_.Add( |
| 199 FrameElement::MemoryElement(NumberInfo::Uninitialized())); |
| 200 } else { |
| 201 entry_frame_->elements_.Add(*target); |
| 202 InitializeEntryElement(index, target); |
| 203 } |
| 204 } |
| 205 |
| 206 // Allocate any still-undetermined frame elements to registers or |
| 207 // memory, from the top down. |
| 208 for (int i = length - 1; i >= 0; i--) { |
| 209 if (elements[i] == NULL) { |
| 210 // Loop over all the reaching frames to check whether the element |
| 211 // is synced on all frames and to count the registers it occupies. |
| 212 bool is_synced = true; |
| 213 RegisterFile candidate_registers; |
| 214 int best_count = kMinInt; |
| 215 int best_reg_num = RegisterAllocator::kInvalidRegister; |
| 216 NumberInfo info = NumberInfo::Uninitialized(); |
| 217 |
| 218 for (int j = 0; j < reaching_frames_.length(); j++) { |
| 219 FrameElement element = reaching_frames_[j]->elements_[i]; |
| 220 if (direction_ == BIDIRECTIONAL) { |
| 221 info = NumberInfo::Unknown(); |
| 222 } else if (!element.is_copy()) { |
| 223 info = NumberInfo::Combine(info, element.number_info()); |
| 224 } else { |
| 225 // New elements will not be copies, so get number information from |
| 226 // backing element in the reaching frame. |
| 227 info = NumberInfo::Combine(info, |
| 228 reaching_frames_[j]->elements_[element.index()].number_info()); |
| 229 } |
| 230 is_synced = is_synced && element.is_synced(); |
| 231 if (element.is_register() && !entry_frame_->is_used(element.reg())) { |
| 232 // Count the register occurrence and remember it if better |
| 233 // than the previous best. |
| 234 int num = RegisterAllocator::ToNumber(element.reg()); |
| 235 candidate_registers.Use(num); |
| 236 if (candidate_registers.count(num) > best_count) { |
| 237 best_count = candidate_registers.count(num); |
| 238 best_reg_num = num; |
| 239 } |
| 240 } |
| 241 } |
| 242 |
| 243 // We must have a number type information now (not for copied elements). |
| 244 ASSERT(entry_frame_->elements_[i].is_copy() |
| 245 || !info.IsUninitialized()); |
| 246 |
| 247 // If the value is synced on all frames, put it in memory. This |
| 248 // costs nothing at the merge code but will incur a |
| 249 // memory-to-register move when the value is needed later. |
| 250 if (is_synced) { |
| 251 // Already recorded as a memory element. |
| 252 // Set combined number info. |
| 253 entry_frame_->elements_[i].set_number_info(info); |
| 254 continue; |
| 255 } |
| 256 |
| 257 // Try to put it in a register. If there was no best choice |
| 258 // consider any free register. |
| 259 if (best_reg_num == RegisterAllocator::kInvalidRegister) { |
| 260 for (int j = 0; j < RegisterAllocator::kNumRegisters; j++) { |
| 261 if (!entry_frame_->is_used(j)) { |
| 262 best_reg_num = j; |
| 263 break; |
| 264 } |
| 265 } |
| 266 } |
| 267 |
| 268 if (best_reg_num != RegisterAllocator::kInvalidRegister) { |
| 269 // If there was a register choice, use it. Preserve the copied |
| 270 // flag on the element. |
| 271 bool is_copied = entry_frame_->elements_[i].is_copied(); |
| 272 Register reg = RegisterAllocator::ToRegister(best_reg_num); |
| 273 entry_frame_->elements_[i] = |
| 274 FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED, |
| 275 NumberInfo::Uninitialized()); |
| 276 if (is_copied) entry_frame_->elements_[i].set_copied(); |
| 277 entry_frame_->set_register_location(reg, i); |
| 278 } |
| 279 // Set combined number info. |
| 280 entry_frame_->elements_[i].set_number_info(info); |
| 281 } |
| 282 } |
| 283 |
| 284 // If we have incoming backward edges assert we forget all number information. |
| 285 #ifdef DEBUG |
| 286 if (direction_ == BIDIRECTIONAL) { |
| 287 for (int i = 0; i < length; ++i) { |
| 288 if (!entry_frame_->elements_[i].is_copy()) { |
| 289 ASSERT(entry_frame_->elements_[i].number_info().IsUnknown()); |
| 290 } |
| 291 } |
| 292 } |
| 293 #endif |
| 294 |
| 295 // The stack pointer is at the highest synced element or the base of |
| 296 // the expression stack. |
| 297 int stack_pointer = length - 1; |
| 298 while (stack_pointer >= entry_frame_->expression_base_index() && |
| 299 !entry_frame_->elements_[stack_pointer].is_synced()) { |
| 300 stack_pointer--; |
| 301 } |
| 302 entry_frame_->stack_pointer_ = stack_pointer; |
| 303 } |
| 304 |
| 305 |
| 306 DeferredCode::DeferredCode() |
| 307 : masm_(CodeGeneratorScope::Current()->masm()), |
| 308 statement_position_(masm_->current_statement_position()), |
| 309 position_(masm_->current_position()) { |
| 310 ASSERT(statement_position_ != RelocInfo::kNoPosition); |
| 311 ASSERT(position_ != RelocInfo::kNoPosition); |
| 312 |
| 313 CodeGeneratorScope::Current()->AddDeferred(this); |
| 314 #ifdef DEBUG |
| 315 comment_ = ""; |
| 316 #endif |
| 317 |
| 318 // Copy the register locations from the code generator's frame. |
| 319 // These are the registers that will be spilled on entry to the |
| 320 // deferred code and restored on exit. |
| 321 VirtualFrame* frame = CodeGeneratorScope::Current()->frame(); |
| 322 int sp_offset = frame->fp_relative(frame->stack_pointer_); |
| 323 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
| 324 int loc = frame->register_location(i); |
| 325 if (loc == VirtualFrame::kIllegalIndex) { |
| 326 registers_[i] = kIgnore; |
| 327 } else if (frame->elements_[loc].is_synced()) { |
| 328 // Needs to be restored on exit but not saved on entry. |
| 329 registers_[i] = frame->fp_relative(loc) | kSyncedFlag; |
| 330 } else { |
| 331 int offset = frame->fp_relative(loc); |
| 332 registers_[i] = (offset < sp_offset) ? kPush : offset; |
| 333 } |
| 334 } |
| 335 } |
| 336 |
| 337 } } // namespace v8::internal |
OLD | NEW |