Commit e90d8314 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

ARM: Don't require the receiver on the stack for load IC

Previously the receier was passed in both r0 and on the stack for a load IC. With this change the receiver is in r0 only.
Review URL: http://codereview.chromium.org/2119007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4681 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 20971120
...@@ -1370,6 +1370,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, ...@@ -1370,6 +1370,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// give us a megamorphic load site. Not super, but it works. // give us a megamorphic load site. Not super, but it works.
LoadAndSpill(applicand); LoadAndSpill(applicand);
Handle<String> name = Factory::LookupAsciiSymbol("apply"); Handle<String> name = Factory::LookupAsciiSymbol("apply");
frame_->Dup();
frame_->CallLoadIC(name, RelocInfo::CODE_TARGET); frame_->CallLoadIC(name, RelocInfo::CODE_TARGET);
frame_->EmitPush(r0); frame_->EmitPush(r0);
...@@ -3009,8 +3010,6 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, ...@@ -3009,8 +3010,6 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
typeof_state == INSIDE_TYPEOF typeof_state == INSIDE_TYPEOF
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT); : RelocInfo::CODE_TARGET_CONTEXT);
// Drop the global object. The result is in r0.
frame_->Drop();
} }
...@@ -3424,7 +3423,6 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { ...@@ -3424,7 +3423,6 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
frame_->Dup(); frame_->Dup();
} }
EmitNamedLoad(name, var != NULL); EmitNamedLoad(name, var != NULL);
frame_->Drop(); // Receiver is left on the stack.
frame_->EmitPush(r0); frame_->EmitPush(r0);
// Perform the binary operation. // Perform the binary operation.
...@@ -5430,26 +5428,30 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { ...@@ -5430,26 +5428,30 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
class DeferredReferenceGetNamedValue: public DeferredCode { class DeferredReferenceGetNamedValue: public DeferredCode {
public: public:
explicit DeferredReferenceGetNamedValue(Handle<String> name) : name_(name) { explicit DeferredReferenceGetNamedValue(Register receiver,
Handle<String> name)
: receiver_(receiver), name_(name) {
set_comment("[ DeferredReferenceGetNamedValue"); set_comment("[ DeferredReferenceGetNamedValue");
} }
virtual void Generate(); virtual void Generate();
private: private:
Register receiver_;
Handle<String> name_; Handle<String> name_;
}; };
void DeferredReferenceGetNamedValue::Generate() { void DeferredReferenceGetNamedValue::Generate() {
ASSERT(receiver_.is(r0) || receiver_.is(r1));
Register scratch1 = VirtualFrame::scratch0(); Register scratch1 = VirtualFrame::scratch0();
Register scratch2 = VirtualFrame::scratch1(); Register scratch2 = VirtualFrame::scratch1();
__ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2); __ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2);
__ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2); __ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2);
// Setup the registers and call load IC. // Ensure receiver in r0 and name in r2 to match load ic calling convention.
// On entry to this deferred code, r0 is assumed to already contain the __ Move(r0, receiver_);
// receiver from the top of the stack.
__ mov(r2, Operand(name_)); __ mov(r2, Operand(name_));
// The rest of the instructions in the deferred code must be together. // The rest of the instructions in the deferred code must be together.
...@@ -5588,10 +5590,11 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { ...@@ -5588,10 +5590,11 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// this code // this code
// Load the receiver from the stack. // Load the receiver from the stack.
frame_->SpillAllButCopyTOSToR0(); Register receiver = frame_->PopToRegister();
VirtualFrame::SpilledScope spilled(frame_);
DeferredReferenceGetNamedValue* deferred = DeferredReferenceGetNamedValue* deferred =
new DeferredReferenceGetNamedValue(name); new DeferredReferenceGetNamedValue(receiver, name);
#ifdef DEBUG #ifdef DEBUG
int kInlinedNamedLoadInstructions = 7; int kInlinedNamedLoadInstructions = 7;
...@@ -5601,19 +5604,19 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { ...@@ -5601,19 +5604,19 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
{ Assembler::BlockConstPoolScope block_const_pool(masm_); { Assembler::BlockConstPoolScope block_const_pool(masm_);
// Check that the receiver is a heap object. // Check that the receiver is a heap object.
__ tst(r0, Operand(kSmiTagMask)); __ tst(receiver, Operand(kSmiTagMask));
deferred->Branch(eq); deferred->Branch(eq);
// Check the map. The null map used below is patched by the inline cache // Check the map. The null map used below is patched by the inline cache
// code. // code.
__ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ mov(r3, Operand(Factory::null_value())); __ mov(r3, Operand(Factory::null_value()));
__ cmp(r2, r3); __ cmp(r2, r3);
deferred->Branch(ne); deferred->Branch(ne);
// Initially use an invalid index. The index will be patched by the // Initially use an invalid index. The index will be patched by the
// inline cache code. // inline cache code.
__ ldr(r0, MemOperand(r0, 0)); __ ldr(r0, MemOperand(receiver, 0));
// Make sure that the expected number of instructions are generated. // Make sure that the expected number of instructions are generated.
ASSERT_EQ(kInlinedNamedLoadInstructions, ASSERT_EQ(kInlinedNamedLoadInstructions,
...@@ -5862,19 +5865,20 @@ void Reference::GetValue() { ...@@ -5862,19 +5865,20 @@ void Reference::GetValue() {
Variable* var = expression_->AsVariableProxy()->AsVariable(); Variable* var = expression_->AsVariableProxy()->AsVariable();
bool is_global = var != NULL; bool is_global = var != NULL;
ASSERT(!is_global || var->is_global()); ASSERT(!is_global || var->is_global());
if (persist_after_get_) {
cgen_->frame()->Dup();
}
cgen_->EmitNamedLoad(GetName(), is_global); cgen_->EmitNamedLoad(GetName(), is_global);
cgen_->frame()->EmitPush(r0); cgen_->frame()->EmitPush(r0);
if (!persist_after_get_) { if (!persist_after_get_) set_unloaded();
cgen_->UnloadReference(this);
}
break; break;
} }
case KEYED: { case KEYED: {
ASSERT(property != NULL);
if (persist_after_get_) { if (persist_after_get_) {
cgen_->frame()->Dup2(); cgen_->frame()->Dup2();
} }
ASSERT(property != NULL);
cgen_->EmitKeyedLoad(); cgen_->EmitKeyedLoad();
cgen_->frame()->EmitPush(r0); cgen_->frame()->EmitPush(r0);
if (!persist_after_get_) set_unloaded(); if (!persist_after_get_) set_unloaded();
......
...@@ -707,13 +707,12 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, ...@@ -707,13 +707,12 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
if (var->is_global() && !var->is_this()) { if (var->is_global() && !var->is_this()) {
Comment cmnt(masm_, "Global variable"); Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in r2 and the global // Use inline caching. Variable name is passed in r2 and the global
// object on the stack. // object (receiver) in r0.
__ ldr(r0, CodeGenerator::GlobalObject()); __ ldr(r0, CodeGenerator::GlobalObject());
__ push(r0);
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
DropAndApply(1, context, r0); Apply(context, r0);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) { } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Comment cmnt(masm_, "Lookup slot"); Comment cmnt(masm_, "Lookup slot");
...@@ -1019,7 +1018,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { ...@@ -1019,7 +1018,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle())); __ mov(r2, Operand(key->handle()));
__ ldr(r0, MemOperand(sp, 0)); // Call load IC. It has arguments receiver and property name r0 and r2.
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
} }
...@@ -1213,14 +1212,12 @@ void FullCodeGenerator::VisitProperty(Property* expr) { ...@@ -1213,14 +1212,12 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property"); Comment cmnt(masm_, "[ Property");
Expression* key = expr->key(); Expression* key = expr->key();
// Evaluate receiver.
VisitForValue(expr->obj(), kStack);
if (key->IsPropertyName()) { if (key->IsPropertyName()) {
VisitForValue(expr->obj(), kAccumulator);
EmitNamedPropertyLoad(expr); EmitNamedPropertyLoad(expr);
// Drop receiver left on the stack by IC. Apply(context_, r0);
DropAndApply(1, context_, r0);
} else { } else {
VisitForValue(expr->obj(), kStack);
VisitForValue(expr->key(), kAccumulator); VisitForValue(expr->key(), kAccumulator);
__ pop(r1); __ pop(r1);
EmitKeyedPropertyLoad(expr); EmitKeyedPropertyLoad(expr);
...@@ -1493,13 +1490,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1493,13 +1490,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
proxy->var()->is_global()) { proxy->var()->is_global()) {
Comment cmnt(masm_, "Global variable"); Comment cmnt(masm_, "Global variable");
__ ldr(r0, CodeGenerator::GlobalObject()); __ ldr(r0, CodeGenerator::GlobalObject());
__ push(r0);
__ mov(r2, Operand(proxy->name())); __ mov(r2, Operand(proxy->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Use a regular load, not a contextual load, to avoid a reference // Use a regular load, not a contextual load, to avoid a reference
// error. // error.
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
__ str(r0, MemOperand(sp)); __ push(r0);
} else if (proxy != NULL && } else if (proxy != NULL &&
proxy->var()->slot() != NULL && proxy->var()->slot() != NULL &&
proxy->var()->slot()->type() == Slot::LOOKUP) { proxy->var()->slot()->type() == Slot::LOOKUP) {
...@@ -1605,10 +1601,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -1605,10 +1601,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ mov(ip, Operand(Smi::FromInt(0))); __ mov(ip, Operand(Smi::FromInt(0)));
__ push(ip); __ push(ip);
} }
VisitForValue(prop->obj(), kStack);
if (assign_type == NAMED_PROPERTY) { if (assign_type == NAMED_PROPERTY) {
// Put the object both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator);
__ push(r0);
EmitNamedPropertyLoad(prop); EmitNamedPropertyLoad(prop);
} else { } else {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator); VisitForValue(prop->key(), kAccumulator);
__ ldr(r1, MemOperand(sp, 0)); __ ldr(r1, MemOperand(sp, 0));
__ push(r0); __ push(r0);
......
...@@ -1617,15 +1617,11 @@ Object* LoadStubCompiler::CompileLoadNonexistent(String* name, ...@@ -1617,15 +1617,11 @@ Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
JSObject* object, JSObject* object,
JSObject* last) { JSObject* last) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : name // -- r0 : receiver
// -- lr : return address // -- lr : return address
// -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
// Load receiver.
__ ldr(r0, MemOperand(sp, 0));
// Check that receiver is not a smi. // Check that receiver is not a smi.
__ tst(r0, Operand(kSmiTagMask)); __ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss); __ b(eq, &miss);
...@@ -1662,14 +1658,12 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object, ...@@ -1662,14 +1658,12 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object,
int index, int index,
String* name) { String* name) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss); GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
__ bind(&miss); __ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC); GenerateLoadMiss(masm(), Code::LOAD_IC);
...@@ -1684,13 +1678,12 @@ Object* LoadStubCompiler::CompileLoadCallback(String* name, ...@@ -1684,13 +1678,12 @@ Object* LoadStubCompiler::CompileLoadCallback(String* name,
JSObject* holder, JSObject* holder,
AccessorInfo* callback) { AccessorInfo* callback) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
__ ldr(r0, MemOperand(sp, 0));
Failure* failure = Failure::InternalError(); Failure* failure = Failure::InternalError();
bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
callback, name, &miss, &failure); callback, name, &miss, &failure);
...@@ -1709,14 +1702,12 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object, ...@@ -1709,14 +1702,12 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
Object* value, Object* value,
String* name) { String* name) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss); GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
__ bind(&miss); __ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC); GenerateLoadMiss(masm(), Code::LOAD_IC);
...@@ -1730,14 +1721,12 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, ...@@ -1730,14 +1721,12 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
JSObject* holder, JSObject* holder,
String* name) { String* name) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
__ ldr(r0, MemOperand(sp, 0));
LookupResult lookup; LookupResult lookup;
LookupPostInterceptor(holder, name, &lookup); LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(object, GenerateLoadInterceptor(object,
...@@ -1763,10 +1752,9 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, ...@@ -1763,10 +1752,9 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
String* name, String* name,
bool is_dont_delete) { bool is_dont_delete) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// -- r0 : receiver
// -- sp[0] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
......
...@@ -309,7 +309,8 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, ...@@ -309,7 +309,8 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) { void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
SpillAllButCopyTOSToR0(); PopToR0();
SpillAll();
__ mov(r2, Operand(name)); __ mov(r2, Operand(name));
CallCodeObject(ic, mode, 0); CallCodeObject(ic, mode, 0);
} }
...@@ -509,36 +510,40 @@ Register VirtualFrame::Peek() { ...@@ -509,36 +510,40 @@ Register VirtualFrame::Peek() {
void VirtualFrame::Dup() { void VirtualFrame::Dup() {
AssertIsNotSpilled(); if (SpilledScope::is_spilled()) {
switch (top_of_stack_state_) { __ ldr(ip, MemOperand(sp, 0));
case NO_TOS_REGISTERS: __ push(ip);
__ ldr(r0, MemOperand(sp, 0)); } else {
top_of_stack_state_ = R0_TOS; switch (top_of_stack_state_) {
break; case NO_TOS_REGISTERS:
case R0_TOS: __ ldr(r0, MemOperand(sp, 0));
__ mov(r1, r0); top_of_stack_state_ = R0_TOS;
// r0 and r1 contains the same value. Prefer a state with r0 holding TOS. break;
top_of_stack_state_ = R0_R1_TOS; case R0_TOS:
break; __ mov(r1, r0);
case R1_TOS: // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
__ mov(r0, r1); top_of_stack_state_ = R0_R1_TOS;
// r0 and r1 contains the same value. Prefer a state with r0 holding TOS. break;
top_of_stack_state_ = R0_R1_TOS; case R1_TOS:
break; __ mov(r0, r1);
case R0_R1_TOS: // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
__ push(r1); top_of_stack_state_ = R0_R1_TOS;
__ mov(r1, r0); break;
// r0 and r1 contains the same value. Prefer a state with r0 holding TOS. case R0_R1_TOS:
top_of_stack_state_ = R0_R1_TOS; __ push(r1);
break; __ mov(r1, r0);
case R1_R0_TOS: // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
__ push(r0); top_of_stack_state_ = R0_R1_TOS;
__ mov(r0, r1); break;
// r0 and r1 contains the same value. Prefer a state with r0 holding TOS. case R1_R0_TOS:
top_of_stack_state_ = R0_R1_TOS; __ push(r0);
break; __ mov(r0, r1);
default: // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
UNREACHABLE(); top_of_stack_state_ = R0_R1_TOS;
break;
default:
UNREACHABLE();
}
} }
element_count_++; element_count_++;
} }
......
...@@ -278,7 +278,8 @@ class VirtualFrame : public ZoneObject { ...@@ -278,7 +278,8 @@ class VirtualFrame : public ZoneObject {
InvokeJSFlags flag, InvokeJSFlags flag,
int arg_count); int arg_count);
// Call load IC. Receiver is on the stack. Result is returned in r0. // Call load IC. Receiver is on the stack and is consumed. Result is returned
// in r0.
void CallLoadIC(Handle<String> name, RelocInfo::Mode mode); void CallLoadIC(Handle<String> name, RelocInfo::Mode mode);
// Call store IC. If the load is contextual, value is found on top of the // Call store IC. If the load is contextual, value is found on top of the
......
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