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
This commit is contained in:
parent
209711201d
commit
e90d8314fa
@ -1370,6 +1370,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
|
||||
// give us a megamorphic load site. Not super, but it works.
|
||||
LoadAndSpill(applicand);
|
||||
Handle<String> 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<String> name) : name_(name) {
|
||||
explicit DeferredReferenceGetNamedValue(Register receiver,
|
||||
Handle<String> name)
|
||||
: receiver_(receiver), name_(name) {
|
||||
set_comment("[ DeferredReferenceGetNamedValue");
|
||||
}
|
||||
|
||||
virtual void Generate();
|
||||
|
||||
private:
|
||||
Register receiver_;
|
||||
Handle<String> 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<String> 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<String> 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();
|
||||
|
@ -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<Code> 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<Code> 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<Code> 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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -309,7 +309,8 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
|
||||
|
||||
void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||
SpillAllButCopyTOSToR0();
|
||||
PopToR0();
|
||||
SpillAll();
|
||||
__ mov(r2, Operand(name));
|
||||
CallCodeObject(ic, mode, 0);
|
||||
}
|
||||
@ -509,7 +510,10 @@ Register VirtualFrame::Peek() {
|
||||
|
||||
|
||||
void VirtualFrame::Dup() {
|
||||
AssertIsNotSpilled();
|
||||
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));
|
||||
@ -517,29 +521,30 @@ void VirtualFrame::Dup() {
|
||||
break;
|
||||
case R0_TOS:
|
||||
__ mov(r1, r0);
|
||||
// r0 and r1 contains the same value. Prefer a state with r0 holding TOS.
|
||||
// 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 a state with r0 holding TOS.
|
||||
// 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 a state with r0 holding TOS.
|
||||
// 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 a state with r0 holding TOS.
|
||||
// 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_++;
|
||||
}
|
||||
|
||||
|
@ -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<String> name, RelocInfo::Mode mode);
|
||||
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
|
Loading…
Reference in New Issue
Block a user