Reviewers: Mads Ager,

Description:
Optimize functions needing a local context.

Allocate the context in the prologue. Two issues had to be solved:
(1) deoptimization needs to handle functions with a local context,
(2) we need a safepoint in the prologue.
(Thanks to Kevin.)


Please review this at http://codereview.chromium.org/6534022/

SVN Base: http://v8.googlecode.com/svn/branches/bleeding_edge/

Affected files:
  M     src/hydrogen.cc
  M     src/ia32/deoptimizer-ia32.cc
  M     src/ia32/lithium-codegen-ia32.cc


Index: src/hydrogen.cc
===================================================================
--- src/hydrogen.cc     (revision 6838)
+++ src/hydrogen.cc     (working copy)
@@ -2292,9 +2292,6 @@
   // We don't yet handle the function name for named function expressions.
   if (scope->function() != NULL) BAILOUT("named function expression");

-  // We can't handle heap-allocated locals.
-  if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals");
-
   HConstant* undefined_constant =
       new HConstant(Factory::undefined_value(), Representation::Tagged());
   AddInstruction(undefined_constant);
@@ -2316,6 +2313,10 @@
   // Handle the arguments and arguments shadow variables specially (they do
   // not have declarations).
   if (scope->arguments() != NULL) {
+    if (!scope->arguments()->IsStackAllocated() ||
+        !scope->arguments_shadow()->IsStackAllocated()) {
+      BAILOUT("context-allocated arguments");
+    }
     HArgumentsObject* object = new HArgumentsObject;
     AddInstruction(object);
     graph()->SetArgumentsObject(object);
@@ -4023,6 +4024,7 @@
     }
     return false;
   }
+  if (inner_info.scope()->num_heap_slots() > 0) return false;
   FunctionLiteral* function = inner_info.function();

   // Count the number of AST nodes added by inlining this call.
Index: src/ia32/deoptimizer-ia32.cc
===================================================================
--- src/ia32/deoptimizer-ia32.cc        (revision 6838)
+++ src/ia32/deoptimizer-ia32.cc        (working copy)
@@ -431,14 +431,16 @@
            fp_value, output_offset, value);
   }

-  // The context can be gotten from the function so long as we don't
-  // optimize functions that need local contexts.
+ // For the bottommost output frame the context can be gotten from the input + // frame. For all subsequent output frames it can be gotten from the function
+  // so long as we don't inline functions that need local contexts.
   output_offset -= kPointerSize;
   input_offset -= kPointerSize;
-  value = reinterpret_cast<uint32_t>(function->context());
-  // The context for the bottommost output frame should also agree with the
-  // input frame.
-  ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
+  if (is_bottommost) {
+    value = input_->GetFrameSlot(input_offset);
+  } else {
+    value = reinterpret_cast<uint32_t>(function->context());
+  }
   output_frame->SetFrameSlot(output_offset, value);
   if (is_topmost) output_frame->SetRegister(esi.code(), value);
   if (FLAG_trace_deopt) {
Index: src/ia32/lithium-codegen-ia32.cc
===================================================================
--- src/ia32/lithium-codegen-ia32.cc    (revision 6838)
+++ src/ia32/lithium-codegen-ia32.cc    (working copy)
@@ -137,6 +137,46 @@
   __ push(esi);  // Callee's context.
   __ push(edi);  // Callee's JS function.

+  // Possibly allocate a local context.
+  int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+  if (heap_slots > 0) {
+    Comment(";;; Allocate local context");
+    // Argument to NewContext is the function, which is still in edi.
+    __ push(edi);
+    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(heap_slots);
+      __ CallStub(&stub);
+    } else {
+      __ CallRuntime(Runtime::kNewContext, 1);
+    }
+    safepoints_.DefineSafepoint(masm(), Safepoint::kSimple, 0,
+                                Safepoint::kNoDeoptimizationIndex);
+    // Context is returned in both eax and esi.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in esi.
+    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
+
+    // Copy parameters into context if necessary.
+    int num_parameters = scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Slot* slot = scope()->parameter(i)->AsSlot();
+      if (slot != NULL && slot->type() == Slot::CONTEXT) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+            (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ mov(eax, Operand(ebp, parameter_offset));
+        // Store it in the context.
+        int context_offset = Context::SlotOffset(slot->index());
+        __ mov(Operand(esi, context_offset), eax);
+        // Update the write barrier. This clobbers all involved
+        // registers, so we have use a third register to avoid
+        // clobbering esi.
+        __ mov(ecx, esi);
+        __ RecordWrite(ecx, context_offset, eax, ebx);
+      }
+    }
+    Comment(";;; End allocate local context");
+  }
+
   // Reserve space for the stack slots needed by the code.
   int slots = StackSlotCount();
   if (slots > 0) {


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

Reply via email to