Revision: 4856
Author: [email protected]
Date: Mon Jun 14 04:37:05 2010
Log: ARM: Change code generation for function return

Generating code for function return on ARM is now aligned with the other platforms. The first non-shadowed return statement encountered will emit code for function return and all other returns including the fall through at the bottom of a function will jump to that.
Review URL: http://codereview.chromium.org/2815003
http://code.google.com/p/v8/source/detail?r=4856

Modified:
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/virtual-frame-arm.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/virtual-frame-light-inl.h

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Jun 14 04:20:36 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Jun 14 04:37:05 2010
@@ -342,56 +342,27 @@
     }
   }

-  // Generate the return sequence if necessary.
-  if (has_valid_frame() || function_return_.is_linked()) {
-    if (!function_return_.is_linked()) {
-      CodeForReturnPosition(info->function());
-    }
-    // exit
-    // r0: result
-    // sp: stack pointer
-    // fp: frame pointer
-    // cp: callee's context
+  // Handle the return from the function.
+  if (has_valid_frame()) {
+    // If there is a valid frame, control flow can fall off the end of
+    // the body.  In that case there is an implicit return statement.
+    ASSERT(!function_return_is_shadowed_);
+    frame_->PrepareForReturn();
     __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
-
-    function_return_.Bind();
-    if (FLAG_trace) {
-      // Push the return value on the stack as the parameter.
-      // Runtime::TraceExit returns the parameter as it is.
-      frame_->EmitPush(r0);
-      frame_->CallRuntime(Runtime::kTraceExit, 1);
-    }
-
-#ifdef DEBUG
-    // Add a label for checking the size of the code used for returning.
-    Label check_exit_codesize;
-    masm_->bind(&check_exit_codesize);
-#endif
-    // Make sure that the constant pool is not emitted inside of the return
-    // sequence.
-    { Assembler::BlockConstPoolScope block_const_pool(masm_);
- // Tear down the frame which will restore the caller's frame pointer and
-      // the link register.
-      frame_->Exit();
-
- // Here we use masm_-> instead of the __ macro to avoid the code coverage
-      // tool from instrumenting as we rely on the code size here.
-      int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
-      masm_->add(sp, sp, Operand(sp_delta));
-      masm_->Jump(lr);
-
-#ifdef DEBUG
-      // Check that the size of the code used for returning matches what is
- // expected by the debugger. If the sp_delts above cannot be encoded in
-      // the add instruction the add will generate two instructions.
-      int return_sequence_length =
-          masm_->InstructionsGeneratedSince(&check_exit_codesize);
-      CHECK(return_sequence_length ==
-            Assembler::kJSReturnSequenceInstructions ||
-            return_sequence_length ==
-            Assembler::kJSReturnSequenceInstructions + 1);
-#endif
-    }
+    if (function_return_.is_bound()) {
+      function_return_.Jump();
+    } else {
+      function_return_.Bind();
+      GenerateReturnSequence();
+    }
+  } else if (function_return_.is_linked()) {
+    // If the return target has dangling jumps to it, then we have not
+    // yet generated the return sequence.  This can happen when (a)
+    // control does not flow off the end of the body so we did not
+    // compile an artificial return statement just above, and (b) there
+    // are return statements in the body but (c) they are all shadowed.
+    function_return_.Bind();
+    GenerateReturnSequence();
   }

   // Adjust for function-level loop nesting.
@@ -1958,8 +1929,56 @@
     // returning thus making it easier to merge.
     frame_->EmitPop(r0);
     frame_->PrepareForReturn();
-
-    function_return_.Jump();
+    if (function_return_.is_bound()) {
+      // If the function return label is already bound we reuse the
+      // code by jumping to the return site.
+      function_return_.Jump();
+    } else {
+      function_return_.Bind();
+      GenerateReturnSequence();
+    }
+  }
+}
+
+
+void CodeGenerator::GenerateReturnSequence() {
+  if (FLAG_trace) {
+    // Push the return value on the stack as the parameter.
+    // Runtime::TraceExit returns the parameter as it is.
+    frame_->EmitPush(r0);
+    frame_->CallRuntime(Runtime::kTraceExit, 1);
+  }
+
+#ifdef DEBUG
+  // Add a label for checking the size of the code used for returning.
+  Label check_exit_codesize;
+  masm_->bind(&check_exit_codesize);
+#endif
+  // Make sure that the constant pool is not emitted inside of the return
+  // sequence.
+  { Assembler::BlockConstPoolScope block_const_pool(masm_);
+ // Tear down the frame which will restore the caller's frame pointer and
+    // the link register.
+    frame_->Exit();
+
+ // Here we use masm_-> instead of the __ macro to avoid the code coverage
+    // tool from instrumenting as we rely on the code size here.
+    int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
+    masm_->add(sp, sp, Operand(sp_delta));
+    masm_->Jump(lr);
+    DeleteFrame();
+
+#ifdef DEBUG
+    // Check that the size of the code used for returning matches what is
+    // expected by the debugger. If the sp_delts above cannot be encoded in
+    // the add instruction the add will generate two instructions.
+    int return_sequence_length =
+        masm_->InstructionsGeneratedSince(&check_exit_codesize);
+    CHECK(return_sequence_length ==
+          Assembler::kJSReturnSequenceInstructions ||
+          return_sequence_length ==
+          Assembler::kJSReturnSequenceInstructions + 1);
+#endif
   }
 }

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Fri Jun 11 03:18:44 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Jun 14 04:37:05 2010
@@ -315,6 +315,12 @@
   // Main code generation function
   void Generate(CompilationInfo* info);

+  // Generate the return sequence code.  Should be called no more than
+  // once per compiled function, immediately after binding the return
+ // target (which can not be done more than once). The return value should
+  // be in r0.
+  void GenerateReturnSequence();
+
   // Returns the arguments allocation mode.
   ArgumentsAllocationMode ArgumentsMode();

=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.h Wed Jun 2 02:37:02 2010 +++ /branches/bleeding_edge/src/arm/virtual-frame-arm.h Mon Jun 14 04:37:05 2010
@@ -212,10 +212,9 @@
   void Enter();
   void Exit();

-  // Prepare for returning from the frame by spilling locals and
-  // dropping all non-locals elements in the virtual frame.  This
+ // Prepare for returning from the frame by elements in the virtual frame. This
   // avoids generating unnecessary merge code when jumping to the
-  // shared return site.  Emits code for spills.
+ // shared return site. No spill code emitted. Value to return should be in r0.
   inline void PrepareForReturn();

   // Number of local variables after when we use a loop for allocating.
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Jun 14 03:21:24 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Jun 14 04:37:05 2010
@@ -3278,6 +3278,9 @@


void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
+#ifdef DEBUG
+  int original_height = frame_->height();
+#endif
   ASSERT(in_spilled_code());
   set_in_spilled_code(false);
   VisitStatements(statements);
@@ -3285,14 +3288,20 @@
     frame_->SpillAll();
   }
   set_in_spilled_code(true);
+
+  ASSERT(!has_valid_frame() || frame_->height() == original_height);
 }


 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
+#ifdef DEBUG
+  int original_height = frame_->height();
+#endif
   ASSERT(!in_spilled_code());
   for (int i = 0; has_valid_frame() && i < statements->length(); i++) {
     Visit(statements->at(i));
   }
+  ASSERT(!has_valid_frame() || frame_->height() == original_height);
 }


=======================================
--- /branches/bleeding_edge/src/virtual-frame-light-inl.h Wed Jun 2 02:37:02 2010 +++ /branches/bleeding_edge/src/virtual-frame-light-inl.h Mon Jun 14 04:37:05 2010
@@ -74,7 +74,9 @@


 void VirtualFrame::PrepareForReturn() {
-  SpillAll();
+  // Don't bother flushing tos registers as returning does not require more
+  // access to the expression stack.
+  top_of_stack_state_ = NO_TOS_REGISTERS;
 }


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

Reply via email to