Revision: 4645
Author: [email protected]
Date: Wed May 12 02:12:23 2010
Log: Refactor the fast-case code for loading local/global variables and
arguments in the presence of eval to avoid code duplication. Almost
the same code was duplicated for loading properties and calling
properties.

Review URL: http://codereview.chromium.org/2053003
http://code.google.com/p/v8/source/detail?r=4645

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

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed May 12 02:00:29 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed May 12 02:12:23 2010
@@ -2791,60 +2791,13 @@
     JumpTarget slow;
     JumpTarget 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, &slow);
-      frame_->SpillAll();
-      done.Jump();
-
-    } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
-      frame_->SpillAll();
-      Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        __ ldr(r0,
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 r1,
-                                                 r2,
-                                                 &slow));
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-          __ cmp(r0, ip);
-          __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
-        }
-        done.Jump();
-      } else if (rewrite != NULL) {
-        // Generate fast case for argument loads.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            __ ldr(r0,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                     r1,
-                                                     r2,
-                                                     &slow));
-            frame_->EmitPush(r0);
-            __ mov(r1, Operand(key_literal->handle()));
-            frame_->EmitPush(r1);
-            EmitKeyedLoad();
-            done.Jump();
-          }
-        }
-      }
-    }
+    // Generate fast case for loading from slots that correspond to
+    // local/global variables or arguments unless they are shadowed by
+    // eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(slot,
+                                    typeof_state,
+                                    &slow,
+                                    &done);

     slow.Bind();
     VirtualFrame::SpilledScope spilled_scope(frame_);
@@ -3057,6 +3010,67 @@
   // Drop the global object. The result is in r0.
   frame_->Drop();
 }
+
+
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+                                                    JumpTarget* slow,
+                                                    JumpTarget* 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, slow);
+    frame_->SpillAll();
+    done->Jump();
+
+  } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+    frame_->SpillAll();
+    Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
+    Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
+    if (potential_slot != NULL) {
+      // Generate fast case for locals that rewrite to slots.
+      __ ldr(r0,
+             ContextSlotOperandCheckExtensions(potential_slot,
+                                               r1,
+                                               r2,
+                                               slow));
+      if (potential_slot->var()->mode() == Variable::CONST) {
+        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+        __ cmp(r0, ip);
+        __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+      }
+      done->Jump();
+    } else if (rewrite != NULL) {
+      // Generate fast case for argument loads.
+      Property* property = rewrite->AsProperty();
+      if (property != NULL) {
+        VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
+        Literal* key_literal = property->key()->AsLiteral();
+        if (obj_proxy != NULL &&
+            key_literal != NULL &&
+            obj_proxy->IsArguments() &&
+            key_literal->handle()->IsSmi()) {
+          // Load arguments object if there are no eval-introduced
+          // variables. Then load the argument from the arguments
+          // object using keyed load.
+          __ ldr(r0,
+ ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+                                                   r1,
+                                                   r2,
+                                                   slow));
+          frame_->EmitPush(r0);
+          __ mov(r1, Operand(key_literal->handle()));
+          frame_->EmitPush(r1);
+          EmitKeyedLoad();
+          done->Jump();
+        }
+      }
+    }
+  }
+}


 void CodeGenerator::VisitSlot(Slot* node) {
@@ -3756,67 +3770,15 @@

     // JumpTargets do not yet support merging frames so the frame must be
     // spilled when jumping to these targets.
-    JumpTarget slow;
-    JumpTarget 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 (var->mode() == Variable::DYNAMIC_GLOBAL) {
- LoadFromGlobalSlotCheckExtensions(var->slot(), NOT_INSIDE_TYPEOF, &slow);
-      frame_->EmitPush(r0);
-      LoadGlobalReceiver(r1);
-      done.Jump();
-
-    } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
-      Slot* potential_slot = var->local_if_not_shadowed()->slot();
-      Expression* rewrite = var->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        __ ldr(r0,
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 r1,
-                                                 r2,
-                                                 &slow));
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-          __ cmp(r0, ip);
-          __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
-        }
-        frame_->EmitPush(r0);
-        LoadGlobalReceiver(r1);
-        done.Jump();
-      } else if (rewrite != NULL) {
-        // Generate fast case for calls of an argument function.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            __ ldr(r0,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                     r1,
-                                                     r2,
-                                                     &slow));
-            frame_->EmitPush(r0);
-            __ mov(r1, Operand(key_literal->handle()));
-            frame_->EmitPush(r1);
-            EmitKeyedLoad();
-            frame_->EmitPush(r0);
-            LoadGlobalReceiver(r1);
-            done.Jump();
-          }
-        }
-      }
-    }
+    JumpTarget slow, done;
+
+    // Generate fast case for loading functions from slots that
+    // correspond to local/global variables or arguments unless they
+    // are shadowed by eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(var->slot(),
+                                    NOT_INSIDE_TYPEOF,
+                                    &slow,
+                                    &done);

     slow.Bind();
     // Load the function
@@ -3830,7 +3792,18 @@
     frame_->EmitPush(r0);  // function
     frame_->EmitPush(r1);  // receiver

-    done.Bind();
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      JumpTarget call;
+      call.Jump();
+      done.Bind();
+      frame_->EmitPush(r0);  // function
+      LoadGlobalReceiver(r1);  // receiver
+      call.Bind();
+    }
+
     // Call the function. At this point, everything is spilled but the
     // function and receiver are in r0 and r1.
     CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Mon May 10 06:23:42 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Wed May 12 02:12:23 2010
@@ -314,6 +314,7 @@
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
   void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
+
   // Store the value on top of the stack to a slot.
   void StoreToSlot(Slot* slot, InitState init_state);

@@ -343,6 +344,15 @@
                                          TypeofState typeof_state,
                                          JumpTarget* slow);

+  // Support for loading from local/global variables and arguments
+  // whose location is known unless they are shadowed by
+  // eval-introduced bindings. Generates no code for unsupported slot
+  // types and therefore expects to fall through to the slow jump target.
+  void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+                                       TypeofState typeof_state,
+                                       JumpTarget* slow,
+                                       JumpTarget* done);
+
   // Special code for typeof expressions: Unfortunately, we must
   // be careful when loading the expression in 'typeof'
   // expressions. We are not allowed to throw reference errors for
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue May 11 05:38:30 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Wed May 12 02:12:23 2010
@@ -4723,62 +4723,14 @@
     JumpTarget slow;
     JumpTarget 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) {
- result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
-      done.Jump(&result);
-
-    } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
-      Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        // Allocate a fresh register to use as a temp in
-        // ContextSlotOperandCheckExtensions and to hold the result
-        // value.
-        result = allocator()->Allocate();
-        ASSERT(result.is_valid());
-        __ mov(result.reg(),
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 result,
-                                                 &slow));
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ cmp(result.reg(), Factory::the_hole_value());
-          done.Branch(not_equal, &result);
-          __ mov(result.reg(), Factory::undefined_value());
-        }
-        done.Jump(&result);
-      } else if (rewrite != NULL) {
-        // Generate fast case for argument loads.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            Result arguments = allocator()->Allocate();
-            ASSERT(arguments.is_valid());
-            __ mov(arguments.reg(),
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                     arguments,
-                                                     &slow));
-            frame_->Push(&arguments);
-            frame_->Push(key_literal->handle());
-            result = EmitKeyedLoad();
-            done.Jump(&result);
-          }
-        }
-      }
-    }
+    // Generate fast case for loading from slots that correspond to
+    // local/global variables or arguments unless they are shadowed by
+    // eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(slot,
+                                    typeof_state,
+                                    &result,
+                                    &slow,
+                                    &done);

     slow.Bind();
     // A runtime call is inevitable.  We eagerly sync frame elements
@@ -4945,6 +4897,68 @@
   __ nop();
   return answer;
 }
+
+
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+                                                    Result* result,
+                                                    JumpTarget* slow,
+                                                    JumpTarget* 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) {
+    *result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow);
+    done->Jump(result);
+
+  } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+    Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
+    Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
+    if (potential_slot != NULL) {
+      // Generate fast case for locals that rewrite to slots.
+      // Allocate a fresh register to use as a temp in
+      // ContextSlotOperandCheckExtensions and to hold the result
+      // value.
+      *result = allocator()->Allocate();
+      ASSERT(result->is_valid());
+      __ mov(result->reg(),
+ ContextSlotOperandCheckExtensions(potential_slot, *result, slow));
+      if (potential_slot->var()->mode() == Variable::CONST) {
+        __ cmp(result->reg(), Factory::the_hole_value());
+        done->Branch(not_equal, result);
+        __ mov(result->reg(), Factory::undefined_value());
+      }
+      done->Jump(result);
+    } else if (rewrite != NULL) {
+      // Generate fast case for calls of an argument function.
+      Property* property = rewrite->AsProperty();
+      if (property != NULL) {
+        VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
+        Literal* key_literal = property->key()->AsLiteral();
+        if (obj_proxy != NULL &&
+            key_literal != NULL &&
+            obj_proxy->IsArguments() &&
+            key_literal->handle()->IsSmi()) {
+          // Load arguments object if there are no eval-introduced
+          // variables. Then load the argument from the arguments
+          // object using keyed load.
+          Result arguments = allocator()->Allocate();
+          ASSERT(arguments.is_valid());
+          __ mov(arguments.reg(),
+ ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+                                                   arguments,
+                                                   slow));
+          frame_->Push(&arguments);
+          frame_->Push(key_literal->handle());
+          *result = EmitKeyedLoad();
+          done->Jump(result);
+        }
+      }
+    }
+  }
+}


 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
@@ -5792,75 +5806,17 @@
     //  }
     // ----------------------------------

-    JumpTarget slow;
-    JumpTarget 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 (var->mode() == Variable::DYNAMIC_GLOBAL) {
-      Result function = LoadFromGlobalSlotCheckExtensions(var->slot(),
- NOT_INSIDE_TYPEOF,
-                                                          &slow);
-      frame_->Push(&function);
-      LoadGlobalReceiver();
-      done.Jump();
-
-    } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
-      Slot* potential_slot = var->local_if_not_shadowed()->slot();
-      Expression* rewrite = var->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        // Allocate a fresh register to use as a temp in
-        // ContextSlotOperandCheckExtensions and to hold the result
-        // value.
-        Result function = allocator()->Allocate();
-        ASSERT(function.is_valid());
-        __ mov(function.reg(),
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 function,
-                                                 &slow));
-        JumpTarget push_function_and_receiver;
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ cmp(function.reg(), Factory::the_hole_value());
-          push_function_and_receiver.Branch(not_equal, &function);
-          __ mov(function.reg(), Factory::undefined_value());
-        }
-        push_function_and_receiver.Bind(&function);
-        frame_->Push(&function);
-        LoadGlobalReceiver();
-        done.Jump();
-      } else if (rewrite != NULL) {
-        // Generate fast case for calls of an argument function.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            Result arguments = allocator()->Allocate();
-            ASSERT(arguments.is_valid());
-            __ mov(arguments.reg(),
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                     arguments,
-                                                     &slow));
-            frame_->Push(&arguments);
-            frame_->Push(key_literal->handle());
-            Result value = EmitKeyedLoad();
-            frame_->Push(&value);
-            LoadGlobalReceiver();
-            done.Jump();
-          }
-        }
-      }
-    }
+    JumpTarget slow, done;
+    Result function;
+
+    // Generate fast case for loading functions from slots that
+    // correspond to local/global variables or arguments unless they
+    // are shadowed by eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(var->slot(),
+                                    NOT_INSIDE_TYPEOF,
+                                    &function,
+                                    &slow,
+                                    &done);

     slow.Bind();
     // Enter the runtime system to load the function from the context.
@@ -5882,7 +5838,18 @@
     ASSERT(!allocator()->is_used(edx));
     frame_->EmitPush(edx);

-    done.Bind();
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      JumpTarget call;
+      call.Jump();
+      done.Bind(&function);
+      frame_->Push(&function);
+      LoadGlobalReceiver();
+      call.Bind();
+    }
+
     // Call the function.
     CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());

=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Tue May 11 05:38:30 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Wed May 12 02:12:23 2010
@@ -465,6 +465,16 @@
                                            TypeofState typeof_state,
                                            JumpTarget* slow);

+  // Support for loading from local/global variables and arguments
+  // whose location is known unless they are shadowed by
+  // eval-introduced bindings. Generates no code for unsupported slot
+  // types and therefore expects to fall through to the slow jump target.
+  void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+                                       TypeofState typeof_state,
+                                       Result* result,
+                                       JumpTarget* slow,
+                                       JumpTarget* done);
+
// Store the value on top of the expression stack into a slot, leaving the
   // value in place.
   void StoreToSlot(Slot* slot, InitState init_state);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Tue May 11 01:32:13 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed May 12 02:12:23 2010
@@ -2876,77 +2876,17 @@
     //  }
     // ----------------------------------

-    JumpTarget slow;
-    JumpTarget 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.
+    JumpTarget slow, done;
     Result function;
-    if (var->mode() == Variable::DYNAMIC_GLOBAL) {
-      function = LoadFromGlobalSlotCheckExtensions(var->slot(),
-                                                   NOT_INSIDE_TYPEOF,
-                                                   &slow);
-      frame_->Push(&function);
-      LoadGlobalReceiver();
-      done.Jump();
-
-    } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
-      Slot* potential_slot = var->local_if_not_shadowed()->slot();
-      Expression* rewrite = var->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        // Allocate a fresh register to use as a temp in
-        // ContextSlotOperandCheckExtensions and to hold the result
-        // value.
-        function = allocator()->Allocate();
-        ASSERT(function.is_valid());
-        __ movq(function.reg(),
-                ContextSlotOperandCheckExtensions(potential_slot,
-                                                  function,
-                                                  &slow));
-        JumpTarget push_function_and_receiver;
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ CompareRoot(function.reg(), Heap::kTheHoleValueRootIndex);
-          push_function_and_receiver.Branch(not_equal, &function);
-          __ LoadRoot(function.reg(), Heap::kUndefinedValueRootIndex);
-        }
-        push_function_and_receiver.Bind(&function);
-        frame_->Push(&function);
-        LoadGlobalReceiver();
-        done.Jump();
-      } else if (rewrite != NULL) {
-        // Generate fast case for calls of an argument function.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            Result arguments = allocator()->Allocate();
-            ASSERT(arguments.is_valid());
-            __ movq(arguments.reg(),
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                      arguments,
-                                                      &slow));
-            frame_->Push(&arguments);
-            frame_->Push(key_literal->handle());
-            Result value = EmitKeyedLoad(false);
-            frame_->Drop(2);  // Drop key and receiver.
-            frame_->Push(&value);
-            LoadGlobalReceiver();
-            done.Jump();
-          }
-        }
-      }
-    }
+
+    // Generate fast case for loading functions from slots that
+    // correspond to local/global variables or arguments unless they
+    // are shadowed by eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(var->slot(),
+                                    NOT_INSIDE_TYPEOF,
+                                    &function,
+                                    &slow,
+                                    &done);

     slow.Bind();
     // Load the function from the context.  Sync the frame so we can
@@ -2967,7 +2907,18 @@
     ASSERT(!allocator()->is_used(rdx));
     frame_->EmitPush(rdx);

-    done.Bind();
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      JumpTarget call;
+      call.Jump();
+      done.Bind(&function);
+      frame_->Push(&function);
+      LoadGlobalReceiver();
+      call.Bind();
+    }
+
     // Call the function.
     CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());

@@ -5367,63 +5318,14 @@
     JumpTarget done;
     Result value;

-    // 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) {
-      value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
-      done.Jump(&value);
-
-    } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
-      Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
-      if (potential_slot != NULL) {
-        // Generate fast case for locals that rewrite to slots.
-        // Allocate a fresh register to use as a temp in
-        // ContextSlotOperandCheckExtensions and to hold the result
-        // value.
-        value = allocator_->Allocate();
-        ASSERT(value.is_valid());
-        __ movq(value.reg(),
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 value,
-                                                 &slow));
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
-          done.Branch(not_equal, &value);
-          __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex);
-        }
-        done.Jump(&value);
-      } else if (rewrite != NULL) {
-        // Generate fast case for argument loads.
-        Property* property = rewrite->AsProperty();
-        if (property != NULL) {
-          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
-          Literal* key_literal = property->key()->AsLiteral();
-          if (obj_proxy != NULL &&
-              key_literal != NULL &&
-              obj_proxy->IsArguments() &&
-              key_literal->handle()->IsSmi()) {
-            // Load arguments object if there are no eval-introduced
-            // variables. Then load the argument from the arguments
-            // object using keyed load.
-            Result arguments = allocator()->Allocate();
-            ASSERT(arguments.is_valid());
-            __ movq(arguments.reg(),
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
-                                                      arguments,
-                                                      &slow));
-            frame_->Push(&arguments);
-            frame_->Push(key_literal->handle());
-            value = EmitKeyedLoad(false);
-            frame_->Drop(2);  // Drop key and receiver.
-            done.Jump(&value);
-          }
-        }
-      }
-    }
+    // Generate fast case for loading from slots that correspond to
+    // local/global variables or arguments unless they are shadowed by
+    // eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(slot,
+                                    typeof_state,
+                                    &value,
+                                    &slow,
+                                    &done);

     slow.Bind();
     // A runtime call is inevitable.  We eagerly sync frame elements
@@ -5687,6 +5589,71 @@
   frame_->Drop();
   return answer;
 }
+
+
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+                                                    Result* result,
+                                                    JumpTarget* slow,
+                                                    JumpTarget* 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) {
+    *result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow);
+    done->Jump(result);
+
+  } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+    Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
+    Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
+    if (potential_slot != NULL) {
+      // Generate fast case for locals that rewrite to slots.
+      // Allocate a fresh register to use as a temp in
+      // ContextSlotOperandCheckExtensions and to hold the result
+      // value.
+      *result = allocator_->Allocate();
+      ASSERT(result->is_valid());
+      __ movq(result->reg(),
+              ContextSlotOperandCheckExtensions(potential_slot,
+                                                *result,
+                                                slow));
+      if (potential_slot->var()->mode() == Variable::CONST) {
+        __ CompareRoot(result->reg(), Heap::kTheHoleValueRootIndex);
+        done->Branch(not_equal, result);
+        __ LoadRoot(result->reg(), Heap::kUndefinedValueRootIndex);
+      }
+      done->Jump(result);
+    } else if (rewrite != NULL) {
+      // Generate fast case for argument loads.
+      Property* property = rewrite->AsProperty();
+      if (property != NULL) {
+        VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
+        Literal* key_literal = property->key()->AsLiteral();
+        if (obj_proxy != NULL &&
+            key_literal != NULL &&
+            obj_proxy->IsArguments() &&
+            key_literal->handle()->IsSmi()) {
+          // Load arguments object if there are no eval-introduced
+          // variables. Then load the argument from the arguments
+          // object using keyed load.
+          Result arguments = allocator()->Allocate();
+          ASSERT(arguments.is_valid());
+          __ movq(arguments.reg(),
+ ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+                                                    arguments,
+                                                    slow));
+          frame_->Push(&arguments);
+          frame_->Push(key_literal->handle());
+          *result = EmitKeyedLoad(false);
+          frame_->Drop(2);  // Drop key and receiver.
+          done->Jump(result);
+        }
+      }
+    }
+  }
+}


 void CodeGenerator::LoadGlobal() {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Mon May 10 04:38:58 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Wed May 12 02:12:23 2010
@@ -435,6 +435,16 @@
                                            TypeofState typeof_state,
                                            JumpTarget* slow);

+  // Support for loading from local/global variables and arguments
+  // whose location is known unless they are shadowed by
+  // eval-introduced bindings. Generates no code for unsupported slot
+  // types and therefore expects to fall through to the slow jump target.
+  void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+                                       TypeofState typeof_state,
+                                       Result* result,
+                                       JumpTarget* slow,
+                                       JumpTarget* done);
+
// Store the value on top of the expression stack into a slot, leaving the
   // value in place.
   void StoreToSlot(Slot* slot, InitState init_state);

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

Reply via email to