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