mirror of https://github.com/lukechilds/node.git
Ryan Dahl
15 years ago
43 changed files with 2594 additions and 1823 deletions
File diff suppressed because it is too large
@ -0,0 +1,588 @@ |
|||||
|
// 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
|
@ -0,0 +1,379 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
#ifndef V8_FLOW_GRAPH_H_ |
||||
|
#define V8_FLOW_GRAPH_H_ |
||||
|
|
||||
|
#include "v8.h" |
||||
|
|
||||
|
#include "data-flow.h" |
||||
|
#include "zone.h" |
||||
|
|
||||
|
namespace v8 { |
||||
|
namespace internal { |
||||
|
|
||||
|
// Flow-graph nodes.
|
||||
|
class Node: public ZoneObject { |
||||
|
public: |
||||
|
Node() : number_(-1), mark_(false) {} |
||||
|
|
||||
|
virtual ~Node() {} |
||||
|
|
||||
|
virtual bool IsExitNode() { return false; } |
||||
|
virtual bool IsBlockNode() { return false; } |
||||
|
virtual bool IsBranchNode() { return false; } |
||||
|
virtual bool IsJoinNode() { return false; } |
||||
|
|
||||
|
virtual void AddPredecessor(Node* predecessor) = 0; |
||||
|
virtual void AddSuccessor(Node* successor) = 0; |
||||
|
|
||||
|
bool IsMarkedWith(bool mark) { return mark_ == mark; } |
||||
|
void MarkWith(bool mark) { mark_ = mark; } |
||||
|
|
||||
|
// Perform a depth first search and record preorder and postorder
|
||||
|
// traversal orders.
|
||||
|
virtual void Traverse(bool mark, |
||||
|
ZoneList<Node*>* preorder, |
||||
|
ZoneList<Node*>* postorder) = 0; |
||||
|
|
||||
|
int number() { return number_; } |
||||
|
void set_number(int number) { number_ = number; } |
||||
|
|
||||
|
// Functions used by data-flow analyses.
|
||||
|
virtual void InitializeReachingDefinitions(int definition_count, |
||||
|
List<BitVector*>* variables, |
||||
|
WorkList<Node>* worklist, |
||||
|
bool mark); |
||||
|
virtual void ComputeRDOut(BitVector* result) = 0; |
||||
|
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0; |
||||
|
virtual void PropagateReachingDefinitions(List<BitVector*>* variables); |
||||
|
|
||||
|
// Functions used by dead-code elimination.
|
||||
|
virtual void MarkCriticalInstructions( |
||||
|
List<AstNode*>* stack, |
||||
|
ZoneList<Expression*>* body_definitions, |
||||
|
int variable_count); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
void AssignNodeNumber(); |
||||
|
void PrintReachingDefinitions(); |
||||
|
virtual void PrintText() = 0; |
||||
|
#endif |
||||
|
|
||||
|
protected: |
||||
|
ReachingDefinitionsData rd_; |
||||
|
|
||||
|
private: |
||||
|
int number_; |
||||
|
bool mark_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(Node); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// An exit node has a arbitrarily many predecessors and no successors.
|
||||
|
class ExitNode: public Node { |
||||
|
public: |
||||
|
ExitNode() : predecessors_(4) {} |
||||
|
|
||||
|
virtual bool IsExitNode() { return true; } |
||||
|
|
||||
|
virtual void AddPredecessor(Node* predecessor) { |
||||
|
ASSERT(predecessor != NULL); |
||||
|
predecessors_.Add(predecessor); |
||||
|
} |
||||
|
|
||||
|
virtual void AddSuccessor(Node* successor) { UNREACHABLE(); } |
||||
|
|
||||
|
virtual void Traverse(bool mark, |
||||
|
ZoneList<Node*>* preorder, |
||||
|
ZoneList<Node*>* postorder); |
||||
|
|
||||
|
virtual void ComputeRDOut(BitVector* result); |
||||
|
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
virtual void PrintText(); |
||||
|
#endif |
||||
|
|
||||
|
private: |
||||
|
ZoneList<Node*> predecessors_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(ExitNode); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Block nodes have a single successor and predecessor and a list of
|
||||
|
// instructions.
|
||||
|
class BlockNode: public Node { |
||||
|
public: |
||||
|
BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {} |
||||
|
|
||||
|
static BlockNode* cast(Node* node) { |
||||
|
ASSERT(node->IsBlockNode()); |
||||
|
return reinterpret_cast<BlockNode*>(node); |
||||
|
} |
||||
|
|
||||
|
virtual bool IsBlockNode() { return true; } |
||||
|
|
||||
|
bool is_empty() { return instructions_.is_empty(); } |
||||
|
|
||||
|
ZoneList<AstNode*>* instructions() { return &instructions_; } |
||||
|
|
||||
|
virtual void AddPredecessor(Node* predecessor) { |
||||
|
ASSERT(predecessor_ == NULL && predecessor != NULL); |
||||
|
predecessor_ = predecessor; |
||||
|
} |
||||
|
|
||||
|
virtual void AddSuccessor(Node* successor) { |
||||
|
ASSERT(successor_ == NULL && successor != NULL); |
||||
|
successor_ = successor; |
||||
|
} |
||||
|
|
||||
|
void AddInstruction(AstNode* instruction) { |
||||
|
instructions_.Add(instruction); |
||||
|
} |
||||
|
|
||||
|
virtual void Traverse(bool mark, |
||||
|
ZoneList<Node*>* preorder, |
||||
|
ZoneList<Node*>* postorder); |
||||
|
|
||||
|
virtual void InitializeReachingDefinitions(int definition_count, |
||||
|
List<BitVector*>* variables, |
||||
|
WorkList<Node>* worklist, |
||||
|
bool mark); |
||||
|
virtual void ComputeRDOut(BitVector* result); |
||||
|
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark); |
||||
|
virtual void PropagateReachingDefinitions(List<BitVector*>* variables); |
||||
|
|
||||
|
virtual void MarkCriticalInstructions( |
||||
|
List<AstNode*>* stack, |
||||
|
ZoneList<Expression*>* body_definitions, |
||||
|
int variable_count); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
virtual void PrintText(); |
||||
|
#endif |
||||
|
|
||||
|
private: |
||||
|
Node* predecessor_; |
||||
|
Node* successor_; |
||||
|
ZoneList<AstNode*> instructions_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(BlockNode); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Branch nodes have a single predecessor and a pair of successors.
|
||||
|
class BranchNode: public Node { |
||||
|
public: |
||||
|
BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {} |
||||
|
|
||||
|
virtual bool IsBranchNode() { return true; } |
||||
|
|
||||
|
virtual void AddPredecessor(Node* predecessor) { |
||||
|
ASSERT(predecessor_ == NULL && predecessor != NULL); |
||||
|
predecessor_ = predecessor; |
||||
|
} |
||||
|
|
||||
|
virtual void AddSuccessor(Node* successor) { |
||||
|
ASSERT(successor1_ == NULL && successor != NULL); |
||||
|
if (successor0_ == NULL) { |
||||
|
successor0_ = successor; |
||||
|
} else { |
||||
|
successor1_ = successor; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void Traverse(bool mark, |
||||
|
ZoneList<Node*>* preorder, |
||||
|
ZoneList<Node*>* postorder); |
||||
|
|
||||
|
virtual void ComputeRDOut(BitVector* result); |
||||
|
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
virtual void PrintText(); |
||||
|
#endif |
||||
|
|
||||
|
private: |
||||
|
Node* predecessor_; |
||||
|
Node* successor0_; |
||||
|
Node* successor1_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(BranchNode); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Join nodes have arbitrarily many predecessors and a single successor.
|
||||
|
class JoinNode: public Node { |
||||
|
public: |
||||
|
JoinNode() : predecessors_(2), successor_(NULL) {} |
||||
|
|
||||
|
static JoinNode* cast(Node* node) { |
||||
|
ASSERT(node->IsJoinNode()); |
||||
|
return reinterpret_cast<JoinNode*>(node); |
||||
|
} |
||||
|
|
||||
|
virtual bool IsJoinNode() { return true; } |
||||
|
|
||||
|
virtual void AddPredecessor(Node* predecessor) { |
||||
|
ASSERT(predecessor != NULL); |
||||
|
predecessors_.Add(predecessor); |
||||
|
} |
||||
|
|
||||
|
virtual void AddSuccessor(Node* successor) { |
||||
|
ASSERT(successor_ == NULL && successor != NULL); |
||||
|
successor_ = successor; |
||||
|
} |
||||
|
|
||||
|
virtual void Traverse(bool mark, |
||||
|
ZoneList<Node*>* preorder, |
||||
|
ZoneList<Node*>* postorder); |
||||
|
|
||||
|
virtual void ComputeRDOut(BitVector* result); |
||||
|
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
virtual void PrintText(); |
||||
|
#endif |
||||
|
|
||||
|
private: |
||||
|
ZoneList<Node*> predecessors_; |
||||
|
Node* successor_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(JoinNode); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Flow graphs have a single entry and single exit. The empty flowgraph is
|
||||
|
// represented by both entry and exit being NULL.
|
||||
|
class FlowGraph BASE_EMBEDDED { |
||||
|
public: |
||||
|
static FlowGraph Empty() { |
||||
|
FlowGraph graph; |
||||
|
graph.entry_ = new BlockNode(); |
||||
|
graph.exit_ = graph.entry_; |
||||
|
return graph; |
||||
|
} |
||||
|
|
||||
|
bool is_empty() const { |
||||
|
return entry_ == exit_ && BlockNode::cast(entry_)->is_empty(); |
||||
|
} |
||||
|
Node* entry() const { return entry_; } |
||||
|
Node* exit() const { return exit_; } |
||||
|
|
||||
|
// Add a single instruction to the end of this flowgraph.
|
||||
|
void AppendInstruction(AstNode* instruction); |
||||
|
|
||||
|
// Add a single node to the end of this flow graph.
|
||||
|
void AppendNode(Node* node); |
||||
|
|
||||
|
// Add a flow graph fragment to the end of this one.
|
||||
|
void AppendGraph(FlowGraph* graph); |
||||
|
|
||||
|
// Concatenate an if-then-else flow-graph to this one. Control is split
|
||||
|
// and merged, so the graph remains single-entry, single-exit.
|
||||
|
void Split(BranchNode* branch, |
||||
|
FlowGraph* left, |
||||
|
FlowGraph* right, |
||||
|
JoinNode* merge); |
||||
|
|
||||
|
// Concatenate a forward loop (e.g., while or for loop) flow-graph to this
|
||||
|
// one. Control is split by the condition and merged back from the back
|
||||
|
// edge at end of the body to the beginning of the condition. The single
|
||||
|
// (free) exit of the result graph is the right (false) arm of the branch
|
||||
|
// node.
|
||||
|
void Loop(JoinNode* merge, |
||||
|
FlowGraph* condition, |
||||
|
BranchNode* branch, |
||||
|
FlowGraph* body); |
||||
|
|
||||
|
#ifdef DEBUG |
||||
|
void PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder); |
||||
|
#endif |
||||
|
|
||||
|
private: |
||||
|
FlowGraph() : entry_(NULL), exit_(NULL) {} |
||||
|
|
||||
|
Node* entry_; |
||||
|
Node* exit_; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Construct a flow graph from a function literal. Build pre- and postorder
|
||||
|
// traversal orders as a byproduct.
|
||||
|
class FlowGraphBuilder: public AstVisitor { |
||||
|
public: |
||||
|
explicit FlowGraphBuilder(int variable_count) |
||||
|
: graph_(FlowGraph::Empty()), |
||||
|
global_exit_(NULL), |
||||
|
preorder_(4), |
||||
|
postorder_(4), |
||||
|
variable_count_(variable_count), |
||||
|
body_definitions_(4) { |
||||
|
} |
||||
|
|
||||
|
void Build(FunctionLiteral* lit); |
||||
|
|
||||
|
FlowGraph* graph() { return &graph_; } |
||||
|
ZoneList<Node*>* preorder() { return &preorder_; } |
||||
|
ZoneList<Node*>* postorder() { return &postorder_; } |
||||
|
ZoneList<Expression*>* body_definitions() { return &body_definitions_; } |
||||
|
|
||||
|
private: |
||||
|
ExitNode* global_exit() { return global_exit_; } |
||||
|
|
||||
|
// Helpers to allow tranforming the ast during flow graph construction.
|
||||
|
void VisitStatements(ZoneList<Statement*>* stmts); |
||||
|
Statement* ProcessStatement(Statement* stmt); |
||||
|
|
||||
|
// AST node visit functions.
|
||||
|
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); |
||||
|
AST_NODE_LIST(DECLARE_VISIT) |
||||
|
#undef DECLARE_VISIT |
||||
|
|
||||
|
FlowGraph graph_; |
||||
|
ExitNode* global_exit_; |
||||
|
ZoneList<Node*> preorder_; |
||||
|
ZoneList<Node*> postorder_; |
||||
|
|
||||
|
// The flow graph builder collects a list of explicit definitions
|
||||
|
// (assignments and count operations) to stack-allocated variables to use
|
||||
|
// for reaching definitions analysis. It does not count the implicit
|
||||
|
// definition at function entry. AST node numbers in the AST are used to
|
||||
|
// refer into this list.
|
||||
|
int variable_count_; |
||||
|
ZoneList<Expression*> body_definitions_; |
||||
|
|
||||
|
DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
} } // namespace v8::internal
|
||||
|
|
||||
|
#endif // V8_FLOW_GRAPH_H_
|
Loading…
Reference in new issue