Move flow graph and helper classes to their own file.
The FlowGraph, FlowGraphBuilder, and flow graph node classes are moved to src/flow-graph.cc. Review URL: http://codereview.chromium.org/1253009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4287 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
94a2a0956b
commit
70bbac9c56
@ -61,6 +61,7 @@ SOURCES = {
|
||||
execution.cc
|
||||
factory.cc
|
||||
flags.cc
|
||||
flow-graph.cc
|
||||
frame-element.cc
|
||||
frames.cc
|
||||
full-codegen.cc
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "data-flow.h"
|
||||
#include "debug.h"
|
||||
#include "fast-codegen.h"
|
||||
#include "flow-graph.h"
|
||||
#include "full-codegen.h"
|
||||
#include "liveedit.h"
|
||||
#include "oprofile-agent.h"
|
||||
|
1321
src/data-flow.cc
1321
src/data-flow.cc
File diff suppressed because it is too large
Load Diff
341
src/data-flow.h
341
src/data-flow.h
@ -37,6 +37,9 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Forward declarations.
|
||||
class Node;
|
||||
|
||||
class BitVector: public ZoneObject {
|
||||
public:
|
||||
explicit BitVector(int length)
|
||||
@ -205,344 +208,6 @@ struct ReachingDefinitionsData BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
||||
// This class is used to number all expressions in the AST according to
|
||||
// their evaluation order (post-order left-to-right traversal).
|
||||
class AstLabeler: public AstVisitor {
|
||||
|
588
src/flow-graph.cc
Normal file
588
src/flow-graph.cc
Normal file
@ -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
|
379
src/flow-graph.h
Normal file
379
src/flow-graph.h
Normal file
@ -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_
|
@ -282,6 +282,8 @@
|
||||
'../../src/flag-definitions.h',
|
||||
'../../src/flags.cc',
|
||||
'../../src/flags.h',
|
||||
'../../src/flow-graph.cc',
|
||||
'../../src/flow-graph.h',
|
||||
'../../src/frame-element.cc',
|
||||
'../../src/frame-element.h',
|
||||
'../../src/frames-inl.h',
|
||||
|
@ -464,6 +464,14 @@
|
||||
RelativePath="..\..\src\flags.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\frame-element.cc"
|
||||
>
|
||||
|
@ -448,6 +448,14 @@
|
||||
RelativePath="..\..\src\flags.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\frame-element.cc"
|
||||
>
|
||||
|
@ -440,6 +440,14 @@
|
||||
RelativePath="..\..\src\flags.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\flow-graph.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\frame-element.cc"
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user