Commit cc5808cd authored by Georgia Kouveli's avatar Georgia Kouveli Committed by Commit Bot

[arm64] 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).

Due to the 16 byte stack alignment requirement on arm64, we only skip
the arguments adaptor frame creation when the difference between the
expected and the actual argument number is even. When it is odd, we
would still need to copy the actual arguments in the existing frame to
account for the padding, which would defeat the point of the improvement.

Bug: v8:8895
Tbr: jgruber@chromium.org
Doc: http://bit.ly/v8-faster-calls-with-arguments-mismatch
Change-Id: I7f13f6f0ba86edb483e088aac145cfcf9c937fef
Reviewed-on: https://chromium-review.googlesource.com/c/1491633
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59983}
parent 5bdb6b83
...@@ -2829,13 +2829,34 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -2829,13 +2829,34 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Register argc_actual = x0; // Excluding the receiver. Register argc_actual = x0; // Excluding the receiver.
Register argc_expected = x2; // Excluding the receiver. Register argc_expected = x2; // Excluding the receiver.
Register function = x1; Register function = x1;
Register argc_actual_minus_expected = x5;
Label dont_adapt_arguments, stack_overflow; Label create_adaptor_frame, dont_adapt_arguments, stack_overflow,
adapt_arguments_in_place;
Label enough_arguments;
__ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel); __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
__ B(eq, &dont_adapt_arguments); __ B(eq, &dont_adapt_arguments);
// When the difference between argc_actual and argc_expected is odd, we
// create an arguments adaptor frame.
__ Sub(argc_actual_minus_expected, argc_actual, argc_expected);
__ Tbnz(argc_actual_minus_expected, 0, &create_adaptor_frame);
// When the difference is even, check if we are allowed to adjust the
// existing frame instead.
__ LoadTaggedPointerField(
x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w4, FieldMemOperand(x4, SharedFunctionInfo::kFlagsOffset));
__ TestAndBranchIfAnySet(
w4, SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask,
&adapt_arguments_in_place);
// -------------------------------------------
// Create an arguments adaptor frame.
// -------------------------------------------
__ Bind(&create_adaptor_frame);
{
__ RecordComment("-- Adapt arguments --");
EnterArgumentsAdaptorFrame(masm); EnterArgumentsAdaptorFrame(masm);
Register copy_from = x10; Register copy_from = x10;
...@@ -2865,6 +2886,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -2865,6 +2886,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// (1) If we don't have enough arguments, fill the remaining expected // (1) If we don't have enough arguments, fill the remaining expected
// arguments with undefined, otherwise skip this step. // arguments with undefined, otherwise skip this step.
Label enough_arguments;
__ Subs(scratch1, argc_actual, argc_expected); __ Subs(scratch1, argc_actual, argc_expected);
__ Csel(argc_unused_actual, xzr, scratch1, lt); __ Csel(argc_unused_actual, xzr, scratch1, lt);
__ Csel(argc_to_copy, argc_expected, argc_actual, ge); __ Csel(argc_to_copy, argc_expected, argc_actual, ge);
...@@ -2892,15 +2914,17 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -2892,15 +2914,17 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Label skip_copy; Label skip_copy;
__ RecordComment("-- Copy actual arguments --"); __ RecordComment("-- Copy actual arguments --");
__ Cbz(argc_to_copy, &skip_copy); __ Cbz(argc_to_copy, &skip_copy);
__ Add(copy_end, copy_to, Operand(argc_to_copy, LSL, kSystemPointerSizeLog2)); __ Add(copy_end, copy_to,
Operand(argc_to_copy, LSL, kSystemPointerSizeLog2));
__ Add(copy_from, fp, 2 * kSystemPointerSize); __ Add(copy_from, fp, 2 * kSystemPointerSize);
// Adjust for difference between actual and expected arguments. // Adjust for difference between actual and expected arguments.
__ Add(copy_from, copy_from, __ Add(copy_from, copy_from,
Operand(argc_unused_actual, LSL, kSystemPointerSizeLog2)); Operand(argc_unused_actual, LSL, kSystemPointerSizeLog2));
// Copy arguments. We use load/store pair instructions, so we might overshoot // Copy arguments. We use load/store pair instructions, so we might
// by one slot, but since we copy the arguments starting from the last one, if // overshoot by one slot, but since we copy the arguments starting from the
// we do overshoot, the extra slot will be overwritten later by the receiver. // last one, if we do overshoot, the extra slot will be overwritten later by
// the receiver.
Label copy_2_by_2; Label copy_2_by_2;
__ Bind(&copy_2_by_2); __ Bind(&copy_2_by_2);
__ Ldp(scratch1, scratch2, __ Ldp(scratch1, scratch2,
...@@ -2911,20 +2935,21 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -2911,20 +2935,21 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ B(hi, &copy_2_by_2); __ B(hi, &copy_2_by_2);
__ Bind(&skip_copy); __ Bind(&skip_copy);
// (3) Store padding, which might be overwritten by the receiver, if it is not // (3) Store padding, which might be overwritten by the receiver, if it is
// necessary. // not necessary.
__ RecordComment("-- Store padding --"); __ RecordComment("-- Store padding --");
__ Str(padreg, MemOperand(fp, -5 * kSystemPointerSize)); __ Str(padreg, MemOperand(fp, -5 * kSystemPointerSize));
// (4) Store receiver. Calculate target address from the sp to avoid checking // (4) Store receiver. Calculate target address from the sp to avoid
// for padding. Storing the receiver will overwrite either the extra slot // checking for padding. Storing the receiver will overwrite either the
// we copied with the actual arguments, if we did copy one, or the padding we // extra slot we copied with the actual arguments, if we did copy one, or
// stored above. // the padding we stored above.
__ RecordComment("-- Store receiver --"); __ RecordComment("-- Store receiver --");
__ Add(copy_from, fp, 2 * kSystemPointerSize); __ Add(copy_from, fp, 2 * kSystemPointerSize);
__ Ldr(scratch1, __ Ldr(scratch1,
MemOperand(copy_from, argc_actual, LSL, kSystemPointerSizeLog2)); MemOperand(copy_from, argc_actual, LSL, kSystemPointerSizeLog2));
__ Str(scratch1, MemOperand(sp, argc_expected, LSL, kSystemPointerSizeLog2)); __ Str(scratch1,
MemOperand(sp, argc_expected, LSL, kSystemPointerSizeLog2));
// Arguments have been adapted. Now call the entry point. // Arguments have been adapted. Now call the entry point.
__ RecordComment("-- Call entry point --"); __ RecordComment("-- Call entry point --");
...@@ -2933,24 +2958,69 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -2933,24 +2958,69 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// x1 : function (passed through to callee) // x1 : function (passed through to callee)
// x3 : new target (passed through to callee) // x3 : new target (passed through to callee)
static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch"); static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch");
__ LoadTaggedPointerField(x2, __ LoadTaggedPointerField(
FieldMemOperand(function, JSFunction::kCodeOffset)); x2, FieldMemOperand(function, JSFunction::kCodeOffset));
__ CallCodeObject(x2); __ CallCodeObject(x2);
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(
masm->pc_offset());
// Exit frame and return. // Exit frame and return.
LeaveArgumentsAdaptorFrame(masm); LeaveArgumentsAdaptorFrame(masm);
__ Ret(); __ Ret();
}
// -----------------------------------------
// Adapt arguments in the existing frame.
// -----------------------------------------
__ Bind(&adapt_arguments_in_place);
{
__ RecordComment("-- Update arguments in place --");
// 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;
__ Tbnz(argc_actual_minus_expected, kXSignBit, &under_application);
__ Bind(&over_application);
{
// Remove superfluous arguments from the stack. The number of superflous
// arguments is even.
__ RecordComment("-- Over-application --");
__ Mov(argc_actual, argc_expected);
__ Drop(argc_actual_minus_expected);
__ B(&dont_adapt_arguments);
}
__ Bind(&under_application);
{
// Fill remaining expected arguments with undefined values.
__ RecordComment("-- Under-application --");
Label fill;
Register undef_value = x16;
__ LoadRoot(undef_value, RootIndex::kUndefinedValue);
__ Bind(&fill);
__ Add(argc_actual, argc_actual, 2);
__ Push(undef_value, undef_value);
__ Cmp(argc_actual, argc_expected);
__ B(lt, &fill);
__ B(&dont_adapt_arguments);
}
}
// -------------------------------------------
// Dont adapt arguments.
// -------------------------------------------
__ Bind(&dont_adapt_arguments);
{
// Call the entry point without adapting the arguments. // Call the entry point without adapting the arguments.
__ RecordComment("-- Call without adapting args --"); __ RecordComment("-- Call without adapting args --");
__ Bind(&dont_adapt_arguments);
static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch"); static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch");
__ LoadTaggedPointerField(x2, __ LoadTaggedPointerField(
FieldMemOperand(function, JSFunction::kCodeOffset)); x2, FieldMemOperand(function, JSFunction::kCodeOffset));
__ JumpCodeObject(x2); __ JumpCodeObject(x2);
}
__ Bind(&stack_overflow); __ Bind(&stack_overflow);
__ RecordComment("-- Stack overflow --"); __ RecordComment("-- Stack overflow --");
......
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