Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: src/flow-graph.cc

Issue 1530003: Rework flow graph construction. (Closed)
Patch Set: Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/flow-graph.h ('K') | « src/flow-graph.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "flow-graph.h" 28 #include "flow-graph.h"
29 #include "scopes.h"
29 30
30 namespace v8 { 31 namespace v8 {
31 namespace internal { 32 namespace internal {
32 33
33 void FlowGraph::AppendInstruction(AstNode* instruction) { 34 void BasicBlock::BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
34 // Add a (non-null) AstNode to the end of the graph fragment. 35 ZoneList<BasicBlock*>* postorder,
35 ASSERT(instruction != NULL); 36 bool mark) {
36 if (exit()->IsExitNode()) return; 37 if (mark_ == mark) return;
37 if (!exit()->IsBlockNode()) AppendNode(new BlockNode()); 38 mark_ = mark;
38 BlockNode::cast(exit())->AddInstruction(instruction); 39 preorder->Add(this);
39 } 40 if (right_successor_ != NULL) {
40 41 right_successor_->BuildTraversalOrder(preorder, postorder, mark);
41
42 void FlowGraph::AppendNode(Node* node) {
43 // Add a node to the end of the graph. An empty block is added to
44 // maintain edge-split form (that no join nodes or exit nodes as
45 // successors to branch nodes).
46 ASSERT(node != NULL);
47 if (exit()->IsExitNode()) return;
48 if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
49 AppendNode(new BlockNode());
50 } 42 }
51 exit()->AddSuccessor(node); 43 if (left_successor_ != NULL) {
52 node->AddPredecessor(exit()); 44 left_successor_->BuildTraversalOrder(preorder, postorder, mark);
53 exit_ = node;
54 }
55
56
57 void FlowGraph::AppendGraph(FlowGraph* graph) {
58 // Add a flow graph fragment to the end of this one. An empty block is
59 // added to maintain edge-split form (that no join nodes or exit nodes as
60 // successors to branch nodes).
61 ASSERT(graph != NULL);
62 if (exit()->IsExitNode()) return;
63 Node* node = graph->entry();
64 if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
65 AppendNode(new BlockNode());
66 }
67 exit()->AddSuccessor(node);
68 node->AddPredecessor(exit());
69 exit_ = graph->exit();
70 }
71
72
73 void FlowGraph::Split(BranchNode* branch,
74 FlowGraph* left,
75 FlowGraph* right,
76 JoinNode* join) {
77 // Add the branch node, left flowgraph, join node.
78 AppendNode(branch);
79 AppendGraph(left);
80 AppendNode(join);
81
82 // Splice in the right flowgraph.
83 right->AppendNode(join);
84 branch->AddSuccessor(right->entry());
85 right->entry()->AddPredecessor(branch);
86 }
87
88
89 void FlowGraph::Loop(JoinNode* join,
90 FlowGraph* condition,
91 BranchNode* branch,
92 FlowGraph* body) {
93 // Add the join, condition and branch. Add join's predecessors in
94 // left-to-right order.
95 AppendNode(join);
96 body->AppendNode(join);
97 AppendGraph(condition);
98 AppendNode(branch);
99
100 // Splice in the body flowgraph.
101 branch->AddSuccessor(body->entry());
102 body->entry()->AddPredecessor(branch);
103 }
104
105
106 void ExitNode::Traverse(bool mark,
107 ZoneList<Node*>* preorder,
108 ZoneList<Node*>* postorder) {
109 preorder->Add(this);
110 postorder->Add(this);
111 }
112
113
114 void BlockNode::Traverse(bool mark,
115 ZoneList<Node*>* preorder,
116 ZoneList<Node*>* postorder) {
117 ASSERT(successor_ != NULL);
118 preorder->Add(this);
119 if (!successor_->IsMarkedWith(mark)) {
120 successor_->MarkWith(mark);
121 successor_->Traverse(mark, preorder, postorder);
122 } 45 }
123 postorder->Add(this); 46 postorder->Add(this);
124 } 47 }
125 48
126 49
127 void BranchNode::Traverse(bool mark, 50 FlowGraph* FlowGraphBuilder::Build(FunctionLiteral* lit) {
128 ZoneList<Node*>* preorder, 51 // Create new entry and exit nodes. These will not change during
129 ZoneList<Node*>* postorder) { 52 // construction.
130 ASSERT(successor0_ != NULL && successor1_ != NULL); 53 entry_ = new BasicBlock(NULL);
131 preorder->Add(this); 54 exit_ = new BasicBlock(NULL);
132 if (!successor1_->IsMarkedWith(mark)) { 55 // Begin accumulating instructions in the entry block.
133 successor1_->MarkWith(mark); 56 current_ = entry_;
134 successor1_->Traverse(mark, preorder, postorder); 57
58 VisitDeclarations(lit->scope()->declarations());
59 VisitStatements(lit->body());
60 // In the event of stack overflow or failure to handle a syntactic
61 // construct, return an invalid flow graph.
62 if (HasStackOverflow()) return new FlowGraph(NULL, NULL);
63
64 // If current is not the exit, add a link to the exit.
65 if (current_ != exit_) {
66 // If current already has a successor (i.e., will be a branch node) and
67 // if the exit already has a predecessor, insert an empty block to
68 // maintain edge split form.
69 if (current_->HasSuccessor() && exit_->HasPredecessor()) {
70 current_ = new BasicBlock(current_);
71 }
72 Literal* undefined = new Literal(Factory::undefined_value());
73 current_->AddInstruction(new ReturnStatement(undefined));
74 exit_->AddPredecessor(current_);
135 } 75 }
136 if (!successor0_->IsMarkedWith(mark)) { 76
137 successor0_->MarkWith(mark); 77 FlowGraph* graph = new FlowGraph(entry_, exit_);
138 successor0_->Traverse(mark, preorder, postorder); 78 bool mark = !entry_->GetMark();
79 entry_->BuildTraversalOrder(graph->preorder(), graph->postorder(), mark);
80
81 #ifdef DEBUG
82 // Number the nodes in reverse postorder.
83 int n = 0;
84 for (int i = graph->postorder()->length() - 1; i >= 0; --i) {
85 graph->postorder()->at(i)->set_number(n++);
139 } 86 }
140 postorder->Add(this); 87 #endif
88
89 return graph;
141 } 90 }
142 91
143 92
144 void JoinNode::Traverse(bool mark, 93 void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
145 ZoneList<Node*>* preorder, 94 Variable* var = decl->proxy()->AsVariable();
146 ZoneList<Node*>* postorder) { 95 Slot* slot = var->slot();
147 ASSERT(successor_ != NULL); 96 // We allow only declarations that do not require code generation.
148 preorder->Add(this); 97 // The following all require code generation: global variables and
149 if (!successor_->IsMarkedWith(mark)) { 98 // functions, variables with slot type LOOKUP, declarations with
150 successor_->MarkWith(mark); 99 // mode CONST, and functions.
151 successor_->Traverse(mark, preorder, postorder);
152 }
153 postorder->Add(this);
154 }
155 100
156 101 if (var->is_global() ||
157 void FlowGraphBuilder::Build(FunctionLiteral* lit) { 102 (slot != NULL && slot->type() == Slot::LOOKUP) ||
158 global_exit_ = new ExitNode(); 103 decl->mode() == Variable::CONST ||
159 VisitStatements(lit->body()); 104 decl->fun() != NULL) {
160 105 // Here and in the rest of the flow graph builder we indicate an
161 if (HasStackOverflow()) return; 106 // unsupported syntactic construct by setting the stack overflow
162 107 // flag on the visitor. This causes bailout of the visitor.
163 // The graph can end with a branch node (if the function ended with a 108 SetStackOverflow();
164 // loop). Maintain edge-split form (no join nodes or exit nodes as
165 // successors to branch nodes).
166 if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
167 graph_.AppendNode(global_exit_);
168
169 // Build preorder and postorder traversal orders. All the nodes in
170 // the graph have the same mark flag. For the traversal, use that
171 // flag's negation. Traversal will flip all the flags.
172 bool mark = graph_.entry()->IsMarkedWith(false);
173 graph_.entry()->MarkWith(mark);
174 graph_.entry()->Traverse(mark, &preorder_, &postorder_);
175 }
176
177
178 // This function peels off one iteration of a for-loop. The return value
179 // is either a block statement containing the peeled loop or NULL in case
180 // there is a stack overflow.
181 static Statement* PeelForLoop(ForStatement* stmt) {
182 // Mark this for-statement as processed.
183 stmt->set_peel_this_loop(false);
184
185 // Create new block containing the init statement of the for-loop and
186 // an if-statement containing the peeled iteration and the original
187 // loop without the init-statement.
188 Block* block = new Block(NULL, 2, false);
189 if (stmt->init() != NULL) {
190 Statement* init = stmt->init();
191 // The init statement gets the statement position of the for-loop
192 // to make debugging of peeled loops possible.
193 init->set_statement_pos(stmt->statement_pos());
194 block->AddStatement(init);
195 }
196
197 // Copy the condition.
198 CopyAstVisitor copy_visitor;
199 Expression* cond_copy = stmt->cond() != NULL
200 ? copy_visitor.DeepCopyExpr(stmt->cond())
201 : new Literal(Factory::true_value());
202 if (copy_visitor.HasStackOverflow()) return NULL;
203
204 // Construct a block with the peeled body and the rest of the for-loop.
205 Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
206 if (copy_visitor.HasStackOverflow()) return NULL;
207
208 Statement* next_copy = stmt->next() != NULL
209 ? copy_visitor.DeepCopyStmt(stmt->next())
210 : new EmptyStatement();
211 if (copy_visitor.HasStackOverflow()) return NULL;
212
213 Block* peeled_body = new Block(NULL, 3, false);
214 peeled_body->AddStatement(body_copy);
215 peeled_body->AddStatement(next_copy);
216 peeled_body->AddStatement(stmt);
217
218 // Remove the duplicated init statement from the for-statement.
219 stmt->set_init(NULL);
220
221 // Create new test at the top and add it to the newly created block.
222 IfStatement* test = new IfStatement(cond_copy,
223 peeled_body,
224 new EmptyStatement());
225 block->AddStatement(test);
226 return block;
227 }
228
229
230 void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
231 for (int i = 0, len = stmts->length(); i < len; i++) {
232 stmts->at(i) = ProcessStatement(stmts->at(i));
233 } 109 }
234 } 110 }
235 111
236 112
237 Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
238 if (FLAG_loop_peeling &&
239 stmt->AsForStatement() != NULL &&
240 stmt->AsForStatement()->peel_this_loop()) {
241 Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
242 if (tmp_stmt == NULL) {
243 SetStackOverflow();
244 } else {
245 stmt = tmp_stmt;
246 }
247 }
248 Visit(stmt);
249 return stmt;
250 }
251
252
253 void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
254 UNREACHABLE();
255 }
256
257
258 void FlowGraphBuilder::VisitBlock(Block* stmt) { 113 void FlowGraphBuilder::VisitBlock(Block* stmt) {
259 VisitStatements(stmt->statements()); 114 VisitStatements(stmt->statements());
260 } 115 }
261 116
262 117
263 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { 118 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
264 Visit(stmt->expression()); 119 Visit(stmt->expression());
265 } 120 }
266 121
267 122
268 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 123 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
269 // Nothing to do. 124 // Nothing to do.
270 } 125 }
271 126
272 127
273 void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) { 128 void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
129 // Build a diamond in the flow graph. First accumulate the instructions
130 // of the test in the current basic block.
274 Visit(stmt->condition()); 131 Visit(stmt->condition());
275 132
276 BranchNode* branch = new BranchNode(); 133 // Remember the branch node and accumulate the true branch as its left
277 FlowGraph original = graph_; 134 // successor. This relies on the successors being added left to right.
278 graph_ = FlowGraph::Empty(); 135 BasicBlock* branch = current_;
279 stmt->set_then_statement(ProcessStatement(stmt->then_statement())); 136 current_ = new BasicBlock(branch);
137 Visit(stmt->then_statement());
280 138
281 FlowGraph left = graph_; 139 // Construct a join node and then accumulate the false branch in a fresh
282 graph_ = FlowGraph::Empty(); 140 // successor of the branch node.
283 stmt->set_else_statement(ProcessStatement(stmt->else_statement())); 141 BasicBlock* join = new BasicBlock(current_);
142 current_ = new BasicBlock(branch);
143 Visit(stmt->else_statement());
144 join->AddPredecessor(current_);
284 145
285 if (HasStackOverflow()) return; 146 current_ = join;
286 JoinNode* join = new JoinNode();
287 original.Split(branch, &left, &graph_, join);
288 graph_ = original;
289 } 147 }
290 148
291 149
292 void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { 150 void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
293 SetStackOverflow(); 151 SetStackOverflow();
294 } 152 }
295 153
296 154
297 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 155 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
298 SetStackOverflow(); 156 SetStackOverflow();
(...skipping 24 matching lines...) Expand all
323 SetStackOverflow(); 181 SetStackOverflow();
324 } 182 }
325 183
326 184
327 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 185 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
328 SetStackOverflow(); 186 SetStackOverflow();
329 } 187 }
330 188
331 189
332 void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) { 190 void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
333 if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init())); 191 // Build a loop in the flow graph. First accumulate the instructions of
192 // the initializer in the current basic block.
193 if (stmt->init() != NULL) Visit(stmt->init());
334 194
335 JoinNode* join = new JoinNode(); 195 // Create a new basic block for the test. This will be the join node.
336 FlowGraph original = graph_; 196 BasicBlock* join = new BasicBlock(current_);
337 graph_ = FlowGraph::Empty(); 197 current_ = join;
338 if (stmt->cond() != NULL) Visit(stmt->cond()); 198 if (stmt->cond() != NULL) Visit(stmt->cond());
339 199
340 BranchNode* branch = new BranchNode(); 200 // The current node is the branch node. Create a new basic block to begin
341 FlowGraph condition = graph_; 201 // the body.
342 graph_ = FlowGraph::Empty(); 202 BasicBlock* branch = current_;
343 stmt->set_body(ProcessStatement(stmt->body())); 203 current_ = new BasicBlock(branch);
204 Visit(stmt->body());
205 if (stmt->next() != NULL) Visit(stmt->next());
344 206
345 if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next())); 207 // Add the backward edge from the end of the body and continue with the
346 208 // false arm of the branch.
347 if (HasStackOverflow()) return; 209 join->AddPredecessor(current_);
348 original.Loop(join, &condition, branch, &graph_); 210 current_ = new BasicBlock(branch);
349 graph_ = original;
350 } 211 }
351 212
352 213
353 void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 214 void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
354 SetStackOverflow(); 215 SetStackOverflow();
355 } 216 }
356 217
357 218
358 void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 219 void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
359 SetStackOverflow(); 220 SetStackOverflow();
(...skipping 20 matching lines...) Expand all
380 SetStackOverflow(); 241 SetStackOverflow();
381 } 242 }
382 243
383 244
384 void FlowGraphBuilder::VisitConditional(Conditional* expr) { 245 void FlowGraphBuilder::VisitConditional(Conditional* expr) {
385 SetStackOverflow(); 246 SetStackOverflow();
386 } 247 }
387 248
388 249
389 void FlowGraphBuilder::VisitSlot(Slot* expr) { 250 void FlowGraphBuilder::VisitSlot(Slot* expr) {
251 // Slots do not appear in the AST.
390 UNREACHABLE(); 252 UNREACHABLE();
391 } 253 }
392 254
393 255
394 void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 256 void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
395 graph_.AppendInstruction(expr); 257 current_->AddInstruction(expr);
396 } 258 }
397 259
398 260
399 void FlowGraphBuilder::VisitLiteral(Literal* expr) { 261 void FlowGraphBuilder::VisitLiteral(Literal* expr) {
400 graph_.AppendInstruction(expr); 262 current_->AddInstruction(expr);
fschneider 2010/03/29 13:49:59 UNREACHABLE() here? Since literals are always triv
401 } 263 }
402 264
403 265
404 void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 266 void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
405 SetStackOverflow(); 267 SetStackOverflow();
406 } 268 }
407 269
408 270
409 void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 271 void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
410 SetStackOverflow(); 272 SetStackOverflow();
411 } 273 }
412 274
413 275
414 void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 276 void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
415 SetStackOverflow(); 277 SetStackOverflow();
416 } 278 }
417 279
418 280
419 void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { 281 void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
420 SetStackOverflow(); 282 SetStackOverflow();
421 } 283 }
422 284
423 285
424 void FlowGraphBuilder::VisitAssignment(Assignment* expr) { 286 void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
287 // There are three basic kinds of assignment: variable assignments,
288 // property assignments, and invalid left-hand sides (which are translated
289 // to "throw ReferenceError" by the parser).
425 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); 290 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
426 Property* prop = expr->target()->AsProperty(); 291 Property* prop = expr->target()->AsProperty();
427 // Left-hand side can be a variable or property (or reference error) but
428 // not both.
429 ASSERT(var == NULL || prop == NULL); 292 ASSERT(var == NULL || prop == NULL);
430 if (var != NULL) { 293 if (var != NULL) {
431 if (expr->is_compound()) Visit(expr->target()); 294 if (expr->is_compound() && !expr->target()->IsTrivial()) {
432 Visit(expr->value()); 295 Visit(expr->target());
433 if (var->IsStackAllocated()) {
434 // The first definition in the body is numbered n, where n is the
435 // number of parameters and stack-allocated locals.
436 expr->set_num(body_definitions_.length() + variable_count_);
437 body_definitions_.Add(expr);
438 } 296 }
297 if (!expr->value()->IsTrivial()) Visit(expr->value());
298 current_->AddInstruction(expr);
439 299
440 } else if (prop != NULL) { 300 } else if (prop != NULL) {
441 Visit(prop->obj()); 301 if (!prop->obj()->IsTrivial()) Visit(prop->obj());
442 if (!prop->key()->IsPropertyName()) Visit(prop->key()); 302 if (!prop->key()->IsPropertyName() && !prop->key()->IsTrivial()) {
443 Visit(expr->value()); 303 Visit(prop->key());
304 }
305 if (!expr->value()->IsTrivial()) Visit(expr->value());
306 current_->AddInstruction(expr);
307
308 } else {
309 Visit(expr->target());
444 } 310 }
445
446 if (HasStackOverflow()) return;
447 graph_.AppendInstruction(expr);
448 } 311 }
449 312
450 313
451 void FlowGraphBuilder::VisitThrow(Throw* expr) { 314 void FlowGraphBuilder::VisitThrow(Throw* expr) {
452 SetStackOverflow(); 315 SetStackOverflow();
453 } 316 }
454 317
455 318
456 void FlowGraphBuilder::VisitProperty(Property* expr) { 319 void FlowGraphBuilder::VisitProperty(Property* expr) {
457 Visit(expr->obj()); 320 if (!expr->obj()->IsTrivial()) Visit(expr->obj());
458 if (!expr->key()->IsPropertyName()) Visit(expr->key()); 321 if (!expr->key()->IsPropertyName() && !expr->key()->IsTrivial()) {
459 322 Visit(expr->key());
460 if (HasStackOverflow()) return; 323 }
461 graph_.AppendInstruction(expr); 324 current_->AddInstruction(expr);
462 } 325 }
463 326
464 327
465 void FlowGraphBuilder::VisitCall(Call* expr) { 328 void FlowGraphBuilder::VisitCall(Call* expr) {
466 Visit(expr->expression()); 329 Visit(expr->expression());
467 ZoneList<Expression*>* arguments = expr->arguments(); 330 VisitExpressions(expr->arguments());
468 for (int i = 0, len = arguments->length(); i < len; i++) { 331 current_->AddInstruction(expr);
469 Visit(arguments->at(i));
470 }
471
472 if (HasStackOverflow()) return;
473 graph_.AppendInstruction(expr);
474 } 332 }
475 333
476 334
477 void FlowGraphBuilder::VisitCallNew(CallNew* expr) { 335 void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
478 SetStackOverflow(); 336 SetStackOverflow();
479 } 337 }
480 338
481 339
482 void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 340 void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
483 SetStackOverflow(); 341 SetStackOverflow();
484 } 342 }
485 343
486 344
487 void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 345 void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
488 switch (expr->op()) { 346 switch (expr->op()) {
489 case Token::NOT: 347 case Token::NOT:
490 case Token::BIT_NOT: 348 case Token::BIT_NOT:
491 case Token::DELETE: 349 case Token::DELETE:
492 case Token::TYPEOF: 350 case Token::TYPEOF:
493 case Token::VOID: 351 case Token::VOID:
494 SetStackOverflow(); 352 SetStackOverflow();
495 break; 353 break;
496 354
497 case Token::ADD: 355 case Token::ADD:
498 case Token::SUB: 356 case Token::SUB:
499 Visit(expr->expression()); 357 Visit(expr->expression());
500 if (HasStackOverflow()) return; 358 current_->AddInstruction(expr);
501 graph_.AppendInstruction(expr);
502 break; 359 break;
503 360
504 default: 361 default:
505 UNREACHABLE(); 362 UNREACHABLE();
506 } 363 }
507 } 364 }
508 365
509 366
510 void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) { 367 void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
511 Visit(expr->expression()); 368 Visit(expr->expression());
512 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 369 current_->AddInstruction(expr);
513 if (var != NULL && var->IsStackAllocated()) {
514 // The first definition in the body is numbered n, where n is the number
515 // of parameters and stack-allocated locals.
516 expr->set_num(body_definitions_.length() + variable_count_);
517 body_definitions_.Add(expr);
518 }
519
520 if (HasStackOverflow()) return;
521 graph_.AppendInstruction(expr);
522 } 370 }
523 371
524 372
525 void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 373 void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
526 switch (expr->op()) { 374 switch (expr->op()) {
527 case Token::COMMA: 375 case Token::COMMA:
528 case Token::OR: 376 case Token::OR:
529 case Token::AND: 377 case Token::AND:
530 SetStackOverflow(); 378 SetStackOverflow();
531 break; 379 break;
532 380
533 case Token::BIT_OR: 381 case Token::BIT_OR:
534 case Token::BIT_XOR: 382 case Token::BIT_XOR:
535 case Token::BIT_AND: 383 case Token::BIT_AND:
536 case Token::SHL: 384 case Token::SHL:
385 case Token::SAR:
537 case Token::SHR: 386 case Token::SHR:
538 case Token::ADD: 387 case Token::ADD:
539 case Token::SUB: 388 case Token::SUB:
540 case Token::MUL: 389 case Token::MUL:
541 case Token::DIV: 390 case Token::DIV:
542 case Token::MOD: 391 case Token::MOD:
543 case Token::SAR: 392 if (!expr->left()->IsTrivial()) Visit(expr->left());
544 Visit(expr->left()); 393 if (!expr->right()->IsTrivial()) Visit(expr->right());
545 Visit(expr->right()); 394 current_->AddInstruction(expr);
546 if (HasStackOverflow()) return;
547 graph_.AppendInstruction(expr);
548 break; 395 break;
549 396
550 default: 397 default:
551 UNREACHABLE(); 398 UNREACHABLE();
552 } 399 }
553 } 400 }
554 401
555 402
556 void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 403 void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
557 switch (expr->op()) { 404 switch (expr->op()) {
558 case Token::EQ: 405 case Token::EQ:
559 case Token::NE: 406 case Token::NE:
560 case Token::EQ_STRICT: 407 case Token::EQ_STRICT:
561 case Token::NE_STRICT: 408 case Token::NE_STRICT:
562 case Token::INSTANCEOF: 409 case Token::INSTANCEOF:
563 case Token::IN: 410 case Token::IN:
564 SetStackOverflow(); 411 SetStackOverflow();
565 break; 412 break;
566 413
567 case Token::LT: 414 case Token::LT:
568 case Token::GT: 415 case Token::GT:
569 case Token::LTE: 416 case Token::LTE:
570 case Token::GTE: 417 case Token::GTE:
571 Visit(expr->left()); 418 if (!expr->left()->IsTrivial()) Visit(expr->left());
572 Visit(expr->right()); 419 if (!expr->right()->IsTrivial()) Visit(expr->right());
573 if (HasStackOverflow()) return; 420 current_->AddInstruction(expr);
574 graph_.AppendInstruction(expr);
575 break; 421 break;
576 422
577 default: 423 default:
578 UNREACHABLE(); 424 UNREACHABLE();
579 } 425 }
580 } 426 }
581 427
582 428
583 void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) { 429 void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
584 SetStackOverflow(); 430 SetStackOverflow();
585 } 431 }
586 432
587 433
434 #ifdef DEBUG
435
436 // Print a textual representation of an instruction in a flow graph. Using
437 // the AstVisitor is overkill because there is no recursion here. It is
438 // however only used for printing in debug mode.
439 class InstructionPrinter: public AstVisitor {
440 public:
441 InstructionPrinter() {}
442
443 private:
444 // Overridden from the base class.
445 virtual void VisitExpressions(ZoneList<Expression*>* exprs);
446
447 // AST node visit functions.
448 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
449 AST_NODE_LIST(DECLARE_VISIT)
450 #undef DECLARE_VISIT
451
452 DISALLOW_COPY_AND_ASSIGN(InstructionPrinter);
453 };
454
455
456 static void PrintSubexpression(Expression* expr) {
457 if (!expr->IsTrivial()) {
458 PrintF("@%d", expr->num());
459 } else if (expr->AsLiteral() != NULL) {
460 expr->AsLiteral()->handle()->Print();
461 } else if (expr->AsVariableProxy() != NULL) {
462 PrintF("%s", *expr->AsVariableProxy()->name()->ToCString());
463 } else {
464 UNREACHABLE();
465 }
466 }
467
468
469 void InstructionPrinter::VisitExpressions(ZoneList<Expression*>* exprs) {
470 for (int i = 0; i < exprs->length(); ++i) {
471 if (i != 0) PrintF(", ");
472 PrintF("@%d", exprs->at(i)->num());
473 }
474 }
475
476
477 // We only define printing functions for the node types that can occur as
478 // instructions in a flow graph. The rest are unreachable.
479 void InstructionPrinter::VisitDeclaration(Declaration* decl) {
480 UNREACHABLE();
481 }
482
483
484 void InstructionPrinter::VisitBlock(Block* stmt) {
485 UNREACHABLE();
486 }
487
488
489 void InstructionPrinter::VisitExpressionStatement(ExpressionStatement* stmt) {
490 UNREACHABLE();
491 }
492
493
494 void InstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
495 UNREACHABLE();
496 }
497
498
499 void InstructionPrinter::VisitIfStatement(IfStatement* stmt) {
500 UNREACHABLE();
501 }
502
503
504 void InstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
505 UNREACHABLE();
506 }
507
508
509 void InstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
510 UNREACHABLE();
511 }
512
513
514 void InstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
515 PrintF("return ");
516 PrintSubexpression(stmt->expression());
517 }
518
519
520 void InstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
521 UNREACHABLE();
522 }
523
524
525 void InstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
526 UNREACHABLE();
527 }
528
529
530 void InstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
531 UNREACHABLE();
532 }
533
534
535 void InstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
536 UNREACHABLE();
537 }
538
539
540 void InstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
541 UNREACHABLE();
542 }
543
544
545 void InstructionPrinter::VisitForStatement(ForStatement* stmt) {
546 UNREACHABLE();
547 }
548
549
550 void InstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
551 UNREACHABLE();
552 }
553
554
555 void InstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
556 UNREACHABLE();
557 }
558
559
560 void InstructionPrinter::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
561 UNREACHABLE();
562 }
563
564
565 void InstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
566 UNREACHABLE();
567 }
568
569
570 void InstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
571 UNREACHABLE();
572 }
573
574
575 void InstructionPrinter::VisitSharedFunctionInfoLiteral(
576 SharedFunctionInfoLiteral* expr) {
577 UNREACHABLE();
578 }
579
580
581 void InstructionPrinter::VisitConditional(Conditional* expr) {
582 UNREACHABLE();
583 }
584
585
586 void InstructionPrinter::VisitSlot(Slot* expr) {
587 UNREACHABLE();
588 }
589
590
591 void InstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
592 Variable* var = expr->AsVariable();
593 if (var != NULL) {
594 PrintF("%s", *var->name()->ToCString());
595 } else {
596 ASSERT(expr->AsProperty() != NULL);
597 VisitProperty(expr->AsProperty());
598 }
599 }
600
601
602 void InstructionPrinter::VisitLiteral(Literal* expr) {
603 expr->handle()->Print();
604 }
605
606
607 void InstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
608 UNREACHABLE();
609 }
610
611
612 void InstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
613 UNREACHABLE();
614 }
615
616
617 void InstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
618 UNREACHABLE();
619 }
620
621
622 void InstructionPrinter::VisitCatchExtensionObject(
623 CatchExtensionObject* expr) {
624 UNREACHABLE();
625 }
626
627
628 void InstructionPrinter::VisitAssignment(Assignment* expr) {
629 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
630 Property* prop = expr->target()->AsProperty();
631
632 // Print the left-hand side.
633 Visit(expr->target());
634 if (var == NULL && prop == NULL) return; // Throw reference error.
635 PrintF(" = ");
636 // For compound assignments, print the left-hand side again and the
637 // corresponding binary operator.
638 if (expr->is_compound()) {
639 PrintSubexpression(expr->target());
640 PrintF(" %s ", Token::String(expr->binary_op()));
641 }
642
643 // Print the right-hand side.
644 PrintSubexpression(expr->value());
645 }
646
647
648 void InstructionPrinter::VisitThrow(Throw* expr) {
649 UNREACHABLE();
650 }
651
652
653 void InstructionPrinter::VisitProperty(Property* expr) {
654 PrintSubexpression(expr->obj());
655 if (expr->key()->IsPropertyName()) {
656 PrintF(".");
657 ASSERT(expr->key()->AsLiteral() != NULL);
658 expr->key()->AsLiteral()->handle()->Print();
659 } else {
660 PrintF("[");
661 PrintSubexpression(expr->key());
662 PrintF("]");
663 }
664 }
665
666
667 void InstructionPrinter::VisitCall(Call* expr) {
668 PrintF("@%d(", expr->expression()->num());
669 VisitExpressions(expr->arguments());
670 PrintF(")");
671 }
672
673
674 void InstructionPrinter::VisitCallNew(CallNew* expr) {
675 UNREACHABLE();
676 }
677
678
679 void InstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
680 UNREACHABLE();
681 }
682
683
684 void InstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
685 PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
686 }
687
688
689 void InstructionPrinter::VisitCountOperation(CountOperation* expr) {
690 if (expr->is_prefix()) {
691 PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
692 } else {
693 PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
694 }
695 }
696
697
698 void InstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
699 PrintSubexpression(expr->left());
700 PrintF(" %s ", Token::String(expr->op()));
701 PrintSubexpression(expr->right());
702 }
703
704
705 void InstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
706 PrintSubexpression(expr->left());
707 PrintF(" %s ", Token::String(expr->op()));
708 PrintSubexpression(expr->right());
709 }
710
711
712 void InstructionPrinter::VisitThisFunction(ThisFunction* expr) {
713 UNREACHABLE();
714 }
715
716
717 int BasicBlock::PrintAsText(int instruction_number) {
718 // Print a label for all blocks except the entry.
719 if (HasPredecessor()) {
720 PrintF("L%d:", number());
721 }
722
723 // Number and print the instructions. Since AST child nodes are visited
724 // before their parents, the parent nodes can refer to them by number.
725 InstructionPrinter printer;
726 for (int i = 0; i < instructions_.length(); ++i) {
727 PrintF("\n%d ", instruction_number);
728 instructions_[i]->set_num(instruction_number++);
729 printer.Visit(instructions_[i]);
730 }
731
732 // If this is the exit, print "exit". If there is a single successor,
733 // print "goto" successor on a separate line. If there are two
734 // successors, print "goto" successor on the same line as the last
735 // instruction in the block. There is a blank line between blocks (and
736 // after the last one).
737 if (left_successor_ == NULL) {
738 PrintF("\nexit\n\n");
739 } else if (right_successor_ == NULL) {
740 PrintF("\ngoto L%d\n\n", left_successor_->number());
741 } else {
742 PrintF(", goto (L%d, L%d)\n\n",
743 left_successor_->number(),
744 right_successor_->number());
745 }
746
747 return instruction_number;
748 }
749
750
751 void FlowGraph::PrintAsText(Handle<String> name) {
752 PrintF("\n==== name = \"%s\" ====\n", *name->ToCString());
753 // Print nodes in reverse postorder. Note that AST node numbers are used
754 // during printing of instructions and thus their current values are
755 // destroyed.
756 int number = 0;
757 for (int i = postorder_.length() - 1; i >= 0; --i) {
758 number = postorder_[i]->PrintAsText(number);
759 }
760 }
761
762 #endif // DEBUG
763
764
588 } } // namespace v8::internal 765 } } // namespace v8::internal
OLDNEW
« src/flow-graph.h ('K') | « src/flow-graph.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698