From c7fe99d3ff6124a513192d62fb90c7f5e2fb78b2 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Fri, 12 Feb 2010 10:32:24 +0000 Subject: [PATCH] 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 --- src/full-codegen.cc | 8 ++++- src/ia32/codegen-ia32.cc | 29 ++++++++++------ src/ia32/debug-ia32.cc | 3 +- src/ia32/full-codegen-ia32.cc | 21 ++++++------ src/ia32/ic-ia32.cc | 63 +++++++++++++++++----------------- src/ia32/stub-cache-ia32.cc | 26 ++++++-------- src/ia32/virtual-frame-ia32.cc | 23 ++++++++++--- src/ia32/virtual-frame-ia32.h | 2 +- 8 files changed, 99 insertions(+), 76 deletions(-) diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 5c66f7463b..40a1d6661f 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -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); diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index ee17510e65..9fe67587ab 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -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 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 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); - } } diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc index 1f34b3026e..a9e26263f5 100644 --- a/src/ia32/debug-ia32.cc +++ b/src/ia32/debug-ia32.cc @@ -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); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 3163b1906c..c6bb78b4b0 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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 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 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); } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 024aba50b3..3c62337e8f 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -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 diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index efd0d4162e..69e3bec5d1 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -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(cell))); - __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset)); + __ mov(ebx, Immediate(Handle(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); diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index f0309353e2..4e1341b884 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -888,13 +888,28 @@ Result VirtualFrame::RawCallCodeObject(Handle 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 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); } diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 672a31069d..4d55c9af6d 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -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