Index: src/codegen-ia32.cc |
=================================================================== |
--- src/codegen-ia32.cc (revision 1668) |
+++ src/codegen-ia32.cc (working copy) |
@@ -274,25 +274,29 @@ |
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. |
- // Compiling a return statement will jump to the return sequence if |
- // it is already generated or generate it if not. |
ASSERT(!function_return_is_shadowed_); |
- Literal undefined(Factory::undefined_value()); |
- ReturnStatement statement(&undefined); |
- statement.set_statement_pos(fun->end_position()); |
- VisitReturnStatement(&statement); |
+ CodeForReturnPosition(fun); |
+ frame_->PrepareForReturn(); |
+ Result undefined(Factory::undefined_value(), this); |
+ if (function_return_.is_bound()) { |
+ function_return_.Jump(&undefined); |
+ } else { |
+ // Though this is a (possibly) backward block, the frames |
+ // can only differ on their top element. |
+ function_return_.Bind(&undefined, 1); |
+ GenerateReturnSequence(&undefined); |
+ } |
} 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. |
- // |
- // There is no valid frame here but it is safe (also necessary) to |
- // load the return value into eax. |
- __ mov(eax, Immediate(Factory::undefined_value())); |
- function_return_.Bind(); |
- GenerateReturnSequence(); |
+ Result return_value(this); |
+ // Though this is a (possibly) backward block, the frames can |
+ // only differ on their top element. |
+ function_return_.Bind(&return_value, 1); |
+ GenerateReturnSequence(&return_value); |
} |
} |
} |
@@ -1943,52 +1947,37 @@ |
ASSERT(!in_spilled_code()); |
Comment cmnt(masm_, "[ ReturnStatement"); |
+ CodeForStatementPosition(node); |
+ Load(node->expression()); |
+ Result return_value = frame_->Pop(); |
if (function_return_is_shadowed_) { |
- // If the function return is shadowed, we spill all information |
- // and just jump to the label. |
- VirtualFrame::SpilledScope spilled_scope(this); |
- CodeForStatementPosition(node); |
- LoadAndSpill(node->expression()); |
- frame_->EmitPop(eax); |
- function_return_.Jump(); |
+ function_return_.Jump(&return_value); |
} else { |
- // Load the returned value. |
- CodeForStatementPosition(node); |
- Load(node->expression()); |
- |
- // Pop the result from the frame and prepare the frame for |
- // returning thus making it easier to merge. |
- Result result = frame_->Pop(); |
frame_->PrepareForReturn(); |
- |
- // Move the result into register eax where it belongs. |
- result.ToRegister(eax); |
- // TODO(203): Instead of explictly calling Unuse on the result, it |
- // might be better to pass the result to Jump and Bind below. |
- result.Unuse(); |
- |
- // If the function return label is already bound, we reuse the |
- // code by jumping to the return site. |
if (function_return_.is_bound()) { |
- function_return_.Jump(); |
+ // If the function return label is already bound we reuse the |
+ // code by jumping to the return site. |
+ function_return_.Jump(&return_value); |
} else { |
- function_return_.Bind(); |
- GenerateReturnSequence(); |
+ // Though this is a (possibly) backward block, the frames can |
+ // only differ on their top element. |
+ function_return_.Bind(&return_value, 1); |
+ GenerateReturnSequence(&return_value); |
} |
} |
} |
-void CodeGenerator::GenerateReturnSequence() { |
+void CodeGenerator::GenerateReturnSequence(Result* return_value) { |
// The return value is a live (but not currently reference counted) |
// reference to eax. This is safe because the current frame does not |
// contain a reference to eax (it is prepared for the return by spilling |
// all registers). |
- ASSERT(has_valid_frame()); |
if (FLAG_trace) { |
- frame_->Push(eax); // Materialize result on the stack. |
- frame_->CallRuntime(Runtime::kTraceExit, 1); |
+ frame_->Push(return_value); |
+ *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1); |
} |
+ return_value->ToRegister(eax); |
// Add a label for checking the size of the code used for returning. |
Label check_exit_codesize; |
@@ -2921,14 +2910,22 @@ |
} |
} |
- // Generate unlink code for the (formerly) shadowing targets that have been |
- // jumped to. Deallocate each shadow target. |
+ // Generate unlink code for the (formerly) shadowing targets that |
+ // have been jumped to. Deallocate each shadow target. |
+ Result return_value(this); |
for (int i = 0; i < shadows.length(); i++) { |
if (shadows[i]->is_linked()) { |
- // Unlink from try chain; be careful not to destroy the TOS. |
- shadows[i]->Bind(); |
- // Because we can be jumping here (to spilled code) from unspilled |
- // code, we need to reestablish a spilled frame at this block. |
+ // Unlink from try chain; be careful not to destroy the TOS if |
+ // there is one. |
+ if (i == kReturnShadowIndex) { |
+ shadows[i]->Bind(&return_value); |
+ return_value.ToRegister(eax); |
+ } else { |
+ shadows[i]->Bind(); |
+ } |
+ // Because we can be jumping here (to spilled code) from |
+ // unspilled code, we need to reestablish a spilled frame at |
+ // this block. |
frame_->SpillAll(); |
// Reload sp from the top handler, because some statements that we |
@@ -2943,10 +2940,12 @@ |
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
// next_sp popped. |
- if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
- frame_->PrepareForReturn(); |
+ if (i == kReturnShadowIndex) { |
+ if (!function_return_is_shadowed_) frame_->PrepareForReturn(); |
+ shadows[i]->other_target()->Jump(&return_value); |
+ } else { |
+ shadows[i]->other_target()->Jump(); |
} |
- shadows[i]->other_target()->Jump(); |
} |
delete shadows[i]; |
} |
@@ -3043,13 +3042,18 @@ |
for (int i = 0; i < shadows.length(); i++) { |
if (shadows[i]->is_linked()) { |
// If we have come from the shadowed return, the return value is |
- // in (a non-refcounted reference to) eax. We must preserve it |
- // until it is pushed. |
- // |
+ // on the virtual frame. We must preserve it until it is |
+ // pushed. |
+ if (i == kReturnShadowIndex) { |
+ Result return_value(this); |
+ shadows[i]->Bind(&return_value); |
+ return_value.ToRegister(eax); |
+ } else { |
+ shadows[i]->Bind(); |
+ } |
// Because we can be jumping here (to spilled code) from |
// unspilled code, we need to reestablish a spilled frame at |
// this block. |
- shadows[i]->Bind(); |
frame_->SpillAll(); |
// Reload sp from the top handler, because some statements that |
@@ -3103,14 +3107,23 @@ |
// formerly shadowing targets. Deallocate each shadow target. |
for (int i = 0; i < shadows.length(); i++) { |
if (has_valid_frame() && shadows[i]->is_bound()) { |
- JumpTarget* original = shadows[i]->other_target(); |
+ BreakTarget* original = shadows[i]->other_target(); |
__ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
- if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
- JumpTarget skip(this); |
- skip.Branch(not_equal); |
- frame_->PrepareForReturn(); |
- original->Jump(); |
- skip.Bind(); |
+ if (i == kReturnShadowIndex) { |
+ // The return value is (already) in eax. |
+ Result return_value = allocator_->Allocate(eax); |
+ ASSERT(return_value.is_valid()); |
+ if (function_return_is_shadowed_) { |
+ original->Branch(equal, &return_value); |
+ } else { |
+ // Branch around the preparation for return which may emit |
+ // code. |
+ JumpTarget skip(this); |
+ skip.Branch(not_equal); |
+ frame_->PrepareForReturn(); |
+ original->Jump(&return_value); |
+ skip.Bind(); |
+ } |
} else { |
original->Branch(equal); |
} |