1 // Copyright 2014 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_AST_GRAPH_BUILDER_H_
6 #define V8_COMPILER_AST_GRAPH_BUILDER_H_
7
8 #include "src/v8.h"
9
10 #include "src/ast.h"
11 #include "src/compiler/graph-builder.h"
12 #include "src/compiler/js-graph.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 class ControlBuilder;
19 class LoopBuilder;
20 class Graph;
21
22 // The AstGraphBuilder produces a high-level IR graph, based on an
23 // underlying AST. The produced graph can either be compiled into a
24 // stand-alone function or be wired into another graph for the purposes
25 // of function inlining.
26 class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
27 public:
28 AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph);
29
30 // Creates a graph by visiting the entire AST.
31 bool CreateGraph();
32
33 protected:
34 class AstContext;
35 class AstEffectContext;
36 class AstValueContext;
37 class AstTestContext;
38 class BreakableScope;
39 class ContextScope;
40 class Environment;
41
environment()42 Environment* environment() {
43 return reinterpret_cast<Environment*>(
44 StructuredGraphBuilder::environment());
45 }
46
ast_context()47 AstContext* ast_context() const { return ast_context_; }
breakable()48 BreakableScope* breakable() const { return breakable_; }
execution_context()49 ContextScope* execution_context() const { return execution_context_; }
50
set_ast_context(AstContext * ctx)51 void set_ast_context(AstContext* ctx) { ast_context_ = ctx; }
set_breakable(BreakableScope * brk)52 void set_breakable(BreakableScope* brk) { breakable_ = brk; }
set_execution_context(ContextScope * ctx)53 void set_execution_context(ContextScope* ctx) { execution_context_ = ctx; }
54
55 // Support for control flow builders. The concrete type of the environment
56 // depends on the graph builder, but environments themselves are not virtual.
57 typedef StructuredGraphBuilder::Environment BaseEnvironment;
58 virtual BaseEnvironment* CopyEnvironment(BaseEnvironment* env);
59
60 // TODO(mstarzinger): The pipeline only needs to be a friend to access the
61 // function context. Remove as soon as the context is a parameter.
62 friend class Pipeline;
63
64 // Getters for values in the activation record.
65 Node* GetFunctionClosure();
66 Node* GetFunctionContext();
67
68 //
69 // The following build methods all generate graph fragments and return one
70 // resulting node. The operand stack height remains the same, variables and
71 // other dependencies tracked by the environment might be mutated though.
72 //
73
74 // Builder to create a local function context.
75 Node* BuildLocalFunctionContext(Node* context, Node* closure);
76
77 // Builder to create an arguments object if it is used.
78 Node* BuildArgumentsObject(Variable* arguments);
79
80 // Builders for variable load and assignment.
81 Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op,
82 BailoutId bailout_id);
83 Node* BuildVariableDelete(Variable* var);
84 Node* BuildVariableLoad(Variable* var, BailoutId bailout_id,
85 ContextualMode mode = CONTEXTUAL);
86
87 // Builders for accessing the function context.
88 Node* BuildLoadBuiltinsObject();
89 Node* BuildLoadGlobalObject();
90 Node* BuildLoadClosure();
91 Node* BuildLoadObjectField(Node* object, int offset);
92
93 // Builders for automatic type conversion.
94 Node* BuildToBoolean(Node* value);
95
96 // Builders for error reporting at runtime.
97 Node* BuildThrowReferenceError(Variable* var);
98
99 // Builders for dynamic hole-checks at runtime.
100 Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
101 Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole);
102
103 // Builders for binary operations.
104 Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
105
106 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
107 // Visiting functions for AST nodes make this an AstVisitor.
108 AST_NODE_LIST(DECLARE_VISIT)
109 #undef DECLARE_VISIT
110
111 // Visiting function for declarations list is overridden.
112 virtual void VisitDeclarations(ZoneList<Declaration*>* declarations);
113
114 private:
115 CompilationInfo* info_;
116 AstContext* ast_context_;
117 JSGraph* jsgraph_;
118
119 // List of global declarations for functions and variables.
120 ZoneList<Handle<Object> > globals_;
121
122 // Stack of breakable statements entered by the visitor.
123 BreakableScope* breakable_;
124
125 // Stack of context objects pushed onto the chain by the visitor.
126 ContextScope* execution_context_;
127
128 // Nodes representing values in the activation record.
129 SetOncePointer<Node> function_closure_;
130 SetOncePointer<Node> function_context_;
131
info()132 CompilationInfo* info() { return info_; }
strict_mode()133 StrictMode strict_mode() { return info()->strict_mode(); }
jsgraph()134 JSGraph* jsgraph() { return jsgraph_; }
javascript()135 JSOperatorBuilder* javascript() { return jsgraph_->javascript(); }
globals()136 ZoneList<Handle<Object> >* globals() { return &globals_; }
137
138 // Current scope during visitation.
139 inline Scope* current_scope() const;
140
141 // Process arguments to a call by popping {arity} elements off the operand
142 // stack and build a call node using the given call operator.
143 Node* ProcessArguments(const Operator* op, int arity);
144
145 // Visit statements.
146 void VisitIfNotNull(Statement* stmt);
147
148 // Visit expressions.
149 void VisitForTest(Expression* expr);
150 void VisitForEffect(Expression* expr);
151 void VisitForValue(Expression* expr);
152 void VisitForValueOrNull(Expression* expr);
153 void VisitForValues(ZoneList<Expression*>* exprs);
154
155 // Common for all IterationStatement bodies.
156 void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop, int);
157
158 // Dispatched from VisitCallRuntime.
159 void VisitCallJSRuntime(CallRuntime* expr);
160
161 // Dispatched from VisitUnaryOperation.
162 void VisitDelete(UnaryOperation* expr);
163 void VisitVoid(UnaryOperation* expr);
164 void VisitTypeof(UnaryOperation* expr);
165 void VisitNot(UnaryOperation* expr);
166
167 // Dispatched from VisitBinaryOperation.
168 void VisitComma(BinaryOperation* expr);
169 void VisitLogicalExpression(BinaryOperation* expr);
170 void VisitArithmeticExpression(BinaryOperation* expr);
171
172 // Dispatched from VisitForInStatement.
173 void VisitForInAssignment(Expression* expr, Node* value);
174
175 // Builds deoptimization for a given node.
176 void PrepareFrameState(Node* node, BailoutId ast_id,
177 OutputFrameStateCombine combine = kIgnoreOutput);
178
179 OutputFrameStateCombine StateCombineFromAstContext();
180
181 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
182 DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder);
183 };
184
185
186 // The abstract execution environment for generated code consists of
187 // parameter variables, local variables and the operand stack. The
188 // environment will perform proper SSA-renaming of all tracked nodes
189 // at split and merge points in the control flow. Internally all the
190 // values are stored in one list using the following layout:
191 //
192 // [parameters (+receiver)] [locals] [operand stack]
193 //
194 class AstGraphBuilder::Environment
195 : public StructuredGraphBuilder::Environment {
196 public:
197 Environment(AstGraphBuilder* builder, Scope* scope, Node* control_dependency);
198 Environment(const Environment& copy);
199
parameters_count()200 int parameters_count() const { return parameters_count_; }
locals_count()201 int locals_count() const { return locals_count_; }
stack_height()202 int stack_height() {
203 return static_cast<int>(values()->size()) - parameters_count_ -
204 locals_count_;
205 }
206
207 // Operations on parameter or local variables. The parameter indices are
208 // shifted by 1 (receiver is parameter index -1 but environment index 0).
Bind(Variable * variable,Node * node)209 void Bind(Variable* variable, Node* node) {
210 DCHECK(variable->IsStackAllocated());
211 if (variable->IsParameter()) {
212 values()->at(variable->index() + 1) = node;
213 } else {
214 DCHECK(variable->IsStackLocal());
215 values()->at(variable->index() + parameters_count_) = node;
216 }
217 }
Lookup(Variable * variable)218 Node* Lookup(Variable* variable) {
219 DCHECK(variable->IsStackAllocated());
220 if (variable->IsParameter()) {
221 return values()->at(variable->index() + 1);
222 } else {
223 DCHECK(variable->IsStackLocal());
224 return values()->at(variable->index() + parameters_count_);
225 }
226 }
227
228 // Operations on the operand stack.
Push(Node * node)229 void Push(Node* node) {
230 values()->push_back(node);
231 }
Top()232 Node* Top() {
233 DCHECK(stack_height() > 0);
234 return values()->back();
235 }
Pop()236 Node* Pop() {
237 DCHECK(stack_height() > 0);
238 Node* back = values()->back();
239 values()->pop_back();
240 return back;
241 }
242
243 // Direct mutations of the operand stack.
Poke(int depth,Node * node)244 void Poke(int depth, Node* node) {
245 DCHECK(depth >= 0 && depth < stack_height());
246 int index = static_cast<int>(values()->size()) - depth - 1;
247 values()->at(index) = node;
248 }
Peek(int depth)249 Node* Peek(int depth) {
250 DCHECK(depth >= 0 && depth < stack_height());
251 int index = static_cast<int>(values()->size()) - depth - 1;
252 return values()->at(index);
253 }
Drop(int depth)254 void Drop(int depth) {
255 DCHECK(depth >= 0 && depth <= stack_height());
256 values()->erase(values()->end() - depth, values()->end());
257 }
258
259 // Preserve a checkpoint of the environment for the IR graph. Any
260 // further mutation of the environment will not affect checkpoints.
261 Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine);
262
263 protected:
builder()264 AstGraphBuilder* builder() const {
265 return reinterpret_cast<AstGraphBuilder*>(
266 StructuredGraphBuilder::Environment::builder());
267 }
268
269 private:
270 void UpdateStateValues(Node** state_values, int offset, int count);
271
272 int parameters_count_;
273 int locals_count_;
274 Node* parameters_node_;
275 Node* locals_node_;
276 Node* stack_node_;
277 };
278
279
280 // Each expression in the AST is evaluated in a specific context. This context
281 // decides how the evaluation result is passed up the visitor.
282 class AstGraphBuilder::AstContext BASE_EMBEDDED {
283 public:
IsEffect()284 bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue()285 bool IsValue() const { return kind_ == Expression::kValue; }
IsTest()286 bool IsTest() const { return kind_ == Expression::kTest; }
287
288 // Determines how to combine the frame state with the value
289 // that is about to be plugged into this AstContext.
GetStateCombine()290 OutputFrameStateCombine GetStateCombine() {
291 return IsEffect() ? kIgnoreOutput : kPushOutput;
292 }
293
294 // Plug a node into this expression context. Call this function in tail
295 // position in the Visit functions for expressions.
296 virtual void ProduceValue(Node* value) = 0;
297
298 // Unplugs a node from this expression context. Call this to retrieve the
299 // result of another Visit function that already plugged the context.
300 virtual Node* ConsumeValue() = 0;
301
302 // Shortcut for "context->ProduceValue(context->ConsumeValue())".
ReplaceValue()303 void ReplaceValue() { ProduceValue(ConsumeValue()); }
304
305 protected:
306 AstContext(AstGraphBuilder* owner, Expression::Context kind);
307 virtual ~AstContext();
308
owner()309 AstGraphBuilder* owner() const { return owner_; }
environment()310 Environment* environment() const { return owner_->environment(); }
311
312 // We want to be able to assert, in a context-specific way, that the stack
313 // height makes sense when the context is filled.
314 #ifdef DEBUG
315 int original_height_;
316 #endif
317
318 private:
319 Expression::Context kind_;
320 AstGraphBuilder* owner_;
321 AstContext* outer_;
322 };
323
324
325 // Context to evaluate expression for its side effects only.
326 class AstGraphBuilder::AstEffectContext FINAL : public AstContext {
327 public:
AstEffectContext(AstGraphBuilder * owner)328 explicit AstEffectContext(AstGraphBuilder* owner)
329 : AstContext(owner, Expression::kEffect) {}
330 virtual ~AstEffectContext();
331 virtual void ProduceValue(Node* value) OVERRIDE;
332 virtual Node* ConsumeValue() OVERRIDE;
333 };
334
335
336 // Context to evaluate expression for its value (and side effects).
337 class AstGraphBuilder::AstValueContext FINAL : public AstContext {
338 public:
AstValueContext(AstGraphBuilder * owner)339 explicit AstValueContext(AstGraphBuilder* owner)
340 : AstContext(owner, Expression::kValue) {}
341 virtual ~AstValueContext();
342 virtual void ProduceValue(Node* value) OVERRIDE;
343 virtual Node* ConsumeValue() OVERRIDE;
344 };
345
346
347 // Context to evaluate expression for a condition value (and side effects).
348 class AstGraphBuilder::AstTestContext FINAL : public AstContext {
349 public:
AstTestContext(AstGraphBuilder * owner)350 explicit AstTestContext(AstGraphBuilder* owner)
351 : AstContext(owner, Expression::kTest) {}
352 virtual ~AstTestContext();
353 virtual void ProduceValue(Node* value) OVERRIDE;
354 virtual Node* ConsumeValue() OVERRIDE;
355 };
356
357
358 // Scoped class tracking breakable statements entered by the visitor. Allows to
359 // properly 'break' and 'continue' iteration statements as well as to 'break'
360 // from blocks within switch statements.
361 class AstGraphBuilder::BreakableScope BASE_EMBEDDED {
362 public:
BreakableScope(AstGraphBuilder * owner,BreakableStatement * target,ControlBuilder * control,int drop_extra)363 BreakableScope(AstGraphBuilder* owner, BreakableStatement* target,
364 ControlBuilder* control, int drop_extra)
365 : owner_(owner),
366 target_(target),
367 next_(owner->breakable()),
368 control_(control),
369 drop_extra_(drop_extra) {
370 owner_->set_breakable(this); // Push.
371 }
372
~BreakableScope()373 ~BreakableScope() {
374 owner_->set_breakable(next_); // Pop.
375 }
376
377 // Either 'break' or 'continue' the target statement.
378 void BreakTarget(BreakableStatement* target);
379 void ContinueTarget(BreakableStatement* target);
380
381 private:
382 AstGraphBuilder* owner_;
383 BreakableStatement* target_;
384 BreakableScope* next_;
385 ControlBuilder* control_;
386 int drop_extra_;
387
388 // Find the correct scope for the target statement. Note that this also drops
389 // extra operands from the environment for each scope skipped along the way.
390 BreakableScope* FindBreakable(BreakableStatement* target);
391 };
392
393
394 // Scoped class tracking context objects created by the visitor. Represents
395 // mutations of the context chain within the function body and allows to
396 // change the current {scope} and {context} during visitation.
397 class AstGraphBuilder::ContextScope BASE_EMBEDDED {
398 public:
ContextScope(AstGraphBuilder * owner,Scope * scope,Node * context)399 ContextScope(AstGraphBuilder* owner, Scope* scope, Node* context)
400 : owner_(owner),
401 next_(owner->execution_context()),
402 outer_(owner->current_context()),
403 scope_(scope) {
404 owner_->set_execution_context(this); // Push.
405 owner_->set_current_context(context);
406 }
407
~ContextScope()408 ~ContextScope() {
409 owner_->set_execution_context(next_); // Pop.
410 owner_->set_current_context(outer_);
411 }
412
413 // Current scope during visitation.
scope()414 Scope* scope() const { return scope_; }
415
416 private:
417 AstGraphBuilder* owner_;
418 ContextScope* next_;
419 Node* outer_;
420 Scope* scope_;
421 };
422
current_scope()423 Scope* AstGraphBuilder::current_scope() const {
424 return execution_context_->scope();
425 }
426 }
427 }
428 } // namespace v8::internal::compiler
429
430 #endif // V8_COMPILER_AST_GRAPH_BUILDER_H_
431