From cafe25f25829d0236880e81125567b750c8e6945 Mon Sep 17 00:00:00 2001 From: "ager@chromium.org" Date: Wed, 18 Feb 2009 13:54:13 +0000 Subject: [PATCH] ARM side of load optimization in the presence of eval. Review URL: http://codereview.chromium.org/20453 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1301 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/codegen-arm.cc | 101 +++++++++++++++++++++++++++++++++++++++++++- src/codegen-arm.h | 10 +++++ src/codegen-ia32.cc | 14 +++--- 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc index a8a99e8ca5..31a174e228 100644 --- a/src/codegen-arm.cc +++ b/src/codegen-arm.cc @@ -369,7 +369,7 @@ MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { ASSERT(!tmp.is(cp)); // do not overwrite context register Register context = cp; int chain_length = scope()->ContextChainLength(slot->var()->scope()); - for (int i = chain_length; i-- > 0;) { + for (int i = 0; i < chain_length; i++) { // Load the closure. // (All contexts, even 'with' contexts, have a closure, // and it is the same for all contexts inside a function. @@ -397,6 +397,35 @@ MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { } +MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, + Register tmp, + Register tmp2, + Label* slow) { + ASSERT(slot->type() == Slot::CONTEXT); + int index = slot->index(); + Register context = cp; + for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { + if (s->num_heap_slots() > 0) { + if (s->calls_eval()) { + // Check that extension is NULL. + __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); + __ tst(tmp2, tmp2); + __ b(ne, slow); + } + __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); + __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); + context = tmp; + } + } + // Check that last extension is NULL. + __ ldr(tmp2, ContextOperand(tmp, Context::EXTENSION_INDEX)); + __ tst(tmp2, tmp2); + __ b(ne, slow); + __ ldr(tmp, ContextOperand(tmp, Context::FCONTEXT_INDEX)); + return ContextOperand(tmp, index); +} + + // Loads a value on TOS. If it is a boolean value, the result may have been // (partially) translated into branches, or it may have set the condition // code register. If force_cc is set, the value is forced to set the @@ -1985,7 +2014,28 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { if (slot->type() == Slot::LOOKUP) { ASSERT(slot->var()->is_dynamic()); - // For now, just do a runtime call. + Label slow, done; + + // Generate fast-case code for variables that might be shadowed by + // eval-introduced variables. Eval is used a lot without + // introducing variables. In those cases, we do not want to + // perform a runtime call for all variables in the scope + // containing the eval. + if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { + LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow); + __ b(&done); + + } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { + Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); + __ ldr(r0, + ContextSlotOperandCheckExtensions(potential_slot, + r1, + r2, + &slow)); + __ b(&done); + } + + __ bind(&slow); frame_->Push(cp); __ mov(r0, Operand(slot->var()->name())); frame_->Push(r0); @@ -1995,6 +2045,8 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { } else { __ CallRuntime(Runtime::kLoadContextSlot, 2); } + + __ bind(&done); frame_->Push(r0); } else { @@ -2019,6 +2071,51 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { } +void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, + TypeofState typeof_state, + Register tmp, + Register tmp2, + Label* slow) { + // Check that no extension objects have been created by calls to + // eval from the current scope to the global scope. + Register context = cp; + for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { + if (s->num_heap_slots() > 0) { + if (s->calls_eval()) { + // Check that extension is NULL. + __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); + __ tst(tmp2, tmp2); + __ b(ne, slow); + } + // Load next context in chain. + __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); + __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); + context = tmp; + } + // If no outer scope calls eval, we do not need to check more + // context extensions. + if (!s->outer_scope_calls_eval()) break; + } + + // All extension objects were empty and it is safe to use a global + // load IC call. + Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + // Load the global object. + LoadGlobal(); + // Setup the name register. + __ mov(r2, Operand(slot->var()->name())); + // Call IC stub. + if (typeof_state == INSIDE_TYPEOF) { + __ Call(ic, RelocInfo::CODE_TARGET); + } else { + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + } + + // Pop the global object. The result is in r0. + frame_->Pop(); +} + + void CodeGenerator::VisitSlot(Slot* node) { Comment cmnt(masm_, "[ Slot"); LoadFromSlot(node, typeof_state()); diff --git a/src/codegen-arm.h b/src/codegen-arm.h index c1a823b910..4ab5ce6082 100644 --- a/src/codegen-arm.h +++ b/src/codegen-arm.h @@ -256,6 +256,11 @@ class CodeGenerator: public AstVisitor { MemOperand SlotOperand(Slot* slot, Register tmp); + MemOperand ContextSlotOperandCheckExtensions(Slot* slot, + Register tmp, + Register tmp2, + Label* slow); + // Expressions MemOperand GlobalObject() const { return ContextOperand(cp, Context::GLOBAL_INDEX); @@ -272,6 +277,11 @@ class CodeGenerator: public AstVisitor { // Read a value from a slot and leave it on top of the expression stack. void LoadFromSlot(Slot* slot, TypeofState typeof_state); + void LoadFromGlobalSlotCheckExtensions(Slot* slot, + TypeofState typeof_state, + Register tmp, + Register tmp2, + Label* slow); // Special code for typeof expressions: Unfortunately, we must // be careful when loading the expression in 'typeof' diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc index 2d5a127f6d..6427669680 100644 --- a/src/codegen-ia32.cc +++ b/src/codegen-ia32.cc @@ -455,16 +455,17 @@ Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, Label* slow) { ASSERT(slot->type() == Slot::CONTEXT); int index = slot->index(); - __ mov(tmp, Operand(esi)); + Register context = esi; for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { if (s->calls_eval()) { // Check that extension is NULL. - __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0)); + __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); __ j(not_equal, slow, not_taken); } - __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX)); + __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); + context = tmp; } } // Check that last extension is NULL. @@ -2412,17 +2413,18 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, Label* slow) { // Check that no extension objects have been created by calls to // eval from the current scope to the global scope. - __ mov(tmp, Operand(esi)); + Register context = esi; for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { if (s->num_heap_slots() > 0) { if (s->calls_eval()) { // Check that extension is NULL. - __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0)); + __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); __ j(not_equal, slow, not_taken); } // Load next context in chain. - __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX)); + __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); + context = tmp; } // If no outer scope calls eval, we do not need to check more // context extensions.