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