Commit 4f62b4bb authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[arm] Port the skipping of arguments adaptor frames.

This is a port of the improvements to the ArgumentsAdaptorTrampoline
that previously landed for x64. It skips the arguments adaptor frame
creation if the callee cannot observe the actual arguments (as indicated
by the "is_safe_to_skip_arguments_adaptor" bit on the SharedFunctionInfo),
and instead just massages the current stack frame appropriately (either
by pushing more undefineds in case of under application, or by removing
the superfluous arguments in case of over application).

Bug: v8:8895
Doc: http://bit.ly/v8-faster-calls-with-arguments-mismatch
Change-Id: I96a0425d390f041001df0356d4bfd71ad1e98b5a
Reviewed-on: https://chromium-review.googlesource.com/c/1491592Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59918}
parent 0a6ae5b4
......@@ -2308,111 +2308,157 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -- r3 : new target (passed through to callee)
// -----------------------------------
Label invoke, dont_adapt_arguments, stack_overflow;
Label enough, too_few;
Label dont_adapt_arguments, stack_overflow, skip_adapt_arguments;
__ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
__ b(eq, &dont_adapt_arguments);
__ cmp(r0, r2);
__ b(lt, &too_few);
Register scratch = r5;
{ // Enough parameters: actual >= expected
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, scratch, &stack_overflow);
// Calculate copy start address into r0 and copy end address into r4.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
// adjust for return address and receiver
__ add(r0, r0, Operand(2 * kPointerSize));
__ sub(r4, r0, Operand(r2, LSL, kPointerSizeLog2));
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
// r4: copy end address
Label copy;
__ bind(&copy);
__ ldr(scratch, MemOperand(r0, 0));
__ push(scratch);
__ cmp(r0, r4); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
__ b(&invoke);
}
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
__ tst(r4,
Operand(SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask));
__ b(ne, &skip_adapt_arguments);
{ // Too few parameters: Actual < expected
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, scratch, &stack_overflow);
// -------------------------------------------
// Adapt arguments.
// -------------------------------------------
{
Label under_application, over_application, invoke;
__ cmp(r0, r2);
__ b(lt, &under_application);
// Calculate copy start address into r0 and copy end address is fp.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
// Enough parameters: actual >= expected
__ bind(&over_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
// Calculate copy start address into r0 and copy end address into r4.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
// adjust for return address and receiver
__ add(r0, r0, Operand(2 * kPointerSize));
__ sub(r4, r0, Operand(r2, LSL, kPointerSizeLog2));
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
// r4: copy end address
Label copy;
__ bind(&copy);
__ ldr(r5, MemOperand(r0, 0));
__ push(r5);
__ cmp(r0, r4); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
__ b(&invoke);
}
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
Label copy;
__ bind(&copy);
// Too few parameters: Actual < expected
__ bind(&under_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
// Calculate copy start address into r0 and copy end address is fp.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
Label copy;
__ bind(&copy);
// Adjust load for return address and receiver.
__ ldr(r5, MemOperand(r0, 2 * kPointerSize));
__ push(r5);
__ cmp(r0, fp); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
// Fill the remaining expected arguments with undefined.
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ LoadRoot(r5, RootIndex::kUndefinedValue);
__ sub(r4, fp, Operand(r2, LSL, kPointerSizeLog2));
// Adjust for frame.
__ sub(r4, r4,
Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp +
kPointerSize));
Label fill;
__ bind(&fill);
__ push(r5);
__ cmp(sp, r4);
__ b(ne, &fill);
}
// Adjust load for return address and receiver.
__ ldr(scratch, MemOperand(r0, 2 * kPointerSize));
__ push(scratch);
// Call the entry point.
__ bind(&invoke);
__ mov(r0, r2);
// r0 : expected number of arguments
// r1 : function (passed through to callee)
// r3 : new target (passed through to callee)
static_assert(kJavaScriptCallCodeStartRegister == r2, "ABI mismatch");
__ ldr(r2, FieldMemOperand(r1, JSFunction::kCodeOffset));
__ CallCodeObject(r2);
__ cmp(r0, fp); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(
masm->pc_offset());
// Fill the remaining expected arguments with undefined.
// r1: function
// r2: expected number of arguments
// r3: new target (passed through to callee)
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
__ sub(r4, fp, Operand(r2, LSL, kPointerSizeLog2));
// Adjust for frame.
__ sub(r4, r4,
Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp +
kPointerSize));
Label fill;
__ bind(&fill);
__ push(scratch);
__ cmp(sp, r4);
__ b(ne, &fill);
// Exit frame and return.
LeaveArgumentsAdaptorFrame(masm);
__ Jump(lr);
}
// Call the entry point.
__ bind(&invoke);
__ mov(r0, r2);
// r0 : expected number of arguments
// r1 : function (passed through to callee)
// r3 : new target (passed through to callee)
static_assert(kJavaScriptCallCodeStartRegister == r2, "ABI mismatch");
__ ldr(r2, FieldMemOperand(r1, JSFunction::kCodeOffset));
__ CallCodeObject(r2);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
// -------------------------------------------
// Skip adapt arguments.
// -------------------------------------------
__ bind(&skip_adapt_arguments);
{
// The callee cannot observe the actual arguments, so it's safe to just
// pass the expected arguments by massaging the stack appropriately. See
// http://bit.ly/v8-faster-calls-with-arguments-mismatch for details.
Label under_application, over_application;
__ cmp(r0, r2);
__ b(lt, &under_application);
__ bind(&over_application);
{
// Remove superfluous parameters from the stack.
__ sub(r4, r0, r2);
__ mov(r0, r2);
__ add(sp, sp, Operand(r4, LSL, kPointerSizeLog2));
__ b(&dont_adapt_arguments);
}
// Exit frame and return.
LeaveArgumentsAdaptorFrame(masm);
__ Jump(lr);
__ bind(&under_application);
{
// Fill remaining expected arguments with undefined values.
Label fill;
__ LoadRoot(r4, RootIndex::kUndefinedValue);
__ bind(&fill);
__ add(r0, r0, Operand(1));
__ push(r4);
__ cmp(r0, r2);
__ b(lt, &fill);
__ b(&dont_adapt_arguments);
}
}
// -------------------------------------------
// Dont adapt 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