1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_COMPILER_GRAPH_BUILDER_H_
6 #define V8_COMPILER_GRAPH_BUILDER_H_
7 
8 #include "src/v8.h"
9 
10 #include "src/allocation.h"
11 #include "src/compiler/common-operator.h"
12 #include "src/compiler/graph.h"
13 #include "src/unique.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
19 class Node;
20 
21 // A common base class for anything that creates nodes in a graph.
22 class GraphBuilder {
23  public:
GraphBuilder(Graph * graph)24   explicit GraphBuilder(Graph* graph) : graph_(graph) {}
~GraphBuilder()25   virtual ~GraphBuilder() {}
26 
NewNode(const Operator * op)27   Node* NewNode(const Operator* op) {
28     return MakeNode(op, 0, static_cast<Node**>(NULL));
29   }
30 
NewNode(const Operator * op,Node * n1)31   Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
32 
NewNode(const Operator * op,Node * n1,Node * n2)33   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
34     Node* buffer[] = {n1, n2};
35     return MakeNode(op, arraysize(buffer), buffer);
36   }
37 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3)38   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
39     Node* buffer[] = {n1, n2, n3};
40     return MakeNode(op, arraysize(buffer), buffer);
41   }
42 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4)43   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
44     Node* buffer[] = {n1, n2, n3, n4};
45     return MakeNode(op, arraysize(buffer), buffer);
46   }
47 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5)48   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
49                 Node* n5) {
50     Node* buffer[] = {n1, n2, n3, n4, n5};
51     return MakeNode(op, arraysize(buffer), buffer);
52   }
53 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5,Node * n6)54   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
55                 Node* n5, Node* n6) {
56     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
57     return MakeNode(op, arraysize(nodes), nodes);
58   }
59 
NewNode(const Operator * op,int value_input_count,Node ** value_inputs)60   Node* NewNode(const Operator* op, int value_input_count,
61                 Node** value_inputs) {
62     return MakeNode(op, value_input_count, value_inputs);
63   }
64 
graph()65   Graph* graph() const { return graph_; }
66 
67  protected:
68   // Base implementation used by all factory methods.
69   virtual Node* MakeNode(const Operator* op, int value_input_count,
70                          Node** value_inputs) = 0;
71 
72  private:
73   Graph* graph_;
74 };
75 
76 
77 // The StructuredGraphBuilder produces a high-level IR graph. It is used as the
78 // base class for concrete implementations (e.g the AstGraphBuilder or the
79 // StubGraphBuilder).
80 class StructuredGraphBuilder : public GraphBuilder {
81  public:
82   StructuredGraphBuilder(Graph* graph, CommonOperatorBuilder* common);
~StructuredGraphBuilder()83   virtual ~StructuredGraphBuilder() {}
84 
85   // Creates a new Phi node having {count} input values.
86   Node* NewPhi(int count, Node* input, Node* control);
87   Node* NewEffectPhi(int count, Node* input, Node* control);
88 
89   // Helpers for merging control, effect or value dependencies.
90   Node* MergeControl(Node* control, Node* other);
91   Node* MergeEffect(Node* value, Node* other, Node* control);
92   Node* MergeValue(Node* value, Node* other, Node* control);
93 
94   // Helpers to create new control nodes.
NewIfTrue()95   Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
NewIfFalse()96   Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
NewMerge()97   Node* NewMerge() { return NewNode(common()->Merge(1)); }
NewLoop()98   Node* NewLoop() { return NewNode(common()->Loop(1)); }
NewBranch(Node * condition)99   Node* NewBranch(Node* condition) {
100     return NewNode(common()->Branch(), condition);
101   }
102 
103  protected:
104   class Environment;
105   friend class Environment;
106   friend class ControlBuilder;
107 
108   // The following method creates a new node having the specified operator and
109   // ensures effect and control dependencies are wired up. The dependencies
110   // tracked by the environment might be mutated.
111   virtual Node* MakeNode(const Operator* op, int value_input_count,
112                          Node** value_inputs) FINAL;
113 
environment()114   Environment* environment() const { return environment_; }
set_environment(Environment * env)115   void set_environment(Environment* env) { environment_ = env; }
116 
current_context()117   Node* current_context() const { return current_context_; }
set_current_context(Node * context)118   void set_current_context(Node* context) { current_context_ = context; }
119 
exit_control()120   Node* exit_control() const { return exit_control_; }
set_exit_control(Node * node)121   void set_exit_control(Node* node) { exit_control_ = node; }
122 
123   Node* dead_control();
124 
125   // TODO(mstarzinger): Use phase-local zone instead!
zone()126   Zone* zone() const { return graph()->zone(); }
isolate()127   Isolate* isolate() const { return zone()->isolate(); }
common()128   CommonOperatorBuilder* common() const { return common_; }
129 
130   // Helper to wrap a Handle<T> into a Unique<T>.
131   template <class T>
MakeUnique(Handle<T> object)132   Unique<T> MakeUnique(Handle<T> object) {
133     return Unique<T>::CreateUninitialized(object);
134   }
135 
136   // Support for control flow builders. The concrete type of the environment
137   // depends on the graph builder, but environments themselves are not virtual.
138   virtual Environment* CopyEnvironment(Environment* env);
139 
140   // Helper to indicate a node exits the function body.
141   void UpdateControlDependencyToLeaveFunction(Node* exit);
142 
143  private:
144   CommonOperatorBuilder* common_;
145   Environment* environment_;
146 
147   // Node representing the control dependency for dead code.
148   SetOncePointer<Node> dead_control_;
149 
150   // Node representing the current context within the function body.
151   Node* current_context_;
152 
153   // Merge of all control nodes that exit the function body.
154   Node* exit_control_;
155 
156   DISALLOW_COPY_AND_ASSIGN(StructuredGraphBuilder);
157 };
158 
159 
160 // The abstract execution environment contains static knowledge about
161 // execution state at arbitrary control-flow points. It allows for
162 // simulation of the control-flow at compile time.
163 class StructuredGraphBuilder::Environment : public ZoneObject {
164  public:
165   Environment(StructuredGraphBuilder* builder, Node* control_dependency);
166   Environment(const Environment& copy);
167 
168   // Control dependency tracked by this environment.
GetControlDependency()169   Node* GetControlDependency() { return control_dependency_; }
UpdateControlDependency(Node * dependency)170   void UpdateControlDependency(Node* dependency) {
171     control_dependency_ = dependency;
172   }
173 
174   // Effect dependency tracked by this environment.
GetEffectDependency()175   Node* GetEffectDependency() { return effect_dependency_; }
UpdateEffectDependency(Node * dependency)176   void UpdateEffectDependency(Node* dependency) {
177     effect_dependency_ = dependency;
178   }
179 
180   // Mark this environment as being unreachable.
MarkAsUnreachable()181   void MarkAsUnreachable() {
182     UpdateControlDependency(builder()->dead_control());
183   }
IsMarkedAsUnreachable()184   bool IsMarkedAsUnreachable() {
185     return GetControlDependency()->opcode() == IrOpcode::kDead;
186   }
187 
188   // Merge another environment into this one.
189   void Merge(Environment* other);
190 
191   // Copies this environment at a control-flow split point.
CopyForConditional()192   Environment* CopyForConditional() { return builder()->CopyEnvironment(this); }
193 
194   // Copies this environment to a potentially unreachable control-flow point.
CopyAsUnreachable()195   Environment* CopyAsUnreachable() {
196     Environment* env = builder()->CopyEnvironment(this);
197     env->MarkAsUnreachable();
198     return env;
199   }
200 
201   // Copies this environment at a loop header control-flow point.
CopyForLoop()202   Environment* CopyForLoop() {
203     PrepareForLoop();
204     return builder()->CopyEnvironment(this);
205   }
206 
GetContext()207   Node* GetContext() { return builder_->current_context(); }
208 
209  protected:
210   // TODO(mstarzinger): Use phase-local zone instead!
zone()211   Zone* zone() const { return graph()->zone(); }
graph()212   Graph* graph() const { return builder_->graph(); }
builder()213   StructuredGraphBuilder* builder() const { return builder_; }
common()214   CommonOperatorBuilder* common() { return builder_->common(); }
values()215   NodeVector* values() { return &values_; }
216 
217   // Prepare environment to be used as loop header.
218   void PrepareForLoop();
219 
220  private:
221   StructuredGraphBuilder* builder_;
222   Node* control_dependency_;
223   Node* effect_dependency_;
224   NodeVector values_;
225 };
226 }
227 }
228 }  // namespace v8::internal::compiler
229 
230 #endif  // V8_COMPILER_GRAPH_BUILDER_H__
231