diff --git a/src/codegen-arm.h b/src/codegen-arm.h index 7c4b069528..54c5e882ed 100644 --- a/src/codegen-arm.h +++ b/src/codegen-arm.h @@ -394,6 +394,7 @@ class CodeGenerator: public AstVisitor { // positions are collected by the assembler and emitted with the relocation // information. void CodeForFunctionPosition(FunctionLiteral* fun); + void CodeForReturnPosition(FunctionLiteral* fun); void CodeForStatementPosition(Node* node); void CodeForSourcePosition(int pos); diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc index b6d8c0196a..0e2a370017 100644 --- a/src/codegen-ia32.cc +++ b/src/codegen-ia32.cc @@ -274,25 +274,29 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) { 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 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { 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 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { } } - // 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 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { 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 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) { 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 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) { // 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); } diff --git a/src/codegen-ia32.h b/src/codegen-ia32.h index ceede0c7bf..d2a31f56ef 100644 --- a/src/codegen-ia32.h +++ b/src/codegen-ia32.h @@ -371,11 +371,10 @@ class CodeGenerator: public AstVisitor { // Main code generation function void GenCode(FunctionLiteral* fun); - // Generate the return sequence code. Should be called no more than once - // per compiled function (it binds the return target, which can not be - // done more than once). The return value is assumed to be in eax by the - // code generated. - void GenerateReturnSequence(); + // 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). + void GenerateReturnSequence(Result* return_value); // The following are used by class Reference. void LoadReference(Reference* ref); @@ -567,6 +566,7 @@ class CodeGenerator: public AstVisitor { // positions are collected by the assembler and emitted with the relocation // information. void CodeForFunctionPosition(FunctionLiteral* fun); + void CodeForReturnPosition(FunctionLiteral* fun); void CodeForStatementPosition(Node* node); void CodeForSourcePosition(int pos); diff --git a/src/codegen.cc b/src/codegen.cc index b00f002b5a..c8f69c734c 100644 --- a/src/codegen.cc +++ b/src/codegen.cc @@ -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) { if (FLAG_debug_info) { int pos = node->statement_pos(); if (pos != RelocInfo::kNoPosition) { masm()->RecordStatementPosition(pos); - CodeForSourcePosition(pos); + masm()->RecordPosition(pos); } } } diff --git a/src/codegen.h b/src/codegen.h index 3086638fc5..dd43cc0c8e 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -35,37 +35,41 @@ // Include the declaration of the architecture defined class CodeGenerator. // The contract to the shared code is that the the CodeGenerator is a subclass // of Visitor and that the following methods are available publicly: -// CodeGenerator::MakeCode -// CodeGenerator::SetFunctionInfo -// CodeGenerator::masm -// CodeGenerator::frame -// CodeGenerator::has_valid_frame -// CodeGenerator::SetFrame -// CodeGenerator::DeleteFrame -// CodeGenerator::allocator -// CodeGenerator::AddDeferred -// CodeGenerator::in_spilled_code -// CodeGenerator::set_in_spilled_code +// MakeCode +// SetFunctionInfo +// masm +// frame +// has_valid_frame +// SetFrame +// DeleteFrame +// allocator +// AddDeferred +// in_spilled_code +// set_in_spilled_code // // These methods are either used privately by the shared code or implemented as // shared code: -// CodeGenerator::CodeGenerator -// CodeGenerator::~CodeGenerator -// CodeGenerator::ProcessDeferred -// CodeGenerator::ClearDeferred -// CodeGenerator::GenCode -// CodeGenerator::BuildBoilerplate -// CodeGenerator::ComputeCallInitialize -// CodeGenerator::ComputeCallInitializeInLoop -// CodeGenerator::ProcessDeclarations -// CodeGenerator::DeclareGlobals -// CodeGenerator::CheckForInlineRuntimeCall -// CodeGenerator::GenerateFastCaseSwitchStatement -// CodeGenerator::GenerateFastCaseSwitchCases -// CodeGenerator::TryGenerateFastCaseSwitchStatement -// CodeGenerator::GenerateFastCaseSwitchJumpTable -// CodeGenerator::FastCaseSwitchMinCaseCount -// CodeGenerator::FastCaseSwitchMaxOverheadFactor +// CodeGenerator +// ~CodeGenerator +// ProcessDeferred +// ClearDeferred +// GenCode +// BuildBoilerplate +// ComputeCallInitialize +// ComputeCallInitializeInLoop +// ProcessDeclarations +// DeclareGlobals +// CheckForInlineRuntimeCall +// GenerateFastCaseSwitchStatement +// GenerateFastCaseSwitchCases +// TryGenerateFastCaseSwitchStatement +// GenerateFastCaseSwitchJumpTable +// FastCaseSwitchMinCaseCount +// FastCaseSwitchMaxOverheadFactor +// CodeForFunctionPosition +// CodeForReturnPosition +// CodeForStatementPosition +// CodeForSourcePosition #ifdef ARM #include "codegen-arm.h" diff --git a/src/jump-target-arm.cc b/src/jump-target-arm.cc index 41b80e2deb..3ce5f308ef 100644 --- a/src/jump-target-arm.cc +++ b/src/jump-target-arm.cc @@ -37,7 +37,7 @@ namespace v8 { namespace internal { #define __ masm_-> -void JumpTarget::Jump() { +void JumpTarget::DoJump() { ASSERT(cgen_ != NULL); ASSERT(cgen_->has_valid_frame()); // Live non-frame registers are not allowed at unconditional jumps @@ -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_->has_valid_frame()); @@ -148,7 +148,7 @@ void JumpTarget::Call() { } -void JumpTarget::Bind(int mergable_elements) { +void JumpTarget::DoBind(int mergable_elements) { ASSERT(cgen_ != NULL); ASSERT(!is_bound()); diff --git a/src/jump-target-ia32.cc b/src/jump-target-ia32.cc index d2d35ca618..8afb0a8ada 100644 --- a/src/jump-target-ia32.cc +++ b/src/jump-target-ia32.cc @@ -37,7 +37,7 @@ namespace v8 { namespace internal { #define __ masm_-> -void JumpTarget::Jump() { +void JumpTarget::DoJump() { ASSERT(cgen_ != NULL); ASSERT(cgen_->has_valid_frame()); // Live non-frame registers are not allowed at unconditional jumps @@ -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_->has_valid_frame()); @@ -148,7 +148,7 @@ void JumpTarget::Call() { } -void JumpTarget::Bind(int mergable_elements) { +void JumpTarget::DoBind(int mergable_elements) { ASSERT(cgen_ != NULL); ASSERT(!is_bound()); diff --git a/src/jump-target.cc b/src/jump-target.cc index 04affc907e..c38ef5b73b 100644 --- a/src/jump-target.cc +++ b/src/jump-target.cc @@ -298,12 +298,17 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { } +void JumpTarget::Jump() { + DoJump(); +} + + void JumpTarget::Jump(Result* arg) { ASSERT(cgen_ != NULL); ASSERT(cgen_->has_valid_frame()); cgen_->frame()->Push(arg); - Jump(); + DoJump(); } @@ -313,7 +318,7 @@ void JumpTarget::Jump(Result* arg0, Result* arg1) { cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg1); - Jump(); + DoJump(); } @@ -324,7 +329,12 @@ void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) { cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg1); 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) { DECLARE_ARGCHECK_VARS(arg); cgen_->frame()->Push(arg); - Branch(cc, hint); + DoBranch(cc, hint); *arg = cgen_->frame()->Pop(); ASSERT_ARGCHECK(arg); @@ -370,7 +380,7 @@ void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) { cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg1); - Branch(cc, hint); + DoBranch(cc, hint); *arg1 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop(); @@ -396,7 +406,7 @@ void JumpTarget::Branch(Condition cc, cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg2); - Branch(cc, hint); + DoBranch(cc, hint); *arg2 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop(); @@ -427,7 +437,7 @@ void JumpTarget::Branch(Condition cc, cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg3); - Branch(cc, hint); + DoBranch(cc, hint); *arg3 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop(); @@ -439,17 +449,47 @@ void JumpTarget::Branch(Condition cc, 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 ASSERT_ARGCHECK +void JumpTarget::Bind(int mergable_elements) { + DoBind(mergable_elements); +} + + void JumpTarget::Bind(Result* arg, int mergable_elements) { ASSERT(cgen_ != NULL); if (cgen_->has_valid_frame()) { cgen_->frame()->Push(arg); } - Bind(mergable_elements); + DoBind(mergable_elements); *arg = cgen_->frame()->Pop(); } @@ -461,7 +501,7 @@ void JumpTarget::Bind(Result* arg0, Result* arg1, int mergable_elements) { cgen_->frame()->Push(arg0); cgen_->frame()->Push(arg1); } - Bind(mergable_elements); + DoBind(mergable_elements); *arg1 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop(); } @@ -478,7 +518,7 @@ void JumpTarget::Bind(Result* arg0, cgen_->frame()->Push(arg1); cgen_->frame()->Push(arg2); } - Bind(mergable_elements); + DoBind(mergable_elements); *arg2 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop(); *arg0 = cgen_->frame()->Pop(); @@ -498,7 +538,7 @@ void JumpTarget::Bind(Result* arg0, cgen_->frame()->Push(arg2); cgen_->frame()->Push(arg3); } - Bind(mergable_elements); + DoBind(mergable_elements); *arg3 = cgen_->frame()->Pop(); *arg2 = cgen_->frame()->Pop(); *arg1 = cgen_->frame()->Pop(); @@ -548,10 +588,20 @@ void BreakTarget::Jump() { ASSERT(cgen_ != NULL); ASSERT(cgen_->has_valid_frame()); - // This is a break target so drop leftover statement state from the - // frame before merging. + // Drop leftover statement state from the frame before merging. 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) { int count = cgen_->frame()->height() - expected_height_; if (count > 0) { - // We negate and branch here rather than using - // JumpTarget::Branch's negate and branch. This gives us a hook - // to remove statement state from the frame. + // 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. @@ -571,14 +621,13 @@ void BreakTarget::Branch(Condition cc, Hint hint) { Jump(); // May emit merge code here. fall_through.Bind(); } else { - JumpTarget::Branch(cc, hint); + DoBranch(cc, hint); } } void BreakTarget::Bind(int mergable_elements) { #ifdef DEBUG - ASSERT(mergable_elements == kAllElements); ASSERT(cgen_ != NULL); // All the forward-reaching frames should have been adjusted at the // jumps to this target. @@ -587,13 +636,35 @@ void BreakTarget::Bind(int mergable_elements) { reaching_frames_[i]->height() == expected_height_); } #endif - // This is a break target so we drop leftover statement state from - // the frame before merging, even on the fall through. This is - // because we can bind the return target with state on the frame. + // 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()) { cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_); } - JumpTarget::Bind(mergable_elements); + 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()) { + cgen_->frame()->ForgetElements(cgen_->frame()->height() - expected_height_); + cgen_->frame()->Push(arg); + } + DoBind(mergable_elements); + *arg = cgen_->frame()->Pop(); } diff --git a/src/jump-target.h b/src/jump-target.h index 3a57302502..1cfbe29dca 100644 --- a/src/jump-target.h +++ b/src/jump-target.h @@ -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 // jump and there will be no current frame after the 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, Result* arg2); @@ -113,7 +113,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. // frame at the branch. The current frame will fall through to the // code after the branch. 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, @@ -141,7 +141,7 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. // frame elements must be mergable. Mergable elements are ignored // completely for forward-only jump targets. 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, @@ -191,6 +191,12 @@ class JumpTarget : public Malloced { // Shadows are dynamically allocated. bool is_bound_; 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: // Add a virtual frame reaching this labeled block via a forward // jump, and a fresh label for its merge code. @@ -243,16 +249,19 @@ class BreakTarget : public JumpTarget { // 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. virtual void Jump(); + virtual void Jump(Result* arg); // Emit a conditional branch to the target. There must be a current // frame at the branch. The current frame will fall through to the // code after the branch. 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 // site, there must be at least one frame reaching via a forward // jump. virtual void Bind(int mergable_elements = kAllElements); + virtual void Bind(Result* arg, int mergable_elements = kAllElements); // Setter for expected height. void set_expected_height(int expected) { expected_height_ = expected; }