Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 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 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 534 ASSERT(cgen_->HasValidEntryRegisters()); | 534 ASSERT(cgen_->HasValidEntryRegisters()); |
| 535 } | 535 } |
| 536 | 536 |
| 537 | 537 |
| 538 void VirtualFrame::MergeTo(VirtualFrame* expected) { | 538 void VirtualFrame::MergeTo(VirtualFrame* expected) { |
| 539 Comment cmnt(masm_, "[ Merge frame"); | 539 Comment cmnt(masm_, "[ Merge frame"); |
| 540 // We should always be merging the code generator's current frame to an | 540 // We should always be merging the code generator's current frame to an |
| 541 // expected frame. | 541 // expected frame. |
| 542 ASSERT(cgen_->frame() == this); | 542 ASSERT(cgen_->frame() == this); |
| 543 | 543 |
| 544 ASSERT(cgen_ == expected->cgen_); | |
| 545 ASSERT(masm_ == expected->masm_); | |
| 546 ASSERT(elements_.length() == expected->elements_.length()); | |
| 547 ASSERT(parameter_count_ == expected->parameter_count_); | |
| 548 ASSERT(local_count_ == expected->local_count_); | |
| 549 ASSERT(frame_pointer_ == expected->frame_pointer_); | |
| 550 | |
| 551 // Mergable frames have all elements in locations, either memory or | |
| 552 // register. We thus have a series of to-memory and to-register moves. | |
| 553 // First perform all to-memory moves, register-to-memory moves because | |
| 554 // they can free registers and constant-to-memory moves because they do | |
| 555 // not use registers. | |
| 556 MergeMoveRegistersToMemory(expected); | 544 MergeMoveRegistersToMemory(expected); |
| 557 MergeMoveRegistersToRegisters(expected); | 545 MergeMoveRegistersToRegisters(expected); |
| 558 MergeMoveMemoryToRegisters(expected); | 546 MergeMoveMemoryToRegisters(expected); |
| 559 | 547 |
| 560 int height_difference = stack_pointer_ - expected->stack_pointer_; | 548 int height_difference = stack_pointer_ - expected->stack_pointer_; |
| 561 if (stack_pointer_ > expected->stack_pointer_) { | 549 if (stack_pointer_ > expected->stack_pointer_) { |
| 562 #ifdef DEBUG | 550 #ifdef DEBUG |
| 563 for (int i = stack_pointer_; i > expected->stack_pointer_; i--) { | 551 for (int i = stack_pointer_; i > expected->stack_pointer_; i--) { |
| 564 ASSERT(!elements_[i].is_memory()); | 552 ASSERT(!elements_[i].is_memory()); |
| 565 ASSERT(!elements_[i].is_synced()); | 553 ASSERT(!elements_[i].is_synced()); |
| 566 } | 554 } |
| 567 #endif | 555 #endif |
| 568 __ add(Operand(esp), Immediate(height_difference * kPointerSize)); | 556 __ add(Operand(esp), Immediate(height_difference * kPointerSize)); |
| 569 stack_pointer_ = expected->stack_pointer_; | 557 stack_pointer_ = expected->stack_pointer_; |
| 570 } else if (stack_pointer_ < expected->stack_pointer_) { | 558 } else if (stack_pointer_ < expected->stack_pointer_) { |
| 571 // Put valid data on the stack, that will only be accessed by GC. | 559 // Put valid data on the stack, that will only be accessed by GC. |
| 572 while (stack_pointer_ < expected->stack_pointer_) { | 560 while (stack_pointer_ < expected->stack_pointer_) { |
| 573 __ push(Immediate(Smi::FromInt(0))); | 561 __ push(Immediate(Smi::FromInt(0))); |
| 574 stack_pointer_++; | 562 stack_pointer_++; |
| 575 } | 563 } |
| 576 } | 564 } |
| 577 | 565 |
| 578 // At this point, the frames should be identical. | 566 // At this point, the frames should be identical. |
| 579 // TODO(208): Consider an "equals" method for frames. | 567 ASSERT(Equals(expected)); |
| 580 ASSERT(stack_pointer_ == expected->stack_pointer_); | |
| 581 #ifdef DEBUG | |
| 582 for (int i = 0; i < elements_.length(); i++) { | |
| 583 FrameElement expect = expected->elements_[i]; | |
| 584 if (!expect.is_valid()) { | |
| 585 ASSERT(!elements_[i].is_valid()); | |
| 586 } else if (expect.is_memory()) { | |
| 587 ASSERT(elements_[i].is_memory()); | |
| 588 ASSERT(elements_[i].is_synced() && expect.is_synced()); | |
| 589 } else if (expect.is_register()) { | |
| 590 ASSERT(elements_[i].is_register()); | |
| 591 ASSERT(elements_[i].reg().is(expect.reg())); | |
| 592 ASSERT(elements_[i].is_synced() == expect.is_synced()); | |
| 593 } else { | |
| 594 ASSERT(expect.is_constant()); | |
| 595 ASSERT(elements_[i].is_constant()); | |
| 596 ASSERT(elements_[i].handle().location() == | |
| 597 expect.handle().location()); | |
| 598 ASSERT(elements_[i].is_synced() == expect.is_synced()); | |
| 599 } | |
| 600 } | |
| 601 #endif | |
| 602 } | 568 } |
| 603 | 569 |
| 604 | 570 |
| 605 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame *expected) { | 571 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) { |
| 606 // Move registers, constants, and copies to memory. | 572 // Adjust the stack pointer upward (toward the top of the virtual |
| 607 for (int i = 0; i < elements_.length(); i++) { | 573 // frame) if necessary. |
| 608 FrameElement source = elements_[i]; | 574 if (stack_pointer_ < expected->stack_pointer_) { |
| 575 int difference = expected->stack_pointer_ - stack_pointer_; | |
| 576 stack_pointer_ = expected->stack_pointer_; | |
| 577 __ sub(Operand(esp), Immediate(difference * kPointerSize)); | |
| 578 } | |
| 579 ASSERT(stack_pointer_ >= expected->stack_pointer_); | |
| 580 | |
| 581 // Move registers, constants, and copies to memory. Perform moves | |
| 582 // from the top downward in the frame in order to leave the backing | |
| 583 // stores of copies in registers. | |
| 584 // | |
| 585 // Moving memory-backed copies to memory requires a spare register | |
| 586 // for the memory-to-memory moves. Since we are performing a merge, | |
| 587 // we use esi (which is already saved in the frame). We keep track | |
| 588 // of the index of the frame element esi is caching or kIllegalIndex | |
| 589 // if esi has not been disturbed. | |
| 590 int esi_caches = kIllegalIndex; | |
| 591 // A "singleton" memory element. | |
| 592 FrameElement memory_element = FrameElement::MemoryElement(); | |
| 593 for (int i = stack_pointer_; i >= 0; i--) { | |
| 609 FrameElement target = expected->elements_[i]; | 594 FrameElement target = expected->elements_[i]; |
| 610 if (target.is_memory() && !source.is_memory()) { | 595 if (target.is_memory()) { |
| 611 ASSERT(source.is_register() || | 596 FrameElement source = elements_[i]; |
| 612 source.is_constant() || | 597 switch (source.type()) { |
| 613 source.is_copy()); | 598 case FrameElement::INVALID: |
| 614 SpillElementAt(i); | 599 // Not a legal merge move. |
| 600 UNREACHABLE(); | |
| 601 break; | |
| 602 | |
| 603 case FrameElement::MEMORY: | |
| 604 // Already in place. | |
| 605 break; | |
| 606 | |
| 607 case FrameElement::REGISTER: | |
| 608 Unuse(source.reg()); | |
| 609 if (!source.is_synced()) { | |
| 610 __ mov(Operand(ebp, fp_relative(i)), source.reg()); | |
| 611 } | |
| 612 break; | |
| 613 | |
| 614 case FrameElement::CONSTANT: | |
| 615 if (!source.is_synced()) { | |
| 616 __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle())); | |
| 617 } | |
| 618 break; | |
| 619 | |
| 620 case FrameElement::COPY: | |
| 621 if (!source.is_synced()) { | |
| 622 int backing_index = source.index(); | |
| 623 FrameElement backing_element = elements_[backing_index]; | |
| 624 if (backing_element.is_memory()) { | |
| 625 // If we have to spill a register, we spill esi. | |
| 626 if (esi_caches != backing_index) { | |
| 627 esi_caches = backing_index; | |
| 628 __ mov(esi, Operand(ebp, fp_relative(backing_index))); | |
| 629 } | |
| 630 __ mov(Operand(ebp, fp_relative(i)), esi); | |
| 631 } else { | |
| 632 ASSERT(backing_element.is_register()); | |
| 633 __ mov(Operand(ebp, fp_relative(i)), backing_element.reg()); | |
| 634 } | |
| 635 } | |
| 636 break; | |
| 637 } | |
| 638 elements_[i] = memory_element; | |
| 615 } | 639 } |
| 616 } | 640 } |
| 641 | |
| 642 if (esi_caches != kIllegalIndex) { | |
| 643 __ mov(esi, Operand(ebp, fp_relative(context_index()))); | |
| 644 } | |
| 617 } | 645 } |
| 618 | 646 |
| 619 | 647 |
| 620 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame *expected) { | 648 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { |
| 649 // We have already done X-to-memory moves. | |
| 650 ASSERT(stack_pointer_ >= expected->stack_pointer_); | |
| 651 | |
| 621 // Perform register-to-register moves. | 652 // Perform register-to-register moves. |
| 622 int start = 0; | 653 int start = 0; |
| 623 int end = elements_.length() - 1; | 654 int end = elements_.length() - 1; |
| 624 bool any_moves_blocked; // Did we fail to make some moves this iteration? | 655 bool any_moves_blocked; // Did we fail to make some moves this iteration? |
| 625 bool should_break_cycles = false; | 656 bool should_break_cycles = false; |
| 626 bool any_moves_made; // Did we make any progress this iteration? | 657 bool any_moves_made; // Did we make any progress this iteration? |
| 627 do { | 658 do { |
| 628 any_moves_blocked = false; | 659 any_moves_blocked = false; |
| 629 any_moves_made = false; | 660 any_moves_made = false; |
| 630 int first_move_blocked = kIllegalIndex; | 661 int first_move_blocked = kIllegalIndex; |
| 631 int last_move_blocked = kIllegalIndex; | 662 int last_move_blocked = kIllegalIndex; |
| 632 for (int i = start; i <= end; i++) { | 663 for (int i = start; i <= end; i++) { |
| 633 FrameElement source = elements_[i]; | 664 FrameElement source = elements_[i]; |
| 634 FrameElement target = expected->elements_[i]; | 665 FrameElement target = expected->elements_[i]; |
| 635 if (source.is_register() && target.is_register()) { | 666 if (source.is_register() && target.is_register()) { |
|
William Hesse
2009/02/11 09:46:47
What is the precondition on the frame and expected
| |
| 636 if (target.reg().is(source.reg())) { | 667 if (target.reg().is(source.reg())) { |
| 637 if (target.is_synced() && !source.is_synced()) { | 668 if (target.is_synced() && !source.is_synced()) { |
| 638 SyncElementAt(i); | 669 __ mov(Operand(ebp, fp_relative(i)), source.reg()); |
| 639 } | 670 } |
| 640 elements_[i] = target; | 671 elements_[i] = target; |
| 641 } else { | 672 } else { |
| 642 // We need to move source to target. | 673 // We need to move source to target. |
| 643 if (frame_registers_.is_used(target.reg())) { | 674 if (frame_registers_.is_used(target.reg())) { |
| 644 // The move is blocked because the target contains valid data. | 675 // The move is blocked because the target contains valid data. |
| 645 // If we are stuck with only cycles remaining, then we spill source. | 676 // If we are stuck with only cycles remaining, then we spill source. |
| 646 // Otherwise, we just need more iterations. | 677 // Otherwise, we just need more iterations. |
| 647 if (should_break_cycles) { | 678 if (should_break_cycles) { |
| 648 SpillElementAt(i); | 679 SpillElementAt(i); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 753 void VirtualFrame::Enter() { | 784 void VirtualFrame::Enter() { |
| 754 // Registers live on entry: esp, ebp, esi, edi. | 785 // Registers live on entry: esp, ebp, esi, edi. |
| 755 Comment cmnt(masm_, "[ Enter JS frame"); | 786 Comment cmnt(masm_, "[ Enter JS frame"); |
| 756 EmitPush(ebp); | 787 EmitPush(ebp); |
| 757 | 788 |
| 758 frame_pointer_ = stack_pointer_; | 789 frame_pointer_ = stack_pointer_; |
| 759 __ mov(ebp, Operand(esp)); | 790 __ mov(ebp, Operand(esp)); |
| 760 | 791 |
| 761 // Store the context in the frame. The context is kept in esi and a | 792 // Store the context in the frame. The context is kept in esi and a |
| 762 // copy is stored in the frame. The external reference to esi | 793 // copy is stored in the frame. The external reference to esi |
| 763 // remains in addition to the cached copy in the frame. | 794 // remains. |
| 764 Push(esi); | 795 EmitPush(esi); |
|
William Hesse
2009/02/11 09:46:47
I didn't know we were keeping EmitPush(). Which o
| |
| 765 SyncElementAt(elements_.length() - 1); | |
| 766 | 796 |
| 767 // Store the function in the frame. The frame owns the register | 797 // Store the function in the frame. The frame owns the register |
| 768 // reference now (ie, it can keep it in edi or spill it later). | 798 // reference now (ie, it can keep it in edi or spill it later). |
| 769 Push(edi); | 799 Push(edi); |
| 800 SyncElementAt(elements_.length() - 1); | |
| 770 cgen_->allocator()->Unuse(edi); | 801 cgen_->allocator()->Unuse(edi); |
| 771 SpillElementAt(elements_.length() - 1); | |
| 772 } | 802 } |
| 773 | 803 |
| 774 | 804 |
| 775 void VirtualFrame::Exit() { | 805 void VirtualFrame::Exit() { |
| 776 Comment cmnt(masm_, "[ Exit JS frame"); | 806 Comment cmnt(masm_, "[ Exit JS frame"); |
| 777 // Record the location of the JS exit code for patching when setting | 807 // Record the location of the JS exit code for patching when setting |
| 778 // break point. | 808 // break point. |
| 779 __ RecordJSReturn(); | 809 __ RecordJSReturn(); |
| 780 | 810 |
| 781 // Avoid using the leave instruction here, because it is too | 811 // Avoid using the leave instruction here, because it is too |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 901 ASSERT(value->is_constant()); | 931 ASSERT(value->is_constant()); |
| 902 elements_[frame_index] = | 932 elements_[frame_index] = |
| 903 FrameElement::ConstantElement(value->handle(), | 933 FrameElement::ConstantElement(value->handle(), |
| 904 FrameElement::NOT_SYNCED); | 934 FrameElement::NOT_SYNCED); |
| 905 } | 935 } |
| 906 value->Unuse(); | 936 value->Unuse(); |
| 907 } | 937 } |
| 908 | 938 |
| 909 | 939 |
| 910 void VirtualFrame::SaveContextRegister() { | 940 void VirtualFrame::SaveContextRegister() { |
| 911 FrameElement current = elements_[context_index()]; | 941 ASSERT(elements_[context_index()].is_memory()); |
| 912 ASSERT(current.is_register() || current.is_memory()); | 942 __ mov(Operand(ebp, fp_relative(context_index())), esi); |
| 913 if (!current.is_register() || !current.reg().is(esi)) { | |
| 914 if (current.is_register()) { | |
| 915 Unuse(current.reg()); | |
| 916 } | |
| 917 Use(esi); | |
| 918 elements_[context_index()] = | |
| 919 FrameElement::RegisterElement(esi, FrameElement::NOT_SYNCED); | |
| 920 } | |
| 921 } | 943 } |
| 922 | 944 |
| 923 | 945 |
| 924 void VirtualFrame::RestoreContextRegister() { | 946 void VirtualFrame::RestoreContextRegister() { |
| 925 FrameElement current = elements_[context_index()]; | 947 ASSERT(elements_[context_index()].is_memory()); |
| 926 ASSERT(current.is_register() || current.is_memory()); | 948 __ mov(esi, Operand(ebp, fp_relative(context_index()))); |
| 927 if (current.is_register() && !current.reg().is(esi)) { | |
| 928 Unuse(current.reg()); | |
| 929 Use(esi); | |
| 930 __ mov(esi, current.reg()); | |
| 931 elements_[context_index()] = | |
| 932 FrameElement::RegisterElement(esi, FrameElement::NOT_SYNCED); | |
| 933 } else if (current.is_memory()) { | |
| 934 Use(esi); | |
| 935 __ mov(esi, Operand(ebp, fp_relative(context_index()))); | |
| 936 elements_[context_index()] = | |
| 937 FrameElement::RegisterElement(esi, FrameElement::SYNCED); | |
| 938 } | |
| 939 } | 949 } |
| 940 | 950 |
| 941 | 951 |
| 942 void VirtualFrame::PushReceiverSlotAddress() { | 952 void VirtualFrame::PushReceiverSlotAddress() { |
| 943 Result temp = cgen_->allocator()->Allocate(); | 953 Result temp = cgen_->allocator()->Allocate(); |
| 944 ASSERT(temp.is_valid()); | 954 ASSERT(temp.is_valid()); |
| 945 __ lea(temp.reg(), ParameterAt(-1)); | 955 __ lea(temp.reg(), ParameterAt(-1)); |
| 946 Push(&temp); | 956 Push(&temp); |
| 947 } | 957 } |
| 948 | 958 |
| (...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1540 if (num_dropped == 0) return; | 1550 if (num_dropped == 0) return; |
| 1541 Result tos = Pop(); | 1551 Result tos = Pop(); |
| 1542 if (num_dropped > 1) { | 1552 if (num_dropped > 1) { |
| 1543 Drop(num_dropped - 1); | 1553 Drop(num_dropped - 1); |
| 1544 } | 1554 } |
| 1545 SetElementAt(0, &tos); | 1555 SetElementAt(0, &tos); |
| 1546 } | 1556 } |
| 1547 | 1557 |
| 1548 | 1558 |
| 1549 #ifdef DEBUG | 1559 #ifdef DEBUG |
| 1550 bool VirtualFrame::IsSpilled() { | 1560 bool FrameElement::Equals(FrameElement other) { |
| 1561 if (type() != other.type()) return false; | |
| 1562 if (is_synced() != other.is_synced()) return false; | |
| 1563 | |
| 1564 if (is_register()) { | |
| 1565 if (!reg().is(other.reg())) return false; | |
| 1566 } else if (is_constant()) { | |
| 1567 if (!handle().is_identical_to(other.handle())) return false; | |
| 1568 } else if (is_copy()) { | |
| 1569 if (index() != other.index()) return false; | |
| 1570 } | |
| 1571 | |
| 1572 return true; | |
| 1573 } | |
| 1574 | |
| 1575 | |
| 1576 bool VirtualFrame::Equals(VirtualFrame* other) { | |
| 1577 if (cgen_ != other->cgen_) return false; | |
| 1578 if (masm_ != other->masm_) return false; | |
| 1579 if (elements_.length() != other->elements_.length()) return false; | |
| 1580 | |
| 1551 for (int i = 0; i < elements_.length(); i++) { | 1581 for (int i = 0; i < elements_.length(); i++) { |
| 1552 if (!elements_[i].is_memory()) { | 1582 if (!elements_[i].Equals(other->elements_[i])) return false; |
| 1583 } | |
| 1584 | |
| 1585 if (parameter_count_ != other->parameter_count_) return false; | |
| 1586 if (local_count_ != other->local_count_) return false; | |
| 1587 if (stack_pointer_ != other->stack_pointer_) return false; | |
| 1588 if (frame_pointer_ != other->frame_pointer_) return false; | |
| 1589 | |
| 1590 for (int i = 0; i < RegisterFile::kNumRegisters; i++) { | |
| 1591 if (frame_registers_.count(i) != other->frame_registers_.count(i)) { | |
| 1553 return false; | 1592 return false; |
| 1554 } | 1593 } |
| 1555 } | 1594 } |
| 1595 | |
| 1556 return true; | 1596 return true; |
| 1557 } | 1597 } |
| 1558 #endif | 1598 #endif |
| 1559 | 1599 |
| 1560 #undef __ | 1600 #undef __ |
| 1561 | 1601 |
| 1562 } } // namespace v8::internal | 1602 } } // namespace v8::internal |
| OLD | NEW |