| 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 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 815 | 815 |
| 816 if (!csp.Is(StackPointer()) && emit_debug_code()) { | 816 if (!csp.Is(StackPointer()) && emit_debug_code()) { |
| 817 // It is safe to leave csp where it is when unwinding the JavaScript stack, | 817 // It is safe to leave csp where it is when unwinding the JavaScript stack, |
| 818 // but if we keep it matching StackPointer, the simulator can detect memory | 818 // but if we keep it matching StackPointer, the simulator can detect memory |
| 819 // accesses in the now-free part of the stack. | 819 // accesses in the now-free part of the stack. |
| 820 Mov(csp, StackPointer()); | 820 Mov(csp, StackPointer()); |
| 821 } | 821 } |
| 822 } | 822 } |
| 823 | 823 |
| 824 | 824 |
| 825 void MacroAssembler::PushPopQueue::PushQueued() { |
| 826 if (queued_.empty()) return; |
| 827 |
| 828 masm_->PrepareForPush(size_); |
| 829 |
| 830 int count = queued_.size(); |
| 831 int index = 0; |
| 832 while (index < count) { |
| 833 // PushHelper can only handle registers with the same size and type, and it |
| 834 // can handle only four at a time. Batch them up accordingly. |
| 835 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg}; |
| 836 int batch_index = 0; |
| 837 do { |
| 838 batch[batch_index++] = queued_[index++]; |
| 839 } while ((batch_index < 4) && (index < count) && |
| 840 batch[0].IsSameSizeAndType(queued_[index])); |
| 841 |
| 842 masm_->PushHelper(batch_index, batch[0].SizeInBytes(), |
| 843 batch[0], batch[1], batch[2], batch[3]); |
| 844 } |
| 845 |
| 846 queued_.clear(); |
| 847 } |
| 848 |
| 849 |
| 850 void MacroAssembler::PushPopQueue::PopQueued() { |
| 851 if (queued_.empty()) return; |
| 852 |
| 853 masm_->PrepareForPop(size_); |
| 854 |
| 855 int count = queued_.size(); |
| 856 int index = 0; |
| 857 while (index < count) { |
| 858 // PopHelper can only handle registers with the same size and type, and it |
| 859 // can handle only four at a time. Batch them up accordingly. |
| 860 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg}; |
| 861 int batch_index = 0; |
| 862 do { |
| 863 batch[batch_index++] = queued_[index++]; |
| 864 } while ((batch_index < 4) && (index < count) && |
| 865 batch[0].IsSameSizeAndType(queued_[index])); |
| 866 |
| 867 masm_->PopHelper(batch_index, batch[0].SizeInBytes(), |
| 868 batch[0], batch[1], batch[2], batch[3]); |
| 869 } |
| 870 |
| 871 queued_.clear(); |
| 872 } |
| 873 |
| 874 |
| 825 void MacroAssembler::PushCPURegList(CPURegList registers) { | 875 void MacroAssembler::PushCPURegList(CPURegList registers) { |
| 826 int size = registers.RegisterSizeInBytes(); | 876 int size = registers.RegisterSizeInBytes(); |
| 827 | 877 |
| 828 PrepareForPush(registers.Count(), size); | 878 PrepareForPush(registers.Count(), size); |
| 829 // Push up to four registers at a time because if the current stack pointer is | 879 // Push up to four registers at a time because if the current stack pointer is |
| 830 // csp and reg_size is 32, registers must be pushed in blocks of four in order | 880 // csp and reg_size is 32, registers must be pushed in blocks of four in order |
| 831 // to maintain the 16-byte alignment for csp. | 881 // to maintain the 16-byte alignment for csp. |
| 832 while (!registers.IsEmpty()) { | 882 while (!registers.IsEmpty()) { |
| 833 int count_before = registers.Count(); | 883 int count_before = registers.Count(); |
| 834 const CPURegister& src0 = registers.PopHighestIndex(); | 884 const CPURegister& src0 = registers.PopHighestIndex(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 860 | 910 |
| 861 if (!csp.Is(StackPointer()) && emit_debug_code()) { | 911 if (!csp.Is(StackPointer()) && emit_debug_code()) { |
| 862 // It is safe to leave csp where it is when unwinding the JavaScript stack, | 912 // It is safe to leave csp where it is when unwinding the JavaScript stack, |
| 863 // but if we keep it matching StackPointer, the simulator can detect memory | 913 // but if we keep it matching StackPointer, the simulator can detect memory |
| 864 // accesses in the now-free part of the stack. | 914 // accesses in the now-free part of the stack. |
| 865 Mov(csp, StackPointer()); | 915 Mov(csp, StackPointer()); |
| 866 } | 916 } |
| 867 } | 917 } |
| 868 | 918 |
| 869 | 919 |
| 870 void MacroAssembler::PushMultipleTimes(int count, Register src) { | 920 void MacroAssembler::PushMultipleTimes(CPURegister src, int count) { |
| 871 int size = src.SizeInBytes(); | 921 int size = src.SizeInBytes(); |
| 872 | 922 |
| 873 PrepareForPush(count, size); | 923 PrepareForPush(count, size); |
| 874 | 924 |
| 875 if (FLAG_optimize_for_size && count > 8) { | 925 if (FLAG_optimize_for_size && count > 8) { |
| 876 Label loop; | 926 Label loop; |
| 877 __ Mov(Tmp0(), count / 2); | 927 __ Mov(Tmp0(), count / 2); |
| 878 __ Bind(&loop); | 928 __ Bind(&loop); |
| 879 PushHelper(2, size, src, src, NoReg, NoReg); | 929 PushHelper(2, size, src, src, NoReg, NoReg); |
| 880 __ Subs(Tmp0(), Tmp0(), 1); | 930 __ Subs(Tmp0(), Tmp0(), 1); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 895 count -= 2; | 945 count -= 2; |
| 896 } | 946 } |
| 897 if (count == 1) { | 947 if (count == 1) { |
| 898 PushHelper(1, size, src, NoReg, NoReg, NoReg); | 948 PushHelper(1, size, src, NoReg, NoReg, NoReg); |
| 899 count -= 1; | 949 count -= 1; |
| 900 } | 950 } |
| 901 ASSERT(count == 0); | 951 ASSERT(count == 0); |
| 902 } | 952 } |
| 903 | 953 |
| 904 | 954 |
| 955 void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) { |
| 956 PrepareForPush(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes()))); |
| 957 |
| 958 Register temp = AppropriateTempFor(count); |
| 959 |
| 960 if (FLAG_optimize_for_size) { |
| 961 Label loop, done; |
| 962 |
| 963 Subs(temp, count, 1); |
| 964 B(mi, &done); |
| 965 |
| 966 // Push all registers individually, to save code size. |
| 967 Bind(&loop); |
| 968 Subs(temp, temp, 1); |
| 969 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg); |
| 970 B(pl, &loop); |
| 971 |
| 972 Bind(&done); |
| 973 } else { |
| 974 Label loop, leftover2, leftover1, done; |
| 975 |
| 976 Subs(temp, count, 4); |
| 977 B(mi, &leftover2); |
| 978 |
| 979 // Push groups of four first. |
| 980 Bind(&loop); |
| 981 Subs(temp, temp, 4); |
| 982 PushHelper(4, src.SizeInBytes(), src, src, src, src); |
| 983 B(pl, &loop); |
| 984 |
| 985 // Push groups of two. |
| 986 Bind(&leftover2); |
| 987 Tbz(count, 1, &leftover1); |
| 988 PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg); |
| 989 |
| 990 // Push the last one (if required). |
| 991 Bind(&leftover1); |
| 992 Tbz(count, 0, &done); |
| 993 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg); |
| 994 |
| 995 Bind(&done); |
| 996 } |
| 997 } |
| 998 |
| 999 |
| 905 void MacroAssembler::PushHelper(int count, int size, | 1000 void MacroAssembler::PushHelper(int count, int size, |
| 906 const CPURegister& src0, | 1001 const CPURegister& src0, |
| 907 const CPURegister& src1, | 1002 const CPURegister& src1, |
| 908 const CPURegister& src2, | 1003 const CPURegister& src2, |
| 909 const CPURegister& src3) { | 1004 const CPURegister& src3) { |
| 910 // Ensure that we don't unintentially modify scratch or debug registers. | 1005 // Ensure that we don't unintentially modify scratch or debug registers. |
| 911 InstructionAccurateScope scope(this); | 1006 InstructionAccurateScope scope(this); |
| 912 | 1007 |
| 913 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); | 1008 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); |
| 914 ASSERT(size == src0.SizeInBytes()); | 1009 ASSERT(size == src0.SizeInBytes()); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 // for csp at all times. | 1071 // for csp at all times. |
| 977 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); | 1072 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); |
| 978 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); | 1073 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); |
| 979 break; | 1074 break; |
| 980 default: | 1075 default: |
| 981 UNREACHABLE(); | 1076 UNREACHABLE(); |
| 982 } | 1077 } |
| 983 } | 1078 } |
| 984 | 1079 |
| 985 | 1080 |
| 986 void MacroAssembler::PrepareForPush(int count, int size) { | 1081 void MacroAssembler::PrepareForPush(Operand total_size) { |
| 987 // TODO(jbramley): Use AssertStackConsistency here, if possible. See the | |
| 988 // AssertStackConsistency for details of why we can't at the moment. | |
| 989 if (csp.Is(StackPointer())) { | |
| 990 // If the current stack pointer is csp, then it must be aligned to 16 bytes | |
| 991 // on entry and the total size of the specified registers must also be a | |
| 992 // multiple of 16 bytes. | |
| 993 ASSERT((count * size) % 16 == 0); | |
| 994 } else { | |
| 995 // Even if the current stack pointer is not the system stack pointer (csp), | |
| 996 // the system stack pointer will still be modified in order to comply with | |
| 997 // ABI rules about accessing memory below the system stack pointer. | |
| 998 BumpSystemStackPointer(count * size); | |
| 999 } | |
| 1000 } | |
| 1001 | |
| 1002 | |
| 1003 void MacroAssembler::PrepareForPop(int count, int size) { | |
| 1004 AssertStackConsistency(); | 1082 AssertStackConsistency(); |
| 1005 if (csp.Is(StackPointer())) { | 1083 if (csp.Is(StackPointer())) { |
| 1006 // If the current stack pointer is csp, then it must be aligned to 16 bytes | 1084 // If the current stack pointer is csp, then it must be aligned to 16 bytes |
| 1007 // on entry and the total size of the specified registers must also be a | 1085 // on entry and the total size of the specified registers must also be a |
| 1008 // multiple of 16 bytes. | 1086 // multiple of 16 bytes. |
| 1009 ASSERT((count * size) % 16 == 0); | 1087 if (total_size.IsImmediate()) { |
| 1088 ASSERT((total_size.immediate() % 16) == 0); |
| 1089 } |
| 1090 |
| 1091 // Don't check access size for non-immediate sizes. It's difficult to do |
| 1092 // well, and it will be caught by hardware (or the simulator) anyway. |
| 1093 } else { |
| 1094 // Even if the current stack pointer is not the system stack pointer (csp), |
| 1095 // the system stack pointer will still be modified in order to comply with |
| 1096 // ABI rules about accessing memory below the system stack pointer. |
| 1097 BumpSystemStackPointer(total_size); |
| 1010 } | 1098 } |
| 1011 } | 1099 } |
| 1012 | 1100 |
| 1101 |
| 1102 void MacroAssembler::PrepareForPop(Operand total_size) { |
| 1103 AssertStackConsistency(); |
| 1104 if (csp.Is(StackPointer())) { |
| 1105 // If the current stack pointer is csp, then it must be aligned to 16 bytes |
| 1106 // on entry and the total size of the specified registers must also be a |
| 1107 // multiple of 16 bytes. |
| 1108 if (total_size.IsImmediate()) { |
| 1109 ASSERT((total_size.immediate() % 16) == 0); |
| 1110 } |
| 1111 |
| 1112 // Don't check access size for non-immediate sizes. It's difficult to do |
| 1113 // well, and it will be caught by hardware (or the simulator) anyway. |
| 1114 } |
| 1115 } |
| 1116 |
| 1013 | 1117 |
| 1014 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { | 1118 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { |
| 1015 if (offset.IsImmediate()) { | 1119 if (offset.IsImmediate()) { |
| 1016 ASSERT(offset.immediate() >= 0); | 1120 ASSERT(offset.immediate() >= 0); |
| 1017 } else if (emit_debug_code()) { | 1121 } else if (emit_debug_code()) { |
| 1018 Cmp(xzr, offset); | 1122 Cmp(xzr, offset); |
| 1019 Check(le, kStackAccessBelowStackPointer); | 1123 Check(le, kStackAccessBelowStackPointer); |
| 1020 } | 1124 } |
| 1021 | 1125 |
| 1022 Str(src, MemOperand(StackPointer(), offset)); | 1126 Str(src, MemOperand(StackPointer(), offset)); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 ldp(x29, x30, tos); | 1199 ldp(x29, x30, tos); |
| 1096 | 1200 |
| 1097 ldp(d8, d9, tos); | 1201 ldp(d8, d9, tos); |
| 1098 ldp(d10, d11, tos); | 1202 ldp(d10, d11, tos); |
| 1099 ldp(d12, d13, tos); | 1203 ldp(d12, d13, tos); |
| 1100 ldp(d14, d15, tos); | 1204 ldp(d14, d15, tos); |
| 1101 } | 1205 } |
| 1102 | 1206 |
| 1103 | 1207 |
| 1104 void MacroAssembler::AssertStackConsistency() { | 1208 void MacroAssembler::AssertStackConsistency() { |
| 1105 if (emit_debug_code() && !csp.Is(StackPointer())) { | 1209 if (emit_debug_code()) { |
| 1106 if (csp.Is(StackPointer())) { | 1210 if (csp.Is(StackPointer())) { |
| 1107 // TODO(jbramley): Check for csp alignment if it is the stack pointer. | 1211 // We can't check the alignment of csp without using a scratch register |
| 1108 } else { | 1212 // (or clobbering the flags), but the processor (or simulator) will abort |
| 1109 // TODO(jbramley): Currently we cannot use this assertion in Push because | 1213 // if it is not properly aligned during a load. |
| 1110 // some calling code assumes that the flags are preserved. For an example, | 1214 ldr(xzr, MemOperand(csp, 0)); |
| 1111 // look at Builtins::Generate_ArgumentsAdaptorTrampoline. | 1215 } else if (FLAG_enable_slow_asserts) { |
| 1112 Cmp(csp, StackPointer()); | 1216 Label ok; |
| 1113 Check(ls, kTheCurrentStackPointerIsBelowCsp); | 1217 // Check that csp <= StackPointer(), preserving all registers and NZCV. |
| 1218 sub(StackPointer(), csp, StackPointer()); |
| 1219 cbz(StackPointer(), &ok); // Ok if csp == StackPointer(). |
| 1220 tbnz(StackPointer(), kXSignBit, &ok); // Ok if csp < StackPointer(). |
| 1221 |
| 1222 Abort(kTheCurrentStackPointerIsBelowCsp); |
| 1223 |
| 1224 bind(&ok); |
| 1225 // Restore StackPointer(). |
| 1226 sub(StackPointer(), csp, StackPointer()); |
| 1114 } | 1227 } |
| 1115 } | 1228 } |
| 1116 } | 1229 } |
| 1117 | 1230 |
| 1118 | 1231 |
| 1119 void MacroAssembler::LoadRoot(Register destination, | 1232 void MacroAssembler::LoadRoot(Register destination, |
| 1120 Heap::RootListIndex index) { | 1233 Heap::RootListIndex index) { |
| 1121 // TODO(jbramley): Most root values are constants, and can be synthesized | 1234 // TODO(jbramley): Most root values are constants, and can be synthesized |
| 1122 // without a load. Refer to the ARM back end for details. | 1235 // without a load. Refer to the ARM back end for details. |
| 1123 Ldr(destination, MemOperand(root, index << kPointerSizeLog2)); | 1236 Ldr(destination, MemOperand(root, index << kPointerSizeLog2)); |
| (...skipping 3391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4515 #endif | 4628 #endif |
| 4516 | 4629 |
| 4517 // Abort is used in some contexts where csp is the stack pointer. In order to | 4630 // Abort is used in some contexts where csp is the stack pointer. In order to |
| 4518 // simplify the CallRuntime code, make sure that jssp is the stack pointer. | 4631 // simplify the CallRuntime code, make sure that jssp is the stack pointer. |
| 4519 // There is no risk of register corruption here because Abort doesn't return. | 4632 // There is no risk of register corruption here because Abort doesn't return. |
| 4520 Register old_stack_pointer = StackPointer(); | 4633 Register old_stack_pointer = StackPointer(); |
| 4521 SetStackPointer(jssp); | 4634 SetStackPointer(jssp); |
| 4522 Mov(jssp, old_stack_pointer); | 4635 Mov(jssp, old_stack_pointer); |
| 4523 | 4636 |
| 4524 if (use_real_aborts()) { | 4637 if (use_real_aborts()) { |
| 4638 // Avoid infinite recursion; Push contains some assertions that use Abort. |
| 4639 NoUseRealAbortsScope no_real_aborts(this); |
| 4640 |
| 4525 Mov(x0, Operand(Smi::FromInt(reason))); | 4641 Mov(x0, Operand(Smi::FromInt(reason))); |
| 4526 Push(x0); | 4642 Push(x0); |
| 4527 | 4643 |
| 4528 if (!has_frame_) { | 4644 if (!has_frame_) { |
| 4529 // We don't actually want to generate a pile of code for this, so just | 4645 // We don't actually want to generate a pile of code for this, so just |
| 4530 // claim there is a stack frame, without generating one. | 4646 // claim there is a stack frame, without generating one. |
| 4531 FrameScope scope(this, StackFrame::NONE); | 4647 FrameScope scope(this, StackFrame::NONE); |
| 4532 CallRuntime(Runtime::kAbort, 1); | 4648 CallRuntime(Runtime::kAbort, 1); |
| 4533 } else { | 4649 } else { |
| 4534 CallRuntime(Runtime::kAbort, 1); | 4650 CallRuntime(Runtime::kAbort, 1); |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4966 } | 5082 } |
| 4967 } | 5083 } |
| 4968 | 5084 |
| 4969 | 5085 |
| 4970 #undef __ | 5086 #undef __ |
| 4971 | 5087 |
| 4972 | 5088 |
| 4973 } } // namespace v8::internal | 5089 } } // namespace v8::internal |
| 4974 | 5090 |
| 4975 #endif // V8_TARGET_ARCH_A64 | 5091 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |