From d931c9b70a239e19567807e1caec5ebf792526fd Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Fri, 19 Feb 2010 15:04:16 +0000 Subject: [PATCH] Improve stores to global variables. Review URL: http://codereview.chromium.org/650028 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3921 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ia32/codegen-ia32.cc | 44 ++++++++++++++++---------- src/ia32/codegen-ia32.h | 5 +-- src/ia32/virtual-frame-ia32.cc | 57 ++++++++++++++-------------------- src/ia32/virtual-frame-ia32.h | 8 ++--- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 1882ac59e..85d8ed9bc 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -695,8 +695,10 @@ void CodeGenerator::LoadReference(Reference* ref) { // The expression is a variable proxy that does not rewrite to a // property. Global variables are treated as named property references. if (var->is_global()) { - // Named loads require object in eax. Named stores don't use references. - // Spilling eax makes it free, so LoadGlobal loads directly into eax. + // If eax is free, the register allocator prefers it. Thus the code + // generator will load the global object into eax, which is where + // LoadIC wants it. Most uses of Reference call LoadIC directly + // after the reference is created. frame_->Spill(eax); LoadGlobal(); ref->set_type(Reference::NAMED); @@ -4316,6 +4318,10 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // load IC call. + // The register allocator prefers eax if it is free, so the code generator + // will load the global object directly into eax, which is where the LoadIC + // expects it. + frame_->Spill(eax); LoadGlobal(); frame_->Push(slot->var()->name()); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) @@ -4601,8 +4607,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { // Duplicate the object as the IC receiver. frame_->Dup(); Load(property->value()); - frame_->Push(key); - Result ignored = frame_->CallStoreIC(); + Result dummy = frame_->CallStoreIC(Handle::cast(key), false); + dummy.Unuse(); break; } // Fall through @@ -4776,10 +4782,9 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { bool is_trivial_receiver = false; if (var != NULL) { name = var->name(); - LoadGlobal(); } else { Literal* lit = prop->key()->AsLiteral(); - ASSERT(lit != NULL); + ASSERT_NOT_NULL(lit); name = Handle::cast(lit->handle()); // Do not materialize the receiver on the frame if it is trivial. is_trivial_receiver = prop->obj()->IsTrivial(); @@ -4787,6 +4792,7 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { } if (node->starts_initialization_block()) { + ASSERT_EQ(NULL, var); // Change to slow case in the beginning of an initialization block to // avoid the quadratic behavior of repeatedly adding fast properties. if (is_trivial_receiver) { @@ -4807,6 +4813,11 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { if (node->is_compound()) { if (is_trivial_receiver) { frame()->Push(prop->obj()); + } else if (var != NULL) { + // The LoadIC stub expects the object in eax. + // Freeing eax causes the code generator to load the global into it. + frame_->Spill(eax); + LoadGlobal(); } else { frame()->Dup(); } @@ -4826,17 +4837,19 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { // Perform the assignment. It is safe to ignore constants here. ASSERT(var == NULL || var->mode() != Variable::CONST); - ASSERT(node->op() != Token::INIT_CONST); + ASSERT_NE(Token::INIT_CONST, node->op()); if (is_trivial_receiver) { Result value = frame()->Pop(); frame()->Push(prop->obj()); frame()->Push(&value); } CodeForSourcePosition(node->position()); - Result answer = EmitNamedStore(name); + bool is_contextual = (var != NULL); + Result answer = EmitNamedStore(name, is_contextual); frame()->Push(&answer); if (node->ends_initialization_block()) { + ASSERT_EQ(NULL, var); // The argument to the runtime call is the receiver. if (is_trivial_receiver) { frame()->Push(prop->obj()); @@ -4851,7 +4864,7 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); } - ASSERT(frame()->height() == original_height + 1); + ASSERT_EQ(frame()->height(), original_height + 1); } @@ -4861,7 +4874,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { #endif Comment cmnt(masm_, "[ Named Property Assignment"); Property* prop = node->target()->AsProperty(); - ASSERT(prop != NULL); + ASSERT_NOT_NULL(prop); // Evaluate the receiver subexpression. Load(prop->obj()); @@ -6779,14 +6792,13 @@ Result CodeGenerator::EmitNamedLoad(Handle name, bool is_contextual) { } -Result CodeGenerator::EmitNamedStore(Handle name) { +Result CodeGenerator::EmitNamedStore(Handle name, bool is_contextual) { #ifdef DEBUG - int original_height = frame()->height(); + int expected_height = frame()->height() - (is_contextual ? 1 : 2); #endif - frame()->Push(name); - Result result = frame()->CallStoreIC(); + Result result = frame()->CallStoreIC(name, is_contextual); - ASSERT(frame()->height() == original_height - 2); + ASSERT_EQ(expected_height, frame()->height()); return result; } @@ -7103,7 +7115,7 @@ void Reference::SetValue(InitState init_state) { case NAMED: { Comment cmnt(masm, "[ Store to named Property"); - Result answer = cgen_->EmitNamedStore(GetName()); + Result answer = cgen_->EmitNamedStore(GetName(), false); cgen_->frame()->Push(&answer); set_unloaded(); break; diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index cd7a7bbb2..99dc340b6 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -438,8 +438,9 @@ class CodeGenerator: public AstVisitor { // Receiver is passed on the frame and consumed. Result EmitNamedLoad(Handle name, bool is_contextual); - // Reciever and value are passed on the frame and consumed. - Result EmitNamedStore(Handle name); + // If the store is contextual, value is passed on the frame and consumed. + // Otherwise, receiver and value are passed on the frame and consumed. + Result EmitNamedStore(Handle name, bool is_contextual); // Receiver and key are passed on the frame and consumed. Result EmitKeyedLoad(); diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index 5e44f94d0..7df028e94 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -948,47 +948,38 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) { } -Result VirtualFrame::CallStoreIC() { - // Name, value, and receiver are on top of the frame. The IC - // expects name in ecx, value in eax, and receiver in edx. +Result VirtualFrame::CallStoreIC(Handle name, bool is_contextual) { + // Value and (if not contextual) receiver are on top of the frame. + // The IC expects name in ecx, value in eax, and receiver in edx. Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - Result name = Pop(); Result value = Pop(); - Result receiver = Pop(); - PrepareForCall(0, 0); + if (is_contextual) { + PrepareForCall(0, 0); + value.ToRegister(eax); + __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ mov(ecx, name); + } else { + Result receiver = Pop(); + PrepareForCall(0, 0); - // Optimized for case in which name is a constant value. - if (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) { - if (!is_used(ecx)) { - name.ToRegister(ecx); - } else if (!is_used(ebx)) { - name.ToRegister(ebx); - } else { - ASSERT(!is_used(edi)); // Only three results are live, so edi is free. - name.ToRegister(edi); - } - } - // Now name is not in edx or eax, so we can fix them, then move name to ecx. - if (value.is_register() && value.reg().is(edx)) { - if (receiver.is_register() && receiver.reg().is(eax)) { - // Wrong registers. - __ xchg(eax, edx); + if (value.is_register() && value.reg().is(edx)) { + if (receiver.is_register() && receiver.reg().is(eax)) { + // Wrong registers. + __ xchg(eax, edx); + } else { + // Register eax is free for value, which frees edx for receiver. + value.ToRegister(eax); + receiver.ToRegister(edx); + } } else { - // Register eax is free for value, which frees edx for receiver. - value.ToRegister(eax); + // Register edx is free for receiver, which guarantees eax is free for + // value. receiver.ToRegister(edx); + value.ToRegister(eax); } - } else { - // Register edx is free for receiver, which guarantees eax is free for - // value. - receiver.ToRegister(edx); - value.ToRegister(eax); } - // Receiver and value are in the right place, so ecx is free for name. - name.ToRegister(ecx); - name.Unuse(); + __ mov(ecx, name); value.Unuse(); - receiver.Unuse(); return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); } diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 59142b40e..7be593cc5 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -339,12 +339,12 @@ class VirtualFrame: public ZoneObject { Result CallLoadIC(RelocInfo::Mode mode); // Call keyed load IC. Key and receiver are found on top of the - // frame. They are not dropped. + // frame. Both are dropped. Result CallKeyedLoadIC(RelocInfo::Mode mode); - // Call store IC. Name, value, and receiver are found on top of the - // frame. Receiver is not dropped. - Result CallStoreIC(); + // Call store IC. If the load is contextual, value is found on top of the + // frame. If not, value and receiver are on the frame. Both are dropped. + Result CallStoreIC(Handle name, bool is_contextual); // Call keyed store IC. Value, key, and receiver are found on top // of the frame. Key and receiver are not dropped. -- 2.34.1