Commit 42df746d authored by Martyn Capewell's avatar Martyn Capewell Committed by Commit Bot

[arm64] Add SlotAddress and merge more stack accesses

Add a SlotAddress macro assembler function to abstract obtaining the address of
an sp-relative double word slot. Then, merge some stack accesses in builtins,
generally changing from push to claim and poke.

Bug: v8:6644
Change-Id: Id7a9f6e276a038fbffd8e2bbaa21f51855f057f1
Reviewed-on: https://chromium-review.googlesource.com/723465
Commit-Queue: Martyn Capewell <martyn.capewell@arm.com>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48685}
parent 855a6b5d
......@@ -351,7 +351,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// - Adjust for the arg[] array.
Register temp_argv = x11;
if (!argv_in_register()) {
__ Add(temp_argv, jssp, Operand(x0, LSL, kPointerSizeLog2));
__ SlotAddress(temp_argv, x0);
// - Adjust for the receiver.
__ Sub(temp_argv, temp_argv, 1 * kPointerSize);
}
......@@ -1045,7 +1045,7 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
// The caller's return address is above the saved temporaries.
// Grab its location for the second argument to the hook.
__ Add(x1, __ StackPointer(), kNumSavedRegs * kPointerSize);
__ SlotAddress(x1, kNumSavedRegs);
{
// Create a dummy frame, as CallCFunction requires this.
......@@ -1793,7 +1793,7 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
DCHECK(!AreAliased(x0, api_function_address));
// x0 = FunctionCallbackInfo&
// Arguments is after the return address.
__ Add(x0, masm->StackPointer(), 1 * kPointerSize);
__ SlotAddress(x0, 1);
// FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
__ Add(x10, args, Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
__ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
......@@ -1882,7 +1882,7 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
// Create v8::PropertyCallbackInfo object on the stack and initialize
// it's args_ field.
__ Poke(x1, 1 * kPointerSize);
__ Add(x1, masm->StackPointer(), 1 * kPointerSize);
__ SlotAddress(x1, 1);
// x1 = v8::PropertyCallbackInfo&
ExternalReference thunk_ref =
......
......@@ -1486,21 +1486,23 @@ void TurboAssembler::CopySlots(int dst, Register src, Register slot_count) {
DCHECK(!src.IsZero());
UseScratchRegisterScope scope(this);
Register dst_reg = scope.AcquireX();
Add(dst_reg, StackPointer(), dst << kPointerSizeLog2);
Add(src, StackPointer(), Operand(src, LSL, kPointerSizeLog2));
SlotAddress(dst_reg, dst);
SlotAddress(src, src);
CopyDoubleWords(dst_reg, src, slot_count);
}
void TurboAssembler::CopySlots(Register dst, Register src,
Register slot_count) {
DCHECK(!dst.IsZero() && !src.IsZero());
Add(dst, StackPointer(), Operand(dst, LSL, kPointerSizeLog2));
Add(src, StackPointer(), Operand(src, LSL, kPointerSizeLog2));
SlotAddress(dst, dst);
SlotAddress(src, src);
CopyDoubleWords(dst, src, slot_count);
}
void TurboAssembler::CopyDoubleWords(Register dst, Register src,
Register count) {
DCHECK(!AreAliased(dst, src, count));
if (emit_debug_code()) {
// Copy requires dst < src || (dst - src) >= count.
Label dst_below_src;
......@@ -1538,6 +1540,14 @@ void TurboAssembler::CopyDoubleWords(Register dst, Register src,
Bind(&done);
}
void TurboAssembler::SlotAddress(Register dst, int slot_offset) {
Add(dst, StackPointer(), slot_offset << kPointerSizeLog2);
}
void TurboAssembler::SlotAddress(Register dst, Register slot_offset) {
Add(dst, StackPointer(), Operand(slot_offset, LSL, kPointerSizeLog2));
}
void TurboAssembler::AssertFPCRState(Register fpcr) {
if (emit_debug_code()) {
Label unexpected_mode, done;
......
......@@ -663,7 +663,8 @@ class TurboAssembler : public Assembler {
// the stack offset specified by dst. The offsets and count are expressed in
// slot-sized units. Offset dst must be less than src, or the gap between
// them must be greater than or equal to slot_count, otherwise the result is
// unpredictable. The function may corrupt its register arguments.
// unpredictable. The function may corrupt its register arguments. The
// registers must not alias each other.
void CopySlots(int dst, Register src, Register slot_count);
void CopySlots(Register dst, Register src, Register slot_count);
......@@ -671,8 +672,15 @@ class TurboAssembler : public Assembler {
// in register dst. Address dst must be less than src, or the gap between
// them must be greater than or equal to count double words, otherwise the
// result is unpredictable. The function may corrupt its register arguments.
// The registers must not alias each other.
void CopyDoubleWords(Register dst, Register src, Register count);
// Calculate the address of a double word-sized slot at slot_offset from the
// stack pointer, and write it to dst. Positive slot_offsets are at addresses
// greater than sp, with slot zero at sp.
void SlotAddress(Register dst, int slot_offset);
void SlotAddress(Register dst, Register slot_offset);
// Load a literal from the inline constant pool.
inline void Ldr(const CPURegister& rt, const Operand& imm);
// Helper function for double immediate.
......
......@@ -204,22 +204,25 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
__ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
// Add slots for the context, tagged argc and receiver.
Register slot_count = x2;
__ Add(slot_count, x0, 3);
__ Claim(slot_count);
// Preserve the incoming parameters on the stack.
__ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
__ SmiTag(x11, x0);
__ Push(cp, x11, x10);
// ----------- S t a t e -------------
// -- x0: number of arguments (untagged)
// -- x1: constructor function
// -- x3: new target
// -- sp[0*kPointerSize]: the hole (receiver)
// -- sp[1*kPointerSize]: number of arguments (tagged)
// -- sp[2*kPointerSize]: context
// -----------------------------------
// Compute a pointer to the slot immediately above the newly claimed area
// of stack.
__ SlotAddress(x2, slot_count);
// Poke the the hole (receiver), number of arguments (tagged) and the
// context into the three highest slots.
__ Stp(x11, cp, MemOperand(x2, -2 * kPointerSize));
__ Str(x10, MemOperand(x2, -3 * kPointerSize));
// Copy arguments to the expression stack.
__ Claim(x0);
{
Register count = x2;
Register dst = x10;
......@@ -230,10 +233,19 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
__ CopyDoubleWords(dst, src, count);
}
// ----------- S t a t e -------------
// -- x0: number of arguments (untagged)
// -- x1: constructor function
// -- x3: new target
// -- sp[0*kPointerSize]: argument n - 1
// -- ...
// -- sp[(n-1)*kPointerSize]: argument 0
// -- sp[(n+0)*kPointerSize]: the hole (receiver)
// -- sp[(n+1)*kPointerSize]: number of arguments (tagged)
// -- sp[(n+2)*kPointerSize]: context
// -----------------------------------
// Call the function.
// x0: number of arguments
// x1: constructor function
// x3: new target
ParameterCount actual(x0);
__ InvokeFunction(x1, x3, actual, CALL_FUNCTION);
......@@ -309,20 +321,16 @@ void Generate_JSConstructStubGeneric(MacroAssembler* masm,
__ Bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(x3);
// Push the allocated receiver to the stack. We need two copies
// because we may have to return the original one and the calling
// conventions dictate that the called function pops the receiver.
__ Push(x0, x0);
__ Peek(x3, 0);
// Restore constructor function and argument count.
__ Ldr(x1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ Ldrsw(x0,
__ Ldrsw(x12,
UntagSmiMemOperand(fp, ConstructFrameConstants::kLengthOffset));
// ----------- S t a t e -------------
// -- x0: number of arguments (untagged)
// -- x3: new target
// -- x12: number of arguments (untagged)
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: implicit receiver
// -- x1 and sp[2*kPointerSize]: constructor function
......@@ -330,19 +338,30 @@ void Generate_JSConstructStubGeneric(MacroAssembler* masm,
// -- sp[4*kPointerSize]: context
// -----------------------------------
// Copy arguments to the expression stack.
__ Claim(x0);
// Copy arguments to the expression stack. Increment the number of slots by
// one to account for the two copies of the receiver, where one overwrites
// the slot used by the new target.
__ Add(x10, x12, 1);
__ Claim(x10);
// Poke the allocated receiver to the stack. We need two copies
// because we may have to return the original one and the calling
// conventions dictate that the called function pops the receiver.
__ Poke(x0, Operand(x10, LSL, kPointerSizeLog2));
__ Poke(x0, Operand(x12, LSL, kPointerSizeLog2));
{
Register count = x2;
Register dst = x10;
Register src = x11;
__ Mov(count, x0);
__ Mov(dst, __ StackPointer());
__ Mov(count, x12);
__ SlotAddress(dst, 0);
__ Add(src, fp, StandardFrameConstants::kCallerSPOffset);
__ CopyDoubleWords(dst, src, count);
}
// Call the function.
__ Mov(x0, x12);
ParameterCount actual(x0);
__ InvokeFunction(x1, x3, actual, CALL_FUNCTION);
......@@ -411,11 +430,10 @@ void Generate_JSConstructStubGeneric(MacroAssembler* masm,
__ Bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ Ldr(x1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ Ldr(w1, UntagSmiMemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
__ SmiUntag(x1);
__ DropArguments(x1, TurboAssembler::kCountExcludesReceiver);
__ Ret();
}
......@@ -482,28 +500,45 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
&prepare_step_in_suspended_generator);
__ Bind(&stepping_prepared);
// Push receiver.
// Get number of arguments for generator function.
__ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w10,
FieldMemOperand(x10, SharedFunctionInfo::kFormalParameterCountOffset));
// Claim slots for arguments and receiver.
__ Add(x11, x10, 1);
__ Claim(x11);
// Poke receiver into highest claimed slot.
__ Ldr(x5, FieldMemOperand(x1, JSGeneratorObject::kReceiverOffset));
__ Push(x5);
__ Poke(x5, Operand(x10, LSL, kPointerSizeLog2));
// ----------- S t a t e -------------
// -- x1 : the JSGeneratorObject to resume
// -- x2 : the resume mode (tagged)
// -- x4 : generator function
// -- cp : generator context
// -- lr : return address
// -- jssp[0] : generator receiver
// -- x1 : the JSGeneratorObject to resume
// -- x2 : the resume mode (tagged)
// -- x4 : generator function
// -- x10 : argument count
// -- cp : generator context
// -- lr : return address
// -- jssp[arg count] : generator receiver
// -- jssp[0 .. arg count - 1] : claimed for args
// -----------------------------------
// Push holes for arguments to generator function. Since the parser forced
// context allocation for any variables in generators, the actual argument
// values have already been copied into the context and these dummy values
// will never be used.
__ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w10,
FieldMemOperand(x10, SharedFunctionInfo::kFormalParameterCountOffset));
__ LoadRoot(x11, Heap::kTheHoleValueRootIndex);
__ PushMultipleTimes(x11, w10);
{
Label loop, done;
__ Cbz(x10, &done);
__ LoadRoot(x11, Heap::kTheHoleValueRootIndex);
__ Bind(&loop);
__ Sub(x10, x10, 1);
__ Poke(x11, Operand(x10, LSL, kPointerSizeLog2));
__ Cbnz(x10, &loop);
__ Bind(&done);
}
// Underlying function needs to have bytecode available.
if (FLAG_debug_code) {
......@@ -616,24 +651,35 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ Push(function, receiver);
// Check if we have enough stack space to push all arguments.
// Expects argument count in eax. Clobbers ecx, edx, edi.
Generate_CheckStackOverflow(masm, argc, kArgcIsUntaggedInt);
// Copy arguments to the stack in a loop, in reverse order.
// x3: argc.
// x4: argv.
Label loop, entry;
// Compute the copy end address.
__ Add(scratch, argv, Operand(argc, LSL, kPointerSizeLog2));
Label loop, done;
// Skip the argument set up if we have no arguments.
__ Cbz(argc, &done);
// Set scratch to the current position of the stack pointer, which marks
// the end of the argument copy.
__ SlotAddress(scratch, 0);
// Claim enough space for the arguments.
__ Claim(argc);
__ B(&entry);
__ Bind(&loop);
// Load the handle.
__ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
__ Ldr(x12, MemOperand(x11)); // Dereference the handle.
__ Push(x12); // Push the argument.
__ Bind(&entry);
__ Cmp(scratch, argv);
__ B(ne, &loop);
// Dereference the handle.
__ Ldr(x11, MemOperand(x11));
// Poke the result into the stack.
__ Str(x11, MemOperand(scratch, -kPointerSize, PreIndex));
// Loop if we've not reached the end of copy marker.
__ Cmp(__ StackPointer(), scratch);
__ B(lt, &loop);
__ Bind(&done);
__ Mov(scratch, argc);
__ Mov(argc, new_target);
......@@ -1753,7 +1799,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
{
Label loop;
// Calculate the copy start address (destination). Copy end address is jssp.
__ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
__ SlotAddress(scratch2, argc);
__ Sub(scratch1, scratch2, kPointerSize);
__ Bind(&loop);
......@@ -2218,13 +2264,14 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
Label loop;
__ Ldrsw(x4, UntagSmiFieldMemOperand(x2, FixedArray::kLengthOffset));
__ Add(x2, x2, FixedArray::kHeaderSize - kHeapObjectTag);
__ SlotAddress(x11, x0);
__ Add(x0, x0, x4);
__ Bind(&loop);
__ Sub(x4, x4, 1);
__ Ldr(x10, MemOperand(x2, x4, LSL, kPointerSizeLog2));
__ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
__ Add(x0, x0, 1);
__ Cmp(x4, 0);
__ B(gt, &loop);
// Poke into claimed area of stack.
__ Str(x10, MemOperand(x11, kPointerSize, PostIndex));
__ Cbnz(x4, &loop);
}
}
__ Bind(&no_bound_arguments);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment