Author: [email protected]
Date: Wed Feb 18 05:54:13 2009
New Revision: 1301

Modified:
    branches/bleeding_edge/src/codegen-arm.cc
    branches/bleeding_edge/src/codegen-arm.h
    branches/bleeding_edge/src/codegen-ia32.cc

Log:
ARM side of load optimization in the presence of eval.
Review URL: http://codereview.chromium.org/20453

Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc   (original)
+++ branches/bleeding_edge/src/codegen-arm.cc   Wed Feb 18 05:54:13 2009
@@ -369,7 +369,7 @@
        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::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 @@
    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 @@
      } else {
        __ CallRuntime(Runtime::kLoadContextSlot, 2);
      }
+
+    __ bind(&done);
      frame_->Push(r0);

    } else {
@@ -2016,6 +2068,51 @@
        frame_->Push(r0);
      }
    }
+}
+
+
+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<Code> 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();
  }



Modified: branches/bleeding_edge/src/codegen-arm.h
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.h    (original)
+++ branches/bleeding_edge/src/codegen-arm.h    Wed Feb 18 05:54:13 2009
@@ -256,6 +256,11 @@

    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 @@

    // 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'

Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Wed Feb 18 05:54:13 2009
@@ -455,16 +455,17 @@
                                                           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 @@
                                                        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.

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to