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
This commit is contained in:
parent
9bc64e657a
commit
06860982a9
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user