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