Commit fc24d04e authored by Junliang Yan's avatar Junliang Yan Committed by Commit Bot

[ppc/s390] Remove arguments adaptor frame

Bug: v8:10201

R=victorgomes@chromium.org,neis@chromium.org,ishell@chromium.org

Change-Id: I1bd0ece0e4c91abc84c24ec8331f9cbb17defa56
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2524295
Commit-Queue: Junliang Yan <junyan@redhat.com>
Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarMilad Fa <mfarazma@redhat.com>
Cr-Commit-Position: refs/heads/master@{#71149}
parent 286f03bd
......@@ -65,39 +65,6 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
enum StackLimitKind { kInterruptStackLimit, kRealStackLimit };
void LoadStackLimit(MacroAssembler* masm, Register destination,
StackLimitKind kind) {
DCHECK(masm->root_array_available());
Isolate* isolate = masm->isolate();
ExternalReference limit =
kind == StackLimitKind::kRealStackLimit
? ExternalReference::address_of_real_jslimit(isolate)
: ExternalReference::address_of_jslimit(isolate);
DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
intptr_t offset =
TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
CHECK(is_int32(offset));
__ LoadP(destination, MemOperand(kRootRegister, offset), r0);
}
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch, Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
LoadStackLimit(masm, scratch, StackLimitKind::kRealStackLimit);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ sub(scratch, sp, scratch);
// Check if the arguments will overflow the stack.
__ ShiftLeftImm(r0, num_args, Operand(kSystemPointerSizeLog2));
__ cmp(scratch, r0);
__ ble(stack_overflow); // Signed comparison.
}
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : number of arguments
......@@ -112,7 +79,7 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
Label stack_overflow;
Generate_StackOverflowCheck(masm, r3, r8, &stack_overflow);
__ StackOverflowCheck(r3, scratch, &stack_overflow);
// Enter a construct frame.
{
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
......@@ -123,6 +90,11 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
__ Push(cp, r3);
__ SmiUntag(r3, SetRC);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Set up pointer to last argument (skip receiver).
__ addi(
r7, fp,
......@@ -259,7 +231,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
__ SmiUntag(r3);
Label stack_overflow;
Generate_StackOverflowCheck(masm, r3, r8, &stack_overflow);
__ StackOverflowCheck(r3, r8, &stack_overflow);
// Copy arguments and receiver to the expression stack.
__ PushArray(r7, r3, r8, r0);
......@@ -406,7 +378,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
LoadStackLimit(masm, scratch, StackLimitKind::kRealStackLimit);
__ LoadStackLimit(scratch, StackLimitKind::kRealStackLimit);
__ cmpl(sp, scratch);
__ blt(&stack_overflow);
......@@ -703,28 +675,6 @@ void Builtins::Generate_JSRunMicrotasksEntry(MacroAssembler* masm) {
Builtins::kRunMicrotasksTrampoline);
}
// Clobbers scratch1 and scratch2; preserves all other registers.
static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
Register scratch1, Register scratch2) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
LoadStackLimit(masm, scratch1, StackLimitKind::kRealStackLimit);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ sub(scratch1, sp, scratch1);
// Check if the arguments will overflow the stack.
__ ShiftLeftImm(scratch2, argc, Operand(kSystemPointerSizeLog2));
__ cmp(scratch1, scratch2);
__ bgt(&okay); // Signed comparison.
// Out of stack space.
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&okay);
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from Generate_JS_Entry
......@@ -749,8 +699,16 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ Push(r5);
// Check if we have enough stack space to push all arguments.
Label enough_stack_space, stack_overflow;
__ addi(r3, r7, Operand(1));
Generate_CheckStackOverflow(masm, r3, r9, r0);
__ StackOverflowCheck(r3, r9, &stack_overflow);
__ b(&enough_stack_space);
__ bind(&stack_overflow);
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
__ bind(&enough_stack_space);
// Copy arguments to the stack in a loop.
// r4: function
......@@ -836,19 +794,36 @@ static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm,
OMIT_SMI_CHECK);
}
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) {
Register args_count = scratch;
// Get the arguments + receiver count.
__ LoadP(args_count,
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
Register scratch2) {
Register params_size = scratch1;
// Get the size of the formal parameters + receiver (in bytes).
__ LoadP(params_size,
MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
__ lwz(args_count,
FieldMemOperand(args_count, BytecodeArray::kParameterSizeOffset));
__ lwz(params_size,
FieldMemOperand(params_size, BytecodeArray::kParameterSizeOffset));
#ifdef V8_NO_ARGUMENTS_ADAPTOR
Register actual_params_size = scratch2;
// Compute the size of the actual parameters + receiver (in bytes).
__ LoadP(actual_params_size,
MemOperand(fp, StandardFrameConstants::kArgCOffset));
__ ShiftLeftImm(actual_params_size, actual_params_size,
Operand(kSystemPointerSizeLog2));
__ addi(actual_params_size, actual_params_size, Operand(kSystemPointerSize));
// If actual is bigger than formal, then we should use it to free up the stack
// arguments.
Label corrected_args_count;
__ cmp(params_size, actual_params_size);
__ bge(&corrected_args_count);
__ mr(params_size, actual_params_size);
__ bind(&corrected_args_count);
#endif
// Leave the frame (also dropping the register file).
__ LeaveFrame(StackFrame::INTERPRETED);
__ add(sp, sp, args_count);
__ add(sp, sp, params_size);
}
// Tail-call |function_id| if |actual_marker| == |expected_marker|
......@@ -1139,7 +1114,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
__ sub(r8, sp, r5);
LoadStackLimit(masm, r0, StackLimitKind::kRealStackLimit);
__ LoadStackLimit(r0, StackLimitKind::kRealStackLimit);
__ cmpl(r8, r0);
__ blt(&stack_overflow);
......@@ -1172,7 +1147,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Perform interrupt stack check.
// TODO(solanes): Merge with the real stack limit check above.
Label stack_check_interrupt, after_stack_check_interrupt;
LoadStackLimit(masm, r0, StackLimitKind::kInterruptStackLimit);
__ LoadStackLimit(r0, StackLimitKind::kInterruptStackLimit);
__ cmpl(sp, r0);
__ blt(&stack_check_interrupt);
__ bind(&after_stack_check_interrupt);
......@@ -1216,7 +1191,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ bind(&do_return);
// The return value is in r3.
LeaveInterpreterFrame(masm, r5);
LeaveInterpreterFrame(masm, r5, r7);
__ blr();
__ bind(&stack_check_interrupt);
......@@ -1308,7 +1283,7 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Calculate number of arguments (add one for receiver).
__ addi(r6, r3, Operand(1));
Generate_StackOverflowCheck(masm, r6, ip, &stack_overflow);
__ StackOverflowCheck(r6, ip, &stack_overflow);
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// Don't copy receiver. Argument count is correct.
......@@ -1358,7 +1333,7 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
// -----------------------------------
Label stack_overflow;
__ addi(r8, r3, Operand(1));
Generate_StackOverflowCheck(masm, r8, ip, &stack_overflow);
__ StackOverflowCheck(r8, ip, &stack_overflow);
if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// The spread argument should not be pushed.
......@@ -1923,7 +1898,7 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
// Check for stack overflow.
Label stack_overflow;
Generate_StackOverflowCheck(masm, r7, scratch, &stack_overflow);
__ StackOverflowCheck(r7, scratch, &stack_overflow);
// Move the arguments already in the stack,
// including the receiver and the return address.
......@@ -2003,6 +1978,12 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ bind(&new_target_constructor);
}
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// TODO(victorgomes): Remove this copy when all the arguments adaptor frame
// code is erased.
__ mr(r7, fp);
__ LoadP(r8, MemOperand(fp, StandardFrameConstants::kArgCOffset));
#else
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ LoadP(r7, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
......@@ -2028,6 +2009,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ SmiUntag(r8);
}
__ bind(&arguments_done);
#endif
Label stack_done, stack_overflow;
__ sub(r8, r8, r5, LeaveOE, SetRC);
......@@ -2044,7 +2026,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
// -----------------------------------
// Check for stack overflow.
Generate_StackOverflowCheck(masm, r8, scratch, &stack_overflow);
__ StackOverflowCheck(r8, scratch, &stack_overflow);
// Forward the arguments from the caller frame.
// Point to the first argument to copy (skipping the receiver).
......@@ -2236,7 +2218,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
{
LoadStackLimit(masm, scratch, StackLimitKind::kRealStackLimit);
__ LoadStackLimit(scratch, StackLimitKind::kRealStackLimit);
__ cmpl(r0, scratch);
}
__ bgt(&done); // Signed comparison.
......@@ -2484,7 +2466,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ bind(&over_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r5, r8, &stack_overflow);
__ StackOverflowCheck(r5, r8, &stack_overflow);
// Calculate copy start address into r3 and copy end address into r7.
// r3: actual number of arguments as a smi
......@@ -2520,7 +2502,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ bind(&under_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r5, r8, &stack_overflow);
__ StackOverflowCheck(r5, r8, &stack_overflow);
// Fill the remaining expected arguments with undefined.
// r0: actual number of arguments as a smi
......
......@@ -65,39 +65,6 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
enum StackLimitKind { kInterruptStackLimit, kRealStackLimit };
MemOperand StackLimitAsMemOperand(MacroAssembler* masm, StackLimitKind kind) {
DCHECK(masm->root_array_available());
Isolate* isolate = masm->isolate();
ExternalReference limit =
kind == StackLimitKind::kRealStackLimit
? ExternalReference::address_of_real_jslimit(isolate)
: ExternalReference::address_of_jslimit(isolate);
DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
intptr_t offset =
TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
CHECK(is_int32(offset));
return MemOperand(kRootRegister, offset);
}
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch, Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadP(scratch,
StackLimitAsMemOperand(masm, StackLimitKind::kRealStackLimit));
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ SubP(scratch, sp, scratch);
// Check if the arguments will overflow the stack.
__ ShiftLeftP(r0, num_args, Operand(kSystemPointerSizeLog2));
__ CmpP(scratch, r0);
__ ble(stack_overflow); // Signed comparison.
}
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : number of arguments
......@@ -111,7 +78,7 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
Register scratch = r4;
Label stack_overflow;
Generate_StackOverflowCheck(masm, r2, r7, &stack_overflow);
__ StackOverflowCheck(r2, scratch, &stack_overflow);
// Enter a construct frame.
{
......@@ -122,6 +89,11 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
__ Push(cp, r2);
__ SmiUntag(r2);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Set up pointer to last argument (skip receiver).
__ la(r6, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
......@@ -254,7 +226,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
__ SmiUntag(r2);
Label stack_overflow;
Generate_StackOverflowCheck(masm, r2, r7, &stack_overflow);
__ StackOverflowCheck(r2, r7, &stack_overflow);
// Copy arguments and receiver to the expression stack.
__ PushArray(r6, r2, r1, r0);
......@@ -398,8 +370,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ LoadP(scratch,
StackLimitAsMemOperand(masm, StackLimitKind::kRealStackLimit));
__ LoadP(scratch, __ StackLimitAsMemOperand(StackLimitKind::kRealStackLimit));
__ CmpLogicalP(sp, scratch);
__ blt(&stack_overflow);
......@@ -738,29 +709,6 @@ void Builtins::Generate_JSRunMicrotasksEntry(MacroAssembler* masm) {
Builtins::kRunMicrotasksTrampoline);
}
// Clobbers scratch1 and scratch2; preserves all other registers.
static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
Register scratch1, Register scratch2) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
__ LoadP(scratch1,
StackLimitAsMemOperand(masm, StackLimitKind::kRealStackLimit));
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ SubP(scratch1, sp, scratch1);
// Check if the arguments will overflow the stack.
__ ShiftLeftP(scratch2, argc, Operand(kSystemPointerSizeLog2));
__ CmpP(scratch1, scratch2);
__ bgt(&okay); // Signed comparison.
// Out of stack space.
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&okay);
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from Generate_JS_Entry
......@@ -797,8 +745,16 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ Push(r4);
// Check if we have enough stack space to push all arguments.
Label enough_stack_space, stack_overflow;
__ AddP(r7, r2, Operand(1));
Generate_CheckStackOverflow(masm, r7, r1, r0);
__ StackOverflowCheck(r7, r1, &stack_overflow);
__ b(&enough_stack_space);
__ bind(&stack_overflow);
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
__ bind(&enough_stack_space);
// Copy arguments to the stack in a loop from argv to sp.
// The arguments are actually placed in reverse order on sp
......@@ -894,19 +850,37 @@ static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm,
OMIT_SMI_CHECK);
}
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) {
Register args_count = scratch;
// Get the arguments + receiver count.
__ LoadP(args_count,
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
Register scratch2) {
Register params_size = scratch1;
// Get the size of the formal parameters + receiver (in bytes).
__ LoadP(params_size,
MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
__ LoadlW(args_count,
FieldMemOperand(args_count, BytecodeArray::kParameterSizeOffset));
__ LoadlW(params_size,
FieldMemOperand(params_size, BytecodeArray::kParameterSizeOffset));
#ifdef V8_NO_ARGUMENTS_ADAPTOR
Register actual_params_size = scratch2;
// Compute the size of the actual parameters + receiver (in bytes).
__ LoadP(actual_params_size,
MemOperand(fp, StandardFrameConstants::kArgCOffset));
__ ShiftLeftP(actual_params_size, actual_params_size,
Operand(kSystemPointerSizeLog2));
__ AddP(actual_params_size, actual_params_size, Operand(kSystemPointerSize));
// If actual is bigger than formal, then we should use it to free up the stack
// arguments.
Label corrected_args_count;
__ CmpP(params_size, actual_params_size);
__ bge(&corrected_args_count);
__ LoadRR(params_size, actual_params_size);
__ bind(&corrected_args_count);
#endif
// Leave the frame (also dropping the register file).
__ LeaveFrame(StackFrame::INTERPRETED);
__ AddP(sp, sp, args_count);
__ AddP(sp, sp, params_size);
}
// Tail-call |function_id| if |actual_marker| == |expected_marker|
......@@ -1190,8 +1164,8 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
__ SubP(r8, sp, r4);
__ CmpLogicalP(
r8, StackLimitAsMemOperand(masm, StackLimitKind::kRealStackLimit));
__ CmpLogicalP(r8,
__ StackLimitAsMemOperand(StackLimitKind::kRealStackLimit));
__ blt(&stack_overflow);
// If ok, push undefined as the initial value for all register file entries.
......@@ -1224,8 +1198,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Perform interrupt stack check.
// TODO(solanes): Merge with the real stack limit check above.
Label stack_check_interrupt, after_stack_check_interrupt;
__ LoadP(r0,
StackLimitAsMemOperand(masm, StackLimitKind::kInterruptStackLimit));
__ LoadP(r0, __ StackLimitAsMemOperand(StackLimitKind::kInterruptStackLimit));
__ CmpLogicalP(sp, r0);
__ blt(&stack_check_interrupt);
__ bind(&after_stack_check_interrupt);
......@@ -1270,7 +1243,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ bind(&do_return);
// The return value is in r2.
LeaveInterpreterFrame(masm, r4);
LeaveInterpreterFrame(masm, r4, r6);
__ Ret();
__ bind(&stack_check_interrupt);
......@@ -1361,7 +1334,7 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Calculate number of arguments (AddP one for receiver).
__ AddP(r5, r2, Operand(1));
Generate_StackOverflowCheck(masm, r5, ip, &stack_overflow);
__ StackOverflowCheck(r5, ip, &stack_overflow);
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// Don't copy receiver. Argument count is correct.
......@@ -1411,7 +1384,7 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
// -----------------------------------
Label stack_overflow;
__ AddP(r7, r2, Operand(1));
Generate_StackOverflowCheck(masm, r7, ip, &stack_overflow);
__ StackOverflowCheck(r7, ip, &stack_overflow);
if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// The spread argument should not be pushed.
......@@ -1977,7 +1950,7 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
// Check for stack overflow.
Label stack_overflow;
Generate_StackOverflowCheck(masm, r6, scratch, &stack_overflow);
__ StackOverflowCheck(r6, scratch, &stack_overflow);
// Move the arguments already in the stack,
// including the receiver and the return address.
......@@ -2061,6 +2034,12 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ bind(&new_target_constructor);
}
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// TODO(victorgomes): Remove this copy when all the arguments adaptor frame
// code is erased.
__ LoadRR(r6, fp);
__ LoadP(r7, MemOperand(fp, StandardFrameConstants::kArgCOffset));
#else
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
......@@ -2086,6 +2065,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ SmiUntag(r7);
}
__ bind(&arguments_done);
#endif
Label stack_done, stack_overflow;
__ SubP(r7, r7, r4);
......@@ -2102,7 +2082,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
// -----------------------------------
// Check for stack overflow.
Generate_StackOverflowCheck(masm, r7, scratch, &stack_overflow);
__ StackOverflowCheck(r7, scratch, &stack_overflow);
// Forward the arguments from the caller frame.
__ LoadRR(r5, r5);
......@@ -2300,7 +2280,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
__ CmpLogicalP(
r1, StackLimitAsMemOperand(masm, StackLimitKind::kRealStackLimit));
r1, __ StackLimitAsMemOperand(StackLimitKind::kRealStackLimit));
__ bgt(&done); // Signed comparison.
// Restore the stack pointer.
{
......@@ -2545,7 +2525,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ bind(&over_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r4, r7, &stack_overflow);
__ StackOverflowCheck(r4, r7, &stack_overflow);
// Calculate copy start address into r2 and copy end address into r6.
// r2: actual number of arguments as a smi
......@@ -2581,7 +2561,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ bind(&under_application);
{
EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r4, r7, &stack_overflow);
__ StackOverflowCheck(r4, r7, &stack_overflow);
// Fill the remaining expected arguments with undefined.
// r0: actual number of arguments as a smi
......
......@@ -1340,27 +1340,105 @@ void TurboAssembler::PrepareForTailCall(Register callee_args_count,
mr(sp, dst_reg);
}
void MacroAssembler::LoadStackLimit(Register destination, StackLimitKind kind) {
DCHECK(root_array_available());
Isolate* isolate = this->isolate();
ExternalReference limit =
kind == StackLimitKind::kRealStackLimit
? ExternalReference::address_of_real_jslimit(isolate)
: ExternalReference::address_of_jslimit(isolate);
DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
intptr_t offset =
TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
CHECK(is_int32(offset));
LoadP(destination, MemOperand(kRootRegister, offset), r0);
}
void MacroAssembler::StackOverflowCheck(Register num_args, Register scratch,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
LoadStackLimit(scratch, StackLimitKind::kRealStackLimit);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
sub(scratch, sp, scratch);
// Check if the arguments will overflow the stack.
ShiftLeftImm(r0, num_args, Operand(kSystemPointerSizeLog2));
cmp(scratch, r0);
ble(stack_overflow); // Signed comparison.
}
void MacroAssembler::InvokePrologue(Register expected_parameter_count,
Register actual_parameter_count,
Label* done, InvokeFlag flag) {
Label regular_invoke;
// Check whether the expected and actual arguments count match. If not,
// setup registers according to contract with ArgumentsAdaptorTrampoline:
// r3: actual arguments count
// r4: function (passed through to callee)
// r5: expected arguments count
// The code below is made a lot easier because the calling code already sets
// up actual and expected registers according to the contract if values are
// passed in registers.
DCHECK_EQ(actual_parameter_count, r3);
DCHECK_EQ(expected_parameter_count, r5);
// The code below is made a lot easier because the calling code already sets
// up actual and expected registers according to the contract.
// ARM has some checks as per below, considering add them for PPC
// DCHECK_EQ(actual_parameter_count, r3);
// DCHECK_EQ(expected_parameter_count, r5);
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// If the expected parameter count is equal to the adaptor sentinel, no need
// to push undefined value as arguments.
mov(r0, Operand(kDontAdaptArgumentsSentinel));
cmp(expected_parameter_count, r0);
beq(&regular_invoke);
// If overapplication or if the actual argument count is equal to the
// formal parameter count, no need to push extra undefined values.
sub(expected_parameter_count, expected_parameter_count,
actual_parameter_count, LeaveOE, SetRC);
ble(&regular_invoke, cr0);
Label stack_overflow;
Register scratch = r7;
StackOverflowCheck(expected_parameter_count, scratch, &stack_overflow);
// Underapplication. Move the arguments already in the stack, including the
// receiver and the return address.
{
Label copy;
Register src = r9, dest = r8;
addi(src, sp, Operand(-kSystemPointerSize));
ShiftLeftImm(r0, expected_parameter_count, Operand(kSystemPointerSizeLog2));
sub(sp, sp, r0);
// Update stack pointer.
addi(dest, sp, Operand(-kSystemPointerSize));
addi(r0, actual_parameter_count, Operand(1));
mtctr(r0);
bind(&copy);
LoadPU(r0, MemOperand(src, kSystemPointerSize));
StorePU(r0, MemOperand(dest, kSystemPointerSize));
bdnz(&copy);
}
// Fill remaining expected arguments with undefined values.
LoadRoot(scratch, RootIndex::kUndefinedValue);
{
mtctr(expected_parameter_count);
Label loop;
bind(&loop);
StorePU(scratch, MemOperand(r8, kSystemPointerSize));
bdnz(&loop);
}
b(&regular_invoke);
bind(&stack_overflow);
{
FrameScope frame(this, StackFrame::MANUAL);
CallRuntime(Runtime::kThrowStackOverflow);
bkpt(0);
}
#else
// Check whether the expected and actual arguments count match. If not,
// setup registers according to contract with ArgumentsAdaptorTrampoline.
cmp(expected_parameter_count, actual_parameter_count);
beq(&regular_invoke);
......@@ -1371,7 +1449,8 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);
}
bind(&regular_invoke);
#endif
bind(&regular_invoke);
}
void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
......
......@@ -18,6 +18,8 @@
namespace v8 {
namespace internal {
enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit };
// ----------------------------------------------------------------------------
// Static helper functions
......@@ -947,6 +949,13 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
Register scratch2);
// ---------------------------------------------------------------------------
// Stack limit utilities
void StackOverflowCheck(Register num_args, Register scratch,
Label* stack_overflow);
void LoadStackLimit(Register destination, StackLimitKind kind);
// ---------------------------------------------------------------------------
// Smi utilities
......
......@@ -1359,23 +1359,108 @@ void TurboAssembler::PrepareForTailCall(Register callee_args_count,
LoadRR(sp, dst_reg);
}
MemOperand MacroAssembler::StackLimitAsMemOperand(StackLimitKind kind) {
DCHECK(root_array_available());
Isolate* isolate = this->isolate();
ExternalReference limit =
kind == StackLimitKind::kRealStackLimit
? ExternalReference::address_of_real_jslimit(isolate)
: ExternalReference::address_of_jslimit(isolate);
DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
intptr_t offset =
TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
CHECK(is_int32(offset));
return MemOperand(kRootRegister, offset);
}
void MacroAssembler::StackOverflowCheck(Register num_args, Register scratch,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
LoadP(scratch, StackLimitAsMemOperand(StackLimitKind::kRealStackLimit));
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
SubP(scratch, sp, scratch);
// Check if the arguments will overflow the stack.
ShiftLeftP(r0, num_args, Operand(kSystemPointerSizeLog2));
CmpP(scratch, r0);
ble(stack_overflow); // Signed comparison.
}
void MacroAssembler::InvokePrologue(Register expected_parameter_count,
Register actual_parameter_count,
Label* done, InvokeFlag flag) {
Label regular_invoke;
// Check whether the expected and actual arguments count match. If not,
// setup registers according to contract with ArgumentsAdaptorTrampoline:
// r2: actual arguments count
// r3: function (passed through to callee)
// r4: expected arguments count
// The code below is made a lot easier because the calling code already sets
// up actual and expected registers according to the contract.
// ARM has some checks as per below, considering add them for S390
DCHECK_EQ(actual_parameter_count, r2);
DCHECK_EQ(expected_parameter_count, r4);
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// If the expected parameter count is equal to the adaptor sentinel, no need
// to push undefined value as arguments.
CmpP(expected_parameter_count, Operand(kDontAdaptArgumentsSentinel));
beq(&regular_invoke);
// If overapplication or if the actual argument count is equal to the
// formal parameter count, no need to push extra undefined values.
SubP(expected_parameter_count, expected_parameter_count,
actual_parameter_count);
ble(&regular_invoke);
Label stack_overflow;
Register scratch = r6;
StackOverflowCheck(expected_parameter_count, scratch, &stack_overflow);
// Underapplication. Move the arguments already in the stack, including the
// receiver and the return address.
{
Label copy, check;
Register num = r7, src = r8, dest = ip; // r7 and r8 are context and root.
LoadRR(src, sp);
// Update stack pointer.
ShiftLeftP(scratch, expected_parameter_count,
Operand(kSystemPointerSizeLog2));
SubP(sp, sp, scratch);
LoadRR(dest, sp);
ltgr(num, actual_parameter_count);
b(&check);
bind(&copy);
LoadP(r0, MemOperand(src));
lay(src, MemOperand(src, kSystemPointerSize));
StoreP(r0, MemOperand(dest));
lay(dest, MemOperand(dest, kSystemPointerSize));
SubP(num, num, Operand(1));
bind(&check);
b(ge, &copy);
}
// Fill remaining expected arguments with undefined values.
LoadRoot(scratch, RootIndex::kUndefinedValue);
{
Label loop;
bind(&loop);
StoreP(scratch, MemOperand(ip));
lay(ip, MemOperand(ip, kSystemPointerSize));
SubP(expected_parameter_count, expected_parameter_count, Operand(1));
bgt(&loop);
}
b(&regular_invoke);
bind(&stack_overflow);
{
FrameScope frame(this, StackFrame::MANUAL);
CallRuntime(Runtime::kThrowStackOverflow);
bkpt(0);
}
#else
// Check whether the expected and actual arguments count match. If not,
// setup registers according to contract with ArgumentsAdaptorTrampoline.
CmpP(expected_parameter_count, actual_parameter_count);
beq(&regular_invoke);
......@@ -1386,7 +1471,8 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);
}
bind(&regular_invoke);
#endif
bind(&regular_invoke);
}
void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
......
......@@ -17,6 +17,8 @@
namespace v8 {
namespace internal {
enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit };
// ----------------------------------------------------------------------------
// Static helper functions
......@@ -1174,6 +1176,14 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
Register scratch2);
void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
Register scratch2);
// ---------------------------------------------------------------------------
// Stack limit utilities
MemOperand StackLimitAsMemOperand(StackLimitKind kind);
void StackOverflowCheck(Register num_args, Register scratch,
Label* stack_overflow);
// ---------------------------------------------------------------------------
// JavaScript invokes
......
......@@ -3805,9 +3805,8 @@ void CodeGenerator::AssembleConstructFrame() {
}
}
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
auto call_descriptor = linkage()->GetIncomingDescriptor();
int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
const int returns = frame()->GetReturnSlotCount();
if (returns != 0) {
......@@ -3829,36 +3828,83 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
if (double_saves != 0) {
__ MultiPopDoubles(double_saves);
}
PPCOperandConverter g(this, nullptr);
unwinding_info_writer_.MarkBlockWillExit();
// We might need r6 for scratch.
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & r6.bit());
PPCOperandConverter g(this, nullptr);
const int parameter_count =
static_cast<int>(call_descriptor->StackParameterCount());
// {aditional_pop_count} is only greater than zero if {parameter_count = 0}.
// Check RawMachineAssembler::PopAndReturn.
if (parameter_count != 0) {
if (additional_pop_count->IsImmediate()) {
DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
} else if (__ emit_debug_code()) {
__ cmpi(g.ToRegister(additional_pop_count), Operand(0));
__ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue);
}
}
Register argc_reg = r6;
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// Functions with JS linkage have at least one parameter (the receiver).
// If {parameter_count} == 0, it means it is a builtin with
// kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
// itself.
const bool drop_jsargs = frame_access_state()->has_frame() &&
call_descriptor->IsJSFunctionCall() &&
parameter_count != 0;
#else
const bool drop_jsargs = false;
#endif
if (call_descriptor->IsCFunctionCall()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now unless they have an variable
// number of stack slot pops
if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
if (additional_pop_count->IsImmediate() &&
g.ToConstant(additional_pop_count).ToInt32() == 0) {
if (return_label_.is_bound()) {
__ b(&return_label_);
return;
} else {
__ bind(&return_label_);
AssembleDeconstructFrame();
}
} else {
AssembleDeconstructFrame();
}
if (drop_jsargs) {
// Get the actual argument count.
__ LoadP(argc_reg, MemOperand(fp, StandardFrameConstants::kArgCOffset));
}
AssembleDeconstructFrame();
}
// Constant pool is unavailable since the frame has been destructed
ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
if (pop->IsImmediate()) {
DCHECK(Constant::kInt32 == g.ToConstant(pop).type() ||
Constant::kInt64 == g.ToConstant(pop).type());
pop_count += g.ToConstant(pop).ToInt32();
if (drop_jsargs) {
// We must pop all arguments from the stack (including the receiver). This
// number of arguments is given by max(1 + argc_reg, parameter_count).
__ addi(argc_reg, argc_reg, Operand(1)); // Also pop the receiver.
if (parameter_count > 1) {
Label skip;
__ cmpi(argc_reg, Operand(parameter_count));
__ bgt(&skip);
__ mov(argc_reg, Operand(parameter_count));
__ bind(&skip);
}
__ Drop(argc_reg);
} else if (additional_pop_count->IsImmediate()) {
DCHECK_EQ(Constant::kInt32, g.ToConstant(additional_pop_count).type());
int additional_count = g.ToConstant(additional_pop_count).ToInt32();
__ Drop(parameter_count + additional_count);
} else if (parameter_count == 0) {
__ Drop(g.ToRegister(additional_pop_count));
} else {
__ Drop(g.ToRegister(pop));
// {additional_pop_count} is guaranteed to be zero if {parameter_count !=
// 0}. Check RawMachineAssembler::PopAndReturn.
__ Drop(parameter_count);
}
__ Drop(pop_count);
__ Ret();
}
......
......@@ -4696,9 +4696,8 @@ void CodeGenerator::AssembleConstructFrame() {
}
}
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
auto call_descriptor = linkage()->GetIncomingDescriptor();
int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
const int returns = frame()->GetReturnSlotCount();
if (returns != 0) {
......@@ -4720,30 +4719,78 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
unwinding_info_writer_.MarkBlockWillExit();
// We might need r3 for scratch.
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & r5.bit());
S390OperandConverter g(this, nullptr);
const int parameter_count =
static_cast<int>(call_descriptor->StackParameterCount());
// {aditional_pop_count} is only greater than zero if {parameter_count = 0}.
// Check RawMachineAssembler::PopAndReturn.
if (parameter_count != 0) {
if (additional_pop_count->IsImmediate()) {
DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
} else if (__ emit_debug_code()) {
__ CmpP(g.ToRegister(additional_pop_count), Operand(0));
__ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue);
}
}
Register argc_reg = r5;
#ifdef V8_NO_ARGUMENTS_ADAPTOR
// Functions with JS linkage have at least one parameter (the receiver).
// If {parameter_count} == 0, it means it is a builtin with
// kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
// itself.
const bool drop_jsargs = frame_access_state()->has_frame() &&
call_descriptor->IsJSFunctionCall() &&
parameter_count != 0;
#else
const bool drop_jsargs = false;
#endif
if (call_descriptor->IsCFunctionCall()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now unless they have an variable
// number of stack slot pops
if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
if (additional_pop_count->IsImmediate() &&
g.ToConstant(additional_pop_count).ToInt32() == 0) {
if (return_label_.is_bound()) {
__ b(&return_label_);
return;
} else {
__ bind(&return_label_);
AssembleDeconstructFrame();
}
} else {
AssembleDeconstructFrame();
}
if (drop_jsargs) {
// Get the actual argument count.
__ LoadP(argc_reg, MemOperand(fp, StandardFrameConstants::kArgCOffset));
}
AssembleDeconstructFrame();
}
if (pop->IsImmediate()) {
pop_count += g.ToConstant(pop).ToInt32();
if (drop_jsargs) {
// We must pop all arguments from the stack (including the receiver). This
// number of arguments is given by max(1 + argc_reg, parameter_count).
__ AddP(argc_reg, argc_reg, Operand(1)); // Also pop the receiver.
if (parameter_count > 1) {
Label skip;
__ CmpP(argc_reg, Operand(parameter_count));
__ bgt(&skip);
__ mov(argc_reg, Operand(parameter_count));
__ bind(&skip);
}
__ Drop(argc_reg);
} else if (additional_pop_count->IsImmediate()) {
int additional_count = g.ToConstant(additional_pop_count).ToInt32();
__ Drop(parameter_count + additional_count);
} else if (parameter_count == 0) {
__ Drop(g.ToRegister(additional_pop_count));
} else {
__ Drop(g.ToRegister(pop));
// {additional_pop_count} is guaranteed to be zero if {parameter_count !=
// 0}. Check RawMachineAssembler::PopAndReturn.
__ Drop(parameter_count);
}
__ Drop(pop_count);
__ Ret();
}
......
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