Change LoadIC interface on ia32 to take arguments in registers.

Review URL: http://codereview.chromium.org/573009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3841 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
whesse@chromium.org 2010-02-12 10:32:24 +00:00
parent 85c24cee57
commit c7fe99d3ff
8 changed files with 99 additions and 76 deletions

View File

@ -1050,7 +1050,13 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Nothing to do here.
break;
case NAMED_PROPERTY:
VisitForValue(prop->obj(), kStack);
if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator);
__ push(result_register());
} else {
VisitForValue(prop->obj(), kStack);
}
break;
case KEYED_PROPERTY:
VisitForValue(prop->obj(), kStack);

View File

@ -2327,6 +2327,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// Load applicand.apply onto the stack. This will usually
// give us a megamorphic load site. Not super, but it works.
Load(applicand);
frame()->Dup();
Handle<String> name = Factory::LookupAsciiSymbol("apply");
frame()->Push(name);
Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
@ -4197,8 +4198,6 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
// property case was inlined. Ensure that there is not a test eax
// instruction here.
__ nop();
// Discard the global object. The result is in answer.
frame_->Drop();
return answer;
}
@ -6276,7 +6275,7 @@ bool CodeGenerator::HasValidEntryRegisters() {
// Emit a LoadIC call to get the value from receiver and leave it in
// dst. The receiver register is restored after the call.
// dst.
class DeferredReferenceGetNamedValue: public DeferredCode {
public:
DeferredReferenceGetNamedValue(Register dst,
@ -6299,7 +6298,9 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
void DeferredReferenceGetNamedValue::Generate() {
__ push(receiver_);
if (!receiver_.is(eax)) {
__ mov(eax, receiver_);
}
__ Set(ecx, Immediate(name_));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
@ -6316,7 +6317,6 @@ void DeferredReferenceGetNamedValue::Generate() {
__ IncrementCounter(&Counters::named_load_inline_miss, 1);
if (!dst_.is(eax)) __ mov(dst_, eax);
__ pop(receiver_);
}
@ -6570,6 +6570,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;
}
@ -6578,6 +6581,9 @@ void Reference::GetValue() {
bool is_global = var != NULL;
ASSERT(!is_global || var->is_global());
if (persist_after_get_) {
cgen_->frame()->Dup();
}
// Do not inline the inobject property case for loads from the global
// object. Also do not inline for unoptimized code. This saves time
// in the code generator. Unoptimized code is toplevel code or code
@ -6636,9 +6642,11 @@ void Reference::GetValue() {
__ IncrementCounter(&Counters::named_load_inline, 1);
deferred->BindExit();
cgen_->frame()->Push(&receiver);
cgen_->frame()->Push(&value);
}
if (!persist_after_get_) {
set_unloaded();
}
break;
}
@ -6648,16 +6656,15 @@ void Reference::GetValue() {
ASSERT(!is_global || var->is_global());
Result value = cgen_->EmitKeyedLoad(is_global);
cgen_->frame()->Push(&value);
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
break;
}
default:
default:
UNREACHABLE();
}
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
}

View File

@ -125,9 +125,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
// Register state for IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -----------------------------------
Generate_DebugBreakCallHelper(masm, ecx.bit(), false);
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false);
}

View File

@ -808,7 +808,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in ecx and the global
// object on the stack.
__ push(CodeGenerator::GlobalObject());
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(ecx, var->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
@ -817,7 +817,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
// Remember that the assembler may choose to do peephole optimization
// (eg, push/pop elimination).
__ nop();
DropAndApply(1, context, eax);
Apply(context, eax);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Comment cmnt(masm_, "Lookup slot");
@ -1183,14 +1183,12 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
// Evaluate the 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_, eax);
Apply(context_, eax);
} else {
VisitForValue(expr->obj(), kStack);
VisitForValue(expr->key(), kStack);
EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
@ -1455,13 +1453,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
!proxy->var()->is_this() &&
proxy->var()->is_global()) {
Comment cmnt(masm_, "Global variable");
__ push(CodeGenerator::GlobalObject());
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(ecx, Immediate(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);
__ mov(Operand(esp, 0), eax);
__ push(eax);
} else if (proxy != NULL &&
proxy->var()->slot() != NULL &&
proxy->var()->slot()->type() == Slot::LOOKUP) {
@ -1565,10 +1563,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
if (expr->is_postfix() && context_ != Expression::kEffect) {
__ push(Immediate(Smi::FromInt(0)));
}
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(eax);
EmitNamedPropertyLoad(prop);
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
EmitKeyedPropertyLoad(prop);
}

View File

@ -50,28 +50,29 @@ namespace internal {
// or if name is not a symbol, and will jump to the miss_label in that case.
static void GenerateDictionaryLoad(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Register name,
Register r0,
Register r1,
Register r2,
Register name,
DictionaryCheck check_dictionary) {
// Register use:
//
// name - holds the name of the property and is unchanged.
// receiver - holds the receiver and is unchanged.
// Scratch registers:
// r0 - used to hold the property dictionary.
//
// r1 - initially the receiver
// - used for the index into the property dictionary
// r1 - used for the index into the property dictionary
// - holds the result on exit.
//
// r2 - used to hold the capacity of the property dictionary.
//
// name - holds the name of the property and is unchanged.
Label done;
// Check for the absence of an interceptor.
// Load the map into r0.
__ mov(r0, FieldOperand(r1, JSObject::kMapOffset));
__ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
// Test the has_named_interceptor bit in the map.
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
@ -91,7 +92,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
__ j(equal, miss_label, not_taken);
// Load properties array.
__ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
__ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
// Check that the properties array is a dictionary.
if (check_dictionary == CHECK_DICTIONARY) {
@ -176,14 +177,12 @@ const int LoadIC::kOffsetToLoadInstruction = 13;
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@ -192,14 +191,12 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@ -208,14 +205,12 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@ -364,13 +359,14 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ bind(&probe_dictionary);
GenerateDictionaryLoad(masm,
&slow,
ebx,
ecx,
edx,
eax,
ebx,
edx,
edi,
DICTIONARY_CHECK_DONE);
GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
__ mov(eax, Operand(ecx));
GenerateCheckNonObjectOrLoaded(masm, &slow, edx, ebx);
__ mov(eax, Operand(edx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
@ -1001,7 +997,7 @@ static void GenerateNormalHelper(MacroAssembler* masm,
// Search dictionary - put result in register edi.
__ mov(edi, edx);
GenerateDictionaryLoad(masm, miss, eax, edi, ebx, ecx, CHECK_DICTIONARY);
GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
// Check that the result is not a smi.
__ test(edi, Immediate(kSmiTagMask));
@ -1150,13 +1146,11 @@ Object* LoadIC_Miss(Arguments args);
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
__ mov(eax, Operand(esp, kPointerSize));
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
NOT_IN_LOOP,
@ -1170,14 +1164,12 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss, probe, global;
__ mov(eax, Operand(esp, kPointerSize));
// Check that the receiver isn't a smi.
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &miss, not_taken);
@ -1202,8 +1194,16 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
// Search the dictionary placing the result in eax.
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx, CHECK_DICTIONARY);
GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx);
GenerateDictionaryLoad(masm,
&miss,
eax,
ecx,
edx,
edi,
ebx,
CHECK_DICTIONARY);
GenerateCheckNonObjectOrLoaded(masm, &miss, edi, edx);
__ mov(eax, edi);
__ ret(0);
// Global object access: Check access rights.
@ -1213,20 +1213,19 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
// Cache miss: Restore receiver from stack and jump to runtime.
__ bind(&miss);
__ mov(eax, Operand(esp, 1 * kPointerSize));
GenerateMiss(masm);
}
void LoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
__ pop(ebx);
__ push(Operand(esp, 0)); // receiver
__ push(eax); // receiver
__ push(ecx); // name
__ push(ebx); // return address

View File

@ -1767,13 +1767,12 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object,
int index,
String* name) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@ -1788,13 +1787,12 @@ Object* LoadStubCompiler::CompileLoadCallback(String* name,
JSObject* holder,
AccessorInfo* callback) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
Failure* failure = Failure::InternalError();
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
callback, name, &miss, &failure);
@ -1813,13 +1811,12 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
Object* value,
String* name) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ mov(eax, Operand(esp, kPointerSize));
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@ -1833,16 +1830,15 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
LookupResult lookup;
LookupPostInterceptor(holder, name, &lookup);
__ mov(eax, Operand(esp, kPointerSize));
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptor(receiver,
@ -1869,15 +1865,12 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
String* name,
bool is_dont_delete) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
// Get the receiver from the stack.
__ mov(eax, Operand(esp, kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual loads. In this case,
// the receiver cannot be a smi.
@ -1890,19 +1883,20 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
// Get the value from the cell.
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
__ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
__ cmp(eax, Factory::the_hole_value());
__ cmp(ebx, Factory::the_hole_value());
__ j(equal, &miss, not_taken);
} else if (FLAG_debug_code) {
__ cmp(eax, Factory::the_hole_value());
__ cmp(ebx, Factory::the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
__ IncrementCounter(&Counters::named_load_global_inline, 1);
__ mov(eax, ebx);
__ ret(0);
__ bind(&miss);

View File

@ -888,13 +888,28 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
// Name and receiver are on the top of the frame. The IC expects
// name in ecx and receiver on the stack. It does not drop the
// receiver.
// name in ecx and receiver in eax.
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Result name = Pop();
PrepareForCall(1, 0); // One stack arg, not callee-dropped.
name.ToRegister(ecx);
Result receiver = Pop();
PrepareForCall(0, 0); // No stack arguments.
// Move results to the right registers:
if (name.is_register() && name.reg().is(eax)) {
if (receiver.is_register() && receiver.reg().is(ecx)) {
// Wrong registers.
__ xchg(eax, ecx);
} else {
// Register ecx is free for name, which frees eax for receiver.
name.ToRegister(ecx);
receiver.ToRegister(eax);
}
} else {
// Register eax is free for receiver, which frees ecx for name.
receiver.ToRegister(eax);
name.ToRegister(ecx);
}
name.Unuse();
receiver.Unuse();
return RawCallCodeObject(ic, mode);
}

View File

@ -333,7 +333,7 @@ class VirtualFrame: public ZoneObject {
Result InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag, int arg_count);
// Call load IC. Name and receiver are found on top of the frame.
// Receiver is not dropped.
// Both are dropped.
Result CallLoadIC(RelocInfo::Mode mode);
// Call keyed load IC. Key and receiver are found on top of the