| Index: src/flow-graph.h
|
| diff --git a/src/flow-graph.h b/src/flow-graph.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..183b71d5b08082f068365f47519e276d615820fb
|
| --- /dev/null
|
| +++ b/src/flow-graph.h
|
| @@ -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_
|
|
|