Clean up return statements in the code generator by explicitly

counting the reference to the return value and passing it to the
return label.  This requires threading it through try/catch and
try/finally.  The return value is loaded into eax more lazily than
before.

Also, perform some related refactoring of jump targets.
Review URL: http://codereview.chromium.org/56172

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1669 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9bc64e65
...@@ -394,6 +394,7 @@ class CodeGenerator: public AstVisitor { ...@@ -394,6 +394,7 @@ class CodeGenerator: public AstVisitor {
// positions are collected by the assembler and emitted with the relocation // positions are collected by the assembler and emitted with the relocation
// information. // information.
void CodeForFunctionPosition(FunctionLiteral* fun); void CodeForFunctionPosition(FunctionLiteral* fun);
void CodeForReturnPosition(FunctionLiteral* fun);
void CodeForStatementPosition(Node* node); void CodeForStatementPosition(Node* node);
void CodeForSourcePosition(int pos); void CodeForSourcePosition(int pos);
......
...@@ -274,25 +274,29 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -274,25 +274,29 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
if (has_valid_frame()) { if (has_valid_frame()) {
// If there is a valid frame, control flow can fall off the end of // 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. // 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_); ASSERT(!function_return_is_shadowed_);
Literal undefined(Factory::undefined_value()); CodeForReturnPosition(fun);
ReturnStatement statement(&undefined); frame_->PrepareForReturn();
statement.set_statement_pos(fun->end_position()); Result undefined(Factory::undefined_value(), this);
VisitReturnStatement(&statement); 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()) { } else if (function_return_.is_linked()) {
// If the return target has dangling jumps to it, then we have not // If the return target has dangling jumps to it, then we have not
// yet generated the return sequence. This can happen when (a) // yet generated the return sequence. This can happen when (a)
// control does not flow off the end of the body so we did not // control does not flow off the end of the body so we did not
// compile an artificial return statement just above, and (b) there // compile an artificial return statement just above, and (b) there
// are return statements in the body but (c) they are all shadowed. // are return statements in the body but (c) they are all shadowed.
// Result return_value(this);
// There is no valid frame here but it is safe (also necessary) to // Though this is a (possibly) backward block, the frames can
// load the return value into eax. // only differ on their top element.
__ mov(eax, Immediate(Factory::undefined_value())); function_return_.Bind(&return_value, 1);
function_return_.Bind(); GenerateReturnSequence(&return_value);
GenerateReturnSequence();
} }
} }
} }
...@@ -1943,52 +1947,37 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { ...@@ -1943,52 +1947,37 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
CodeForStatementPosition(node);
Load(node->expression());
Result return_value = frame_->Pop();
if (function_return_is_shadowed_) { if (function_return_is_shadowed_) {
// If the function return is shadowed, we spill all information function_return_.Jump(&return_value);
// and just jump to the label.
VirtualFrame::SpilledScope spilled_scope(this);
CodeForStatementPosition(node);
LoadAndSpill(node->expression());
frame_->EmitPop(eax);
function_return_.Jump();
} else { } 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(); 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()) { 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 { } else {
function_return_.Bind(); // Though this is a (possibly) backward block, the frames can
GenerateReturnSequence(); // 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) // The return value is a live (but not currently reference counted)
// reference to eax. This is safe because the current frame does not // 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 // contain a reference to eax (it is prepared for the return by spilling
// all registers). // all registers).
ASSERT(has_valid_frame());
if (FLAG_trace) { if (FLAG_trace) {
frame_->Push(eax); // Materialize result on the stack. frame_->Push(return_value);
frame_->CallRuntime(Runtime::kTraceExit, 1); *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
} }
return_value->ToRegister(eax);
// Add a label for checking the size of the code used for returning. // Add a label for checking the size of the code used for returning.
Label check_exit_codesize; Label check_exit_codesize;
...@@ -2921,14 +2910,22 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { ...@@ -2921,14 +2910,22 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
} }
} }
// Generate unlink code for the (formerly) shadowing targets that have been // Generate unlink code for the (formerly) shadowing targets that
// jumped to. Deallocate each shadow target. // have been jumped to. Deallocate each shadow target.
Result return_value(this);
for (int i = 0; i < shadows.length(); i++) { for (int i = 0; i < shadows.length(); i++) {
if (shadows[i]->is_linked()) { if (shadows[i]->is_linked()) {
// Unlink from try chain; be careful not to destroy the TOS. // Unlink from try chain; be careful not to destroy the TOS if
shadows[i]->Bind(); // there is one.
// Because we can be jumping here (to spilled code) from unspilled if (i == kReturnShadowIndex) {
// code, we need to reestablish a spilled frame at this block. 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(); frame_->SpillAll();
// Reload sp from the top handler, because some statements that we // Reload sp from the top handler, because some statements that we
...@@ -2943,10 +2940,12 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { ...@@ -2943,10 +2940,12 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// next_sp popped. // next_sp popped.
if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { if (i == kReturnShadowIndex) {
frame_->PrepareForReturn(); 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]; delete shadows[i];
} }
...@@ -3043,13 +3042,18 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) { ...@@ -3043,13 +3042,18 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
for (int i = 0; i < shadows.length(); i++) { for (int i = 0; i < shadows.length(); i++) {
if (shadows[i]->is_linked()) { if (shadows[i]->is_linked()) {
// If we have come from the shadowed return, the return value is // If we have come from the shadowed return, the return value is
// in (a non-refcounted reference to) eax. We must preserve it // on the virtual frame. We must preserve it until it is
// until it is pushed. // 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 // Because we can be jumping here (to spilled code) from
// unspilled code, we need to reestablish a spilled frame at // unspilled code, we need to reestablish a spilled frame at
// this block. // this block.
shadows[i]->Bind();
frame_->SpillAll(); frame_->SpillAll();
// Reload sp from the top handler, because some statements that // Reload sp from the top handler, because some statements that
...@@ -3103,14 +3107,23 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) { ...@@ -3103,14 +3107,23 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
// formerly shadowing targets. Deallocate each shadow target. // formerly shadowing targets. Deallocate each shadow target.
for (int i = 0; i < shadows.length(); i++) { for (int i = 0; i < shadows.length(); i++) {
if (has_valid_frame() && shadows[i]->is_bound()) { 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))); __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { if (i == kReturnShadowIndex) {
JumpTarget skip(this); // The return value is (already) in eax.
skip.Branch(not_equal); Result return_value = allocator_->Allocate(eax);
frame_->PrepareForReturn(); ASSERT(return_value.is_valid());
original->Jump(); if (function_return_is_shadowed_) {
skip.Bind(); 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 { } else {
original->Branch(equal); original->Branch(equal);
} }
......
...@@ -371,11 +371,10 @@ class CodeGenerator: public AstVisitor { ...@@ -371,11 +371,10 @@ class CodeGenerator: public AstVisitor {
// Main code generation function // Main code generation function
void GenCode(FunctionLiteral* fun); void GenCode(FunctionLiteral* fun);
// Generate the return sequence code. Should be called no more than once // Generate the return sequence code. Should be called no more than
// per compiled function (it binds the return target, which can not be // once per compiled function, immediately after binding the return
// done more than once). The return value is assumed to be in eax by the // target (which can not be done more than once).
// code generated. void GenerateReturnSequence(Result* return_value);
void GenerateReturnSequence();
// The following are used by class Reference. // The following are used by class Reference.
void LoadReference(Reference* ref); void LoadReference(Reference* ref);
...@@ -567,6 +566,7 @@ class CodeGenerator: public AstVisitor { ...@@ -567,6 +566,7 @@ class CodeGenerator: public AstVisitor {
// positions are collected by the assembler and emitted with the relocation // positions are collected by the assembler and emitted with the relocation
// information. // information.
void CodeForFunctionPosition(FunctionLiteral* fun); void CodeForFunctionPosition(FunctionLiteral* fun);
void CodeForReturnPosition(FunctionLiteral* fun);
void CodeForStatementPosition(Node* node); void CodeForStatementPosition(Node* node);
void CodeForSourcePosition(int pos); void CodeForSourcePosition(int pos);
......
...@@ -566,12 +566,23 @@ void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) { ...@@ -566,12 +566,23 @@ void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
} }
void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) {
int pos = fun->start_position();
if (pos != RelocInfo::kNoPosition) {
masm()->RecordStatementPosition(pos);
masm()->RecordPosition(pos);
}
}
}
void CodeGenerator::CodeForStatementPosition(Node* node) { void CodeGenerator::CodeForStatementPosition(Node* node) {
if (FLAG_debug_info) { if (FLAG_debug_info) {
int pos = node->statement_pos(); int pos = node->statement_pos();
if (pos != RelocInfo::kNoPosition) { if (pos != RelocInfo::kNoPosition) {
masm()->RecordStatementPosition(pos); masm()->RecordStatementPosition(pos);
CodeForSourcePosition(pos); masm()->RecordPosition(pos);
} }
} }
} }
......
...@@ -35,37 +35,41 @@ ...@@ -35,37 +35,41 @@
// Include the declaration of the architecture defined class CodeGenerator. // Include the declaration of the architecture defined class CodeGenerator.
// The contract to the shared code is that the the CodeGenerator is a subclass // The contract to the shared code is that the the CodeGenerator is a subclass
// of Visitor and that the following methods are available publicly: // of Visitor and that the following methods are available publicly:
// CodeGenerator::MakeCode // MakeCode
// CodeGenerator::SetFunctionInfo // SetFunctionInfo
// CodeGenerator::masm // masm
// CodeGenerator::frame // frame
// CodeGenerator::has_valid_frame // has_valid_frame
// CodeGenerator::SetFrame // SetFrame
// CodeGenerator::DeleteFrame // DeleteFrame
// CodeGenerator::allocator // allocator
// CodeGenerator::AddDeferred // AddDeferred
// CodeGenerator::in_spilled_code // in_spilled_code
// CodeGenerator::set_in_spilled_code // set_in_spilled_code
// //
// These methods are either used privately by the shared code or implemented as // These methods are either used privately by the shared code or implemented as
// shared code: // shared code:
// CodeGenerator::CodeGenerator // CodeGenerator
// CodeGenerator::~CodeGenerator // ~CodeGenerator
// CodeGenerator::ProcessDeferred // ProcessDeferred
// CodeGenerator::ClearDeferred // ClearDeferred
// CodeGenerator::GenCode // GenCode
// CodeGenerator::BuildBoilerplate // BuildBoilerplate
// CodeGenerator::ComputeCallInitialize // ComputeCallInitialize
// CodeGenerator::ComputeCallInitializeInLoop // ComputeCallInitializeInLoop
// CodeGenerator::ProcessDeclarations // ProcessDeclarations
// CodeGenerator::DeclareGlobals // DeclareGlobals
// CodeGenerator::CheckForInlineRuntimeCall // CheckForInlineRuntimeCall
// CodeGenerator::GenerateFastCaseSwitchStatement // GenerateFastCaseSwitchStatement
// CodeGenerator::GenerateFastCaseSwitchCases // GenerateFastCaseSwitchCases
// CodeGenerator::TryGenerateFastCaseSwitchStatement // TryGenerateFastCaseSwitchStatement
// CodeGenerator::GenerateFastCaseSwitchJumpTable // GenerateFastCaseSwitchJumpTable
// CodeGenerator::FastCaseSwitchMinCaseCount // FastCaseSwitchMinCaseCount
// CodeGenerator::FastCaseSwitchMaxOverheadFactor // FastCaseSwitchMaxOverheadFactor
// CodeForFunctionPosition
// CodeForReturnPosition
// CodeForStatementPosition
// CodeForSourcePosition
#ifdef ARM #ifdef ARM
#include "codegen-arm.h" #include "codegen-arm.h"
......
...@@ -37,7 +37,7 @@ namespace v8 { namespace internal { ...@@ -37,7 +37,7 @@ namespace v8 { namespace internal {
#define __ masm_-> #define __ masm_->
void JumpTarget::Jump() { void JumpTarget::DoJump() {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
// Live non-frame registers are not allowed at unconditional jumps // Live non-frame registers are not allowed at unconditional jumps
...@@ -65,7 +65,7 @@ void JumpTarget::Jump() { ...@@ -65,7 +65,7 @@ void JumpTarget::Jump() {
} }
void JumpTarget::Branch(Condition cc, Hint ignored) { void JumpTarget::DoBranch(Condition cc, Hint ignored) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
...@@ -148,7 +148,7 @@ void JumpTarget::Call() { ...@@ -148,7 +148,7 @@ void JumpTarget::Call() {
} }
void JumpTarget::Bind(int mergable_elements) { void JumpTarget::DoBind(int mergable_elements) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(!is_bound()); ASSERT(!is_bound());
......
...@@ -37,7 +37,7 @@ namespace v8 { namespace internal { ...@@ -37,7 +37,7 @@ namespace v8 { namespace internal {
#define __ masm_-> #define __ masm_->
void JumpTarget::Jump() { void JumpTarget::DoJump() {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
// Live non-frame registers are not allowed at unconditional jumps // Live non-frame registers are not allowed at unconditional jumps
...@@ -65,7 +65,7 @@ void JumpTarget::Jump() { ...@@ -65,7 +65,7 @@ void JumpTarget::Jump() {
} }
void JumpTarget::Branch(Condition cc, Hint hint) { void JumpTarget::DoBranch(Condition cc, Hint hint) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
...@@ -148,7 +148,7 @@ void JumpTarget::Call() { ...@@ -148,7 +148,7 @@ void JumpTarget::Call() {
} }
void JumpTarget::Bind(int mergable_elements) { void JumpTarget::DoBind(int mergable_elements) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(!is_bound()); ASSERT(!is_bound());
......
...@@ -298,12 +298,17 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { ...@@ -298,12 +298,17 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
} }
void JumpTarget::Jump() {
DoJump();
}
void JumpTarget::Jump(Result* arg) { void JumpTarget::Jump(Result* arg) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
cgen_->frame()->Push(arg); cgen_->frame()->Push(arg);
Jump(); DoJump();
} }
...@@ -313,7 +318,7 @@ void JumpTarget::Jump(Result* arg0, Result* arg1) { ...@@ -313,7 +318,7 @@ void JumpTarget::Jump(Result* arg0, Result* arg1) {
cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg0);
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
Jump(); DoJump();
} }
...@@ -324,7 +329,12 @@ void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) { ...@@ -324,7 +329,12 @@ void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) {
cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg0);
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg2);
Jump(); DoJump();
}
void JumpTarget::Branch(Condition cc, Hint hint) {
DoBranch(cc, hint);
} }
...@@ -352,7 +362,7 @@ void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) { ...@@ -352,7 +362,7 @@ void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
DECLARE_ARGCHECK_VARS(arg); DECLARE_ARGCHECK_VARS(arg);
cgen_->frame()->Push(arg); cgen_->frame()->Push(arg);
Branch(cc, hint); DoBranch(cc, hint);
*arg = cgen_->frame()->Pop(); *arg = cgen_->frame()->Pop();
ASSERT_ARGCHECK(arg); ASSERT_ARGCHECK(arg);
...@@ -370,7 +380,7 @@ void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) { ...@@ -370,7 +380,7 @@ void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg0);
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
Branch(cc, hint); DoBranch(cc, hint);
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
*arg0 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop();
...@@ -396,7 +406,7 @@ void JumpTarget::Branch(Condition cc, ...@@ -396,7 +406,7 @@ void JumpTarget::Branch(Condition cc,
cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg0);
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg2);
Branch(cc, hint); DoBranch(cc, hint);
*arg2 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop();
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
*arg0 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop();
...@@ -427,7 +437,7 @@ void JumpTarget::Branch(Condition cc, ...@@ -427,7 +437,7 @@ void JumpTarget::Branch(Condition cc,
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg2);
cgen_->frame()->Push(arg3); cgen_->frame()->Push(arg3);
Branch(cc, hint); DoBranch(cc, hint);
*arg3 = cgen_->frame()->Pop(); *arg3 = cgen_->frame()->Pop();
*arg2 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop();
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
...@@ -439,17 +449,47 @@ void JumpTarget::Branch(Condition cc, ...@@ -439,17 +449,47 @@ void JumpTarget::Branch(Condition cc,
ASSERT_ARGCHECK(arg3); ASSERT_ARGCHECK(arg3);
} }
void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame());
int count = cgen_->frame()->height() - expected_height_;
if (count > 0) {
// We negate and branch here rather than using DoBranch's negate
// and branch. This gives us a hook to remove statement state
// from the frame.
JumpTarget fall_through(cgen_);
// Branch to fall through will not negate, because it is a
// forward-only target.
fall_through.Branch(NegateCondition(cc), NegateHint(hint));
Jump(arg); // May emit merge code here.
fall_through.Bind();
} else {
DECLARE_ARGCHECK_VARS(arg);
cgen_->frame()->Push(arg);
DoBranch(cc, hint);
*arg = cgen_->frame()->Pop();
ASSERT_ARGCHECK(arg);
}
}
#undef DECLARE_ARGCHECK_VARS #undef DECLARE_ARGCHECK_VARS
#undef ASSERT_ARGCHECK #undef ASSERT_ARGCHECK
void JumpTarget::Bind(int mergable_elements) {
DoBind(mergable_elements);
}
void JumpTarget::Bind(Result* arg, int mergable_elements) { void JumpTarget::Bind(Result* arg, int mergable_elements) {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
if (cgen_->has_valid_frame()) { if (cgen_->has_valid_frame()) {
cgen_->frame()->Push(arg); cgen_->frame()->Push(arg);
} }
Bind(mergable_elements); DoBind(mergable_elements);
*arg = cgen_->frame()->Pop(); *arg = cgen_->frame()->Pop();
} }
...@@ -461,7 +501,7 @@ void JumpTarget::Bind(Result* arg0, Result* arg1, int mergable_elements) { ...@@ -461,7 +501,7 @@ void JumpTarget::Bind(Result* arg0, Result* arg1, int mergable_elements) {
cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg0);
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
} }
Bind(mergable_elements); DoBind(mergable_elements);
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
*arg0 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop();
} }
...@@ -478,7 +518,7 @@ void JumpTarget::Bind(Result* arg0, ...@@ -478,7 +518,7 @@ void JumpTarget::Bind(Result* arg0,
cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg1);
cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg2);
} }
Bind(mergable_elements); DoBind(mergable_elements);
*arg2 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop();
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
*arg0 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop();
...@@ -498,7 +538,7 @@ void JumpTarget::Bind(Result* arg0, ...@@ -498,7 +538,7 @@ void JumpTarget::Bind(Result* arg0,
cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg2);
cgen_->frame()->Push(arg3); cgen_->frame()->Push(arg3);
} }
Bind(mergable_elements); DoBind(mergable_elements);
*arg3 = cgen_->frame()->Pop(); *arg3 = cgen_->frame()->Pop();
*arg2 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop();
*arg1 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop();
...@@ -548,10 +588,20 @@ void BreakTarget::Jump() { ...@@ -548,10 +588,20 @@ void BreakTarget::Jump() {
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame()); ASSERT(cgen_->has_valid_frame());
// This is a break target so drop leftover statement state from the // Drop leftover statement state from the frame before merging.
// frame before merging.
cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_); cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_);
JumpTarget::Jump(); DoJump();
}
void BreakTarget::Jump(Result* arg) {
ASSERT(cgen_ != NULL);
ASSERT(cgen_->has_valid_frame());
// Drop leftover statement state from the frame before merging.
cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_);
cgen_->frame()->Push(arg);
DoJump();
} }
...@@ -561,9 +611,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) { ...@@ -561,9 +611,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
int count = cgen_->frame()->height() - expected_height_; int count = cgen_->frame()->height() - expected_height_;
if (count > 0) { if (count > 0) {
// We negate and branch here rather than using // We negate and branch here rather than using DoBranch's negate
// JumpTarget::Branch's negate and branch. This gives us a hook // and branch. This gives us a hook to remove statement state
// to remove statement state from the frame. // from the frame.
JumpTarget fall_through(cgen_); JumpTarget fall_through(cgen_);
// Branch to fall through will not negate, because it is a // Branch to fall through will not negate, because it is a
// forward-only target. // forward-only target.
...@@ -571,14 +621,13 @@ void BreakTarget::Branch(Condition cc, Hint hint) { ...@@ -571,14 +621,13 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
Jump(); // May emit merge code here. Jump(); // May emit merge code here.
fall_through.Bind(); fall_through.Bind();
} else { } else {
JumpTarget::Branch(cc, hint); DoBranch(cc, hint);
} }
} }
void BreakTarget::Bind(int mergable_elements) { void BreakTarget::Bind(int mergable_elements) {
#ifdef DEBUG #ifdef DEBUG
ASSERT(mergable_elements == kAllElements);
ASSERT(cgen_ != NULL); ASSERT(cgen_ != NULL);
// All the forward-reaching frames should have been adjusted at the // All the forward-reaching frames should have been adjusted at the
// jumps to this target. // jumps to this target.
...@@ -587,13 +636,35 @@ void BreakTarget::Bind(int mergable_elements) { ...@@ -587,13 +636,35 @@ void BreakTarget::Bind(int mergable_elements) {
reaching_frames_[i]->height() == expected_height_); reaching_frames_[i]->height() == expected_height_);
} }
#endif #endif
// This is a break target so we drop leftover statement state from // Drop leftover statement state from the frame before merging, even
// the frame before merging, even on the fall through. This is // on the fall through. This is so we can bind the return target
// because we can bind the return target with state on the frame. // with state on the frame.
if (cgen_->has_valid_frame()) {
cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_);
}
DoBind(mergable_elements);
}
void BreakTarget::Bind(Result* arg, int mergable_elements) {
#ifdef DEBUG
ASSERT(cgen_ != NULL);
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_ + 1);
}
#endif
// Drop leftover statement state from the frame before merging, even
// on the fall through. This is so we can bind the return target
// with state on the frame.
if (cgen_->has_valid_frame()) { if (cgen_->has_valid_frame()) {
cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_); cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_);
cgen_->frame()->Push(arg);
} }
JumpTarget::Bind(mergable_elements); DoBind(mergable_elements);
*arg = cgen_->frame()->Pop();
} }
......
...@@ -105,7 +105,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. ...@@ -105,7 +105,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated.
// Emit a jump to the target. There must be a current frame at the // Emit a jump to the target. There must be a current frame at the
// jump and there will be no current frame after the jump. // jump and there will be no current frame after the jump.
virtual void Jump(); virtual void Jump();
void Jump(Result* arg); virtual void Jump(Result* arg);
void Jump(Result* arg0, Result* arg1); void Jump(Result* arg0, Result* arg1);
void Jump(Result* arg0, Result* arg1, Result* arg2); void Jump(Result* arg0, Result* arg1, Result* arg2);
...@@ -113,7 +113,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. ...@@ -113,7 +113,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated.
// frame at the branch. The current frame will fall through to the // frame at the branch. The current frame will fall through to the
// code after the branch. // code after the branch.
virtual void Branch(Condition cc, Hint hint = no_hint); virtual void Branch(Condition cc, Hint hint = no_hint);
void Branch(Condition cc, Result* arg, Hint hint = no_hint); virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
void Branch(Condition cc, Result* arg0, Result* arg1, Hint hint = no_hint); void Branch(Condition cc, Result* arg0, Result* arg1, Hint hint = no_hint);
void Branch(Condition cc, void Branch(Condition cc,
Result* arg0, Result* arg0,
...@@ -141,7 +141,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. ...@@ -141,7 +141,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated.
// frame elements must be mergable. Mergable elements are ignored // frame elements must be mergable. Mergable elements are ignored
// completely for forward-only jump targets. // completely for forward-only jump targets.
virtual void Bind(int mergable_elements = kAllElements); virtual void Bind(int mergable_elements = kAllElements);
void Bind(Result* arg, int mergable_elements = kAllElements); virtual void Bind(Result* arg, int mergable_elements = kAllElements);
void Bind(Result* arg0, Result* arg1, int mergable_elements = kAllElements); void Bind(Result* arg0, Result* arg1, int mergable_elements = kAllElements);
void Bind(Result* arg0, void Bind(Result* arg0,
Result* arg1, Result* arg1,
...@@ -191,6 +191,12 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. ...@@ -191,6 +191,12 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated.
bool is_bound_; bool is_bound_;
bool is_linked_; bool is_linked_;
// Implementations of Jump, Branch, and Bind with all arguments and
// return values using the virtual frame.
void DoJump();
void DoBranch(Condition cc, Hint hint);
void DoBind(int mergable_elements);
private: private:
// Add a virtual frame reaching this labeled block via a forward // Add a virtual frame reaching this labeled block via a forward
// jump, and a fresh label for its merge code. // jump, and a fresh label for its merge code.
...@@ -243,16 +249,19 @@ class BreakTarget : public JumpTarget { ...@@ -243,16 +249,19 @@ class BreakTarget : public JumpTarget {
// Emit a jump to the target. There must be a current frame at the // Emit a jump to the target. There must be a current frame at the
// jump and there will be no current frame after the jump. // jump and there will be no current frame after the jump.
virtual void Jump(); virtual void Jump();
virtual void Jump(Result* arg);
// Emit a conditional branch to the target. There must be a current // Emit a conditional branch to the target. There must be a current
// frame at the branch. The current frame will fall through to the // frame at the branch. The current frame will fall through to the
// code after the branch. // code after the branch.
virtual void Branch(Condition cc, Hint hint = no_hint); virtual void Branch(Condition cc, Hint hint = no_hint);
virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
// Bind a break target. If there is no current frame at the binding // Bind a break target. If there is no current frame at the binding
// site, there must be at least one frame reaching via a forward // site, there must be at least one frame reaching via a forward
// jump. // jump.
virtual void Bind(int mergable_elements = kAllElements); virtual void Bind(int mergable_elements = kAllElements);
virtual void Bind(Result* arg, int mergable_elements = kAllElements);
// Setter for expected height. // Setter for expected height.
void set_expected_height(int expected) { expected_height_ = expected; } void set_expected_height(int expected) { expected_height_ = expected; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment