Revision: 6903
Author: [email protected]
Date: Tue Feb 22 08:56:57 2011
Log: 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.)

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

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

=======================================
--- /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Mon Feb 14 04:07:48 2011 +++ /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Tue Feb 22 08:56:57 2011
@@ -429,14 +429,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<intptr_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<intptr_t>(function->context());
+  }
   output_frame->SetFrameSlot(output_offset, value);
   if (is_topmost) {
     output_frame->SetRegister(cp.code(), value);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Feb 21 03:29:45 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Feb 22 08:56:57 2011
@@ -143,6 +143,44 @@
       __ sub(sp,  sp, Operand(slots * kPointerSize));
     }
   }
+
+  // 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 in r1.
+    __ push(r1);
+    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(heap_slots);
+      __ CallStub(&stub);
+    } else {
+      __ CallRuntime(Runtime::kNewContext, 1);
+    }
+    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
+    // Context is returned in both r0 and cp.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in cp.
+    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    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.
+        __ ldr(r0, MemOperand(fp, parameter_offset));
+        // Store it in the context.
+        __ mov(r1, Operand(Context::SlotOffset(slot->index())));
+        __ str(r0, MemOperand(cp, r1));
+        // Update the write barrier. This clobbers all involved
+        // registers, so we have to use two more registers to avoid
+        // clobbering cp.
+        __ mov(r2, Operand(cp));
+        __ RecordWrite(r2, Operand(r1), r3, r0);
+      }
+    }
+    Comment(";;; End allocate local context");
+  }

   // Trace the call.
   if (FLAG_trace) {
@@ -613,6 +651,12 @@
                                int deoptimization_index) {
   RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
 }
+
+
+void LCodeGen::RecordSafepoint(int deoptimization_index) {
+  LPointerMap empty_pointers(RelocInfo::kNoPosition);
+  RecordSafepoint(&empty_pointers, deoptimization_index);
+}


 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Mon Feb 21 02:30:25 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Tue Feb 22 08:56:57 2011
@@ -221,6 +221,7 @@
                        int arguments,
                        int deoptimization_index);
   void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
+  void RecordSafepoint(int deoptimization_index);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
                                     int deoptimization_index);
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Feb 22 08:31:24 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Feb 22 08:56:57 2011
@@ -2275,9 +2275,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);
@@ -2299,6 +2296,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);
@@ -4060,6 +4061,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.
=======================================
--- /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Tue Feb 15 08:12:46 2011 +++ /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Tue Feb 22 08:56:57 2011
@@ -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) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Feb 22 04:28:33 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Feb 22 08:56:57 2011
@@ -173,6 +173,45 @@
 #endif
     }
   }
+
+  // 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);
+    }
+    RecordSafepoint(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 to use a third register to avoid
+        // clobbering esi.
+        __ mov(ecx, esi);
+        __ RecordWrite(ecx, context_offset, eax, ebx);
+      }
+    }
+    Comment(";;; End allocate local context");
+  }

   // Trace the call.
   if (FLAG_trace) {
@@ -623,6 +662,12 @@
                                int deoptimization_index) {
   RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
 }
+
+
+void LCodeGen::RecordSafepoint(int deoptimization_index) {
+  LPointerMap empty_pointers(RelocInfo::kNoPosition);
+  RecordSafepoint(&empty_pointers, deoptimization_index);
+}


 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Tue Feb 22 04:28:33 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Tue Feb 22 08:56:57 2011
@@ -210,6 +210,7 @@
                        int arguments,
                        int deoptimization_index);
   void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
+  void RecordSafepoint(int deoptimization_index);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
                                     int deoptimization_index);
=======================================
--- /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Tue Feb 15 05:37:10 2011 +++ /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Tue Feb 22 08:56:57 2011
@@ -358,14 +358,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<intptr_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<intptr_t>(function->context());
+  }
   output_frame->SetFrameSlot(output_offset, value);
   if (is_topmost) output_frame->SetRegister(rsi.code(), value);
   if (FLAG_trace_deopt) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Feb 22 06:40:13 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Feb 22 08:56:57 2011
@@ -162,6 +162,45 @@
 #endif
     }
   }
+
+  // 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 rdi.
+    __ push(rdi);
+    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(heap_slots);
+      __ CallStub(&stub);
+    } else {
+      __ CallRuntime(Runtime::kNewContext, 1);
+    }
+    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
+    // Context is returned in both rax and rsi.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in rsi.
+    __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
+
+    // Copy any necessary parameters into the context.
+    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.
+        __ movq(rax, Operand(rbp, parameter_offset));
+        // Store it in the context.
+        int context_offset = Context::SlotOffset(slot->index());
+        __ movq(Operand(rsi, context_offset), rax);
+        // Update the write barrier. This clobbers all involved
+        // registers, so we have use a third register to avoid
+        // clobbering rsi.
+        __ movq(rcx, rsi);
+        __ RecordWrite(rcx, context_offset, rax, rbx);
+      }
+    }
+    Comment(";;; End allocate local context");
+  }

   // Trace the call.
   if (FLAG_trace) {
@@ -568,6 +607,12 @@
                                int deoptimization_index) {
   RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
 }
+
+
+void LCodeGen::RecordSafepoint(int deoptimization_index) {
+  LPointerMap empty_pointers(RelocInfo::kNoPosition);
+  RecordSafepoint(&empty_pointers, deoptimization_index);
+}


 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Fri Feb 18 06:00:46 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Feb 22 08:56:57 2011
@@ -197,6 +197,7 @@
                        int arguments,
                        int deoptimization_index);
   void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
+  void RecordSafepoint(int deoptimization_index);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
                                     int deoptimization_index);

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

Reply via email to