OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |