1// Copyright 2009 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 34namespace v8 { 35namespace internal { 36 37// ------------------------------------------------------------------------- 38// JumpTarget implementation. 39 40#define __ ACCESS_MASM(cgen()->masm()) 41 42void JumpTarget::DoJump() { 43 ASSERT(cgen()->has_valid_frame()); 44 // Live non-frame registers are not allowed at unconditional jumps 45 // because we have no way of invalidating the corresponding results 46 // which are still live in the C++ code. 47 ASSERT(cgen()->HasValidEntryRegisters()); 48 49 if (is_bound()) { 50 // Backward jump. There is an expected frame to merge to. 51 ASSERT(direction_ == BIDIRECTIONAL); 52 cgen()->frame()->PrepareMergeTo(entry_frame_); 53 cgen()->frame()->MergeTo(entry_frame_); 54 cgen()->DeleteFrame(); 55 __ jmp(&entry_label_); 56 } else if (entry_frame_ != NULL) { 57 // Forward jump with a preconfigured entry frame. Assert the 58 // current frame matches the expected one and jump to the block. 59 ASSERT(cgen()->frame()->Equals(entry_frame_)); 60 cgen()->DeleteFrame(); 61 __ jmp(&entry_label_); 62 } else { 63 // Forward jump. Remember the current frame and emit a jump to 64 // its merge code. 65 AddReachingFrame(cgen()->frame()); 66 RegisterFile empty; 67 cgen()->SetFrame(NULL, &empty); 68 __ jmp(&merge_labels_.last()); 69 } 70} 71 72 73void JumpTarget::DoBranch(Condition cc, Hint b) { 74 ASSERT(cgen() != NULL); 75 ASSERT(cgen()->has_valid_frame()); 76 77 if (is_bound()) { 78 ASSERT(direction_ == BIDIRECTIONAL); 79 // Backward branch. We have an expected frame to merge to on the 80 // backward edge. 81 82 // Swap the current frame for a copy (we do the swapping to get 83 // the off-frame registers off the fall through) to use for the 84 // branch. 85 VirtualFrame* fall_through_frame = cgen()->frame(); 86 VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame); 87 RegisterFile non_frame_registers; 88 cgen()->SetFrame(branch_frame, &non_frame_registers); 89 90 // Check if we can avoid merge code. 91 cgen()->frame()->PrepareMergeTo(entry_frame_); 92 if (cgen()->frame()->Equals(entry_frame_)) { 93 // Branch right in to the block. 94 cgen()->DeleteFrame(); 95 __ j(cc, &entry_label_); 96 cgen()->SetFrame(fall_through_frame, &non_frame_registers); 97 return; 98 } 99 100 // Check if we can reuse existing merge code. 101 for (int i = 0; i < reaching_frames_.length(); i++) { 102 if (reaching_frames_[i] != NULL && 103 cgen()->frame()->Equals(reaching_frames_[i])) { 104 // Branch to the merge code. 105 cgen()->DeleteFrame(); 106 __ j(cc, &merge_labels_[i]); 107 cgen()->SetFrame(fall_through_frame, &non_frame_registers); 108 return; 109 } 110 } 111 112 // To emit the merge code here, we negate the condition and branch 113 // around the merge code on the fall through path. 114 Label original_fall_through; 115 __ j(NegateCondition(cc), &original_fall_through); 116 cgen()->frame()->MergeTo(entry_frame_); 117 cgen()->DeleteFrame(); 118 __ jmp(&entry_label_); 119 cgen()->SetFrame(fall_through_frame, &non_frame_registers); 120 __ bind(&original_fall_through); 121 122 } else if (entry_frame_ != NULL) { 123 // Forward branch with a preconfigured entry frame. Assert the 124 // current frame matches the expected one and branch to the block. 125 ASSERT(cgen()->frame()->Equals(entry_frame_)); 126 // Explicitly use the macro assembler instead of __ as forward 127 // branches are expected to be a fixed size (no inserted 128 // coverage-checking instructions please). This is used in 129 // Reference::GetValue. 130 cgen()->masm()->j(cc, &entry_label_); 131 132 } else { 133 // Forward branch. A copy of the current frame is remembered and 134 // a branch to the merge code is emitted. Explicitly use the 135 // macro assembler instead of __ as forward branches are expected 136 // to be a fixed size (no inserted coverage-checking instructions 137 // please). This is used in Reference::GetValue. 138 AddReachingFrame(new VirtualFrame(cgen()->frame())); 139 cgen()->masm()->j(cc, &merge_labels_.last()); 140 } 141} 142 143 144void JumpTarget::Call() { 145 // Call is used to push the address of the catch block on the stack as 146 // a return address when compiling try/catch and try/finally. We 147 // fully spill the frame before making the call. The expected frame 148 // at the label (which should be the only one) is the spilled current 149 // frame plus an in-memory return address. The "fall-through" frame 150 // at the return site is the spilled current frame. 151 ASSERT(cgen() != NULL); 152 ASSERT(cgen()->has_valid_frame()); 153 // There are no non-frame references across the call. 154 ASSERT(cgen()->HasValidEntryRegisters()); 155 ASSERT(!is_linked()); 156 157 cgen()->frame()->SpillAll(); 158 VirtualFrame* target_frame = new VirtualFrame(cgen()->frame()); 159 target_frame->Adjust(1); 160 // We do not expect a call with a preconfigured entry frame. 161 ASSERT(entry_frame_ == NULL); 162 AddReachingFrame(target_frame); 163 __ call(&merge_labels_.last()); 164} 165 166 167void JumpTarget::DoBind() { 168 ASSERT(cgen() != NULL); 169 ASSERT(!is_bound()); 170 171 // Live non-frame registers are not allowed at the start of a basic 172 // block. 173 ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters()); 174 175 // Fast case: the jump target was manually configured with an entry 176 // frame to use. 177 if (entry_frame_ != NULL) { 178 // Assert no reaching frames to deal with. 179 ASSERT(reaching_frames_.is_empty()); 180 ASSERT(!cgen()->has_valid_frame()); 181 182 RegisterFile empty; 183 if (direction_ == BIDIRECTIONAL) { 184 // Copy the entry frame so the original can be used for a 185 // possible backward jump. 186 cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty); 187 } else { 188 // Take ownership of the entry frame. 189 cgen()->SetFrame(entry_frame_, &empty); 190 entry_frame_ = NULL; 191 } 192 __ bind(&entry_label_); 193 return; 194 } 195 196 if (!is_linked()) { 197 ASSERT(cgen()->has_valid_frame()); 198 if (direction_ == FORWARD_ONLY) { 199 // Fast case: no forward jumps and no possible backward jumps. 200 // The stack pointer can be floating above the top of the 201 // virtual frame before the bind. Afterward, it should not. 202 VirtualFrame* frame = cgen()->frame(); 203 int difference = frame->stack_pointer_ - (frame->element_count() - 1); 204 if (difference > 0) { 205 frame->stack_pointer_ -= difference; 206 __ addq(rsp, Immediate(difference * kPointerSize)); 207 } 208 } else { 209 ASSERT(direction_ == BIDIRECTIONAL); 210 // Fast case: no forward jumps, possible backward ones. Remove 211 // constants and copies above the watermark on the fall-through 212 // frame and use it as the entry frame. 213 cgen()->frame()->MakeMergable(); 214 entry_frame_ = new VirtualFrame(cgen()->frame()); 215 } 216 __ bind(&entry_label_); 217 return; 218 } 219 220 if (direction_ == FORWARD_ONLY && 221 !cgen()->has_valid_frame() && 222 reaching_frames_.length() == 1) { 223 // Fast case: no fall-through, a single forward jump, and no 224 // possible backward jumps. Pick up the only reaching frame, take 225 // ownership of it, and use it for the block about to be emitted. 226 VirtualFrame* frame = reaching_frames_[0]; 227 RegisterFile empty; 228 cgen()->SetFrame(frame, &empty); 229 reaching_frames_[0] = NULL; 230 __ bind(&merge_labels_[0]); 231 232 // The stack pointer can be floating above the top of the 233 // virtual frame before the bind. Afterward, it should not. 234 int difference = frame->stack_pointer_ - (frame->element_count() - 1); 235 if (difference > 0) { 236 frame->stack_pointer_ -= difference; 237 __ addq(rsp, Immediate(difference * kPointerSize)); 238 } 239 240 __ bind(&entry_label_); 241 return; 242 } 243 244 // If there is a current frame, record it as the fall-through. It 245 // is owned by the reaching frames for now. 246 bool had_fall_through = false; 247 if (cgen()->has_valid_frame()) { 248 had_fall_through = true; 249 AddReachingFrame(cgen()->frame()); // Return value ignored. 250 RegisterFile empty; 251 cgen()->SetFrame(NULL, &empty); 252 } 253 254 // Compute the frame to use for entry to the block. 255 ComputeEntryFrame(); 256 257 // Some moves required to merge to an expected frame require purely 258 // frame state changes, and do not require any code generation. 259 // Perform those first to increase the possibility of finding equal 260 // frames below. 261 for (int i = 0; i < reaching_frames_.length(); i++) { 262 if (reaching_frames_[i] != NULL) { 263 reaching_frames_[i]->PrepareMergeTo(entry_frame_); 264 } 265 } 266 267 if (is_linked()) { 268 // There were forward jumps. Handle merging the reaching frames 269 // to the entry frame. 270 271 // Loop over the (non-null) reaching frames and process any that 272 // need merge code. Iterate backwards through the list to handle 273 // the fall-through frame first. Set frames that will be 274 // processed after 'i' to NULL if we want to avoid processing 275 // them. 276 for (int i = reaching_frames_.length() - 1; i >= 0; i--) { 277 VirtualFrame* frame = reaching_frames_[i]; 278 279 if (frame != NULL) { 280 // Does the frame (probably) need merge code? 281 if (!frame->Equals(entry_frame_)) { 282 // We could have a valid frame as the fall through to the 283 // binding site or as the fall through from a previous merge 284 // code block. Jump around the code we are about to 285 // generate. 286 if (cgen()->has_valid_frame()) { 287 cgen()->DeleteFrame(); 288 __ jmp(&entry_label_); 289 } 290 // Pick up the frame for this block. Assume ownership if 291 // there cannot be backward jumps. 292 RegisterFile empty; 293 if (direction_ == BIDIRECTIONAL) { 294 cgen()->SetFrame(new VirtualFrame(frame), &empty); 295 } else { 296 cgen()->SetFrame(frame, &empty); 297 reaching_frames_[i] = NULL; 298 } 299 __ bind(&merge_labels_[i]); 300 301 // Loop over the remaining (non-null) reaching frames, 302 // looking for any that can share merge code with this one. 303 for (int j = 0; j < i; j++) { 304 VirtualFrame* other = reaching_frames_[j]; 305 if (other != NULL && other->Equals(cgen()->frame())) { 306 // Set the reaching frame element to null to avoid 307 // processing it later, and then bind its entry label. 308 reaching_frames_[j] = NULL; 309 __ bind(&merge_labels_[j]); 310 } 311 } 312 313 // Emit the merge code. 314 cgen()->frame()->MergeTo(entry_frame_); 315 } else if (i == reaching_frames_.length() - 1 && had_fall_through) { 316 // If this is the fall through frame, and it didn't need 317 // merge code, we need to pick up the frame so we can jump 318 // around subsequent merge blocks if necessary. 319 RegisterFile empty; 320 cgen()->SetFrame(frame, &empty); 321 reaching_frames_[i] = NULL; 322 } 323 } 324 } 325 326 // The code generator may not have a current frame if there was no 327 // fall through and none of the reaching frames needed merging. 328 // In that case, clone the entry frame as the current frame. 329 if (!cgen()->has_valid_frame()) { 330 RegisterFile empty; 331 cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty); 332 } 333 334 // There may be unprocessed reaching frames that did not need 335 // merge code. They will have unbound merge labels. Bind their 336 // merge labels to be the same as the entry label and deallocate 337 // them. 338 for (int i = 0; i < reaching_frames_.length(); i++) { 339 if (!merge_labels_[i].is_bound()) { 340 reaching_frames_[i] = NULL; 341 __ bind(&merge_labels_[i]); 342 } 343 } 344 345 // There are non-NULL reaching frames with bound labels for each 346 // merge block, but only on backward targets. 347 } else { 348 // There were no forward jumps. There must be a current frame and 349 // this must be a bidirectional target. 350 ASSERT(reaching_frames_.length() == 1); 351 ASSERT(reaching_frames_[0] != NULL); 352 ASSERT(direction_ == BIDIRECTIONAL); 353 354 // Use a copy of the reaching frame so the original can be saved 355 // for possible reuse as a backward merge block. 356 RegisterFile empty; 357 cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty); 358 __ bind(&merge_labels_[0]); 359 cgen()->frame()->MergeTo(entry_frame_); 360 } 361 362 __ bind(&entry_label_); 363} 364 365 366void BreakTarget::Jump() { 367 // Drop leftover statement state from the frame before merging, without 368 // emitting code. 369 ASSERT(cgen()->has_valid_frame()); 370 int count = cgen()->frame()->height() - expected_height_; 371 cgen()->frame()->ForgetElements(count); 372 DoJump(); 373} 374 375 376void BreakTarget::Jump(Result* arg) { 377 // Drop leftover statement state from the frame before merging, without 378 // emitting code. 379 ASSERT(cgen()->has_valid_frame()); 380 int count = cgen()->frame()->height() - expected_height_; 381 cgen()->frame()->ForgetElements(count); 382 cgen()->frame()->Push(arg); 383 DoJump(); 384} 385 386 387void BreakTarget::Bind() { 388#ifdef DEBUG 389 // All the forward-reaching frames should have been adjusted at the 390 // jumps to this target. 391 for (int i = 0; i < reaching_frames_.length(); i++) { 392 ASSERT(reaching_frames_[i] == NULL || 393 reaching_frames_[i]->height() == expected_height_); 394 } 395#endif 396 // Drop leftover statement state from the frame before merging, even on 397 // the fall through. This is so we can bind the return target with state 398 // on the frame. 399 if (cgen()->has_valid_frame()) { 400 int count = cgen()->frame()->height() - expected_height_; 401 cgen()->frame()->ForgetElements(count); 402 } 403 DoBind(); 404} 405 406 407void BreakTarget::Bind(Result* arg) { 408#ifdef DEBUG 409 // All the forward-reaching frames should have been adjusted at the 410 // jumps to this target. 411 for (int i = 0; i < reaching_frames_.length(); i++) { 412 ASSERT(reaching_frames_[i] == NULL || 413 reaching_frames_[i]->height() == expected_height_ + 1); 414 } 415#endif 416 // Drop leftover statement state from the frame before merging, even on 417 // the fall through. This is so we can bind the return target with state 418 // on the frame. 419 if (cgen()->has_valid_frame()) { 420 int count = cgen()->frame()->height() - expected_height_; 421 cgen()->frame()->ForgetElements(count); 422 cgen()->frame()->Push(arg); 423 } 424 DoBind(); 425 *arg = cgen()->frame()->Pop(); 426} 427 428 429#undef __ 430 431 432} } // namespace v8::internal 433