Commit 89a7341d authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Pass key and receiver in registers for keyed load IC on ARM

The calling convention for keyed load IC's on ARM now passes the key and receiver in registers r0 and r1.

The code path in the ARM full compiler for handling keyed property load now has the same structure as for ia32 where the keyed load IC is also called with key end receiver in registers.

This change have been tested with an exhaustive combinations of the flags

  --special-command="@ --nofull-compiler"
  --special-command="@ --always-full-compiler"
  --special-command="@ --noenable-vfp3"

to the test runner.
Review URL: http://codereview.chromium.org/2024002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4608 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9c7f6267
......@@ -3473,7 +3473,8 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
if (node->is_compound()) {
// For a compound assignment the right-hand side is a binary operation
// between the current property value and the actual right-hand side.
// Load of the current value leaves receiver and key on the stack.
// Duplicate receiver and key for loading the current property value.
frame_->Dup2();
EmitKeyedLoad();
frame_->EmitPush(r0);
......@@ -3767,19 +3768,23 @@ void CodeGenerator::VisitCall(Call* node) {
// -------------------------------------------
LoadAndSpill(property->obj());
if (!property->is_synthetic()) {
// Duplicate receiver for later use.
__ ldr(r0, MemOperand(sp, 0));
frame_->EmitPush(r0);
}
LoadAndSpill(property->key());
EmitKeyedLoad();
frame_->Drop(); // key
// Put the function below the receiver.
if (property->is_synthetic()) {
// Use the global receiver.
frame_->Drop();
frame_->EmitPush(r0);
frame_->EmitPush(r0); // Function.
LoadGlobalReceiver(r0);
} else {
frame_->EmitPop(r1); // receiver
frame_->EmitPush(r0); // function
frame_->EmitPush(r1); // receiver
// Switch receiver and function.
frame_->EmitPop(r1); // Receiver.
frame_->EmitPush(r0); // Function.
frame_->EmitPush(r1); // Receiver.
}
// Call the function.
......@@ -5388,8 +5393,7 @@ void DeferredReferenceGetKeyedValue::Generate() {
// The rest of the instructions in the deferred code must be together.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
// Call keyed load IC. It has all arguments on the stack and the key in r0.
__ ldr(r0, MemOperand(sp, 0));
// Call keyed load IC. It has the arguments key and receiver in r0 and r1.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
......@@ -5522,12 +5526,13 @@ void CodeGenerator::EmitKeyedLoad() {
__ IncrementCounter(&Counters::keyed_load_inline, 1,
frame_->scratch0(), frame_->scratch1());
// Load the receiver and key from the stack.
frame_->SpillAllButCopyTOSToR1R0();
// Load the key and receiver from the stack to r0 and r1.
frame_->PopToR1R0();
Register receiver = r0;
Register key = r1;
VirtualFrame::SpilledScope spilled(frame_);
// The deferred code expects key and receiver in r0 and r1.
DeferredReferenceGetKeyedValue* deferred =
new DeferredReferenceGetKeyedValue();
......@@ -5721,6 +5726,9 @@ void Reference::GetValue() {
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
break;
}
......@@ -5730,23 +5738,26 @@ void Reference::GetValue() {
ASSERT(!is_global || var->is_global());
cgen_->EmitNamedLoad(GetName(), is_global);
cgen_->frame()->EmitPush(r0);
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
break;
}
case KEYED: {
if (persist_after_get_) {
cgen_->frame()->Dup2();
}
ASSERT(property != NULL);
cgen_->EmitKeyedLoad();
cgen_->frame()->EmitPush(r0);
if (!persist_after_get_) set_unloaded();
break;
}
default:
UNREACHABLE();
}
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
}
......
......@@ -738,15 +738,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
// Load the key.
__ mov(r0, Operand(key_literal->handle()));
// Push both as arguments to ic.
__ Push(r1, r0);
// Call keyed load IC. It has all arguments on the stack and the key in r0.
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC, and push the result.
DropAndApply(2, context, r0);
Apply(context, r0);
}
}
......@@ -935,8 +930,16 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
}
break;
case KEYED_PROPERTY:
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
// We need the key and receiver on both the stack and in r0 and r1.
if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator);
__ ldr(r1, MemOperand(sp, 0));
__ push(r0);
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
}
break;
}
......@@ -1005,8 +1008,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
// Call keyed load IC. It has all arguments on the stack and the key in r0.
__ ldr(r0, MemOperand(sp, 0));
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
}
......@@ -1171,10 +1173,10 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
// Drop receiver left on the stack by IC.
DropAndApply(1, context_, r0);
} else {
VisitForValue(expr->key(), kStack);
VisitForValue(expr->key(), kAccumulator);
__ pop(r1);
EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
DropAndApply(2, context_, r0);
Apply(context_, r0);
}
}
......@@ -1246,24 +1248,31 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a keyed property, use keyed load IC followed by function
// call.
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
VisitForValue(prop->key(), kAccumulator);
// Record source code position for IC call.
SetSourcePosition(prop->position());
// Call keyed load IC. It has all arguments on the stack and the key in
// r0.
__ ldr(r0, MemOperand(sp, 0));
if (prop->is_synthetic()) {
__ pop(r1); // We do not need to keep the receiver.
} else {
__ ldr(r1, MemOperand(sp, 0)); // Keep receiver, to call function on.
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Load receiver object into r1.
if (prop->is_synthetic()) {
// Push result (function).
__ push(r0);
// Push Global receiver.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ push(r1);
} else {
__ ldr(r1, MemOperand(sp, kPointerSize));
// Pop receiver.
__ pop(r1);
// Push result (function).
__ push(r0);
__ push(r1);
}
// Overwrite (object, key) with (function, receiver).
__ str(r0, MemOperand(sp, kPointerSize));
__ str(r1, MemOperand(sp));
EmitCallWithStub(expr);
}
} else {
......@@ -1552,7 +1561,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
if (assign_type == NAMED_PROPERTY) {
EmitNamedPropertyLoad(prop);
} else {
VisitForValue(prop->key(), kStack);
VisitForValue(prop->key(), kAccumulator);
__ ldr(r1, MemOperand(sp, 0));
__ push(r0);
EmitKeyedPropertyLoad(prop);
}
}
......
This diff is collapsed.
......@@ -284,7 +284,9 @@ class MacroAssembler: public Assembler {
// Allocate an object in new space. The object_size is specified in words (not
// bytes). If the new space is exhausted control continues at the gc_required
// label. The allocated object is returned in result. If the flag
// tag_allocated_object is true the result is tagged as as a heap object.
// tag_allocated_object is true the result is tagged as as a heap object. All
// registers are clobbered also when control continues at the gc_required
// label.
void AllocateInNewSpace(int object_size,
Register result,
Register scratch1,
......@@ -328,8 +330,9 @@ class MacroAssembler: public Assembler {
Register scratch2,
Label* gc_required);
// Allocates a heap number or jumps to the need_gc label if the young space
// is full and a scavenge is needed.
// Allocates a heap number or jumps to the gc_required label if the young
// space is full and a scavenge is needed. All registers are clobbered also
// when control continues at the gc_required label.
void AllocateHeapNumber(Register result,
Register scratch1,
Register scratch2,
......
......@@ -1813,8 +1813,7 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
......@@ -1822,7 +1821,6 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1838,8 +1836,7 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
......@@ -1848,7 +1845,6 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
__ b(ne, &miss);
Failure* failure = Failure::InternalError();
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
callback, name, &miss, &failure);
if (!success) return failure;
......@@ -1867,8 +1863,7 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
......@@ -1876,7 +1871,6 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1892,8 +1886,7 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
......@@ -1903,7 +1896,6 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
LookupResult lookup;
LookupPostInterceptor(holder, name, &lookup);
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
GenerateLoadInterceptor(receiver,
holder,
&lookup,
......@@ -1924,8 +1916,7 @@ Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
......@@ -1933,7 +1924,6 @@ Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
GenerateLoadArrayLength(masm(), r1, r2, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1946,8 +1936,7 @@ Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
......@@ -1956,7 +1945,6 @@ Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
__ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
......@@ -1972,8 +1960,7 @@ Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- sp[0] : key
// -- sp[4] : receiver
// -- r1 : receiver
// -----------------------------------
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......
......@@ -323,7 +323,8 @@ void VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
void VirtualFrame::CallKeyedLoadIC() {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
SpillAllButCopyTOSToR0();
PopToR1R0();
SpillAll();
CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
}
......@@ -532,6 +533,47 @@ void VirtualFrame::Dup() {
}
void VirtualFrame::Dup2() {
if (SpilledScope::is_spilled()) {
__ ldr(ip, MemOperand(sp, kPointerSize));
EmitPush(ip);
__ ldr(ip, MemOperand(sp, kPointerSize));
EmitPush(ip);
} else {
switch (top_of_stack_state_) {
case NO_TOS_REGISTERS:
__ ldr(r0, MemOperand(sp, 0));
__ ldr(r1, MemOperand(sp, kPointerSize));
top_of_stack_state_ = R0_R1_TOS;
break;
case R0_TOS:
__ push(r0);
__ ldr(r1, MemOperand(sp, kPointerSize));
top_of_stack_state_ = R0_R1_TOS;
break;
case R1_TOS:
__ push(r1);
__ ldr(r0, MemOperand(sp, kPointerSize));
top_of_stack_state_ = R1_R0_TOS;
break;
case R0_R1_TOS:
__ push(r1);
__ push(r0);
top_of_stack_state_ = R0_R1_TOS;
break;
case R1_R0_TOS:
__ push(r0);
__ push(r1);
top_of_stack_state_ = R1_R0_TOS;
break;
default:
UNREACHABLE();
}
}
element_count_ += 2;
}
Register VirtualFrame::PopToRegister(Register but_not_to_this_one) {
ASSERT(but_not_to_this_one.is(r0) ||
but_not_to_this_one.is(r1) ||
......
......@@ -316,8 +316,8 @@ class VirtualFrame : public ZoneObject {
// Result is returned in r0.
void CallStoreIC(Handle<String> name, bool is_contextual);
// Call keyed load IC. Key and receiver are on the stack. Result is returned
// in r0.
// Call keyed load IC. Key and receiver are on the stack. Both are consumed.
// Result is returned in r0.
void CallKeyedLoadIC();
// Call keyed store IC. Key and receiver are on the stack and the value is in
......@@ -355,6 +355,9 @@ class VirtualFrame : public ZoneObject {
// Duplicate the top of stack.
void Dup();
// Duplicate the two elements on top of stack.
void Dup2();
// Flushes all registers, but it puts a copy of the top-of-stack in r0.
void SpillAllButCopyTOSToR0();
......
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