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