Split the AST LoopStatement type into separate types for do/while,

while, and for loops.

Previously they were distinguished by a type field, which required
runtime asserts to avoid invalid nodes (since not all loop types have
the same internal structure).  Now they C++ type system is used to
require well-formed loop ASTs.

Because they do not share compilation code, we had very large
functions in the code generators that merely did a runtime dispatch to
a specific implementation based on the type.
Review URL: http://codereview.chromium.org/269049

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3048 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c6729115
...@@ -1539,68 +1539,54 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { ...@@ -1539,68 +1539,54 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
} }
void CodeGenerator::VisitLoopStatement(LoopStatement* node) { void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame_->height(); int original_height = frame_->height();
#endif #endif
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ LoopStatement"); Comment cmnt(masm_, "[ DoWhileStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
// known result for the test expression, with no side effects.
enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
if (node->cond() == NULL) {
ASSERT(node->type() == LoopStatement::FOR_LOOP);
info = ALWAYS_TRUE;
} else {
Literal* lit = node->cond()->AsLiteral();
if (lit != NULL) {
if (lit->IsTrue()) {
info = ALWAYS_TRUE;
} else if (lit->IsFalse()) {
info = ALWAYS_FALSE;
}
}
}
switch (node->type()) {
case LoopStatement::DO_LOOP: {
JumpTarget body(JumpTarget::BIDIRECTIONAL); JumpTarget body(JumpTarget::BIDIRECTIONAL);
// Label the top of the loop for the backward CFG edge. If the test // Label the top of the loop for the backward CFG edge. If the test
// is always true we can use the continue target, and if the test is // is always true we can use the continue target, and if the test is
// always false there is no need. // always false there is no need.
if (info == ALWAYS_TRUE) { ConditionAnalysis info = AnalyzeCondition(node->cond());
switch (info) {
case ALWAYS_TRUE:
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else if (info == ALWAYS_FALSE) { break;
case ALWAYS_FALSE:
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else { break;
ASSERT(info == DONT_KNOW); case DONT_KNOW:
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
body.Bind(); body.Bind();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
VisitAndSpill(node->body()); VisitAndSpill(node->body());
// Compile the test. // Compile the test.
if (info == ALWAYS_TRUE) { switch (info) {
if (has_valid_frame()) { case ALWAYS_TRUE:
// If control can fall off the end of the body, jump back to the // If control can fall off the end of the body, jump back to the
// top. // top.
if (has_valid_frame()) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} else if (info == ALWAYS_FALSE) { break;
// If we have a continue in the body, we only have to bind its jump case ALWAYS_FALSE:
// target. // If we have a continue in the body, we only have to bind its
// jump target.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
} else { break;
ASSERT(info == DONT_KNOW); case DONT_KNOW:
// We have to compile the test expression if it can be reached by // We have to compile the test expression if it can be reached by
// control flow falling out of the body or via continue. // control flow falling out of the body or via continue.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
...@@ -1615,14 +1601,30 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1615,14 +1601,30 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
Branch(true, &body); Branch(true, &body);
} }
} }
}
break; break;
} }
case LoopStatement::WHILE_LOOP: { if (node->break_target()->is_linked()) {
node->break_target()->Bind();
}
ASSERT(!has_valid_frame() || frame_->height() == original_height);
}
void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
#ifdef DEBUG
int original_height = frame_->height();
#endif
VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ WhileStatement");
CodeForStatementPosition(node);
// If the test is never true and has no side effects there is no need // If the test is never true and has no side effects there is no need
// to compile the test or body. // to compile the test or body.
if (info == ALWAYS_FALSE) break; ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
// Label the top of the loop with the continue target for the backward // Label the top of the loop with the continue target for the backward
// CFG edge. // CFG edge.
...@@ -1652,21 +1654,34 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1652,21 +1654,34 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} }
break; if (node->break_target()->is_linked()) {
node->break_target()->Bind();
} }
ASSERT(!has_valid_frame() || frame_->height() == original_height);
}
case LoopStatement::FOR_LOOP: {
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
void CodeGenerator::VisitForStatement(ForStatement* node) {
#ifdef DEBUG
int original_height = frame_->height();
#endif
VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ ForStatement");
CodeForStatementPosition(node);
if (node->init() != NULL) { if (node->init() != NULL) {
VisitAndSpill(node->init()); VisitAndSpill(node->init());
} }
// There is no need to compile the test or body. // If the test is never true there is no need to compile the test or
if (info == ALWAYS_FALSE) break; // body.
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
// If there is no update statement, label the top of the loop with the // If there is no update statement, label the top of the loop with the
// continue target, otherwise with the loop target. // continue target, otherwise with the loop target.
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
if (node->next() == NULL) { if (node->next() == NULL) {
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
...@@ -1715,15 +1730,9 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1715,15 +1730,9 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
} }
} }
break;
}
}
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->continue_target()->Unuse();
node->break_target()->Unuse();
ASSERT(!has_valid_frame() || frame_->height() == original_height); ASSERT(!has_valid_frame() || frame_->height() == original_height);
} }
...@@ -1918,12 +1927,12 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -1918,12 +1927,12 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
} }
void CodeGenerator::VisitTryCatch(TryCatch* node) { void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame_->height(); int original_height = frame_->height();
#endif #endif
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryCatch"); Comment cmnt(masm_, "[ TryCatchStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
JumpTarget try_block; JumpTarget try_block;
...@@ -2043,12 +2052,12 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { ...@@ -2043,12 +2052,12 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
} }
void CodeGenerator::VisitTryFinally(TryFinally* node) { void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame_->height(); int original_height = frame_->height();
#endif #endif
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryFinally"); Comment cmnt(masm_, "[ TryFinallyStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
// State: Used to keep track of reason for entering the finally // State: Used to keep track of reason for entering the finally
......
...@@ -365,6 +365,14 @@ class CodeGenerator: public AstVisitor { ...@@ -365,6 +365,14 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
ALWAYS_TRUE,
ALWAYS_FALSE,
DONT_KNOW
};
ConditionAnalysis AnalyzeCondition(Expression* cond);
// Methods used to indicate which source code is generated for. Source // Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the relocation // positions are collected by the assembler and emitted with the relocation
// information. // information.
......
...@@ -91,20 +91,6 @@ void VariableProxy::BindTo(Variable* var) { ...@@ -91,20 +91,6 @@ void VariableProxy::BindTo(Variable* var) {
} }
#ifdef DEBUG
const char* LoopStatement::OperatorString() const {
switch (type()) {
case DO_LOOP: return "DO";
case FOR_LOOP: return "FOR";
case WHILE_LOOP: return "WHILE";
}
return NULL;
}
#endif // DEBUG
Token::Value Assignment::binary_op() const { Token::Value Assignment::binary_op() const {
switch (op_) { switch (op_) {
case Token::ASSIGN_BIT_OR: return Token::BIT_OR; case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
......
...@@ -64,10 +64,12 @@ namespace internal { ...@@ -64,10 +64,12 @@ namespace internal {
V(WithEnterStatement) \ V(WithEnterStatement) \
V(WithExitStatement) \ V(WithExitStatement) \
V(SwitchStatement) \ V(SwitchStatement) \
V(LoopStatement) \ V(DoWhileStatement) \
V(WhileStatement) \
V(ForStatement) \
V(ForInStatement) \ V(ForInStatement) \
V(TryCatch) \ V(TryCatchStatement) \
V(TryFinally) \ V(TryFinallyStatement) \
V(DebuggerStatement) V(DebuggerStatement)
#define EXPRESSION_NODE_LIST(V) \ #define EXPRESSION_NODE_LIST(V) \
...@@ -294,13 +296,59 @@ class IterationStatement: public BreakableStatement { ...@@ -294,13 +296,59 @@ class IterationStatement: public BreakableStatement {
}; };
class LoopStatement: public IterationStatement { class DoWhileStatement: public IterationStatement {
public: public:
enum Type { DO_LOOP, FOR_LOOP, WHILE_LOOP }; explicit DoWhileStatement(ZoneStringList* labels)
: IterationStatement(labels), cond_(NULL) {
}
void Initialize(Expression* cond, Statement* body) {
IterationStatement::Initialize(body);
cond_ = cond;
}
virtual void Accept(AstVisitor* v);
Expression* cond() const { return cond_; }
private:
Expression* cond_;
};
class WhileStatement: public IterationStatement {
public:
explicit WhileStatement(ZoneStringList* labels)
: IterationStatement(labels),
cond_(NULL),
may_have_function_literal_(true) {
}
void Initialize(Expression* cond, Statement* body) {
IterationStatement::Initialize(body);
cond_ = cond;
}
virtual void Accept(AstVisitor* v);
Expression* cond() const { return cond_; }
bool may_have_function_literal() const {
return may_have_function_literal_;
}
LoopStatement(ZoneStringList* labels, Type type) private:
Expression* cond_;
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
friend class AstOptimizer;
};
class ForStatement: public IterationStatement {
public:
explicit ForStatement(ZoneStringList* labels)
: IterationStatement(labels), : IterationStatement(labels),
type_(type),
init_(NULL), init_(NULL),
cond_(NULL), cond_(NULL),
next_(NULL), next_(NULL),
...@@ -311,8 +359,6 @@ class LoopStatement: public IterationStatement { ...@@ -311,8 +359,6 @@ class LoopStatement: public IterationStatement {
Expression* cond, Expression* cond,
Statement* next, Statement* next,
Statement* body) { Statement* body) {
ASSERT(init == NULL || type_ == FOR_LOOP);
ASSERT(next == NULL || type_ == FOR_LOOP);
IterationStatement::Initialize(body); IterationStatement::Initialize(body);
init_ = init; init_ = init;
cond_ = cond; cond_ = cond;
...@@ -321,7 +367,6 @@ class LoopStatement: public IterationStatement { ...@@ -321,7 +367,6 @@ class LoopStatement: public IterationStatement {
virtual void Accept(AstVisitor* v); virtual void Accept(AstVisitor* v);
Type type() const { return type_; }
Statement* init() const { return init_; } Statement* init() const { return init_; }
Expression* cond() const { return cond_; } Expression* cond() const { return cond_; }
Statement* next() const { return next_; } Statement* next() const { return next_; }
...@@ -329,12 +374,7 @@ class LoopStatement: public IterationStatement { ...@@ -329,12 +374,7 @@ class LoopStatement: public IterationStatement {
return may_have_function_literal_; return may_have_function_literal_;
} }
#ifdef DEBUG
const char* OperatorString() const;
#endif
private: private:
Type type_;
Statement* init_; Statement* init_;
Expression* cond_; Expression* cond_;
Statement* next_; Statement* next_;
...@@ -569,9 +609,11 @@ class TryStatement: public Statement { ...@@ -569,9 +609,11 @@ class TryStatement: public Statement {
}; };
class TryCatch: public TryStatement { class TryCatchStatement: public TryStatement {
public: public:
TryCatch(Block* try_block, Expression* catch_var, Block* catch_block) TryCatchStatement(Block* try_block,
Expression* catch_var,
Block* catch_block)
: TryStatement(try_block), : TryStatement(try_block),
catch_var_(catch_var), catch_var_(catch_var),
catch_block_(catch_block) { catch_block_(catch_block) {
...@@ -589,9 +631,9 @@ class TryCatch: public TryStatement { ...@@ -589,9 +631,9 @@ class TryCatch: public TryStatement {
}; };
class TryFinally: public TryStatement { class TryFinallyStatement: public TryStatement {
public: public:
TryFinally(Block* try_block, Block* finally_block) TryFinallyStatement(Block* try_block, Block* finally_block)
: TryStatement(try_block), : TryStatement(try_block),
finally_block_(finally_block) { } finally_block_(finally_block) { }
......
...@@ -469,6 +469,25 @@ bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name, ...@@ -469,6 +469,25 @@ bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
} }
// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
// known result for the test expression, with no side effects.
CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
Expression* cond) {
if (cond == NULL) return ALWAYS_TRUE;
Literal* lit = cond->AsLiteral();
if (lit == NULL) return DONT_KNOW;
if (lit->IsTrue()) {
return ALWAYS_TRUE;
} else if (lit->IsFalse()) {
return ALWAYS_FALSE;
}
return DONT_KNOW;
}
static inline void RecordPositions(CodeGenerator* cgen, int pos) { static inline void RecordPositions(CodeGenerator* cgen, int pos) {
if (pos != RelocInfo::kNoPosition) { if (pos != RelocInfo::kNoPosition) {
cgen->masm()->RecordStatementPosition(pos); cgen->masm()->RecordStatementPosition(pos);
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
// FindInlineRuntimeLUT // FindInlineRuntimeLUT
// CheckForInlineRuntimeCall // CheckForInlineRuntimeCall
// PatchInlineRuntimeEntry // PatchInlineRuntimeEntry
// AnalyzeCondition
// CodeForFunctionPosition // CodeForFunctionPosition
// CodeForReturnPosition // CodeForReturnPosition
// CodeForStatementPosition // CodeForStatementPosition
......
...@@ -2698,64 +2698,49 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { ...@@ -2698,64 +2698,49 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
} }
void CodeGenerator::VisitLoopStatement(LoopStatement* node) { void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ LoopStatement"); Comment cmnt(masm_, "[ DoWhileStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
// known result for the test expression, with no side effects.
enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
if (node->cond() == NULL) {
ASSERT(node->type() == LoopStatement::FOR_LOOP);
info = ALWAYS_TRUE;
} else {
Literal* lit = node->cond()->AsLiteral();
if (lit != NULL) {
if (lit->IsTrue()) {
info = ALWAYS_TRUE;
} else if (lit->IsFalse()) {
info = ALWAYS_FALSE;
}
}
}
switch (node->type()) {
case LoopStatement::DO_LOOP: {
JumpTarget body(JumpTarget::BIDIRECTIONAL); JumpTarget body(JumpTarget::BIDIRECTIONAL);
IncrementLoopNesting(); IncrementLoopNesting();
ConditionAnalysis info = AnalyzeCondition(node->cond());
// Label the top of the loop for the backward jump if necessary. // Label the top of the loop for the backward jump if necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
// Use the continue target. // Use the continue target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else if (info == ALWAYS_FALSE) { break;
case ALWAYS_FALSE:
// No need to label it. // No need to label it.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else { break;
case DONT_KNOW:
// Continue is the test, so use the backward body target. // Continue is the test, so use the backward body target.
ASSERT(info == DONT_KNOW);
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
body.Bind(); body.Bind();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
Visit(node->body()); Visit(node->body());
// Compile the test. // Compile the test.
if (info == ALWAYS_TRUE) { switch (info) {
// If control flow can fall off the end of the body, jump back case ALWAYS_TRUE:
// to the top and bind the break target at the exit. // If control flow can fall off the end of the body, jump back to
// the top and bind the break target at the exit.
if (has_valid_frame()) { if (has_valid_frame()) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
} else if (info == ALWAYS_FALSE) { case ALWAYS_FALSE:
// We may have had continues or breaks in the body. // We may have had continues or breaks in the body.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
node->continue_target()->Bind(); node->continue_target()->Bind();
...@@ -2763,9 +2748,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2763,9 +2748,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
} else { case DONT_KNOW:
ASSERT(info == DONT_KNOW);
// We have to compile the test expression if it can be reached by // We have to compile the test expression if it can be reached by
// control flow falling out of the body or via continue. // control flow falling out of the body or via continue.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
...@@ -2778,63 +2762,78 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2778,63 +2762,78 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
}
break; break;
} }
case LoopStatement::WHILE_LOOP: { DecrementLoopNesting();
// Do not duplicate conditions that may have function literal }
// subexpressions. This can cause us to compile the function
// literal twice.
bool test_at_bottom = !node->may_have_function_literal();
IncrementLoopNesting();
// If the condition is always false and has no side effects, we void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
// do not need to compile anything. ASSERT(!in_spilled_code());
if (info == ALWAYS_FALSE) break; Comment cmnt(masm_, "[ WhileStatement");
CodeForStatementPosition(node);
// If the condition is always false and has no side effects, we do not
// need to compile anything.
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
// Do not duplicate conditions that may have function literal
// subexpressions. This can cause us to compile the function literal
// twice.
bool test_at_bottom = !node->may_have_function_literal();
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
IncrementLoopNesting();
JumpTarget body; JumpTarget body;
if (test_at_bottom) { if (test_at_bottom) {
body.set_direction(JumpTarget::BIDIRECTIONAL); body.set_direction(JumpTarget::BIDIRECTIONAL);
} }
// Based on the condition analysis, compile the test as necessary. // Based on the condition analysis, compile the test as necessary.
if (info == ALWAYS_TRUE) { switch (info) {
// We will not compile the test expression. Label the top of case ALWAYS_TRUE:
// the loop with the continue target. // We will not compile the test expression. Label the top of the
// loop with the continue target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else { break;
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. case DONT_KNOW: {
if (test_at_bottom) { if (test_at_bottom) {
// Continue is the test at the bottom, no need to label the // Continue is the test at the bottom, no need to label the test
// test at the top. The body is a backward target. // at the top. The body is a backward target.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else { } else {
// Label the test at the top as the continue target. The // Label the test at the top as the continue target. The body
// body is a forward-only target. // is a forward-only target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Compile the test with the body as the true target and // Compile the test with the body as the true target and preferred
// preferred fall-through and with the break target as the // fall-through and with the break target as the false target.
// false target.
ControlDestination dest(&body, node->break_target(), true); ControlDestination dest(&body, node->break_target(), true);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
if (dest.false_was_fall_through()) { if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may // If we got the break target as fall-through, the test may have
// have been unconditionally false (if there are no jumps to // been unconditionally false (if there are no jumps to the
// the body). // body).
if (!body.is_linked()) break; if (!body.is_linked()) {
DecrementLoopNesting();
return;
}
// Otherwise, jump around the body on the fall through and // Otherwise, jump around the body on the fall through and then
// then bind the body target. // bind the body target.
node->break_target()->Unuse(); node->break_target()->Unuse();
node->break_target()->Jump(); node->break_target()->Jump();
body.Bind(); body.Bind();
} }
break;
}
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
...@@ -2842,16 +2841,17 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2842,16 +2841,17 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Based on the condition analysis, compile the backward jump as // Based on the condition analysis, compile the backward jump as
// necessary. // necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
// The loop body has been labeled with the continue target. // The loop body has been labeled with the continue target.
if (has_valid_frame()) { if (has_valid_frame()) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} else { break;
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. case DONT_KNOW:
if (test_at_bottom) { if (test_at_bottom) {
// If we have chosen to recompile the test at the bottom, // If we have chosen to recompile the test at the bottom, then
// then it is the continue target. // it is the continue target.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
...@@ -2862,38 +2862,48 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2862,38 +2862,48 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
} }
} else { } else {
// If we have chosen not to recompile the test at the // If we have chosen not to recompile the test at the bottom,
// bottom, jump back to the one at the top. // jump back to the one at the top.
if (has_valid_frame()) { if (has_valid_frame()) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} }
break;
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
// The break target may be already bound (by the condition), or // The break target may be already bound (by the condition), or there
// there may not be a valid frame. Bind it only if needed. // may not be a valid frame. Bind it only if needed.
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break; DecrementLoopNesting();
} }
case LoopStatement::FOR_LOOP: {
// Do not duplicate conditions that may have function literal void CodeGenerator::VisitForStatement(ForStatement* node) {
// subexpressions. This can cause us to compile the function ASSERT(!in_spilled_code());
// literal twice. Comment cmnt(masm_, "[ ForStatement");
bool test_at_bottom = !node->may_have_function_literal(); CodeForStatementPosition(node);
// Compile the init expression if present. // Compile the init expression if present.
if (node->init() != NULL) { if (node->init() != NULL) {
Visit(node->init()); Visit(node->init());
} }
IncrementLoopNesting(); // If the condition is always false and has no side effects, we do not
// need to compile anything else.
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
// If the condition is always false and has no side effects, we // Do not duplicate conditions that may have function literal
// do not need to compile anything else. // subexpressions. This can cause us to compile the function literal
if (info == ALWAYS_FALSE) break; // twice.
bool test_at_bottom = !node->may_have_function_literal();
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
IncrementLoopNesting();
// Target for backward edge if no test at the bottom, otherwise // Target for backward edge if no test at the bottom, otherwise
// unused. // unused.
...@@ -2907,9 +2917,10 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2907,9 +2917,10 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
// Based on the condition analysis, compile the test as necessary. // Based on the condition analysis, compile the test as necessary.
if (info == ALWAYS_TRUE) { switch (info) {
// We will not compile the test expression. Label the top of case ALWAYS_TRUE:
// the loop. // We will not compile the test expression. Label the top of the
// loop.
if (node->next() == NULL) { if (node->next() == NULL) {
// Use the continue target if there is no update expression. // Use the continue target if there is no update expression.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
...@@ -2919,42 +2930,48 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2919,42 +2930,48 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
loop.Bind(); loop.Bind();
} }
} else { break;
ASSERT(info == DONT_KNOW); case DONT_KNOW: {
if (test_at_bottom) { if (test_at_bottom) {
// Continue is either the update expression or the test at // Continue is either the update expression or the test at the
// the bottom, no need to label the test at the top. // bottom, no need to label the test at the top.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else if (node->next() == NULL) { } else if (node->next() == NULL) {
// We are not recompiling the test at the bottom and there // We are not recompiling the test at the bottom and there is no
// is no update expression. // update expression.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else { } else {
// We are not recompiling the test at the bottom and there // We are not recompiling the test at the bottom and there is an
// is an update expression. // update expression.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
loop.Bind(); loop.Bind();
} }
// Compile the test with the body as the true target and preferred
// Compile the test with the body as the true target and // fall-through and with the break target as the false target.
// preferred fall-through and with the break target as the
// false target.
ControlDestination dest(&body, node->break_target(), true); ControlDestination dest(&body, node->break_target(), true);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
if (dest.false_was_fall_through()) { if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may // If we got the break target as fall-through, the test may have
// have been unconditionally false (if there are no jumps to // been unconditionally false (if there are no jumps to the
// the body). // body).
if (!body.is_linked()) break; if (!body.is_linked()) {
DecrementLoopNesting();
return;
}
// Otherwise, jump around the body on the fall through and // Otherwise, jump around the body on the fall through and then
// then bind the body target. // bind the body target.
node->break_target()->Unuse(); node->break_target()->Unuse();
node->break_target()->Jump(); node->break_target()->Jump();
body.Bind(); body.Bind();
} }
break;
}
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
...@@ -2966,12 +2983,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2966,12 +2983,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Control can reach the update by falling out of the body or // Control can reach the update by falling out of the body or by a
// by a continue. // continue.
if (has_valid_frame()) { if (has_valid_frame()) {
// Record the source position of the statement as this code // Record the source position of the statement as this code which
// which is after the code for the body actually belongs to // is after the code for the body actually belongs to the loop
// the loop statement and not the body. // statement and not the body.
CodeForStatementPosition(node); CodeForStatementPosition(node);
Visit(node->next()); Visit(node->next());
} }
...@@ -2979,7 +2996,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2979,7 +2996,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Based on the condition analysis, compile the backward jump as // Based on the condition analysis, compile the backward jump as
// necessary. // necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
if (has_valid_frame()) { if (has_valid_frame()) {
if (node->next() == NULL) { if (node->next() == NULL) {
node->continue_target()->Jump(); node->continue_target()->Jump();
...@@ -2987,20 +3005,19 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2987,20 +3005,19 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
loop.Jump(); loop.Jump();
} }
} }
} else { case DONT_KNOW:
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here.
if (test_at_bottom) { if (test_at_bottom) {
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
// We can have dangling jumps to the continue target if // We can have dangling jumps to the continue target if there
// there was no update expression. // was no update expression.
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Control can reach the test at the bottom by falling out // Control can reach the test at the bottom by falling out of
// of the body, by a continue in the body, or from the // the body, by a continue in the body, or from the update
// update expression. // expression.
if (has_valid_frame()) { if (has_valid_frame()) {
// The break target is the fall-through (body is a // The break target is the fall-through (body is a backward
// backward jump from here). // jump from here).
ControlDestination dest(&body, node->break_target(), false); ControlDestination dest(&body, node->break_target(), false);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
} }
...@@ -3014,6 +3031,9 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -3014,6 +3031,9 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
} }
} }
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
// The break target may be already bound (by the condition), or // The break target may be already bound (by the condition), or
...@@ -3021,13 +3041,7 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -3021,13 +3041,7 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
}
}
DecrementLoopNesting(); DecrementLoopNesting();
node->continue_target()->Unuse();
node->break_target()->Unuse();
} }
...@@ -3221,10 +3235,10 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -3221,10 +3235,10 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
} }
void CodeGenerator::VisitTryCatch(TryCatch* node) { void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryCatch"); Comment cmnt(masm_, "[ TryCatchStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
JumpTarget try_block; JumpTarget try_block;
...@@ -3357,10 +3371,10 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { ...@@ -3357,10 +3371,10 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
} }
void CodeGenerator::VisitTryFinally(TryFinally* node) { void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryFinally"); Comment cmnt(masm_, "[ TryFinallyStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
// State: Used to keep track of reason for entering the finally // State: Used to keep track of reason for entering the finally
......
...@@ -548,6 +548,14 @@ class CodeGenerator: public AstVisitor { ...@@ -548,6 +548,14 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
ALWAYS_TRUE,
ALWAYS_FALSE,
DONT_KNOW
};
ConditionAnalysis AnalyzeCondition(Expression* cond);
// Methods used to indicate which source code is generated for. Source // Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the relocation // positions are collected by the assembler and emitted with the relocation
// information. // information.
......
...@@ -177,8 +177,8 @@ class Parser { ...@@ -177,8 +177,8 @@ class Parser {
Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
LoopStatement* ParseDoStatement(ZoneStringList* labels, bool* ok); DoWhileStatement* ParseDoWhileStatement(ZoneStringList* labels, bool* ok);
LoopStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok); WhileStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok);
Statement* ParseForStatement(ZoneStringList* labels, bool* ok); Statement* ParseForStatement(ZoneStringList* labels, bool* ok);
Statement* ParseThrowStatement(bool* ok); Statement* ParseThrowStatement(bool* ok);
Expression* MakeCatchContext(Handle<String> id, VariableProxy* value); Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
...@@ -1692,7 +1692,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { ...@@ -1692,7 +1692,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
break; break;
case Token::DO: case Token::DO:
stmt = ParseDoStatement(labels, ok); stmt = ParseDoWhileStatement(labels, ok);
break; break;
case Token::WHILE: case Token::WHILE:
...@@ -2361,7 +2361,7 @@ Block* Parser::WithHelper(Expression* obj, ...@@ -2361,7 +2361,7 @@ Block* Parser::WithHelper(Expression* obj,
exit->AddStatement(NEW(WithExitStatement())); exit->AddStatement(NEW(WithExitStatement()));
// Return a try-finally statement. // Return a try-finally statement.
TryFinally* wrapper = NEW(TryFinally(body, exit)); TryFinallyStatement* wrapper = NEW(TryFinallyStatement(body, exit));
wrapper->set_escaping_targets(collector.targets()); wrapper->set_escaping_targets(collector.targets());
result->AddStatement(wrapper); result->AddStatement(wrapper);
} }
...@@ -2537,7 +2537,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2537,7 +2537,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// 'try { try { } catch { } } finally { }' // 'try { try { } catch { } } finally { }'
if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) { if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) {
TryCatch* statement = NEW(TryCatch(try_block, catch_var, catch_block)); TryCatchStatement* statement =
NEW(TryCatchStatement(try_block, catch_var, catch_block));
statement->set_escaping_targets(collector.targets()); statement->set_escaping_targets(collector.targets());
try_block = NEW(Block(NULL, 1, false)); try_block = NEW(Block(NULL, 1, false));
try_block->AddStatement(statement); try_block->AddStatement(statement);
...@@ -2548,11 +2549,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2548,11 +2549,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (!is_pre_parsing_) { if (!is_pre_parsing_) {
if (catch_block != NULL) { if (catch_block != NULL) {
ASSERT(finally_block == NULL); ASSERT(finally_block == NULL);
result = NEW(TryCatch(try_block, catch_var, catch_block)); result = NEW(TryCatchStatement(try_block, catch_var, catch_block));
result->set_escaping_targets(collector.targets()); result->set_escaping_targets(collector.targets());
} else { } else {
ASSERT(finally_block != NULL); ASSERT(finally_block != NULL);
result = NEW(TryFinally(try_block, finally_block)); result = NEW(TryFinallyStatement(try_block, finally_block));
// Add the jump targets of the try block and the catch block. // Add the jump targets of the try block and the catch block.
for (int i = 0; i < collector.targets()->length(); i++) { for (int i = 0; i < collector.targets()->length(); i++) {
catch_collector.AddTarget(collector.targets()->at(i)); catch_collector.AddTarget(collector.targets()->at(i));
...@@ -2565,11 +2566,12 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2565,11 +2566,12 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
} }
LoopStatement* Parser::ParseDoStatement(ZoneStringList* labels, bool* ok) { DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
bool* ok) {
// DoStatement :: // DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';' // 'do' Statement 'while' '(' Expression ')' ';'
LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::DO_LOOP)); DoWhileStatement* loop = NEW(DoWhileStatement(labels));
Target target(this, loop); Target target(this, loop);
Expect(Token::DO, CHECK_OK); Expect(Token::DO, CHECK_OK);
...@@ -2585,16 +2587,16 @@ LoopStatement* Parser::ParseDoStatement(ZoneStringList* labels, bool* ok) { ...@@ -2585,16 +2587,16 @@ LoopStatement* Parser::ParseDoStatement(ZoneStringList* labels, bool* ok) {
// ExpectSemicolon() functionality here. // ExpectSemicolon() functionality here.
if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON); if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
if (loop) loop->Initialize(NULL, cond, NULL, body); if (loop != NULL) loop->Initialize(cond, body);
return loop; return loop;
} }
LoopStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
// WhileStatement :: // WhileStatement ::
// 'while' '(' Expression ')' Statement // 'while' '(' Expression ')' Statement
LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::WHILE_LOOP)); WhileStatement* loop = NEW(WhileStatement(labels));
Target target(this, loop); Target target(this, loop);
Expect(Token::WHILE, CHECK_OK); Expect(Token::WHILE, CHECK_OK);
...@@ -2603,7 +2605,7 @@ LoopStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { ...@@ -2603,7 +2605,7 @@ LoopStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(NULL, cond, NULL, body); if (loop != NULL) loop->Initialize(cond, body);
return loop; return loop;
} }
...@@ -2676,7 +2678,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2676,7 +2678,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
} }
// Standard 'for' loop // Standard 'for' loop
LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::FOR_LOOP)); ForStatement* loop = NEW(ForStatement(labels));
Target target(this, loop); Target target(this, loop);
// Parsed initializer at this point. // Parsed initializer at this point.
......
...@@ -147,20 +147,27 @@ void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) { ...@@ -147,20 +147,27 @@ void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
} }
void PrettyPrinter::VisitLoopStatement(LoopStatement* node) { void PrettyPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
PrintLabels(node->labels()); PrintLabels(node->labels());
switch (node->type()) {
case LoopStatement::DO_LOOP:
ASSERT(node->init() == NULL);
ASSERT(node->next() == NULL);
Print("do "); Print("do ");
Visit(node->body()); Visit(node->body());
Print(" while ("); Print(" while (");
Visit(node->cond()); Visit(node->cond());
Print(");"); Print(");");
break; }
case LoopStatement::FOR_LOOP:
void PrettyPrinter::VisitWhileStatement(WhileStatement* node) {
PrintLabels(node->labels());
Print("while (");
Visit(node->cond());
Print(") ");
Visit(node->body());
}
void PrettyPrinter::VisitForStatement(ForStatement* node) {
PrintLabels(node->labels());
Print("for ("); Print("for (");
if (node->init() != NULL) { if (node->init() != NULL) {
Visit(node->init()); Visit(node->init());
...@@ -168,25 +175,14 @@ void PrettyPrinter::VisitLoopStatement(LoopStatement* node) { ...@@ -168,25 +175,14 @@ void PrettyPrinter::VisitLoopStatement(LoopStatement* node) {
} else { } else {
Print("; "); Print("; ");
} }
if (node->cond() != NULL) if (node->cond() != NULL) Visit(node->cond());
Visit(node->cond());
Print("; "); Print("; ");
if (node->next() != NULL) if (node->next() != NULL) {
Visit(node->next()); // prints extra ';', unfortunately Visit(node->next()); // prints extra ';', unfortunately
// to fix: should use Expression for next // to fix: should use Expression for next
}
Print(") "); Print(") ");
Visit(node->body()); Visit(node->body());
break;
case LoopStatement::WHILE_LOOP:
ASSERT(node->init() == NULL);
ASSERT(node->next() == NULL);
Print("while (");
Visit(node->cond());
Print(") ");
Visit(node->body());
break;
}
} }
...@@ -201,7 +197,7 @@ void PrettyPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -201,7 +197,7 @@ void PrettyPrinter::VisitForInStatement(ForInStatement* node) {
} }
void PrettyPrinter::VisitTryCatch(TryCatch* node) { void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
Print("try "); Print("try ");
Visit(node->try_block()); Visit(node->try_block());
Print(" catch ("); Print(" catch (");
...@@ -211,7 +207,7 @@ void PrettyPrinter::VisitTryCatch(TryCatch* node) { ...@@ -211,7 +207,7 @@ void PrettyPrinter::VisitTryCatch(TryCatch* node) {
} }
void PrettyPrinter::VisitTryFinally(TryFinally* node) { void PrettyPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
Print("try "); Print("try ");
Visit(node->try_block()); Visit(node->try_block());
Print(" finally "); Print(" finally ");
...@@ -841,12 +837,28 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { ...@@ -841,12 +837,28 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
} }
void AstPrinter::VisitLoopStatement(LoopStatement* node) { void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
IndentedScope indent(node->OperatorString()); IndentedScope indent("DO");
PrintLabelsIndented(NULL, node->labels());
PrintIndentedVisit("BODY", node->body());
PrintIndentedVisit("COND", node->cond());
}
void AstPrinter::VisitWhileStatement(WhileStatement* node) {
IndentedScope indent("WHILE");
PrintLabelsIndented(NULL, node->labels());
PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body());
}
void AstPrinter::VisitForStatement(ForStatement* node) {
IndentedScope indent("FOR");
PrintLabelsIndented(NULL, node->labels()); PrintLabelsIndented(NULL, node->labels());
if (node->init()) PrintIndentedVisit("INIT", node->init()); if (node->init()) PrintIndentedVisit("INIT", node->init());
if (node->cond()) PrintIndentedVisit("COND", node->cond()); if (node->cond()) PrintIndentedVisit("COND", node->cond());
if (node->body()) PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
if (node->next()) PrintIndentedVisit("NEXT", node->next()); if (node->next()) PrintIndentedVisit("NEXT", node->next());
} }
...@@ -859,7 +871,7 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -859,7 +871,7 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
} }
void AstPrinter::VisitTryCatch(TryCatch* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
IndentedScope indent("TRY CATCH"); IndentedScope indent("TRY CATCH");
PrintIndentedVisit("TRY", node->try_block()); PrintIndentedVisit("TRY", node->try_block());
PrintIndentedVisit("CATCHVAR", node->catch_var()); PrintIndentedVisit("CATCHVAR", node->catch_var());
...@@ -867,7 +879,7 @@ void AstPrinter::VisitTryCatch(TryCatch* node) { ...@@ -867,7 +879,7 @@ void AstPrinter::VisitTryCatch(TryCatch* node) {
} }
void AstPrinter::VisitTryFinally(TryFinally* node) { void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
IndentedScope indent("TRY FINALLY"); IndentedScope indent("TRY FINALLY");
PrintIndentedVisit("TRY", node->try_block()); PrintIndentedVisit("TRY", node->try_block());
PrintIndentedVisit("FINALLY", node->finally_block()); PrintIndentedVisit("FINALLY", node->finally_block());
......
...@@ -100,7 +100,21 @@ void AstOptimizer::VisitIfStatement(IfStatement* node) { ...@@ -100,7 +100,21 @@ void AstOptimizer::VisitIfStatement(IfStatement* node) {
} }
void AstOptimizer::VisitLoopStatement(LoopStatement* node) { void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) {
Visit(node->cond());
Visit(node->body());
}
void AstOptimizer::VisitWhileStatement(WhileStatement* node) {
has_function_literal_ = false;
Visit(node->cond());
node->may_have_function_literal_ = has_function_literal_;
Visit(node->body());
}
void AstOptimizer::VisitForStatement(ForStatement* node) {
if (node->init() != NULL) { if (node->init() != NULL) {
Visit(node->init()); Visit(node->init());
} }
...@@ -109,9 +123,7 @@ void AstOptimizer::VisitLoopStatement(LoopStatement* node) { ...@@ -109,9 +123,7 @@ void AstOptimizer::VisitLoopStatement(LoopStatement* node) {
Visit(node->cond()); Visit(node->cond());
node->may_have_function_literal_ = has_function_literal_; node->may_have_function_literal_ = has_function_literal_;
} }
if (node->body() != NULL) {
Visit(node->body()); Visit(node->body());
}
if (node->next() != NULL) { if (node->next() != NULL) {
Visit(node->next()); Visit(node->next());
} }
...@@ -125,14 +137,14 @@ void AstOptimizer::VisitForInStatement(ForInStatement* node) { ...@@ -125,14 +137,14 @@ void AstOptimizer::VisitForInStatement(ForInStatement* node) {
} }
void AstOptimizer::VisitTryCatch(TryCatch* node) { void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) {
Visit(node->try_block()); Visit(node->try_block());
Visit(node->catch_var()); Visit(node->catch_var());
Visit(node->catch_block()); Visit(node->catch_block());
} }
void AstOptimizer::VisitTryFinally(TryFinally* node) { void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) {
Visit(node->try_block()); Visit(node->try_block());
Visit(node->finally_block()); Visit(node->finally_block());
} }
...@@ -553,6 +565,8 @@ class Processor: public AstVisitor { ...@@ -553,6 +565,8 @@ class Processor: public AstVisitor {
virtual void Visit##type(type* node); virtual void Visit##type(type* node);
AST_NODE_LIST(DEF_VISIT) AST_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT #undef DEF_VISIT
void VisitIterationStatement(IterationStatement* stmt);
}; };
...@@ -596,25 +610,35 @@ void Processor::VisitIfStatement(IfStatement* node) { ...@@ -596,25 +610,35 @@ void Processor::VisitIfStatement(IfStatement* node) {
} }
void Processor::VisitIterationStatement(IterationStatement* node) {
// Rewrite the body.
void Processor::VisitLoopStatement(LoopStatement* node) {
// Rewrite loop body statement.
bool set_after_loop = is_set_; bool set_after_loop = is_set_;
Visit(node->body()); Visit(node->body());
is_set_ = is_set_ && set_after_loop; is_set_ = is_set_ && set_after_loop;
} }
void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
VisitIterationStatement(node);
}
void Processor::VisitWhileStatement(WhileStatement* node) {
VisitIterationStatement(node);
}
void Processor::VisitForStatement(ForStatement* node) {
VisitIterationStatement(node);
}
void Processor::VisitForInStatement(ForInStatement* node) { void Processor::VisitForInStatement(ForInStatement* node) {
// Rewrite for-in body statement. VisitIterationStatement(node);
bool set_after_for = is_set_;
Visit(node->body());
is_set_ = is_set_ && set_after_for;
} }
void Processor::VisitTryCatch(TryCatch* node) { void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
// Rewrite both try and catch blocks (reversed order). // Rewrite both try and catch blocks (reversed order).
bool set_after_catch = is_set_; bool set_after_catch = is_set_;
Visit(node->catch_block()); Visit(node->catch_block());
...@@ -626,7 +650,7 @@ void Processor::VisitTryCatch(TryCatch* node) { ...@@ -626,7 +650,7 @@ void Processor::VisitTryCatch(TryCatch* node) {
} }
void Processor::VisitTryFinally(TryFinally* node) { void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
// Rewrite both try and finally block (reversed order). // Rewrite both try and finally block (reversed order).
Visit(node->finally_block()); Visit(node->finally_block());
bool save = in_try_; bool save = in_try_;
......
...@@ -159,14 +159,25 @@ void UsageComputer::VisitSwitchStatement(SwitchStatement* node) { ...@@ -159,14 +159,25 @@ void UsageComputer::VisitSwitchStatement(SwitchStatement* node) {
} }
void UsageComputer::VisitLoopStatement(LoopStatement* node) { void UsageComputer::VisitDoWhileStatement(DoWhileStatement* node) {
if (node->init() != NULL) WeightScaler ws(this, 10.0);
Visit(node->init());
{ WeightScaler ws(this, 10.0); // executed in each iteration
if (node->cond() != NULL)
Read(node->cond()); Read(node->cond());
if (node->next() != NULL) Visit(node->body());
Visit(node->next()); }
void UsageComputer::VisitWhileStatement(WhileStatement* node) {
WeightScaler ws(this, 10.0);
Read(node->cond());
Visit(node->body());
}
void UsageComputer::VisitForStatement(ForStatement* node) {
if (node->init() != NULL) Visit(node->init());
{ WeightScaler ws(this, 10.0); // executed in each iteration
if (node->cond() != NULL) Read(node->cond());
if (node->next() != NULL) Visit(node->next());
Visit(node->body()); Visit(node->body());
} }
} }
...@@ -180,7 +191,7 @@ void UsageComputer::VisitForInStatement(ForInStatement* node) { ...@@ -180,7 +191,7 @@ void UsageComputer::VisitForInStatement(ForInStatement* node) {
} }
void UsageComputer::VisitTryCatch(TryCatch* node) { void UsageComputer::VisitTryCatchStatement(TryCatchStatement* node) {
Visit(node->try_block()); Visit(node->try_block());
{ WeightScaler ws(this, 0.25); { WeightScaler ws(this, 0.25);
Write(node->catch_var()); Write(node->catch_var());
...@@ -189,7 +200,7 @@ void UsageComputer::VisitTryCatch(TryCatch* node) { ...@@ -189,7 +200,7 @@ void UsageComputer::VisitTryCatch(TryCatch* node) {
} }
void UsageComputer::VisitTryFinally(TryFinally* node) { void UsageComputer::VisitTryFinallyStatement(TryFinallyStatement* node) {
Visit(node->try_block()); Visit(node->try_block());
Visit(node->finally_block()); Visit(node->finally_block());
} }
......
...@@ -1292,54 +1292,39 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { ...@@ -1292,54 +1292,39 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
} }
void CodeGenerator::VisitLoopStatement(LoopStatement* node) { void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ LoopStatement"); Comment cmnt(masm_, "[ DoWhileStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
// known result for the test expression, with no side effects.
enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
if (node->cond() == NULL) {
ASSERT(node->type() == LoopStatement::FOR_LOOP);
info = ALWAYS_TRUE;
} else {
Literal* lit = node->cond()->AsLiteral();
if (lit != NULL) {
if (lit->IsTrue()) {
info = ALWAYS_TRUE;
} else if (lit->IsFalse()) {
info = ALWAYS_FALSE;
}
}
}
switch (node->type()) {
case LoopStatement::DO_LOOP: {
JumpTarget body(JumpTarget::BIDIRECTIONAL); JumpTarget body(JumpTarget::BIDIRECTIONAL);
IncrementLoopNesting(); IncrementLoopNesting();
ConditionAnalysis info = AnalyzeCondition(node->cond());
// Label the top of the loop for the backward jump if necessary. // Label the top of the loop for the backward jump if necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
// Use the continue target. // Use the continue target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else if (info == ALWAYS_FALSE) { break;
case ALWAYS_FALSE:
// No need to label it. // No need to label it.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else { break;
case DONT_KNOW:
// Continue is the test, so use the backward body target. // Continue is the test, so use the backward body target.
ASSERT(info == DONT_KNOW);
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
body.Bind(); body.Bind();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
Visit(node->body()); Visit(node->body());
// Compile the test. // Compile the test.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
// If control flow can fall off the end of the body, jump back // If control flow can fall off the end of the body, jump back
// to the top and bind the break target at the exit. // to the top and bind the break target at the exit.
if (has_valid_frame()) { if (has_valid_frame()) {
...@@ -1348,8 +1333,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1348,8 +1333,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
} else if (info == ALWAYS_FALSE) { case ALWAYS_FALSE:
// We may have had continues or breaks in the body. // We may have had continues or breaks in the body.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
node->continue_target()->Bind(); node->continue_target()->Bind();
...@@ -1357,9 +1342,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1357,9 +1342,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
} else { case DONT_KNOW:
ASSERT(info == DONT_KNOW);
// We have to compile the test expression if it can be reached by // We have to compile the test expression if it can be reached by
// control flow falling out of the body or via continue. // control flow falling out of the body or via continue.
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
...@@ -1372,63 +1356,80 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1372,63 +1356,80 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
}
break; break;
} }
case LoopStatement::WHILE_LOOP: { DecrementLoopNesting();
// Do not duplicate conditions that may have function literal node->continue_target()->Unuse();
// subexpressions. This can cause us to compile the function node->break_target()->Unuse();
// literal twice. }
bool test_at_bottom = !node->may_have_function_literal();
IncrementLoopNesting();
// If the condition is always false and has no side effects, we void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
// do not need to compile anything. ASSERT(!in_spilled_code());
if (info == ALWAYS_FALSE) break; Comment cmnt(masm_, "[ WhileStatement");
CodeForStatementPosition(node);
// If the condition is always false and has no side effects, we do not
// need to compile anything.
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
// Do not duplicate conditions that may have function literal
// subexpressions. This can cause us to compile the function literal
// twice.
bool test_at_bottom = !node->may_have_function_literal();
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
IncrementLoopNesting();
JumpTarget body; JumpTarget body;
if (test_at_bottom) { if (test_at_bottom) {
body.set_direction(JumpTarget::BIDIRECTIONAL); body.set_direction(JumpTarget::BIDIRECTIONAL);
} }
// Based on the condition analysis, compile the test as necessary. // Based on the condition analysis, compile the test as necessary.
if (info == ALWAYS_TRUE) { switch (info) {
// We will not compile the test expression. Label the top of case ALWAYS_TRUE:
// the loop with the continue target. // We will not compile the test expression. Label the top of the
// loop with the continue target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else { break;
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. case DONT_KNOW: {
if (test_at_bottom) { if (test_at_bottom) {
// Continue is the test at the bottom, no need to label the // Continue is the test at the bottom, no need to label the test
// test at the top. The body is a backward target. // at the top. The body is a backward target.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else { } else {
// Label the test at the top as the continue target. The // Label the test at the top as the continue target. The body
// body is a forward-only target. // is a forward-only target.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Compile the test with the body as the true target and // Compile the test with the body as the true target and preferred
// preferred fall-through and with the break target as the // fall-through and with the break target as the false target.
// false target.
ControlDestination dest(&body, node->break_target(), true); ControlDestination dest(&body, node->break_target(), true);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
if (dest.false_was_fall_through()) { if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may // If we got the break target as fall-through, the test may have
// have been unconditionally false (if there are no jumps to // been unconditionally false (if there are no jumps to the
// the body). // body).
if (!body.is_linked()) break; if (!body.is_linked()) {
DecrementLoopNesting();
return;
}
// Otherwise, jump around the body on the fall through and // Otherwise, jump around the body on the fall through and then
// then bind the body target. // bind the body target.
node->break_target()->Unuse(); node->break_target()->Unuse();
node->break_target()->Jump(); node->break_target()->Jump();
body.Bind(); body.Bind();
} }
break;
}
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
...@@ -1436,13 +1437,14 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1436,13 +1437,14 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Based on the condition analysis, compile the backward jump as // Based on the condition analysis, compile the backward jump as
// necessary. // necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
// The loop body has been labeled with the continue target. // The loop body has been labeled with the continue target.
if (has_valid_frame()) { if (has_valid_frame()) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} else { break;
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. case DONT_KNOW:
if (test_at_bottom) { if (test_at_bottom) {
// If we have chosen to recompile the test at the bottom, // If we have chosen to recompile the test at the bottom,
// then it is the continue target. // then it is the continue target.
...@@ -1462,32 +1464,42 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1462,32 +1464,42 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->Jump(); node->continue_target()->Jump();
} }
} }
break;
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
// The break target may be already bound (by the condition), or // The break target may be already bound (by the condition), or there
// there may not be a valid frame. Bind it only if needed. // may not be a valid frame. Bind it only if needed.
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break; DecrementLoopNesting();
} }
case LoopStatement::FOR_LOOP: {
// Do not duplicate conditions that may have function literal void CodeGenerator::VisitForStatement(ForStatement* node) {
// subexpressions. This can cause us to compile the function ASSERT(!in_spilled_code());
// literal twice. Comment cmnt(masm_, "[ ForStatement");
bool test_at_bottom = !node->may_have_function_literal(); CodeForStatementPosition(node);
// Compile the init expression if present. // Compile the init expression if present.
if (node->init() != NULL) { if (node->init() != NULL) {
Visit(node->init()); Visit(node->init());
} }
IncrementLoopNesting(); // If the condition is always false and has no side effects, we do not
// need to compile anything else.
ConditionAnalysis info = AnalyzeCondition(node->cond());
if (info == ALWAYS_FALSE) return;
// If the condition is always false and has no side effects, we // Do not duplicate conditions that may have function literal
// do not need to compile anything else. // subexpressions. This can cause us to compile the function literal
if (info == ALWAYS_FALSE) break; // twice.
bool test_at_bottom = !node->may_have_function_literal();
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
IncrementLoopNesting();
// Target for backward edge if no test at the bottom, otherwise // Target for backward edge if no test at the bottom, otherwise
// unused. // unused.
...@@ -1501,9 +1513,10 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1501,9 +1513,10 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
// Based on the condition analysis, compile the test as necessary. // Based on the condition analysis, compile the test as necessary.
if (info == ALWAYS_TRUE) { switch (info) {
// We will not compile the test expression. Label the top of case ALWAYS_TRUE:
// the loop. // We will not compile the test expression. Label the top of the
// loop.
if (node->next() == NULL) { if (node->next() == NULL) {
// Use the continue target if there is no update expression. // Use the continue target if there is no update expression.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
...@@ -1513,42 +1526,49 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1513,42 +1526,49 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
loop.Bind(); loop.Bind();
} }
} else { break;
ASSERT(info == DONT_KNOW); case DONT_KNOW: {
if (test_at_bottom) { if (test_at_bottom) {
// Continue is either the update expression or the test at // Continue is either the update expression or the test at the
// the bottom, no need to label the test at the top. // bottom, no need to label the test at the top.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
} else if (node->next() == NULL) { } else if (node->next() == NULL) {
// We are not recompiling the test at the bottom and there // We are not recompiling the test at the bottom and there is no
// is no update expression. // update expression.
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
} else { } else {
// We are not recompiling the test at the bottom and there // We are not recompiling the test at the bottom and there is an
// is an update expression. // update expression.
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
loop.Bind(); loop.Bind();
} }
// Compile the test with the body as the true target and // Compile the test with the body as the true target and preferred
// preferred fall-through and with the break target as the // fall-through and with the break target as the false target.
// false target.
ControlDestination dest(&body, node->break_target(), true); ControlDestination dest(&body, node->break_target(), true);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
if (dest.false_was_fall_through()) { if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may // If we got the break target as fall-through, the test may have
// have been unconditionally false (if there are no jumps to // been unconditionally false (if there are no jumps to the
// the body). // body).
if (!body.is_linked()) break; if (!body.is_linked()) {
DecrementLoopNesting();
return;
}
// Otherwise, jump around the body on the fall through and // Otherwise, jump around the body on the fall through and then
// then bind the body target. // bind the body target.
node->break_target()->Unuse(); node->break_target()->Unuse();
node->break_target()->Jump(); node->break_target()->Jump();
body.Bind(); body.Bind();
} }
break;
}
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
...@@ -1560,12 +1580,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1560,12 +1580,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Control can reach the update by falling out of the body or // Control can reach the update by falling out of the body or by a
// by a continue. // continue.
if (has_valid_frame()) { if (has_valid_frame()) {
// Record the source position of the statement as this code // Record the source position of the statement as this code which
// which is after the code for the body actually belongs to // is after the code for the body actually belongs to the loop
// the loop statement and not the body. // statement and not the body.
CodeForStatementPosition(node); CodeForStatementPosition(node);
Visit(node->next()); Visit(node->next());
} }
...@@ -1573,7 +1593,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1573,7 +1593,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Based on the condition analysis, compile the backward jump as // Based on the condition analysis, compile the backward jump as
// necessary. // necessary.
if (info == ALWAYS_TRUE) { switch (info) {
case ALWAYS_TRUE:
if (has_valid_frame()) { if (has_valid_frame()) {
if (node->next() == NULL) { if (node->next() == NULL) {
node->continue_target()->Jump(); node->continue_target()->Jump();
...@@ -1581,20 +1602,20 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1581,20 +1602,20 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
loop.Jump(); loop.Jump();
} }
} }
} else { break;
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. case DONT_KNOW:
if (test_at_bottom) { if (test_at_bottom) {
if (node->continue_target()->is_linked()) { if (node->continue_target()->is_linked()) {
// We can have dangling jumps to the continue target if // We can have dangling jumps to the continue target if there
// there was no update expression. // was no update expression.
node->continue_target()->Bind(); node->continue_target()->Bind();
} }
// Control can reach the test at the bottom by falling out // Control can reach the test at the bottom by falling out of
// of the body, by a continue in the body, or from the // the body, by a continue in the body, or from the update
// update expression. // expression.
if (has_valid_frame()) { if (has_valid_frame()) {
// The break target is the fall-through (body is a // The break target is the fall-through (body is a backward
// backward jump from here). // jump from here).
ControlDestination dest(&body, node->break_target(), false); ControlDestination dest(&body, node->break_target(), false);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
} }
...@@ -1608,20 +1629,18 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -1608,20 +1629,18 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
} }
} }
break;
case ALWAYS_FALSE:
UNREACHABLE();
break;
} }
// The break target may be already bound (by the condition), or // The break target may be already bound (by the condition), or there
// there may not be a valid frame. Bind it only if needed. // may not be a valid frame. Bind it only if needed.
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
break;
}
}
DecrementLoopNesting(); DecrementLoopNesting();
node->continue_target()->Unuse();
node->break_target()->Unuse();
} }
...@@ -1813,10 +1832,10 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -1813,10 +1832,10 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
node->break_target()->Unuse(); node->break_target()->Unuse();
} }
void CodeGenerator::VisitTryCatch(TryCatch* node) { void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryCatch"); Comment cmnt(masm_, "[ TryCatchStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
JumpTarget try_block; JumpTarget try_block;
...@@ -1952,10 +1971,10 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { ...@@ -1952,10 +1971,10 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
} }
void CodeGenerator::VisitTryFinally(TryFinally* node) { void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ TryFinally"); Comment cmnt(masm_, "[ TryFinallyStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
// State: Used to keep track of reason for entering the finally // State: Used to keep track of reason for entering the finally
......
...@@ -548,6 +548,14 @@ class CodeGenerator: public AstVisitor { ...@@ -548,6 +548,14 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
ALWAYS_TRUE,
ALWAYS_FALSE,
DONT_KNOW
};
ConditionAnalysis AnalyzeCondition(Expression* cond);
// Methods used to indicate which source code is generated for. Source // Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the relocation // positions are collected by the assembler and emitted with the relocation
// information. // information.
......
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