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 "register-allocator-inl.h" 32 #include "scopes.h" 33 34 namespace v8 { 35 namespace internal { 36 37 #define __ ACCESS_MASM(masm()) 38 39 // ------------------------------------------------------------------------- 40 // VirtualFrame implementation. 41 42 // On entry to a function, the virtual frame already contains the receiver, 43 // the parameters, and a return address. All frame elements are in memory. 44 VirtualFrame::VirtualFrame() 45 : elements_(parameter_count() + local_count() + kPreallocatedElements), 46 stack_pointer_(parameter_count() + 1) { // 0-based index of TOS. 47 for (int i = 0; i <= stack_pointer_; i++) { 48 elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown)); 49 } 50 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 51 register_locations_[i] = kIllegalIndex; 52 } 53 } 54 55 56 void VirtualFrame::SyncElementBelowStackPointer(int index) { 57 // Emit code to write elements below the stack pointer to their 58 // (already allocated) stack address. 59 ASSERT(index <= stack_pointer_); 60 FrameElement element = elements_[index]; 61 ASSERT(!element.is_synced()); 62 switch (element.type()) { 63 case FrameElement::INVALID: 64 break; 65 66 case FrameElement::MEMORY: 67 // This function should not be called with synced elements. 68 // (memory elements are always synced). 69 UNREACHABLE(); 70 break; 71 72 case FrameElement::REGISTER: 73 __ mov(Operand(ebp, fp_relative(index)), element.reg()); 74 break; 75 76 case FrameElement::CONSTANT: 77 if (cgen()->IsUnsafeSmi(element.handle())) { 78 cgen()->StoreUnsafeSmiToLocal(fp_relative(index), element.handle()); 79 } else { 80 __ Set(Operand(ebp, fp_relative(index)), 81 Immediate(element.handle())); 82 } 83 break; 84 85 case FrameElement::COPY: { 86 int backing_index = element.index(); 87 FrameElement backing_element = elements_[backing_index]; 88 if (backing_element.is_memory()) { 89 Result temp = cgen()->allocator()->Allocate(); 90 ASSERT(temp.is_valid()); 91 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); 92 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); 93 } else { 94 ASSERT(backing_element.is_register()); 95 __ mov(Operand(ebp, fp_relative(index)), backing_element.reg()); 96 } 97 break; 98 } 99 } 100 elements_[index].set_sync(); 101 } 102 103 104 void VirtualFrame::SyncElementByPushing(int index) { 105 // Sync an element of the frame that is just above the stack pointer 106 // by pushing it. 107 ASSERT(index == stack_pointer_ + 1); 108 stack_pointer_++; 109 FrameElement element = elements_[index]; 110 111 switch (element.type()) { 112 case FrameElement::INVALID: 113 __ push(Immediate(Smi::FromInt(0))); 114 break; 115 116 case FrameElement::MEMORY: 117 // No memory elements exist above the stack pointer. 118 UNREACHABLE(); 119 break; 120 121 case FrameElement::REGISTER: 122 __ push(element.reg()); 123 break; 124 125 case FrameElement::CONSTANT: 126 if (cgen()->IsUnsafeSmi(element.handle())) { 127 cgen()->PushUnsafeSmi(element.handle()); 128 } else { 129 __ push(Immediate(element.handle())); 130 } 131 break; 132 133 case FrameElement::COPY: { 134 int backing_index = element.index(); 135 FrameElement backing = elements_[backing_index]; 136 ASSERT(backing.is_memory() || backing.is_register()); 137 if (backing.is_memory()) { 138 __ push(Operand(ebp, fp_relative(backing_index))); 139 } else { 140 __ push(backing.reg()); 141 } 142 break; 143 } 144 } 145 elements_[index].set_sync(); 146 } 147 148 149 // Clear the dirty bits for the range of elements in 150 // [min(stack_pointer_ + 1,begin), end]. 151 void VirtualFrame::SyncRange(int begin, int end) { 152 ASSERT(begin >= 0); 153 ASSERT(end < element_count()); 154 // Sync elements below the range if they have not been materialized 155 // on the stack. 156 int start = Min(begin, stack_pointer_ + 1); 157 158 // Emit normal push instructions for elements above stack pointer 159 // and use mov instructions if we are below stack pointer. 160 for (int i = start; i <= end; i++) { 161 if (!elements_[i].is_synced()) { 162 if (i <= stack_pointer_) { 163 SyncElementBelowStackPointer(i); 164 } else { 165 SyncElementByPushing(i); 166 } 167 } 168 } 169 } 170 171 172 void VirtualFrame::MakeMergable() { 173 for (int i = 0; i < element_count(); i++) { 174 FrameElement element = elements_[i]; 175 176 // All number type information is reset to unknown for a mergable frame 177 // because of incoming back edges. 178 if (element.is_constant() || element.is_copy()) { 179 if (element.is_synced()) { 180 // Just spill. 181 elements_[i] = FrameElement::MemoryElement(NumberInfo::kUnknown); 182 } else { 183 // Allocate to a register. 184 FrameElement backing_element; // Invalid if not a copy. 185 if (element.is_copy()) { 186 backing_element = elements_[element.index()]; 187 } 188 Result fresh = cgen()->allocator()->Allocate(); 189 ASSERT(fresh.is_valid()); // A register was spilled if all were in use. 190 elements_[i] = 191 FrameElement::RegisterElement(fresh.reg(), 192 FrameElement::NOT_SYNCED, 193 NumberInfo::kUnknown); 194 Use(fresh.reg(), i); 195 196 // Emit a move. 197 if (element.is_constant()) { 198 if (cgen()->IsUnsafeSmi(element.handle())) { 199 cgen()->MoveUnsafeSmi(fresh.reg(), element.handle()); 200 } else { 201 __ Set(fresh.reg(), Immediate(element.handle())); 202 } 203 } else { 204 ASSERT(element.is_copy()); 205 // Copies are only backed by register or memory locations. 206 if (backing_element.is_register()) { 207 // The backing store may have been spilled by allocating, 208 // but that's OK. If it was, the value is right where we 209 // want it. 210 if (!fresh.reg().is(backing_element.reg())) { 211 __ mov(fresh.reg(), backing_element.reg()); 212 } 213 } else { 214 ASSERT(backing_element.is_memory()); 215 __ mov(fresh.reg(), Operand(ebp, fp_relative(element.index()))); 216 } 217 } 218 } 219 // No need to set the copied flag --- there are no copies. 220 } else { 221 // Clear the copy flag of non-constant, non-copy elements. 222 // They cannot be copied because copies are not allowed. 223 // The copy flag is not relied on before the end of this loop, 224 // including when registers are spilled. 225 elements_[i].clear_copied(); 226 elements_[i].set_number_info(NumberInfo::kUnknown); 227 } 228 } 229 } 230 231 232 void VirtualFrame::MergeTo(VirtualFrame* expected) { 233 Comment cmnt(masm(), "[ Merge frame"); 234 // We should always be merging the code generator's current frame to an 235 // expected frame. 236 ASSERT(cgen()->frame() == this); 237 238 // Adjust the stack pointer upward (toward the top of the virtual 239 // frame) if necessary. 240 if (stack_pointer_ < expected->stack_pointer_) { 241 int difference = expected->stack_pointer_ - stack_pointer_; 242 stack_pointer_ = expected->stack_pointer_; 243 __ sub(Operand(esp), Immediate(difference * kPointerSize)); 244 } 245 246 MergeMoveRegistersToMemory(expected); 247 MergeMoveRegistersToRegisters(expected); 248 MergeMoveMemoryToRegisters(expected); 249 250 // Adjust the stack pointer downward if necessary. 251 if (stack_pointer_ > expected->stack_pointer_) { 252 int difference = stack_pointer_ - expected->stack_pointer_; 253 stack_pointer_ = expected->stack_pointer_; 254 __ add(Operand(esp), Immediate(difference * kPointerSize)); 255 } 256 257 // At this point, the frames should be identical. 258 ASSERT(Equals(expected)); 259 } 260 261 262 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) { 263 ASSERT(stack_pointer_ >= expected->stack_pointer_); 264 265 // Move registers, constants, and copies to memory. Perform moves 266 // from the top downward in the frame in order to leave the backing 267 // stores of copies in registers. 268 // 269 // Moving memory-backed copies to memory requires a spare register 270 // for the memory-to-memory moves. Since we are performing a merge, 271 // we use esi (which is already saved in the frame). We keep track 272 // of the index of the frame element esi is caching or kIllegalIndex 273 // if esi has not been disturbed. 274 int esi_caches = kIllegalIndex; 275 for (int i = element_count() - 1; i >= 0; i--) { 276 FrameElement target = expected->elements_[i]; 277 if (target.is_register()) continue; // Handle registers later. 278 if (target.is_memory()) { 279 FrameElement source = elements_[i]; 280 switch (source.type()) { 281 case FrameElement::INVALID: 282 // Not a legal merge move. 283 UNREACHABLE(); 284 break; 285 286 case FrameElement::MEMORY: 287 // Already in place. 288 break; 289 290 case FrameElement::REGISTER: 291 Unuse(source.reg()); 292 if (!source.is_synced()) { 293 __ mov(Operand(ebp, fp_relative(i)), source.reg()); 294 } 295 break; 296 297 case FrameElement::CONSTANT: 298 if (!source.is_synced()) { 299 if (cgen()->IsUnsafeSmi(source.handle())) { 300 esi_caches = i; 301 cgen()->MoveUnsafeSmi(esi, source.handle()); 302 __ mov(Operand(ebp, fp_relative(i)), esi); 303 } else { 304 __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle())); 305 } 306 } 307 break; 308 309 case FrameElement::COPY: 310 if (!source.is_synced()) { 311 int backing_index = source.index(); 312 FrameElement backing_element = elements_[backing_index]; 313 if (backing_element.is_memory()) { 314 // If we have to spill a register, we spill esi. 315 if (esi_caches != backing_index) { 316 esi_caches = backing_index; 317 __ mov(esi, Operand(ebp, fp_relative(backing_index))); 318 } 319 __ mov(Operand(ebp, fp_relative(i)), esi); 320 } else { 321 ASSERT(backing_element.is_register()); 322 __ mov(Operand(ebp, fp_relative(i)), backing_element.reg()); 323 } 324 } 325 break; 326 } 327 } 328 elements_[i] = target; 329 } 330 331 if (esi_caches != kIllegalIndex) { 332 __ mov(esi, Operand(ebp, fp_relative(context_index()))); 333 } 334 } 335 336 337 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { 338 // We have already done X-to-memory moves. 339 ASSERT(stack_pointer_ >= expected->stack_pointer_); 340 341 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 342 // Move the right value into register i if it is currently in a register. 343 int index = expected->register_location(i); 344 int use_index = register_location(i); 345 // Skip if register i is unused in the target or else if source is 346 // not a register (this is not a register-to-register move). 347 if (index == kIllegalIndex || !elements_[index].is_register()) continue; 348 349 Register target = RegisterAllocator::ToRegister(i); 350 Register source = elements_[index].reg(); 351 if (index != use_index) { 352 if (use_index == kIllegalIndex) { // Target is currently unused. 353 // Copy contents of source from source to target. 354 // Set frame element register to target. 355 Use(target, index); 356 Unuse(source); 357 __ mov(target, source); 358 } else { 359 // Exchange contents of registers source and target. 360 // Nothing except the register backing use_index has changed. 361 elements_[use_index].set_reg(source); 362 set_register_location(target, index); 363 set_register_location(source, use_index); 364 __ xchg(source, target); 365 } 366 } 367 368 if (!elements_[index].is_synced() && 369 expected->elements_[index].is_synced()) { 370 __ mov(Operand(ebp, fp_relative(index)), target); 371 } 372 elements_[index] = expected->elements_[index]; 373 } 374 } 375 376 377 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) { 378 // Move memory, constants, and copies to registers. This is the 379 // final step and since it is not done from the bottom up, but in 380 // register code order, we have special code to ensure that the backing 381 // elements of copies are in their correct locations when we 382 // encounter the copies. 383 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 384 int index = expected->register_location(i); 385 if (index != kIllegalIndex) { 386 FrameElement source = elements_[index]; 387 FrameElement target = expected->elements_[index]; 388 Register target_reg = RegisterAllocator::ToRegister(i); 389 ASSERT(target.reg().is(target_reg)); 390 switch (source.type()) { 391 case FrameElement::INVALID: // Fall through. 392 UNREACHABLE(); 393 break; 394 case FrameElement::REGISTER: 395 ASSERT(source.Equals(target)); 396 // Go to next iteration. Skips Use(target_reg) and syncing 397 // below. It is safe to skip syncing because a target 398 // register frame element would only be synced if all source 399 // elements were. 400 continue; 401 break; 402 case FrameElement::MEMORY: 403 ASSERT(index <= stack_pointer_); 404 __ mov(target_reg, Operand(ebp, fp_relative(index))); 405 break; 406 407 case FrameElement::CONSTANT: 408 if (cgen()->IsUnsafeSmi(source.handle())) { 409 cgen()->MoveUnsafeSmi(target_reg, source.handle()); 410 } else { 411 __ Set(target_reg, Immediate(source.handle())); 412 } 413 break; 414 415 case FrameElement::COPY: { 416 int backing_index = source.index(); 417 FrameElement backing = elements_[backing_index]; 418 ASSERT(backing.is_memory() || backing.is_register()); 419 if (backing.is_memory()) { 420 ASSERT(backing_index <= stack_pointer_); 421 // Code optimization if backing store should also move 422 // to a register: move backing store to its register first. 423 if (expected->elements_[backing_index].is_register()) { 424 FrameElement new_backing = expected->elements_[backing_index]; 425 Register new_backing_reg = new_backing.reg(); 426 ASSERT(!is_used(new_backing_reg)); 427 elements_[backing_index] = new_backing; 428 Use(new_backing_reg, backing_index); 429 __ mov(new_backing_reg, 430 Operand(ebp, fp_relative(backing_index))); 431 __ mov(target_reg, new_backing_reg); 432 } else { 433 __ mov(target_reg, Operand(ebp, fp_relative(backing_index))); 434 } 435 } else { 436 __ mov(target_reg, backing.reg()); 437 } 438 } 439 } 440 // Ensure the proper sync state. 441 if (target.is_synced() && !source.is_synced()) { 442 __ mov(Operand(ebp, fp_relative(index)), target_reg); 443 } 444 Use(target_reg, index); 445 elements_[index] = target; 446 } 447 } 448 } 449 450 451 void VirtualFrame::Enter() { 452 // Registers live on entry: esp, ebp, esi, edi. 453 Comment cmnt(masm(), "[ Enter JS frame"); 454 455 #ifdef DEBUG 456 if (FLAG_debug_code) { 457 // Verify that edi contains a JS function. The following code 458 // relies on eax being available for use. 459 __ test(edi, Immediate(kSmiTagMask)); 460 __ Check(not_zero, 461 "VirtualFrame::Enter - edi is not a function (smi check)."); 462 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 463 __ Check(equal, 464 "VirtualFrame::Enter - edi is not a function (map check)."); 465 } 466 #endif 467 468 EmitPush(ebp); 469 470 __ mov(ebp, Operand(esp)); 471 472 // Store the context in the frame. The context is kept in esi and a 473 // copy is stored in the frame. The external reference to esi 474 // remains. 475 EmitPush(esi); 476 477 // Store the function in the frame. The frame owns the register 478 // reference now (ie, it can keep it in edi or spill it later). 479 Push(edi); 480 SyncElementAt(element_count() - 1); 481 cgen()->allocator()->Unuse(edi); 482 } 483 484 485 void VirtualFrame::Exit() { 486 Comment cmnt(masm(), "[ Exit JS frame"); 487 // Record the location of the JS exit code for patching when setting 488 // break point. 489 __ RecordJSReturn(); 490 491 // Avoid using the leave instruction here, because it is too 492 // short. We need the return sequence to be a least the size of a 493 // call instruction to support patching the exit code in the 494 // debugger. See VisitReturnStatement for the full return sequence. 495 __ mov(esp, Operand(ebp)); 496 stack_pointer_ = frame_pointer(); 497 for (int i = element_count() - 1; i > stack_pointer_; i--) { 498 FrameElement last = elements_.RemoveLast(); 499 if (last.is_register()) { 500 Unuse(last.reg()); 501 } 502 } 503 504 EmitPop(ebp); 505 } 506 507 508 void VirtualFrame::AllocateStackSlots() { 509 int count = local_count(); 510 if (count > 0) { 511 Comment cmnt(masm(), "[ Allocate space for locals"); 512 // The locals are initialized to a constant (the undefined value), but 513 // we sync them with the actual frame to allocate space for spilling 514 // them later. First sync everything above the stack pointer so we can 515 // use pushes to allocate and initialize the locals. 516 SyncRange(stack_pointer_ + 1, element_count() - 1); 517 Handle<Object> undefined = Factory::undefined_value(); 518 FrameElement initial_value = 519 FrameElement::ConstantElement(undefined, FrameElement::SYNCED); 520 if (count == 1) { 521 __ push(Immediate(undefined)); 522 } else if (count < kLocalVarBound) { 523 // For less locals the unrolled loop is more compact. 524 Result temp = cgen()->allocator()->Allocate(); 525 ASSERT(temp.is_valid()); 526 __ Set(temp.reg(), Immediate(undefined)); 527 for (int i = 0; i < count; i++) { 528 __ push(temp.reg()); 529 } 530 } else { 531 // For more locals a loop in generated code is more compact. 532 Label alloc_locals_loop; 533 Result cnt = cgen()->allocator()->Allocate(); 534 Result tmp = cgen()->allocator()->Allocate(); 535 ASSERT(cnt.is_valid()); 536 ASSERT(tmp.is_valid()); 537 __ mov(cnt.reg(), Immediate(count)); 538 __ mov(tmp.reg(), Immediate(undefined)); 539 __ bind(&alloc_locals_loop); 540 __ push(tmp.reg()); 541 __ dec(cnt.reg()); 542 __ j(not_zero, &alloc_locals_loop); 543 } 544 for (int i = 0; i < count; i++) { 545 elements_.Add(initial_value); 546 stack_pointer_++; 547 } 548 } 549 } 550 551 552 void VirtualFrame::SaveContextRegister() { 553 ASSERT(elements_[context_index()].is_memory()); 554 __ mov(Operand(ebp, fp_relative(context_index())), esi); 555 } 556 557 558 void VirtualFrame::RestoreContextRegister() { 559 ASSERT(elements_[context_index()].is_memory()); 560 __ mov(esi, Operand(ebp, fp_relative(context_index()))); 561 } 562 563 564 void VirtualFrame::PushReceiverSlotAddress() { 565 Result temp = cgen()->allocator()->Allocate(); 566 ASSERT(temp.is_valid()); 567 __ lea(temp.reg(), ParameterAt(-1)); 568 Push(&temp); 569 } 570 571 572 int VirtualFrame::InvalidateFrameSlotAt(int index) { 573 FrameElement original = elements_[index]; 574 575 // Is this element the backing store of any copies? 576 int new_backing_index = kIllegalIndex; 577 if (original.is_copied()) { 578 // Verify it is copied, and find first copy. 579 for (int i = index + 1; i < element_count(); i++) { 580 if (elements_[i].is_copy() && elements_[i].index() == index) { 581 new_backing_index = i; 582 break; 583 } 584 } 585 } 586 587 if (new_backing_index == kIllegalIndex) { 588 // No copies found, return kIllegalIndex. 589 if (original.is_register()) { 590 Unuse(original.reg()); 591 } 592 elements_[index] = FrameElement::InvalidElement(); 593 return kIllegalIndex; 594 } 595 596 // This is the backing store of copies. 597 Register backing_reg; 598 if (original.is_memory()) { 599 Result fresh = cgen()->allocator()->Allocate(); 600 ASSERT(fresh.is_valid()); 601 Use(fresh.reg(), new_backing_index); 602 backing_reg = fresh.reg(); 603 __ mov(backing_reg, Operand(ebp, fp_relative(index))); 604 } else { 605 // The original was in a register. 606 backing_reg = original.reg(); 607 set_register_location(backing_reg, new_backing_index); 608 } 609 // Invalidate the element at index. 610 elements_[index] = FrameElement::InvalidElement(); 611 // Set the new backing element. 612 if (elements_[new_backing_index].is_synced()) { 613 elements_[new_backing_index] = 614 FrameElement::RegisterElement(backing_reg, 615 FrameElement::SYNCED, 616 original.number_info()); 617 } else { 618 elements_[new_backing_index] = 619 FrameElement::RegisterElement(backing_reg, 620 FrameElement::NOT_SYNCED, 621 original.number_info()); 622 } 623 // Update the other copies. 624 for (int i = new_backing_index + 1; i < element_count(); i++) { 625 if (elements_[i].is_copy() && elements_[i].index() == index) { 626 elements_[i].set_index(new_backing_index); 627 elements_[new_backing_index].set_copied(); 628 } 629 } 630 return new_backing_index; 631 } 632 633 634 void VirtualFrame::TakeFrameSlotAt(int index) { 635 ASSERT(index >= 0); 636 ASSERT(index <= element_count()); 637 FrameElement original = elements_[index]; 638 int new_backing_store_index = InvalidateFrameSlotAt(index); 639 if (new_backing_store_index != kIllegalIndex) { 640 elements_.Add(CopyElementAt(new_backing_store_index)); 641 return; 642 } 643 644 switch (original.type()) { 645 case FrameElement::MEMORY: { 646 // Emit code to load the original element's data into a register. 647 // Push that register as a FrameElement on top of the frame. 648 Result fresh = cgen()->allocator()->Allocate(); 649 ASSERT(fresh.is_valid()); 650 FrameElement new_element = 651 FrameElement::RegisterElement(fresh.reg(), 652 FrameElement::NOT_SYNCED, 653 original.number_info()); 654 Use(fresh.reg(), element_count()); 655 elements_.Add(new_element); 656 __ mov(fresh.reg(), Operand(ebp, fp_relative(index))); 657 break; 658 } 659 case FrameElement::REGISTER: 660 Use(original.reg(), element_count()); 661 // Fall through. 662 case FrameElement::CONSTANT: 663 case FrameElement::COPY: 664 original.clear_sync(); 665 elements_.Add(original); 666 break; 667 case FrameElement::INVALID: 668 UNREACHABLE(); 669 break; 670 } 671 } 672 673 674 void VirtualFrame::StoreToFrameSlotAt(int index) { 675 // Store the value on top of the frame to the virtual frame slot at 676 // a given index. The value on top of the frame is left in place. 677 // This is a duplicating operation, so it can create copies. 678 ASSERT(index >= 0); 679 ASSERT(index < element_count()); 680 681 int top_index = element_count() - 1; 682 FrameElement top = elements_[top_index]; 683 FrameElement original = elements_[index]; 684 if (top.is_copy() && top.index() == index) return; 685 ASSERT(top.is_valid()); 686 687 InvalidateFrameSlotAt(index); 688 689 // InvalidateFrameSlotAt can potentially change any frame element, due 690 // to spilling registers to allocate temporaries in order to preserve 691 // the copy-on-write semantics of aliased elements. Reload top from 692 // the frame. 693 top = elements_[top_index]; 694 695 if (top.is_copy()) { 696 // There are two cases based on the relative positions of the 697 // stored-to slot and the backing slot of the top element. 698 int backing_index = top.index(); 699 ASSERT(backing_index != index); 700 if (backing_index < index) { 701 // 1. The top element is a copy of a slot below the stored-to 702 // slot. The stored-to slot becomes an unsynced copy of that 703 // same backing slot. 704 elements_[index] = CopyElementAt(backing_index); 705 } else { 706 // 2. The top element is a copy of a slot above the stored-to 707 // slot. The stored-to slot becomes the new (unsynced) backing 708 // slot and both the top element and the element at the former 709 // backing slot become copies of it. The sync state of the top 710 // and former backing elements is preserved. 711 FrameElement backing_element = elements_[backing_index]; 712 ASSERT(backing_element.is_memory() || backing_element.is_register()); 713 if (backing_element.is_memory()) { 714 // Because sets of copies are canonicalized to be backed by 715 // their lowest frame element, and because memory frame 716 // elements are backed by the corresponding stack address, we 717 // have to move the actual value down in the stack. 718 // 719 // TODO(209): considering allocating the stored-to slot to the 720 // temp register. Alternatively, allow copies to appear in 721 // any order in the frame and lazily move the value down to 722 // the slot. 723 Result temp = cgen()->allocator()->Allocate(); 724 ASSERT(temp.is_valid()); 725 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); 726 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); 727 } else { 728 set_register_location(backing_element.reg(), index); 729 if (backing_element.is_synced()) { 730 // If the element is a register, we will not actually move 731 // anything on the stack but only update the virtual frame 732 // element. 733 backing_element.clear_sync(); 734 } 735 } 736 elements_[index] = backing_element; 737 738 // The old backing element becomes a copy of the new backing 739 // element. 740 FrameElement new_element = CopyElementAt(index); 741 elements_[backing_index] = new_element; 742 if (backing_element.is_synced()) { 743 elements_[backing_index].set_sync(); 744 } 745 746 // All the copies of the old backing element (including the top 747 // element) become copies of the new backing element. 748 for (int i = backing_index + 1; i < element_count(); i++) { 749 if (elements_[i].is_copy() && elements_[i].index() == backing_index) { 750 elements_[i].set_index(index); 751 } 752 } 753 } 754 return; 755 } 756 757 // Move the top element to the stored-to slot and replace it (the 758 // top element) with a copy. 759 elements_[index] = top; 760 if (top.is_memory()) { 761 // TODO(209): consider allocating the stored-to slot to the temp 762 // register. Alternatively, allow copies to appear in any order 763 // in the frame and lazily move the value down to the slot. 764 FrameElement new_top = CopyElementAt(index); 765 new_top.set_sync(); 766 elements_[top_index] = new_top; 767 768 // The sync state of the former top element is correct (synced). 769 // Emit code to move the value down in the frame. 770 Result temp = cgen()->allocator()->Allocate(); 771 ASSERT(temp.is_valid()); 772 __ mov(temp.reg(), Operand(esp, 0)); 773 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); 774 } else if (top.is_register()) { 775 set_register_location(top.reg(), index); 776 // The stored-to slot has the (unsynced) register reference and 777 // the top element becomes a copy. The sync state of the top is 778 // preserved. 779 FrameElement new_top = CopyElementAt(index); 780 if (top.is_synced()) { 781 new_top.set_sync(); 782 elements_[index].clear_sync(); 783 } 784 elements_[top_index] = new_top; 785 } else { 786 // The stored-to slot holds the same value as the top but 787 // unsynced. (We do not have copies of constants yet.) 788 ASSERT(top.is_constant()); 789 elements_[index].clear_sync(); 790 } 791 } 792 793 794 void VirtualFrame::PushTryHandler(HandlerType type) { 795 ASSERT(cgen()->HasValidEntryRegisters()); 796 // Grow the expression stack by handler size less one (the return 797 // address is already pushed by a call instruction). 798 Adjust(kHandlerSize - 1); 799 __ PushTryHandler(IN_JAVASCRIPT, type); 800 } 801 802 803 Result VirtualFrame::RawCallStub(CodeStub* stub) { 804 ASSERT(cgen()->HasValidEntryRegisters()); 805 __ CallStub(stub); 806 Result result = cgen()->allocator()->Allocate(eax); 807 ASSERT(result.is_valid()); 808 return result; 809 } 810 811 812 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) { 813 PrepareForCall(0, 0); 814 arg->ToRegister(eax); 815 arg->Unuse(); 816 return RawCallStub(stub); 817 } 818 819 820 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) { 821 PrepareForCall(0, 0); 822 823 if (arg0->is_register() && arg0->reg().is(eax)) { 824 if (arg1->is_register() && arg1->reg().is(edx)) { 825 // Wrong registers. 826 __ xchg(eax, edx); 827 } else { 828 // Register edx is free for arg0, which frees eax for arg1. 829 arg0->ToRegister(edx); 830 arg1->ToRegister(eax); 831 } 832 } else { 833 // Register eax is free for arg1, which guarantees edx is free for 834 // arg0. 835 arg1->ToRegister(eax); 836 arg0->ToRegister(edx); 837 } 838 839 arg0->Unuse(); 840 arg1->Unuse(); 841 return RawCallStub(stub); 842 } 843 844 845 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { 846 PrepareForCall(arg_count, arg_count); 847 ASSERT(cgen()->HasValidEntryRegisters()); 848 __ CallRuntime(f, arg_count); 849 Result result = cgen()->allocator()->Allocate(eax); 850 ASSERT(result.is_valid()); 851 return result; 852 } 853 854 855 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) { 856 PrepareForCall(arg_count, arg_count); 857 ASSERT(cgen()->HasValidEntryRegisters()); 858 __ CallRuntime(id, arg_count); 859 Result result = cgen()->allocator()->Allocate(eax); 860 ASSERT(result.is_valid()); 861 return result; 862 } 863 864 865 #ifdef ENABLE_DEBUGGER_SUPPORT 866 void VirtualFrame::DebugBreak() { 867 PrepareForCall(0, 0); 868 ASSERT(cgen()->HasValidEntryRegisters()); 869 __ DebugBreak(); 870 Result result = cgen()->allocator()->Allocate(eax); 871 ASSERT(result.is_valid()); 872 } 873 #endif 874 875 876 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, 877 InvokeFlag flag, 878 int arg_count) { 879 PrepareForCall(arg_count, arg_count); 880 ASSERT(cgen()->HasValidEntryRegisters()); 881 __ InvokeBuiltin(id, flag); 882 Result result = cgen()->allocator()->Allocate(eax); 883 ASSERT(result.is_valid()); 884 return result; 885 } 886 887 888 Result VirtualFrame::RawCallCodeObject(Handle<Code> code, 889 RelocInfo::Mode rmode) { 890 ASSERT(cgen()->HasValidEntryRegisters()); 891 __ call(code, rmode); 892 Result result = cgen()->allocator()->Allocate(eax); 893 ASSERT(result.is_valid()); 894 return result; 895 } 896 897 898 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) { 899 // Name and receiver are on the top of the frame. The IC expects 900 // name in ecx and receiver in eax. 901 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 902 Result name = Pop(); 903 Result receiver = Pop(); 904 PrepareForCall(0, 0); // No stack arguments. 905 // Move results to the right registers: 906 if (name.is_register() && name.reg().is(eax)) { 907 if (receiver.is_register() && receiver.reg().is(ecx)) { 908 // Wrong registers. 909 __ xchg(eax, ecx); 910 } else { 911 // Register ecx is free for name, which frees eax for receiver. 912 name.ToRegister(ecx); 913 receiver.ToRegister(eax); 914 } 915 } else { 916 // Register eax is free for receiver, which frees ecx for name. 917 receiver.ToRegister(eax); 918 name.ToRegister(ecx); 919 } 920 name.Unuse(); 921 receiver.Unuse(); 922 return RawCallCodeObject(ic, mode); 923 } 924 925 926 Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) { 927 // Key and receiver are on top of the frame. Put them in eax and edx. 928 Result key = Pop(); 929 Result receiver = Pop(); 930 PrepareForCall(0, 0); 931 932 if (!key.is_register() || !key.reg().is(edx)) { 933 // Register edx is available for receiver. 934 receiver.ToRegister(edx); 935 key.ToRegister(eax); 936 } else if (!receiver.is_register() || !receiver.reg().is(eax)) { 937 // Register eax is available for key. 938 key.ToRegister(eax); 939 receiver.ToRegister(edx); 940 } else { 941 __ xchg(edx, eax); 942 } 943 key.Unuse(); 944 receiver.Unuse(); 945 946 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 947 return RawCallCodeObject(ic, mode); 948 } 949 950 951 Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) { 952 // Value and (if not contextual) receiver are on top of the frame. 953 // The IC expects name in ecx, value in eax, and receiver in edx. 954 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 955 Result value = Pop(); 956 if (is_contextual) { 957 PrepareForCall(0, 0); 958 value.ToRegister(eax); 959 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 960 __ mov(ecx, name); 961 } else { 962 Result receiver = Pop(); 963 PrepareForCall(0, 0); 964 965 if (value.is_register() && value.reg().is(edx)) { 966 if (receiver.is_register() && receiver.reg().is(eax)) { 967 // Wrong registers. 968 __ xchg(eax, edx); 969 } else { 970 // Register eax is free for value, which frees edx for receiver. 971 value.ToRegister(eax); 972 receiver.ToRegister(edx); 973 } 974 } else { 975 // Register edx is free for receiver, which guarantees eax is free for 976 // value. 977 receiver.ToRegister(edx); 978 value.ToRegister(eax); 979 } 980 } 981 __ mov(ecx, name); 982 value.Unuse(); 983 return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); 984 } 985 986 987 Result VirtualFrame::CallKeyedStoreIC() { 988 // Value, key, and receiver are on the top of the frame. The IC 989 // expects value in eax and key and receiver on the stack. It does 990 // not drop the key and receiver. 991 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 992 Result value = Pop(); 993 PrepareForCall(2, 0); // Two stack args, neither callee-dropped. 994 value.ToRegister(eax); 995 value.Unuse(); 996 return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); 997 } 998 999 1000 Result VirtualFrame::CallCallIC(RelocInfo::Mode mode, 1001 int arg_count, 1002 int loop_nesting) { 1003 // Function name, arguments, and receiver are on top of the frame. 1004 // The IC expects the name in ecx and the rest on the stack and 1005 // drops them all. 1006 InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP; 1007 Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop); 1008 // Spill args, receiver, and function. The call will drop args and 1009 // receiver. 1010 Result name = Pop(); 1011 PrepareForCall(arg_count + 1, arg_count + 1); // Arguments + receiver. 1012 name.ToRegister(ecx); 1013 name.Unuse(); 1014 return RawCallCodeObject(ic, mode); 1015 } 1016 1017 1018 Result VirtualFrame::CallConstructor(int arg_count) { 1019 // Arguments, receiver, and function are on top of the frame. The 1020 // IC expects arg count in eax, function in edi, and the arguments 1021 // and receiver on the stack. 1022 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); 1023 // Duplicate the function before preparing the frame. 1024 PushElementAt(arg_count + 1); 1025 Result function = Pop(); 1026 PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver. 1027 function.ToRegister(edi); 1028 1029 // Constructors are called with the number of arguments in register 1030 // eax for now. Another option would be to have separate construct 1031 // call trampolines per different arguments counts encountered. 1032 Result num_args = cgen()->allocator()->Allocate(eax); 1033 ASSERT(num_args.is_valid()); 1034 __ Set(num_args.reg(), Immediate(arg_count)); 1035 1036 function.Unuse(); 1037 num_args.Unuse(); 1038 return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL); 1039 } 1040 1041 1042 void VirtualFrame::Drop(int count) { 1043 ASSERT(count >= 0); 1044 ASSERT(height() >= count); 1045 int num_virtual_elements = (element_count() - 1) - stack_pointer_; 1046 1047 // Emit code to lower the stack pointer if necessary. 1048 if (num_virtual_elements < count) { 1049 int num_dropped = count - num_virtual_elements; 1050 stack_pointer_ -= num_dropped; 1051 __ add(Operand(esp), Immediate(num_dropped * kPointerSize)); 1052 } 1053 1054 // Discard elements from the virtual frame and free any registers. 1055 for (int i = 0; i < count; i++) { 1056 FrameElement dropped = elements_.RemoveLast(); 1057 if (dropped.is_register()) { 1058 Unuse(dropped.reg()); 1059 } 1060 } 1061 } 1062 1063 1064 Result VirtualFrame::Pop() { 1065 FrameElement element = elements_.RemoveLast(); 1066 int index = element_count(); 1067 ASSERT(element.is_valid()); 1068 1069 // Get number type information of the result. 1070 NumberInfo::Type info; 1071 if (!element.is_copy()) { 1072 info = element.number_info(); 1073 } else { 1074 info = elements_[element.index()].number_info(); 1075 } 1076 1077 bool pop_needed = (stack_pointer_ == index); 1078 if (pop_needed) { 1079 stack_pointer_--; 1080 if (element.is_memory()) { 1081 Result temp = cgen()->allocator()->Allocate(); 1082 ASSERT(temp.is_valid()); 1083 __ pop(temp.reg()); 1084 temp.set_number_info(info); 1085 return temp; 1086 } 1087 1088 __ add(Operand(esp), Immediate(kPointerSize)); 1089 } 1090 ASSERT(!element.is_memory()); 1091 1092 // The top element is a register, constant, or a copy. Unuse 1093 // registers and follow copies to their backing store. 1094 if (element.is_register()) { 1095 Unuse(element.reg()); 1096 } else if (element.is_copy()) { 1097 ASSERT(element.index() < index); 1098 index = element.index(); 1099 element = elements_[index]; 1100 } 1101 ASSERT(!element.is_copy()); 1102 1103 // The element is memory, a register, or a constant. 1104 if (element.is_memory()) { 1105 // Memory elements could only be the backing store of a copy. 1106 // Allocate the original to a register. 1107 ASSERT(index <= stack_pointer_); 1108 Result temp = cgen()->allocator()->Allocate(); 1109 ASSERT(temp.is_valid()); 1110 Use(temp.reg(), index); 1111 FrameElement new_element = 1112 FrameElement::RegisterElement(temp.reg(), 1113 FrameElement::SYNCED, 1114 element.number_info()); 1115 // Preserve the copy flag on the element. 1116 if (element.is_copied()) new_element.set_copied(); 1117 elements_[index] = new_element; 1118 __ mov(temp.reg(), Operand(ebp, fp_relative(index))); 1119 return Result(temp.reg(), info); 1120 } else if (element.is_register()) { 1121 return Result(element.reg(), info); 1122 } else { 1123 ASSERT(element.is_constant()); 1124 return Result(element.handle()); 1125 } 1126 } 1127 1128 1129 void VirtualFrame::EmitPop(Register reg) { 1130 ASSERT(stack_pointer_ == element_count() - 1); 1131 stack_pointer_--; 1132 elements_.RemoveLast(); 1133 __ pop(reg); 1134 } 1135 1136 1137 void VirtualFrame::EmitPop(Operand operand) { 1138 ASSERT(stack_pointer_ == element_count() - 1); 1139 stack_pointer_--; 1140 elements_.RemoveLast(); 1141 __ pop(operand); 1142 } 1143 1144 1145 void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) { 1146 ASSERT(stack_pointer_ == element_count() - 1); 1147 elements_.Add(FrameElement::MemoryElement(info)); 1148 stack_pointer_++; 1149 __ push(reg); 1150 } 1151 1152 1153 void VirtualFrame::EmitPush(Operand operand, NumberInfo::Type info) { 1154 ASSERT(stack_pointer_ == element_count() - 1); 1155 elements_.Add(FrameElement::MemoryElement(info)); 1156 stack_pointer_++; 1157 __ push(operand); 1158 } 1159 1160 1161 void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) { 1162 ASSERT(stack_pointer_ == element_count() - 1); 1163 elements_.Add(FrameElement::MemoryElement(info)); 1164 stack_pointer_++; 1165 __ push(immediate); 1166 } 1167 1168 1169 void VirtualFrame::Push(Expression* expr) { 1170 ASSERT(expr->IsTrivial()); 1171 1172 Literal* lit = expr->AsLiteral(); 1173 if (lit != NULL) { 1174 Push(lit->handle()); 1175 return; 1176 } 1177 1178 VariableProxy* proxy = expr->AsVariableProxy(); 1179 if (proxy != NULL && proxy->is_this()) { 1180 PushParameterAt(-1); 1181 return; 1182 } 1183 1184 UNREACHABLE(); 1185 } 1186 1187 1188 #undef __ 1189 1190 } } // namespace v8::internal 1191