OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 | 616 |
617 if (!csp.Is(StackPointer()) && emit_debug_code()) { | 617 if (!csp.Is(StackPointer()) && emit_debug_code()) { |
618 // It is safe to leave csp where it is when unwinding the JavaScript stack, | 618 // It is safe to leave csp where it is when unwinding the JavaScript stack, |
619 // but if we keep it matching StackPointer, the simulator can detect memory | 619 // but if we keep it matching StackPointer, the simulator can detect memory |
620 // accesses in the now-free part of the stack. | 620 // accesses in the now-free part of the stack. |
621 Mov(csp, StackPointer()); | 621 Mov(csp, StackPointer()); |
622 } | 622 } |
623 } | 623 } |
624 | 624 |
625 | 625 |
626 void MacroAssembler::PushPopQueue::PushQueued() { | |
627 if (queued_.empty()) return; | |
628 | |
629 masm_->PrepareForPush(size_); | |
630 | |
631 int count = queued_.size(); | |
632 int index = 0; | |
633 while (index < count) { | |
634 // PushHelper can only handle registers with the same size and type, and it | |
635 // can handle only four at a time. Batch them up accordingly. | |
636 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg}; | |
637 int batch_index = 0; | |
638 do { | |
639 batch[batch_index++] = queued_[index++]; | |
640 } while ((batch_index < 4) && (index < count) && | |
641 batch[0].IsSameSizeAndType(queued_[index])); | |
642 | |
643 masm_->PushHelper(batch_index, batch[0].SizeInBytes(), | |
644 batch[0], batch[1], batch[2], batch[3]); | |
645 } | |
646 | |
647 queued_.clear(); | |
648 } | |
649 | |
650 | |
651 void MacroAssembler::PushPopQueue::PopQueued() { | |
rmcilroy
2014/02/17 12:31:06
If I read this right, doing the following would no
jbramley
2014/02/17 12:43:21
That's correct. At the moment, PopQueued() isn't u
| |
652 if (queued_.empty()) return; | |
653 | |
654 masm_->PrepareForPop(size_); | |
655 | |
656 int count = queued_.size(); | |
657 int index = 0; | |
658 while (index < count) { | |
659 // PopHelper can only handle registers with the same size and type, and it | |
660 // can handle only four at a time. Batch them up accordingly. | |
661 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg}; | |
662 int batch_index = 0; | |
663 do { | |
664 batch[batch_index++] = queued_[index++]; | |
665 } while ((batch_index < 4) && (index < count) && | |
666 batch[0].IsSameSizeAndType(queued_[index])); | |
667 | |
668 masm_->PopHelper(batch_index, batch[0].SizeInBytes(), | |
669 batch[0], batch[1], batch[2], batch[3]); | |
670 } | |
671 | |
672 queued_.clear(); | |
673 } | |
674 | |
675 | |
626 void MacroAssembler::PushCPURegList(CPURegList registers) { | 676 void MacroAssembler::PushCPURegList(CPURegList registers) { |
627 int size = registers.RegisterSizeInBytes(); | 677 int size = registers.RegisterSizeInBytes(); |
628 | 678 |
629 PrepareForPush(registers.Count(), size); | 679 PrepareForPush(registers.Count(), size); |
630 // Push up to four registers at a time because if the current stack pointer is | 680 // Push up to four registers at a time because if the current stack pointer is |
631 // csp and reg_size is 32, registers must be pushed in blocks of four in order | 681 // csp and reg_size is 32, registers must be pushed in blocks of four in order |
632 // to maintain the 16-byte alignment for csp. | 682 // to maintain the 16-byte alignment for csp. |
633 while (!registers.IsEmpty()) { | 683 while (!registers.IsEmpty()) { |
634 int count_before = registers.Count(); | 684 int count_before = registers.Count(); |
635 const CPURegister& src0 = registers.PopHighestIndex(); | 685 const CPURegister& src0 = registers.PopHighestIndex(); |
(...skipping 25 matching lines...) Expand all Loading... | |
661 | 711 |
662 if (!csp.Is(StackPointer()) && emit_debug_code()) { | 712 if (!csp.Is(StackPointer()) && emit_debug_code()) { |
663 // It is safe to leave csp where it is when unwinding the JavaScript stack, | 713 // It is safe to leave csp where it is when unwinding the JavaScript stack, |
664 // but if we keep it matching StackPointer, the simulator can detect memory | 714 // but if we keep it matching StackPointer, the simulator can detect memory |
665 // accesses in the now-free part of the stack. | 715 // accesses in the now-free part of the stack. |
666 Mov(csp, StackPointer()); | 716 Mov(csp, StackPointer()); |
667 } | 717 } |
668 } | 718 } |
669 | 719 |
670 | 720 |
671 void MacroAssembler::PushMultipleTimes(int count, Register src) { | 721 void MacroAssembler::PushMultipleTimes(CPURegister src, int count) { |
672 int size = src.SizeInBytes(); | 722 int size = src.SizeInBytes(); |
673 | 723 |
674 PrepareForPush(count, size); | 724 PrepareForPush(count, size); |
675 | 725 |
676 if (FLAG_optimize_for_size && count > 8) { | 726 if (FLAG_optimize_for_size && count > 8) { |
677 Label loop; | 727 Label loop; |
678 __ Mov(Tmp0(), count / 2); | 728 __ Mov(Tmp0(), count / 2); |
679 __ Bind(&loop); | 729 __ Bind(&loop); |
680 PushHelper(2, size, src, src, NoReg, NoReg); | 730 PushHelper(2, size, src, src, NoReg, NoReg); |
681 __ Subs(Tmp0(), Tmp0(), 1); | 731 __ Subs(Tmp0(), Tmp0(), 1); |
(...skipping 14 matching lines...) Expand all Loading... | |
696 count -= 2; | 746 count -= 2; |
697 } | 747 } |
698 if (count == 1) { | 748 if (count == 1) { |
699 PushHelper(1, size, src, NoReg, NoReg, NoReg); | 749 PushHelper(1, size, src, NoReg, NoReg, NoReg); |
700 count -= 1; | 750 count -= 1; |
701 } | 751 } |
702 ASSERT(count == 0); | 752 ASSERT(count == 0); |
703 } | 753 } |
704 | 754 |
705 | 755 |
756 void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) { | |
757 PrepareForPush(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes()))); | |
758 | |
759 Register temp = AppropriateTempFor(count); | |
760 | |
761 if (FLAG_optimize_for_size) { | |
762 Label loop, done; | |
763 | |
764 Subs(temp, count, 1); | |
765 B(mi, &done); | |
766 | |
767 // Push all registers individually, to save code size. | |
768 Bind(&loop); | |
769 Subs(temp, temp, 1); | |
770 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg); | |
771 B(pl, &loop); | |
772 | |
773 Bind(&done); | |
774 } else { | |
775 Label loop, leftover2, leftover1, done; | |
776 | |
777 Subs(temp, count, 4); | |
778 B(mi, &leftover2); | |
779 | |
780 // Push groups of four first. | |
781 Bind(&loop); | |
782 Subs(temp, temp, 4); | |
783 PushHelper(4, src.SizeInBytes(), src, src, src, src); | |
784 B(pl, &loop); | |
785 | |
786 // Push groups of two. | |
787 Bind(&leftover2); | |
788 Tbz(count, 1, &leftover1); | |
789 PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg); | |
790 | |
791 // Push the last one (if required). | |
792 Bind(&leftover1); | |
793 Tbz(count, 0, &done); | |
794 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg); | |
795 | |
796 Bind(&done); | |
797 } | |
798 } | |
799 | |
800 | |
706 void MacroAssembler::PushHelper(int count, int size, | 801 void MacroAssembler::PushHelper(int count, int size, |
707 const CPURegister& src0, | 802 const CPURegister& src0, |
708 const CPURegister& src1, | 803 const CPURegister& src1, |
709 const CPURegister& src2, | 804 const CPURegister& src2, |
710 const CPURegister& src3) { | 805 const CPURegister& src3) { |
711 // Ensure that we don't unintentially modify scratch or debug registers. | 806 // Ensure that we don't unintentially modify scratch or debug registers. |
712 InstructionAccurateScope scope(this); | 807 InstructionAccurateScope scope(this); |
713 | 808 |
714 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); | 809 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); |
715 ASSERT(size == src0.SizeInBytes()); | 810 ASSERT(size == src0.SizeInBytes()); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
777 // for csp at all times. | 872 // for csp at all times. |
778 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); | 873 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); |
779 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); | 874 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); |
780 break; | 875 break; |
781 default: | 876 default: |
782 UNREACHABLE(); | 877 UNREACHABLE(); |
783 } | 878 } |
784 } | 879 } |
785 | 880 |
786 | 881 |
787 void MacroAssembler::PrepareForPush(int count, int size) { | 882 void MacroAssembler::PrepareForPush(Operand total_size) { |
788 // TODO(jbramley): Use AssertStackConsistency here, if possible. See the | |
789 // AssertStackConsistency for details of why we can't at the moment. | |
790 if (csp.Is(StackPointer())) { | |
791 // If the current stack pointer is csp, then it must be aligned to 16 bytes | |
792 // on entry and the total size of the specified registers must also be a | |
793 // multiple of 16 bytes. | |
794 ASSERT((count * size) % 16 == 0); | |
795 } else { | |
796 // Even if the current stack pointer is not the system stack pointer (csp), | |
797 // the system stack pointer will still be modified in order to comply with | |
798 // ABI rules about accessing memory below the system stack pointer. | |
799 BumpSystemStackPointer(count * size); | |
800 } | |
801 } | |
802 | |
803 | |
804 void MacroAssembler::PrepareForPop(int count, int size) { | |
805 AssertStackConsistency(); | 883 AssertStackConsistency(); |
806 if (csp.Is(StackPointer())) { | 884 if (csp.Is(StackPointer())) { |
807 // If the current stack pointer is csp, then it must be aligned to 16 bytes | 885 // If the current stack pointer is csp, then it must be aligned to 16 bytes |
808 // on entry and the total size of the specified registers must also be a | 886 // on entry and the total size of the specified registers must also be a |
809 // multiple of 16 bytes. | 887 // multiple of 16 bytes. |
810 ASSERT((count * size) % 16 == 0); | 888 if (total_size.IsImmediate()) { |
889 ASSERT((total_size.immediate() % 16) == 0); | |
890 } | |
891 | |
892 // Don't check access size for non-immediate sizes. It's difficult to do | |
893 // well, and it will be caught by hardware (or the simulator) anyway. | |
894 } else { | |
895 // Even if the current stack pointer is not the system stack pointer (csp), | |
896 // the system stack pointer will still be modified in order to comply with | |
897 // ABI rules about accessing memory below the system stack pointer. | |
898 BumpSystemStackPointer(total_size); | |
811 } | 899 } |
812 } | 900 } |
813 | 901 |
902 | |
903 void MacroAssembler::PrepareForPop(Operand total_size) { | |
904 AssertStackConsistency(); | |
905 if (csp.Is(StackPointer())) { | |
906 // If the current stack pointer is csp, then it must be aligned to 16 bytes | |
907 // on entry and the total size of the specified registers must also be a | |
908 // multiple of 16 bytes. | |
909 if (total_size.IsImmediate()) { | |
910 ASSERT((total_size.immediate() % 16) == 0); | |
911 } | |
912 | |
913 // Don't check access size for non-immediate sizes. It's difficult to do | |
914 // well, and it will be caught by hardware (or the simulator) anyway. | |
915 } | |
916 } | |
917 | |
814 | 918 |
815 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { | 919 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { |
816 if (offset.IsImmediate()) { | 920 if (offset.IsImmediate()) { |
817 ASSERT(offset.immediate() >= 0); | 921 ASSERT(offset.immediate() >= 0); |
818 } else if (emit_debug_code()) { | 922 } else if (emit_debug_code()) { |
819 Cmp(xzr, offset); | 923 Cmp(xzr, offset); |
820 Check(le, kStackAccessBelowStackPointer); | 924 Check(le, kStackAccessBelowStackPointer); |
821 } | 925 } |
822 | 926 |
823 Str(src, MemOperand(StackPointer(), offset)); | 927 Str(src, MemOperand(StackPointer(), offset)); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
896 ldp(x29, x30, tos); | 1000 ldp(x29, x30, tos); |
897 | 1001 |
898 ldp(d8, d9, tos); | 1002 ldp(d8, d9, tos); |
899 ldp(d10, d11, tos); | 1003 ldp(d10, d11, tos); |
900 ldp(d12, d13, tos); | 1004 ldp(d12, d13, tos); |
901 ldp(d14, d15, tos); | 1005 ldp(d14, d15, tos); |
902 } | 1006 } |
903 | 1007 |
904 | 1008 |
905 void MacroAssembler::AssertStackConsistency() { | 1009 void MacroAssembler::AssertStackConsistency() { |
906 if (emit_debug_code() && !csp.Is(StackPointer())) { | 1010 if (emit_debug_code()) { |
907 if (csp.Is(StackPointer())) { | 1011 if (csp.Is(StackPointer())) { |
908 // TODO(jbramley): Check for csp alignment if it is the stack pointer. | 1012 // We can't check the alignment of csp without using a scratch register |
909 } else { | 1013 // (or clobbering the flags), but the processor (or simulator) will abort |
910 // TODO(jbramley): Currently we cannot use this assertion in Push because | 1014 // if it is not properly aligned during a load. |
911 // some calling code assumes that the flags are preserved. For an example, | 1015 ldr(xzr, MemOperand(csp, 0)); |
912 // look at Builtins::Generate_ArgumentsAdaptorTrampoline. | 1016 } else if (FLAG_enable_slow_asserts) { |
913 Cmp(csp, StackPointer()); | 1017 Label ok; |
914 Check(ls, kTheCurrentStackPointerIsBelowCsp); | 1018 // Check that csp <= StackPointer(), preserving all registers and NZCV. |
1019 sub(StackPointer(), csp, StackPointer()); | |
1020 cbz(StackPointer(), &ok); // Ok if csp == StackPointer(). | |
1021 tbnz(StackPointer(), kXSignBit, &ok); // Ok if csp < StackPointer(). | |
1022 | |
1023 Abort(kTheCurrentStackPointerIsBelowCsp); | |
1024 | |
1025 bind(&ok); | |
1026 // Restore StackPointer(). | |
1027 sub(StackPointer(), csp, StackPointer()); | |
915 } | 1028 } |
916 } | 1029 } |
917 } | 1030 } |
918 | 1031 |
919 | 1032 |
920 void MacroAssembler::LoadRoot(Register destination, | 1033 void MacroAssembler::LoadRoot(Register destination, |
921 Heap::RootListIndex index) { | 1034 Heap::RootListIndex index) { |
922 // TODO(jbramley): Most root values are constants, and can be synthesized | 1035 // TODO(jbramley): Most root values are constants, and can be synthesized |
923 // without a load. Refer to the ARM back end for details. | 1036 // without a load. Refer to the ARM back end for details. |
924 Ldr(destination, MemOperand(root, index << kPointerSizeLog2)); | 1037 Ldr(destination, MemOperand(root, index << kPointerSizeLog2)); |
(...skipping 3412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4337 if (FLAG_trap_on_abort) { | 4450 if (FLAG_trap_on_abort) { |
4338 Brk(0); | 4451 Brk(0); |
4339 return; | 4452 return; |
4340 } | 4453 } |
4341 #endif | 4454 #endif |
4342 | 4455 |
4343 Label msg_address; | 4456 Label msg_address; |
4344 Adr(x0, &msg_address); | 4457 Adr(x0, &msg_address); |
4345 | 4458 |
4346 if (use_real_aborts()) { | 4459 if (use_real_aborts()) { |
4460 // Avoid infinite recursion; Push contains some assertions that use Abort. | |
4461 NoUseRealAbortsScope no_real_aborts(this); | |
4462 | |
4347 // Split the message pointer into two SMI to avoid the GC | 4463 // Split the message pointer into two SMI to avoid the GC |
4348 // trying to scan the string. | 4464 // trying to scan the string. |
4349 STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0)); | 4465 STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0)); |
4350 SmiTag(x1, x0); | 4466 SmiTag(x1, x0); |
4351 Bic(x0, x0, kSmiShiftMask); | 4467 Bic(x0, x0, kSmiShiftMask); |
4352 | 4468 |
4353 Push(x0, x1); | 4469 Push(x0, x1); |
4354 | 4470 |
4355 if (!has_frame_) { | 4471 if (!has_frame_) { |
4356 // We don't actually want to generate a pile of code for this, so just | 4472 // We don't actually want to generate a pile of code for this, so just |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4797 } | 4913 } |
4798 } | 4914 } |
4799 | 4915 |
4800 | 4916 |
4801 #undef __ | 4917 #undef __ |
4802 | 4918 |
4803 | 4919 |
4804 } } // namespace v8::internal | 4920 } } // namespace v8::internal |
4805 | 4921 |
4806 #endif // V8_TARGET_ARCH_A64 | 4922 #endif // V8_TARGET_ARCH_A64 |
OLD | NEW |