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) { ...@@ -2308,111 +2308,157 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -- r3 : new target (passed through to callee) // -- r3 : new target (passed through to callee)
// ----------------------------------- // -----------------------------------
Label invoke, dont_adapt_arguments, stack_overflow; Label dont_adapt_arguments, stack_overflow, skip_adapt_arguments;
Label enough, too_few;
__ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
__ b(eq, &dont_adapt_arguments); __ b(eq, &dont_adapt_arguments);
__ cmp(r0, r2); __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ b(lt, &too_few); __ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
__ tst(r4,
Register scratch = r5; Operand(SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask));
__ b(ne, &skip_adapt_arguments);
{ // 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);
}
{ // Too few parameters: Actual < expected // -------------------------------------------
__ bind(&too_few); // Adapt arguments.
EnterArgumentsAdaptorFrame(masm); // -------------------------------------------
Generate_StackOverflowCheck(masm, r2, scratch, &stack_overflow); {
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. // Enough parameters: actual >= expected
// r0: actual number of arguments as a smi __ bind(&over_application);
// r1: function {
// r2: expected number of arguments EnterArgumentsAdaptorFrame(masm);
// r3: new target (passed through to callee) Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
__ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
// 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. // Too few parameters: Actual < expected
// r0: copy start address __ bind(&under_application);
// r1: function {
// r2: expected number of arguments EnterArgumentsAdaptorFrame(masm);
// r3: new target (passed through to callee) Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
Label copy;
__ bind(&copy); // 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. // Call the entry point.
__ ldr(scratch, MemOperand(r0, 2 * kPointerSize)); __ bind(&invoke);
__ push(scratch); __ 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. // Store offset of return address for deoptimizer.
__ sub(r0, r0, Operand(kPointerSize)); masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(
__ b(ne, &copy); masm->pc_offset());
// Fill the remaining expected arguments with undefined. // Exit frame and return.
// r1: function LeaveArgumentsAdaptorFrame(masm);
// r2: expected number of arguments __ Jump(lr);
// 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);
} }
// Call the entry point. // -------------------------------------------
__ bind(&invoke); // Skip adapt arguments.
__ mov(r0, r2); // -------------------------------------------
// r0 : expected number of arguments __ bind(&skip_adapt_arguments);
// r1 : function (passed through to callee) {
// r3 : new target (passed through to callee) // The callee cannot observe the actual arguments, so it's safe to just
static_assert(kJavaScriptCallCodeStartRegister == r2, "ABI mismatch"); // pass the expected arguments by massaging the stack appropriately. See
__ ldr(r2, FieldMemOperand(r1, JSFunction::kCodeOffset)); // http://bit.ly/v8-faster-calls-with-arguments-mismatch for details.
__ CallCodeObject(r2); Label under_application, over_application;
__ cmp(r0, r2);
// Store offset of return address for deoptimizer. __ b(lt, &under_application);
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
__ 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. __ bind(&under_application);
LeaveArgumentsAdaptorFrame(masm); {
__ Jump(lr); // 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. // 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