Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 576 mov(TMP2, base); | 576 mov(TMP2, base); |
| 577 str(src, Address(TMP2, offset, Address::PreIndex)); | 577 str(src, Address(TMP2, offset, Address::PreIndex)); |
| 578 } else { | 578 } else { |
| 579 // Since offset is 32-bits, it won't be loaded from the pool. | 579 // Since offset is 32-bits, it won't be loaded from the pool. |
| 580 AddImmediate(TMP2, base, offset, kNoRegister); | 580 AddImmediate(TMP2, base, offset, kNoRegister); |
| 581 str(src, Address(TMP2)); | 581 str(src, Address(TMP2)); |
| 582 } | 582 } |
| 583 } | 583 } |
| 584 | 584 |
| 585 | 585 |
| 586 // Store into object. | |
| 587 // Preserves object and value registers. | |
| 588 void Assembler::StoreIntoObjectFilterNoSmi(Register object, | |
| 589 Register value, | |
| 590 Label* no_update) { | |
| 591 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | |
| 592 (kOldObjectAlignmentOffset == 0), young_alignment); | |
| 593 | |
| 594 // Write-barrier triggers if the value is in the new space (has bit set) and | |
| 595 // the object is in the old space (has bit cleared). | |
| 596 // To check that, we compute value & ~object and skip the write barrier | |
|
regis
2014/04/22 18:45:32
value & ~object is a 'bit clear' operation.
Inste
zra
2014/04/22 19:44:02
Done.
| |
| 597 // if the bit is not set. We can't destroy the object. | |
| 598 orn(TMP, ZR, Operand(object)); | |
| 599 and_(TMP, value, Operand(TMP)); | |
| 600 tsti(TMP, kNewObjectAlignmentOffset); | |
| 601 b(no_update, EQ); | |
| 602 } | |
| 603 | |
| 604 | |
| 605 // Preserves object and value registers. | |
| 606 void Assembler::StoreIntoObjectFilter(Register object, | |
| 607 Register value, | |
| 608 Label* no_update) { | |
| 609 // For the value we are only interested in the new/old bit and the tag bit. | |
| 610 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. | |
| 611 Lsl(TMP, value, kObjectAlignmentLog2 - 1); | |
| 612 and_(TMP, value, Operand(TMP)); | |
| 613 // And the result with the negated space bit of the object. | |
| 614 orn(TMP2, ZR, Operand(object)); | |
| 615 and_(TMP, TMP, Operand(TMP2)); | |
| 616 tsti(TMP, kNewObjectAlignmentOffset); | |
|
regis
2014/04/22 18:45:32
Instead of
Lsl(TMP, value, kObjectAlignmentLog2 -
zra
2014/04/22 19:44:02
Done.
| |
| 617 b(no_update, EQ); | |
| 618 } | |
| 619 | |
| 620 | |
| 621 void Assembler::StoreIntoObject(Register object, | |
| 622 const Address& dest, | |
| 623 Register value, | |
| 624 bool can_value_be_smi) { | |
| 625 ASSERT(object != value); | |
| 626 str(value, dest); | |
| 627 Label done; | |
| 628 if (can_value_be_smi) { | |
| 629 StoreIntoObjectFilter(object, value, &done); | |
| 630 } else { | |
| 631 StoreIntoObjectFilterNoSmi(object, value, &done); | |
| 632 } | |
| 633 // A store buffer update is required. | |
| 634 if (value != R0) { | |
| 635 // Preserve R0. | |
| 636 Push(R0); | |
| 637 } | |
| 638 Push(LR); | |
| 639 if (object != R0) { | |
| 640 mov(R0, object); | |
| 641 } | |
| 642 BranchLink(&StubCode::UpdateStoreBufferLabel(), PP); | |
| 643 Pop(LR); | |
| 644 if (value != R0) { | |
| 645 // Restore R0. | |
| 646 Pop(R0); | |
| 647 } | |
| 648 Bind(&done); | |
| 649 } | |
| 650 | |
| 651 | |
| 652 void Assembler::StoreIntoObjectNoBarrier(Register object, | |
| 653 const Address& dest, | |
| 654 Register value) { | |
| 655 str(value, dest); | |
| 656 #if defined(DEBUG) | |
| 657 Label done; | |
| 658 StoreIntoObjectFilter(object, value, &done); | |
| 659 Stop("Store buffer update is required"); | |
| 660 Bind(&done); | |
| 661 #endif // defined(DEBUG) | |
| 662 // No store buffer update. | |
| 663 } | |
| 664 | |
| 665 | |
| 666 void Assembler::StoreIntoObjectNoBarrier(Register object, | |
| 667 const Address& dest, | |
| 668 const Object& value) { | |
| 669 ASSERT(value.IsSmi() || value.InVMHeap() || | |
| 670 (value.IsOld() && value.IsNotTemporaryScopedHandle())); | |
| 671 // No store buffer update. | |
| 672 LoadObject(TMP, value, PP); | |
| 673 str(TMP, dest); | |
| 674 } | |
| 675 | |
| 676 | |
| 677 // Frame entry and exit. | |
| 586 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 678 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 587 // Reserve space for arguments and align frame before entering | 679 // Reserve space for arguments and align frame before entering |
| 588 // the C++ world. | 680 // the C++ world. |
| 589 AddImmediate(SP, SP, -frame_space, kNoRegister); | 681 AddImmediate(SP, SP, -frame_space, kNoRegister); |
| 590 if (OS::ActivationFrameAlignment() > 1) { | 682 if (OS::ActivationFrameAlignment() > 1) { |
| 591 mov(TMP, SP); // SP can't be register operand of andi. | 683 mov(TMP, SP); // SP can't be register operand of andi. |
| 592 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); | 684 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); |
| 593 mov(SP, TMP); | 685 mov(SP, TMP); |
| 594 } | 686 } |
| 595 } | 687 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 | 723 |
| 632 | 724 |
| 633 void Assembler::LeaveDartFrame() { | 725 void Assembler::LeaveDartFrame() { |
| 634 // Restore and untag PP. | 726 // Restore and untag PP. |
| 635 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); | 727 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); |
| 636 sub(PP, PP, Operand(kHeapObjectTag)); | 728 sub(PP, PP, Operand(kHeapObjectTag)); |
| 637 LeaveFrame(); | 729 LeaveFrame(); |
| 638 } | 730 } |
| 639 | 731 |
| 640 | 732 |
| 733 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { | |
| 734 EnterFrame(0); | |
| 735 | |
| 736 // TODO(zra): also save volatile FPU registers. | |
| 737 | |
| 738 for (int i = kDartFirstVolatileCpuReg; i <= kDartLastVolatileCpuReg; i++) { | |
| 739 const Register reg = static_cast<Register>(i); | |
| 740 Push(reg); | |
| 741 } | |
| 742 | |
| 743 ReserveAlignedFrameSpace(frame_size); | |
| 744 } | |
| 745 | |
| 746 | |
| 747 void Assembler::LeaveCallRuntimeFrame() { | |
| 748 // SP might have been modified to reserve space for arguments | |
| 749 // and ensure proper alignment of the stack frame. | |
| 750 // We need to restore it before restoring registers. | |
| 751 // TODO(zra): Also include FPU regs in this count once they are added. | |
| 752 const intptr_t kPushedRegistersSize = | |
| 753 kDartVolatileCpuRegCount * kWordSize; | |
| 754 AddImmediate(SP, FP, -kPushedRegistersSize, PP); | |
| 755 for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) { | |
| 756 const Register reg = static_cast<Register>(i); | |
| 757 Pop(reg); | |
| 758 } | |
| 759 | |
| 760 Pop(FP); | |
| 761 Pop(LR); | |
| 762 } | |
| 763 | |
| 764 | |
| 641 void Assembler::CallRuntime(const RuntimeEntry& entry, | 765 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 642 intptr_t argument_count) { | 766 intptr_t argument_count) { |
| 643 entry.Call(this, argument_count); | 767 entry.Call(this, argument_count); |
| 644 } | 768 } |
| 645 | 769 |
| 646 } // namespace dart | 770 } // namespace dart |
| 647 | 771 |
| 648 #endif // defined TARGET_ARCH_ARM64 | 772 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |