Commit 48d726cd authored by jacob.bramley's avatar jacob.bramley Committed by Commit bot

Reland r21101: "ARM64: use jssp for stack slots"

The original implementation assumed that LPushArguments and
LInvoke/Call* could be assumed to be exclusively sequential. However,
this isn't always the case. For example, GenerateCallFunction pushes
some arguments and then selects between HInvokeFunction and
HCallFunction.

This fixed implementation resets a pushed_arguments_ counter based on
the argument_count() of the preceeding basic block, then tracks it
per-instruction as before (except that now we maintain a count rather
than a boolean flag).

At the same time, since we now track exactly how many arguments have
been pushed onto the stack, I was able to adjust the offset accordingly
and use jssp for stack slots even when arguments have been pushed.

BUG=

Review URL: https://codereview.chromium.org/1038363002

Cr-Commit-Position: refs/heads/master@{#29249}
parent c019d7f4
......@@ -387,6 +387,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
CallFunctionStub stub(isolate(), arity, flags);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
......@@ -401,6 +402,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
DCHECK(ToRegister(instr->result()).is(x0));
}
......@@ -456,6 +458,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
DCHECK(ToRegister(instr->result()).is(x0));
}
......@@ -477,7 +480,7 @@ void LCodeGen::LoadContextFromDeferred(LOperand* context) {
if (context->IsRegister()) {
__ Mov(cp, ToRegister(context));
} else if (context->IsStackSlot()) {
__ Ldr(cp, ToMemOperand(context));
__ Ldr(cp, ToMemOperand(context, kMustUseFramePointer));
} else if (context->IsConstantOperand()) {
HConstant* constant =
chunk_->LookupConstant(LConstantOperand::cast(context));
......@@ -1230,13 +1233,37 @@ static int64_t ArgumentsOffsetWithoutFrame(int index) {
}
MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
MemOperand LCodeGen::ToMemOperand(LOperand* op, StackMode stack_mode) const {
DCHECK(op != NULL);
DCHECK(!op->IsRegister());
DCHECK(!op->IsDoubleRegister());
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
if (NeedsEagerFrame()) {
return MemOperand(fp, StackSlotOffset(op->index()));
int fp_offset = StackSlotOffset(op->index());
// Loads and stores have a bigger reach in positive offset than negative.
// We try to access using jssp (positive offset) first, then fall back to
// fp (negative offset) if that fails.
//
// We can reference a stack slot from jssp only if we know how much we've
// put on the stack. We don't know this in the following cases:
// - stack_mode != kCanUseStackPointer: this is the case when deferred
// code has saved the registers.
// - saves_caller_doubles(): some double registers have been pushed, jssp
// references the end of the double registers and not the end of the stack
// slots.
// In both of the cases above, we _could_ add the tracking information
// required so that we can use jssp here, but in practice it isn't worth it.
if ((stack_mode == kCanUseStackPointer) &&
!info()->saves_caller_doubles()) {
int jssp_offset_to_fp =
StandardFrameConstants::kFixedFrameSizeFromFp +
(pushed_arguments_ + GetStackSlotCount()) * kPointerSize;
int jssp_offset = fp_offset + jssp_offset_to_fp;
if (masm()->IsImmLSScaled(jssp_offset, LSDoubleWord)) {
return MemOperand(masm()->StackPointer(), jssp_offset);
}
}
return MemOperand(fp, fp_offset);
} else {
// Retrieve parameter without eager stack-frame relative to the
// stack-pointer.
......@@ -2011,6 +2038,8 @@ void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
}
generator.AfterCall();
}
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
......@@ -2030,11 +2059,13 @@ void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
__ Call(x10);
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
CallRuntime(instr->function(), instr->arity(), instr);
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
......@@ -2060,6 +2091,7 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
default:
UNREACHABLE();
}
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
......@@ -3118,6 +3150,7 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
instr->hydrogen()->formal_parameter_count(),
instr->arity(), instr);
}
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
}
......@@ -3231,6 +3264,16 @@ void LCodeGen::DoLabel(LLabel* label) {
label->block_id(),
LabelType(label));
// Inherit pushed_arguments_ from the predecessor's argument count.
if (label->block()->HasPredecessor()) {
pushed_arguments_ = label->block()->predecessors()->at(0)->argument_count();
#ifdef DEBUG
for (auto p : *label->block()->predecessors()) {
DCHECK_EQ(p->argument_count(), pushed_arguments_);
}
#endif
}
__ Bind(label->label());
current_block_ = label->block_id();
DoGap(label);
......@@ -4671,6 +4714,8 @@ void LCodeGen::DoPushArguments(LPushArguments* instr) {
// The preamble was done by LPreparePushArguments.
args.PushQueued(MacroAssembler::PushPopQueue::SKIP_PREAMBLE);
RecordPushedArgumentsDelta(instr->ArgumentCount());
}
......
......@@ -36,7 +36,8 @@ class LCodeGen: public LCodeGenBase {
frame_is_built_(false),
safepoints_(info->zone()),
resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) {
expected_safepoint_kind_(Safepoint::kSimple),
pushed_arguments_(0) {
PopulateDeoptimizationLiteralsWithInlinedFunctions();
}
......@@ -80,7 +81,9 @@ class LCodeGen: public LCodeGenBase {
Register ToRegister32(LOperand* op) const;
Operand ToOperand(LOperand* op);
Operand ToOperand32(LOperand* op);
MemOperand ToMemOperand(LOperand* op) const;
enum StackMode { kMustUseFramePointer, kCanUseStackPointer };
MemOperand ToMemOperand(LOperand* op,
StackMode stack_mode = kCanUseStackPointer) const;
Handle<Object> ToHandle(LConstantOperand* op) const;
template <class LI>
......@@ -356,6 +359,15 @@ class LCodeGen: public LCodeGenBase {
Safepoint::Kind expected_safepoint_kind_;
// The number of arguments pushed onto the stack, either by this block or by a
// predecessor.
int pushed_arguments_;
void RecordPushedArgumentsDelta(int delta) {
pushed_arguments_ += delta;
DCHECK(pushed_arguments_ >= 0);
}
int old_position_;
class PushSafepointRegistersScope BASE_EMBEDDED {
......
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