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
This diff is collapsed.
This diff is collapsed.
......@@ -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