589 lines
16 KiB
C++
589 lines
16 KiB
C++
|
// Copyright 2010 the V8 project authors. All rights reserved.
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions are
|
||
|
// met:
|
||
|
//
|
||
|
// * Redistributions of source code must retain the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer.
|
||
|
// * Redistributions in binary form must reproduce the above
|
||
|
// copyright notice, this list of conditions and the following
|
||
|
// disclaimer in the documentation and/or other materials provided
|
||
|
// with the distribution.
|
||
|
// * Neither the name of Google Inc. nor the names of its
|
||
|
// contributors may be used to endorse or promote products derived
|
||
|
// from this software without specific prior written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
||
|
#include "flow-graph.h"
|
||
|
|
||
|
namespace v8 {
|
||
|
namespace internal {
|
||
|
|
||
|
void FlowGraph::AppendInstruction(AstNode* instruction) {
|
||
|
// Add a (non-null) AstNode to the end of the graph fragment.
|
||
|
ASSERT(instruction != NULL);
|
||
|
if (exit()->IsExitNode()) return;
|
||
|
if (!exit()->IsBlockNode()) AppendNode(new BlockNode());
|
||
|
BlockNode::cast(exit())->AddInstruction(instruction);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraph::AppendNode(Node* node) {
|
||
|
// Add a node to the end of the graph. An empty block is added to
|
||
|
// maintain edge-split form (that no join nodes or exit nodes as
|
||
|
// successors to branch nodes).
|
||
|
ASSERT(node != NULL);
|
||
|
if (exit()->IsExitNode()) return;
|
||
|
if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
|
||
|
AppendNode(new BlockNode());
|
||
|
}
|
||
|
exit()->AddSuccessor(node);
|
||
|
node->AddPredecessor(exit());
|
||
|
exit_ = node;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraph::AppendGraph(FlowGraph* graph) {
|
||
|
// Add a flow graph fragment to the end of this one. An empty block is
|
||
|
// added to maintain edge-split form (that no join nodes or exit nodes as
|
||
|
// successors to branch nodes).
|
||
|
ASSERT(graph != NULL);
|
||
|
if (exit()->IsExitNode()) return;
|
||
|
Node* node = graph->entry();
|
||
|
if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
|
||
|
AppendNode(new BlockNode());
|
||
|
}
|
||
|
exit()->AddSuccessor(node);
|
||
|
node->AddPredecessor(exit());
|
||
|
exit_ = graph->exit();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraph::Split(BranchNode* branch,
|
||
|
FlowGraph* left,
|
||
|
FlowGraph* right,
|
||
|
JoinNode* join) {
|
||
|
// Add the branch node, left flowgraph, join node.
|
||
|
AppendNode(branch);
|
||
|
AppendGraph(left);
|
||
|
AppendNode(join);
|
||
|
|
||
|
// Splice in the right flowgraph.
|
||
|
right->AppendNode(join);
|
||
|
branch->AddSuccessor(right->entry());
|
||
|
right->entry()->AddPredecessor(branch);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraph::Loop(JoinNode* join,
|
||
|
FlowGraph* condition,
|
||
|
BranchNode* branch,
|
||
|
FlowGraph* body) {
|
||
|
// Add the join, condition and branch. Add join's predecessors in
|
||
|
// left-to-right order.
|
||
|
AppendNode(join);
|
||
|
body->AppendNode(join);
|
||
|
AppendGraph(condition);
|
||
|
AppendNode(branch);
|
||
|
|
||
|
// Splice in the body flowgraph.
|
||
|
branch->AddSuccessor(body->entry());
|
||
|
body->entry()->AddPredecessor(branch);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ExitNode::Traverse(bool mark,
|
||
|
ZoneList<Node*>* preorder,
|
||
|
ZoneList<Node*>* postorder) {
|
||
|
preorder->Add(this);
|
||
|
postorder->Add(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
void BlockNode::Traverse(bool mark,
|
||
|
ZoneList<Node*>* preorder,
|
||
|
ZoneList<Node*>* postorder) {
|
||
|
ASSERT(successor_ != NULL);
|
||
|
preorder->Add(this);
|
||
|
if (!successor_->IsMarkedWith(mark)) {
|
||
|
successor_->MarkWith(mark);
|
||
|
successor_->Traverse(mark, preorder, postorder);
|
||
|
}
|
||
|
postorder->Add(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
void BranchNode::Traverse(bool mark,
|
||
|
ZoneList<Node*>* preorder,
|
||
|
ZoneList<Node*>* postorder) {
|
||
|
ASSERT(successor0_ != NULL && successor1_ != NULL);
|
||
|
preorder->Add(this);
|
||
|
if (!successor1_->IsMarkedWith(mark)) {
|
||
|
successor1_->MarkWith(mark);
|
||
|
successor1_->Traverse(mark, preorder, postorder);
|
||
|
}
|
||
|
if (!successor0_->IsMarkedWith(mark)) {
|
||
|
successor0_->MarkWith(mark);
|
||
|
successor0_->Traverse(mark, preorder, postorder);
|
||
|
}
|
||
|
postorder->Add(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
void JoinNode::Traverse(bool mark,
|
||
|
ZoneList<Node*>* preorder,
|
||
|
ZoneList<Node*>* postorder) {
|
||
|
ASSERT(successor_ != NULL);
|
||
|
preorder->Add(this);
|
||
|
if (!successor_->IsMarkedWith(mark)) {
|
||
|
successor_->MarkWith(mark);
|
||
|
successor_->Traverse(mark, preorder, postorder);
|
||
|
}
|
||
|
postorder->Add(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::Build(FunctionLiteral* lit) {
|
||
|
global_exit_ = new ExitNode();
|
||
|
VisitStatements(lit->body());
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
|
||
|
// The graph can end with a branch node (if the function ended with a
|
||
|
// loop). Maintain edge-split form (no join nodes or exit nodes as
|
||
|
// successors to branch nodes).
|
||
|
if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
|
||
|
graph_.AppendNode(global_exit_);
|
||
|
|
||
|
// Build preorder and postorder traversal orders. All the nodes in
|
||
|
// the graph have the same mark flag. For the traversal, use that
|
||
|
// flag's negation. Traversal will flip all the flags.
|
||
|
bool mark = graph_.entry()->IsMarkedWith(false);
|
||
|
graph_.entry()->MarkWith(mark);
|
||
|
graph_.entry()->Traverse(mark, &preorder_, &postorder_);
|
||
|
}
|
||
|
|
||
|
|
||
|
// This function peels off one iteration of a for-loop. The return value
|
||
|
// is either a block statement containing the peeled loop or NULL in case
|
||
|
// there is a stack overflow.
|
||
|
static Statement* PeelForLoop(ForStatement* stmt) {
|
||
|
// Mark this for-statement as processed.
|
||
|
stmt->set_peel_this_loop(false);
|
||
|
|
||
|
// Create new block containing the init statement of the for-loop and
|
||
|
// an if-statement containing the peeled iteration and the original
|
||
|
// loop without the init-statement.
|
||
|
Block* block = new Block(NULL, 2, false);
|
||
|
if (stmt->init() != NULL) {
|
||
|
Statement* init = stmt->init();
|
||
|
// The init statement gets the statement position of the for-loop
|
||
|
// to make debugging of peeled loops possible.
|
||
|
init->set_statement_pos(stmt->statement_pos());
|
||
|
block->AddStatement(init);
|
||
|
}
|
||
|
|
||
|
// Copy the condition.
|
||
|
CopyAstVisitor copy_visitor;
|
||
|
Expression* cond_copy = stmt->cond() != NULL
|
||
|
? copy_visitor.DeepCopyExpr(stmt->cond())
|
||
|
: new Literal(Factory::true_value());
|
||
|
if (copy_visitor.HasStackOverflow()) return NULL;
|
||
|
|
||
|
// Construct a block with the peeled body and the rest of the for-loop.
|
||
|
Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
|
||
|
if (copy_visitor.HasStackOverflow()) return NULL;
|
||
|
|
||
|
Statement* next_copy = stmt->next() != NULL
|
||
|
? copy_visitor.DeepCopyStmt(stmt->next())
|
||
|
: new EmptyStatement();
|
||
|
if (copy_visitor.HasStackOverflow()) return NULL;
|
||
|
|
||
|
Block* peeled_body = new Block(NULL, 3, false);
|
||
|
peeled_body->AddStatement(body_copy);
|
||
|
peeled_body->AddStatement(next_copy);
|
||
|
peeled_body->AddStatement(stmt);
|
||
|
|
||
|
// Remove the duplicated init statement from the for-statement.
|
||
|
stmt->set_init(NULL);
|
||
|
|
||
|
// Create new test at the top and add it to the newly created block.
|
||
|
IfStatement* test = new IfStatement(cond_copy,
|
||
|
peeled_body,
|
||
|
new EmptyStatement());
|
||
|
block->AddStatement(test);
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
|
||
|
for (int i = 0, len = stmts->length(); i < len; i++) {
|
||
|
stmts->at(i) = ProcessStatement(stmts->at(i));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
|
||
|
if (FLAG_loop_peeling &&
|
||
|
stmt->AsForStatement() != NULL &&
|
||
|
stmt->AsForStatement()->peel_this_loop()) {
|
||
|
Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
|
||
|
if (tmp_stmt == NULL) {
|
||
|
SetStackOverflow();
|
||
|
} else {
|
||
|
stmt = tmp_stmt;
|
||
|
}
|
||
|
}
|
||
|
Visit(stmt);
|
||
|
return stmt;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitBlock(Block* stmt) {
|
||
|
VisitStatements(stmt->statements());
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
|
||
|
Visit(stmt->expression());
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
|
||
|
// Nothing to do.
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
|
||
|
Visit(stmt->condition());
|
||
|
|
||
|
BranchNode* branch = new BranchNode();
|
||
|
FlowGraph original = graph_;
|
||
|
graph_ = FlowGraph::Empty();
|
||
|
stmt->set_then_statement(ProcessStatement(stmt->then_statement()));
|
||
|
|
||
|
FlowGraph left = graph_;
|
||
|
graph_ = FlowGraph::Empty();
|
||
|
stmt->set_else_statement(ProcessStatement(stmt->else_statement()));
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
JoinNode* join = new JoinNode();
|
||
|
original.Split(branch, &left, &graph_, join);
|
||
|
graph_ = original;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
||
|
if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init()));
|
||
|
|
||
|
JoinNode* join = new JoinNode();
|
||
|
FlowGraph original = graph_;
|
||
|
graph_ = FlowGraph::Empty();
|
||
|
if (stmt->cond() != NULL) Visit(stmt->cond());
|
||
|
|
||
|
BranchNode* branch = new BranchNode();
|
||
|
FlowGraph condition = graph_;
|
||
|
graph_ = FlowGraph::Empty();
|
||
|
stmt->set_body(ProcessStatement(stmt->body()));
|
||
|
|
||
|
if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next()));
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
original.Loop(join, &condition, branch, &graph_);
|
||
|
graph_ = original;
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitSharedFunctionInfoLiteral(
|
||
|
SharedFunctionInfoLiteral* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitConditional(Conditional* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitSlot(Slot* expr) {
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitLiteral(Literal* expr) {
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
|
||
|
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||
|
Property* prop = expr->target()->AsProperty();
|
||
|
// Left-hand side can be a variable or property (or reference error) but
|
||
|
// not both.
|
||
|
ASSERT(var == NULL || prop == NULL);
|
||
|
if (var != NULL) {
|
||
|
if (expr->is_compound()) Visit(expr->target());
|
||
|
Visit(expr->value());
|
||
|
if (var->IsStackAllocated()) {
|
||
|
// The first definition in the body is numbered n, where n is the
|
||
|
// number of parameters and stack-allocated locals.
|
||
|
expr->set_num(body_definitions_.length() + variable_count_);
|
||
|
body_definitions_.Add(expr);
|
||
|
}
|
||
|
|
||
|
} else if (prop != NULL) {
|
||
|
Visit(prop->obj());
|
||
|
if (!prop->key()->IsPropertyName()) Visit(prop->key());
|
||
|
Visit(expr->value());
|
||
|
}
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitThrow(Throw* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitProperty(Property* expr) {
|
||
|
Visit(expr->obj());
|
||
|
if (!expr->key()->IsPropertyName()) Visit(expr->key());
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCall(Call* expr) {
|
||
|
Visit(expr->expression());
|
||
|
ZoneList<Expression*>* arguments = expr->arguments();
|
||
|
for (int i = 0, len = arguments->length(); i < len; i++) {
|
||
|
Visit(arguments->at(i));
|
||
|
}
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
|
||
|
switch (expr->op()) {
|
||
|
case Token::NOT:
|
||
|
case Token::BIT_NOT:
|
||
|
case Token::DELETE:
|
||
|
case Token::TYPEOF:
|
||
|
case Token::VOID:
|
||
|
SetStackOverflow();
|
||
|
break;
|
||
|
|
||
|
case Token::ADD:
|
||
|
case Token::SUB:
|
||
|
Visit(expr->expression());
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||
|
Visit(expr->expression());
|
||
|
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||
|
if (var != NULL && var->IsStackAllocated()) {
|
||
|
// The first definition in the body is numbered n, where n is the number
|
||
|
// of parameters and stack-allocated locals.
|
||
|
expr->set_num(body_definitions_.length() + variable_count_);
|
||
|
body_definitions_.Add(expr);
|
||
|
}
|
||
|
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
|
||
|
switch (expr->op()) {
|
||
|
case Token::COMMA:
|
||
|
case Token::OR:
|
||
|
case Token::AND:
|
||
|
SetStackOverflow();
|
||
|
break;
|
||
|
|
||
|
case Token::BIT_OR:
|
||
|
case Token::BIT_XOR:
|
||
|
case Token::BIT_AND:
|
||
|
case Token::SHL:
|
||
|
case Token::SHR:
|
||
|
case Token::ADD:
|
||
|
case Token::SUB:
|
||
|
case Token::MUL:
|
||
|
case Token::DIV:
|
||
|
case Token::MOD:
|
||
|
case Token::SAR:
|
||
|
Visit(expr->left());
|
||
|
Visit(expr->right());
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
||
|
switch (expr->op()) {
|
||
|
case Token::EQ:
|
||
|
case Token::NE:
|
||
|
case Token::EQ_STRICT:
|
||
|
case Token::NE_STRICT:
|
||
|
case Token::INSTANCEOF:
|
||
|
case Token::IN:
|
||
|
SetStackOverflow();
|
||
|
break;
|
||
|
|
||
|
case Token::LT:
|
||
|
case Token::GT:
|
||
|
case Token::LTE:
|
||
|
case Token::GTE:
|
||
|
Visit(expr->left());
|
||
|
Visit(expr->right());
|
||
|
if (HasStackOverflow()) return;
|
||
|
graph_.AppendInstruction(expr);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
|
||
|
SetStackOverflow();
|
||
|
}
|
||
|
|
||
|
|
||
|
} } // namespace v8::internal
|