summaryrefslogtreecommitdiff
path: root/deps/v8/src/arm64/macro-assembler-arm64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/arm64/macro-assembler-arm64.cc')
-rw-r--r--deps/v8/src/arm64/macro-assembler-arm64.cc107
1 files changed, 79 insertions, 28 deletions
diff --git a/deps/v8/src/arm64/macro-assembler-arm64.cc b/deps/v8/src/arm64/macro-assembler-arm64.cc
index 5edcd7b044..2282c941ba 100644
--- a/deps/v8/src/arm64/macro-assembler-arm64.cc
+++ b/deps/v8/src/arm64/macro-assembler-arm64.cc
@@ -129,7 +129,12 @@ void MacroAssembler::LogicalMacro(const Register& rd,
} else {
// Immediate can't be encoded: synthesize using move immediate.
Register temp = temps.AcquireSameSizeAs(rn);
- Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
+
+ // If the left-hand input is the stack pointer, we can't pre-shift the
+ // immediate, as the encoding won't allow the subsequent post shift.
+ PreShiftImmMode mode = rn.Is(csp) ? kNoShift : kAnyShift;
+ Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode);
+
if (rd.Is(csp)) {
// If rd is the stack pointer we cannot use it as the destination
// register so we use the temp register as an intermediate again.
@@ -437,17 +442,23 @@ bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
return false;
}
-
Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
- int64_t imm) {
+ int64_t imm,
+ PreShiftImmMode mode) {
int reg_size = dst.SizeInBits();
-
// Encode the immediate in a single move instruction, if possible.
if (TryOneInstrMoveImmediate(dst, imm)) {
// The move was successful; nothing to do here.
} else {
// Pre-shift the immediate to the least-significant bits of the register.
int shift_low = CountTrailingZeros(imm, reg_size);
+ if (mode == kLimitShiftForSP) {
+ // When applied to the stack pointer, the subsequent arithmetic operation
+ // can use the extend form to shift left by a maximum of four bits. Right
+ // shifts are not allowed, so we filter them out later before the new
+ // immediate is tested.
+ shift_low = std::min(shift_low, 4);
+ }
int64_t imm_low = imm >> shift_low;
// Pre-shift the immediate to the most-significant bits of the register. We
@@ -456,13 +467,13 @@ Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
// If this new immediate is encodable, the set bits will be eliminated by
// the post shift on the following instruction.
int shift_high = CountLeadingZeros(imm, reg_size);
- int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1);
+ int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
- if (TryOneInstrMoveImmediate(dst, imm_low)) {
+ if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) {
// The new immediate has been moved into the destination's low bits:
// return a new leftward-shifting operand.
return Operand(dst, LSL, shift_low);
- } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
+ } else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) {
// The new immediate has been moved into the destination's high bits:
// return a new rightward-shifting operand.
return Operand(dst, LSR, shift_high);
@@ -498,8 +509,21 @@ void MacroAssembler::AddSubMacro(const Register& rd,
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireSameSizeAs(rn);
if (operand.IsImmediate()) {
+ PreShiftImmMode mode = kAnyShift;
+
+ // If the destination or source register is the stack pointer, we can
+ // only pre-shift the immediate right by values supported in the add/sub
+ // extend encoding.
+ if (rd.Is(csp)) {
+ // If the destination is SP and flags will be set, we can't pre-shift
+ // the immediate at all.
+ mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP;
+ } else if (rn.Is(csp)) {
+ mode = kLimitShiftForSP;
+ }
+
Operand imm_operand =
- MoveImmediateForShiftedOp(temp, operand.ImmediateValue());
+ MoveImmediateForShiftedOp(temp, operand.ImmediateValue(), mode);
AddSub(rd, rn, imm_operand, S, op);
} else {
Mov(temp, operand);
@@ -1791,14 +1815,13 @@ void MacroAssembler::CallCFunction(ExternalReference function,
CallCFunction(temp, num_of_reg_args, num_of_double_args);
}
+static const int kRegisterPassedArguments = 8;
void MacroAssembler::CallCFunction(Register function,
int num_of_reg_args,
int num_of_double_args) {
+ DCHECK_LE(num_of_reg_args + num_of_double_args, kMaxCParameters);
DCHECK(has_frame());
- // We can pass 8 integer arguments in registers. If we need to pass more than
- // that, we'll need to implement support for passing them on the stack.
- DCHECK(num_of_reg_args <= 8);
// If we're passing doubles, we're limited to the following prototypes
// (defined by ExternalReference::Type):
@@ -1811,6 +1834,10 @@ void MacroAssembler::CallCFunction(Register function,
DCHECK((num_of_double_args + num_of_reg_args) <= 2);
}
+ // We rely on the frame alignment being 16 bytes, which means we never need
+ // to align the CSP by an unknown number of bytes and we always know the delta
+ // between the stack pointer and the frame pointer.
+ DCHECK(ActivationFrameAlignment() == 16);
// If the stack pointer is not csp, we need to derive an aligned csp from the
// current stack pointer.
@@ -1819,16 +1846,18 @@ void MacroAssembler::CallCFunction(Register function,
AssertStackConsistency();
int sp_alignment = ActivationFrameAlignment();
- // The ABI mandates at least 16-byte alignment.
- DCHECK(sp_alignment >= 16);
- DCHECK(base::bits::IsPowerOfTwo32(sp_alignment));
-
// The current stack pointer is a callee saved register, and is preserved
// across the call.
DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer));
- // Align and synchronize the system stack pointer with jssp.
- Bic(csp, old_stack_pointer, sp_alignment - 1);
+ // If more than eight arguments are passed to the function, we expect the
+ // ninth argument onwards to have been placed on the csp-based stack
+ // already. We assume csp already points to the last stack-passed argument
+ // in that case.
+ // Otherwise, align and synchronize the system stack pointer with jssp.
+ if (num_of_reg_args <= kRegisterPassedArguments) {
+ Bic(csp, old_stack_pointer, sp_alignment - 1);
+ }
SetStackPointer(csp);
}
@@ -1836,19 +1865,39 @@ void MacroAssembler::CallCFunction(Register function,
// so the return address in the link register stays correct.
Call(function);
- if (!csp.Is(old_stack_pointer)) {
+ if (csp.Is(old_stack_pointer)) {
+ if (num_of_reg_args > kRegisterPassedArguments) {
+ // Drop the register passed arguments.
+ int claim_slots = RoundUp(num_of_reg_args - kRegisterPassedArguments, 2);
+ Drop(claim_slots);
+ }
+ } else {
+ DCHECK(jssp.Is(old_stack_pointer));
if (emit_debug_code()) {
- // Because the stack pointer must be aligned on a 16-byte boundary, the
- // aligned csp can be up to 12 bytes below the jssp. This is the case
- // where we only pushed one W register on top of an aligned jssp.
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireX();
- DCHECK(ActivationFrameAlignment() == 16);
- Sub(temp, csp, old_stack_pointer);
- // We want temp <= 0 && temp >= -12.
- Cmp(temp, 0);
- Ccmp(temp, -12, NFlag, le);
- Check(ge, kTheStackWasCorruptedByMacroAssemblerCall);
+
+ if (num_of_reg_args > kRegisterPassedArguments) {
+ // We don't need to drop stack arguments, as the stack pointer will be
+ // jssp when returning from this function. However, in debug builds, we
+ // can check that jssp is as expected.
+ int claim_slots =
+ RoundUp(num_of_reg_args - kRegisterPassedArguments, 2);
+
+ // Check jssp matches the previous value on the stack.
+ Ldr(temp, MemOperand(csp, claim_slots * kPointerSize));
+ Cmp(jssp, temp);
+ Check(eq, kTheStackWasCorruptedByMacroAssemblerCall);
+ } else {
+ // Because the stack pointer must be aligned on a 16-byte boundary, the
+ // aligned csp can be up to 12 bytes below the jssp. This is the case
+ // where we only pushed one W register on top of an aligned jssp.
+ Sub(temp, csp, old_stack_pointer);
+ // We want temp <= 0 && temp >= -12.
+ Cmp(temp, 0);
+ Ccmp(temp, -12, NFlag, le);
+ Check(ge, kTheStackWasCorruptedByMacroAssemblerCall);
+ }
}
SetStackPointer(old_stack_pointer);
}
@@ -2547,6 +2596,8 @@ void MacroAssembler::TruncateDoubleToI(Register result,
}
Bind(&done);
+ // Keep our invariant that the upper 32 bits are zero.
+ Uxtw(result.W(), result.W());
}
@@ -3733,7 +3784,7 @@ void MacroAssembler::RecordWriteField(
Add(scratch, object, offset - kHeapObjectTag);
if (emit_debug_code()) {
Label ok;
- Tst(scratch, (1 << kPointerSizeLog2) - 1);
+ Tst(scratch, kPointerSize - 1);
B(eq, &ok);
Abort(kUnalignedCellInWriteBarrier);
Bind(&ok);