OLD | NEW |
| (Empty) |
1 // Copyright 2009 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 "v8.h" | |
29 | |
30 #include "bootstrapper.h" | |
31 #include "cfg.h" | |
32 #include "scopeinfo.h" | |
33 #include "scopes.h" | |
34 | |
35 namespace v8 { | |
36 namespace internal { | |
37 | |
38 | |
39 CfgGlobals* CfgGlobals::top_ = NULL; | |
40 | |
41 | |
42 CfgGlobals::CfgGlobals(FunctionLiteral* fun) | |
43 : global_fun_(fun), | |
44 global_exit_(new ExitNode()), | |
45 nowhere_(new Nowhere()), | |
46 #ifdef DEBUG | |
47 node_counter_(0), | |
48 temp_counter_(0), | |
49 #endif | |
50 previous_(top_) { | |
51 top_ = this; | |
52 } | |
53 | |
54 | |
55 #define BAILOUT(reason) \ | |
56 do { return NULL; } while (false) | |
57 | |
58 Cfg* Cfg::Build() { | |
59 FunctionLiteral* fun = CfgGlobals::current()->fun(); | |
60 if (fun->scope()->num_heap_slots() > 0) { | |
61 BAILOUT("function has context slots"); | |
62 } | |
63 if (fun->scope()->num_stack_slots() > kBitsPerPointer) { | |
64 BAILOUT("function has too many locals"); | |
65 } | |
66 if (fun->scope()->num_parameters() > kBitsPerPointer - 1) { | |
67 BAILOUT("function has too many parameters"); | |
68 } | |
69 if (fun->scope()->arguments() != NULL) { | |
70 BAILOUT("function uses .arguments"); | |
71 } | |
72 | |
73 ZoneList<Statement*>* body = fun->body(); | |
74 if (body->is_empty()) { | |
75 BAILOUT("empty function body"); | |
76 } | |
77 | |
78 StatementCfgBuilder builder; | |
79 builder.VisitStatements(body); | |
80 Cfg* graph = builder.graph(); | |
81 if (graph == NULL) { | |
82 BAILOUT("unsupported statement type"); | |
83 } | |
84 if (graph->is_empty()) { | |
85 BAILOUT("function body produces empty cfg"); | |
86 } | |
87 if (graph->has_exit()) { | |
88 BAILOUT("control path without explicit return"); | |
89 } | |
90 graph->PrependEntryNode(); | |
91 return graph; | |
92 } | |
93 | |
94 #undef BAILOUT | |
95 | |
96 | |
97 void Cfg::PrependEntryNode() { | |
98 ASSERT(!is_empty()); | |
99 entry_ = new EntryNode(InstructionBlock::cast(entry())); | |
100 } | |
101 | |
102 | |
103 void Cfg::Append(Instruction* instr) { | |
104 ASSERT(is_empty() || has_exit()); | |
105 if (is_empty()) { | |
106 entry_ = exit_ = new InstructionBlock(); | |
107 } | |
108 InstructionBlock::cast(exit_)->Append(instr); | |
109 } | |
110 | |
111 | |
112 void Cfg::AppendReturnInstruction(Value* value) { | |
113 Append(new ReturnInstr(value)); | |
114 ExitNode* global_exit = CfgGlobals::current()->exit(); | |
115 InstructionBlock::cast(exit_)->set_successor(global_exit); | |
116 exit_ = NULL; | |
117 } | |
118 | |
119 | |
120 void Cfg::Concatenate(Cfg* other) { | |
121 ASSERT(is_empty() || has_exit()); | |
122 if (other->is_empty()) return; | |
123 | |
124 if (is_empty()) { | |
125 entry_ = other->entry(); | |
126 exit_ = other->exit(); | |
127 } else { | |
128 // We have a pair of nonempty fragments and this has an available exit. | |
129 // Destructively glue the fragments together. | |
130 InstructionBlock* first = InstructionBlock::cast(exit_); | |
131 InstructionBlock* second = InstructionBlock::cast(other->entry()); | |
132 first->instructions()->AddAll(*second->instructions()); | |
133 if (second->successor() != NULL) { | |
134 first->set_successor(second->successor()); | |
135 exit_ = other->exit(); | |
136 } | |
137 } | |
138 } | |
139 | |
140 | |
141 void InstructionBlock::Unmark() { | |
142 if (is_marked_) { | |
143 is_marked_ = false; | |
144 successor_->Unmark(); | |
145 } | |
146 } | |
147 | |
148 | |
149 void EntryNode::Unmark() { | |
150 if (is_marked_) { | |
151 is_marked_ = false; | |
152 successor_->Unmark(); | |
153 } | |
154 } | |
155 | |
156 | |
157 void ExitNode::Unmark() { | |
158 is_marked_ = false; | |
159 } | |
160 | |
161 | |
162 Handle<Code> Cfg::Compile(Handle<Script> script) { | |
163 const int kInitialBufferSize = 4 * KB; | |
164 MacroAssembler* masm = new MacroAssembler(NULL, kInitialBufferSize); | |
165 entry()->Compile(masm); | |
166 entry()->Unmark(); | |
167 CodeDesc desc; | |
168 masm->GetCode(&desc); | |
169 FunctionLiteral* fun = CfgGlobals::current()->fun(); | |
170 ZoneScopeInfo info(fun->scope()); | |
171 InLoopFlag in_loop = fun->loop_nesting() ? IN_LOOP : NOT_IN_LOOP; | |
172 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); | |
173 Handle<Code> code = Factory::NewCode(desc, &info, flags, masm->CodeObject()); | |
174 | |
175 // Add unresolved entries in the code to the fixup list. | |
176 Bootstrapper::AddFixup(*code, masm); | |
177 | |
178 #ifdef ENABLE_DISASSEMBLER | |
179 if (FLAG_print_code) { | |
180 // Print the source code if available. | |
181 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | |
182 PrintF("--- Raw source ---\n"); | |
183 StringInputBuffer stream(String::cast(script->source())); | |
184 stream.Seek(fun->start_position()); | |
185 // fun->end_position() points to the last character in the | |
186 // stream. We need to compensate by adding one to calculate the | |
187 // length. | |
188 int source_len = fun->end_position() - fun->start_position() + 1; | |
189 for (int i = 0; i < source_len; i++) { | |
190 if (stream.has_more()) PrintF("%c", stream.GetNext()); | |
191 } | |
192 PrintF("\n\n"); | |
193 } | |
194 PrintF("--- Code ---\n"); | |
195 code->Disassemble(*fun->name()->ToCString()); | |
196 } | |
197 #endif | |
198 | |
199 return code; | |
200 } | |
201 | |
202 | |
203 void ZeroOperandInstruction::FastAllocate(TempLocation* temp) { | |
204 temp->set_where(TempLocation::STACK); | |
205 } | |
206 | |
207 | |
208 void OneOperandInstruction::FastAllocate(TempLocation* temp) { | |
209 temp->set_where((temp == value_) | |
210 ? TempLocation::ACCUMULATOR | |
211 : TempLocation::STACK); | |
212 } | |
213 | |
214 | |
215 void TwoOperandInstruction::FastAllocate(TempLocation* temp) { | |
216 temp->set_where((temp == value0_ || temp == value1_) | |
217 ? TempLocation::ACCUMULATOR | |
218 : TempLocation::STACK); | |
219 } | |
220 | |
221 | |
222 void PositionInstr::Compile(MacroAssembler* masm) { | |
223 if (FLAG_debug_info && pos_ != RelocInfo::kNoPosition) { | |
224 masm->RecordStatementPosition(pos_); | |
225 masm->RecordPosition(pos_); | |
226 } | |
227 } | |
228 | |
229 | |
230 void MoveInstr::Compile(MacroAssembler* masm) { | |
231 location()->Move(masm, value()); | |
232 } | |
233 | |
234 | |
235 // The expression builder should not be used for declarations or statements. | |
236 void ExpressionCfgBuilder::VisitDeclaration(Declaration* decl) { | |
237 UNREACHABLE(); | |
238 } | |
239 | |
240 #define DEFINE_VISIT(type) \ | |
241 void ExpressionCfgBuilder::Visit##type(type* stmt) { UNREACHABLE(); } | |
242 STATEMENT_NODE_LIST(DEFINE_VISIT) | |
243 #undef DEFINE_VISIT | |
244 | |
245 | |
246 // Macros (temporarily) handling unsupported expression types. | |
247 #define BAILOUT(reason) \ | |
248 do { \ | |
249 graph_ = NULL; \ | |
250 return; \ | |
251 } while (false) | |
252 | |
253 void ExpressionCfgBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | |
254 BAILOUT("FunctionLiteral"); | |
255 } | |
256 | |
257 | |
258 void ExpressionCfgBuilder::VisitFunctionBoilerplateLiteral( | |
259 FunctionBoilerplateLiteral* expr) { | |
260 BAILOUT("FunctionBoilerplateLiteral"); | |
261 } | |
262 | |
263 | |
264 void ExpressionCfgBuilder::VisitConditional(Conditional* expr) { | |
265 BAILOUT("Conditional"); | |
266 } | |
267 | |
268 | |
269 void ExpressionCfgBuilder::VisitSlot(Slot* expr) { | |
270 BAILOUT("Slot"); | |
271 } | |
272 | |
273 | |
274 void ExpressionCfgBuilder::VisitVariableProxy(VariableProxy* expr) { | |
275 Expression* rewrite = expr->var()->rewrite(); | |
276 if (rewrite == NULL || rewrite->AsSlot() == NULL) { | |
277 BAILOUT("unsupported variable (not a slot)"); | |
278 } | |
279 Slot* slot = rewrite->AsSlot(); | |
280 if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) { | |
281 BAILOUT("unsupported slot type (not a parameter or local)"); | |
282 } | |
283 // Ignore the passed destination. | |
284 value_ = new SlotLocation(slot->type(), slot->index()); | |
285 } | |
286 | |
287 | |
288 void ExpressionCfgBuilder::VisitLiteral(Literal* expr) { | |
289 // Ignore the passed destination. | |
290 value_ = new Constant(expr->handle()); | |
291 } | |
292 | |
293 | |
294 void ExpressionCfgBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | |
295 BAILOUT("RegExpLiteral"); | |
296 } | |
297 | |
298 | |
299 void ExpressionCfgBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | |
300 BAILOUT("ObjectLiteral"); | |
301 } | |
302 | |
303 | |
304 void ExpressionCfgBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | |
305 BAILOUT("ArrayLiteral"); | |
306 } | |
307 | |
308 | |
309 void ExpressionCfgBuilder::VisitCatchExtensionObject( | |
310 CatchExtensionObject* expr) { | |
311 BAILOUT("CatchExtensionObject"); | |
312 } | |
313 | |
314 | |
315 void ExpressionCfgBuilder::VisitAssignment(Assignment* expr) { | |
316 if (expr->op() != Token::ASSIGN && expr->op() != Token::INIT_VAR) { | |
317 BAILOUT("unsupported compound assignment"); | |
318 } | |
319 Expression* lhs = expr->target(); | |
320 if (lhs->AsProperty() != NULL) { | |
321 BAILOUT("unsupported property assignment"); | |
322 } | |
323 | |
324 Variable* var = lhs->AsVariableProxy()->AsVariable(); | |
325 if (var == NULL) { | |
326 BAILOUT("unsupported invalid left-hand side"); | |
327 } | |
328 if (var->is_global()) { | |
329 BAILOUT("unsupported global variable"); | |
330 } | |
331 Slot* slot = var->slot(); | |
332 ASSERT(slot != NULL); | |
333 if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) { | |
334 BAILOUT("unsupported slot lhs (not a parameter or local)"); | |
335 } | |
336 | |
337 // Parameter and local slot assignments. | |
338 ExpressionCfgBuilder builder; | |
339 SlotLocation* loc = new SlotLocation(slot->type(), slot->index()); | |
340 builder.Build(expr->value(), loc); | |
341 if (builder.graph() == NULL) { | |
342 BAILOUT("unsupported expression in assignment"); | |
343 } | |
344 // If the expression did not come back in the slot location, append | |
345 // a move to the CFG. | |
346 graph_ = builder.graph(); | |
347 if (builder.value() != loc) { | |
348 graph()->Append(new MoveInstr(loc, builder.value())); | |
349 } | |
350 // Record the assignment. | |
351 assigned_vars_.AddElement(loc); | |
352 // Ignore the destination passed to us. | |
353 value_ = loc; | |
354 } | |
355 | |
356 | |
357 void ExpressionCfgBuilder::VisitThrow(Throw* expr) { | |
358 BAILOUT("Throw"); | |
359 } | |
360 | |
361 | |
362 void ExpressionCfgBuilder::VisitProperty(Property* expr) { | |
363 ExpressionCfgBuilder object, key; | |
364 object.Build(expr->obj(), NULL); | |
365 if (object.graph() == NULL) { | |
366 BAILOUT("unsupported object subexpression in propload"); | |
367 } | |
368 key.Build(expr->key(), NULL); | |
369 if (key.graph() == NULL) { | |
370 BAILOUT("unsupported key subexpression in propload"); | |
371 } | |
372 | |
373 if (destination_ == NULL) destination_ = new TempLocation(); | |
374 | |
375 graph_ = object.graph(); | |
376 // Insert a move to a fresh temporary if the object value is in a slot | |
377 // that's assigned in the key. | |
378 Location* temp = NULL; | |
379 if (object.value()->is_slot() && | |
380 key.assigned_vars()->Contains(SlotLocation::cast(object.value()))) { | |
381 temp = new TempLocation(); | |
382 graph()->Append(new MoveInstr(temp, object.value())); | |
383 } | |
384 graph()->Concatenate(key.graph()); | |
385 graph()->Append(new PropLoadInstr(destination_, | |
386 temp == NULL ? object.value() : temp, | |
387 key.value())); | |
388 | |
389 assigned_vars_ = *object.assigned_vars(); | |
390 assigned_vars()->Union(key.assigned_vars()); | |
391 | |
392 value_ = destination_; | |
393 } | |
394 | |
395 | |
396 void ExpressionCfgBuilder::VisitCall(Call* expr) { | |
397 BAILOUT("Call"); | |
398 } | |
399 | |
400 | |
401 void ExpressionCfgBuilder::VisitCallNew(CallNew* expr) { | |
402 BAILOUT("CallNew"); | |
403 } | |
404 | |
405 | |
406 void ExpressionCfgBuilder::VisitCallRuntime(CallRuntime* expr) { | |
407 BAILOUT("CallRuntime"); | |
408 } | |
409 | |
410 | |
411 void ExpressionCfgBuilder::VisitUnaryOperation(UnaryOperation* expr) { | |
412 BAILOUT("UnaryOperation"); | |
413 } | |
414 | |
415 | |
416 void ExpressionCfgBuilder::VisitCountOperation(CountOperation* expr) { | |
417 BAILOUT("CountOperation"); | |
418 } | |
419 | |
420 | |
421 void ExpressionCfgBuilder::VisitBinaryOperation(BinaryOperation* expr) { | |
422 Token::Value op = expr->op(); | |
423 switch (op) { | |
424 case Token::COMMA: | |
425 case Token::OR: | |
426 case Token::AND: | |
427 BAILOUT("unsupported binary operation"); | |
428 | |
429 case Token::BIT_OR: | |
430 case Token::BIT_XOR: | |
431 case Token::BIT_AND: | |
432 case Token::SHL: | |
433 case Token::SAR: | |
434 case Token::SHR: | |
435 case Token::ADD: | |
436 case Token::SUB: | |
437 case Token::MUL: | |
438 case Token::DIV: | |
439 case Token::MOD: { | |
440 ExpressionCfgBuilder left, right; | |
441 left.Build(expr->left(), NULL); | |
442 if (left.graph() == NULL) { | |
443 BAILOUT("unsupported left subexpression in binop"); | |
444 } | |
445 right.Build(expr->right(), NULL); | |
446 if (right.graph() == NULL) { | |
447 BAILOUT("unsupported right subexpression in binop"); | |
448 } | |
449 | |
450 if (destination_ == NULL) destination_ = new TempLocation(); | |
451 | |
452 graph_ = left.graph(); | |
453 // Insert a move to a fresh temporary if the left value is in a | |
454 // slot that's assigned on the right. | |
455 Location* temp = NULL; | |
456 if (left.value()->is_slot() && | |
457 right.assigned_vars()->Contains(SlotLocation::cast(left.value()))) { | |
458 temp = new TempLocation(); | |
459 graph()->Append(new MoveInstr(temp, left.value())); | |
460 } | |
461 graph()->Concatenate(right.graph()); | |
462 graph()->Append(new BinaryOpInstr(destination_, op, | |
463 temp == NULL ? left.value() : temp, | |
464 right.value())); | |
465 | |
466 assigned_vars_ = *left.assigned_vars(); | |
467 assigned_vars()->Union(right.assigned_vars()); | |
468 | |
469 value_ = destination_; | |
470 return; | |
471 } | |
472 | |
473 default: | |
474 UNREACHABLE(); | |
475 } | |
476 } | |
477 | |
478 | |
479 void ExpressionCfgBuilder::VisitCompareOperation(CompareOperation* expr) { | |
480 BAILOUT("CompareOperation"); | |
481 } | |
482 | |
483 | |
484 void ExpressionCfgBuilder::VisitThisFunction(ThisFunction* expr) { | |
485 BAILOUT("ThisFunction"); | |
486 } | |
487 | |
488 #undef BAILOUT | |
489 | |
490 | |
491 // Macros (temporarily) handling unsupported statement types. | |
492 #define BAILOUT(reason) \ | |
493 do { \ | |
494 graph_ = NULL; \ | |
495 return; \ | |
496 } while (false) | |
497 | |
498 #define CHECK_BAILOUT() \ | |
499 if (graph() == NULL) { return; } else {} | |
500 | |
501 void StatementCfgBuilder::VisitStatements(ZoneList<Statement*>* stmts) { | |
502 for (int i = 0, len = stmts->length(); i < len; i++) { | |
503 Visit(stmts->at(i)); | |
504 CHECK_BAILOUT(); | |
505 if (!graph()->has_exit()) return; | |
506 } | |
507 } | |
508 | |
509 | |
510 // The statement builder should not be used for declarations or expressions. | |
511 void StatementCfgBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } | |
512 | |
513 #define DEFINE_VISIT(type) \ | |
514 void StatementCfgBuilder::Visit##type(type* expr) { UNREACHABLE(); } | |
515 EXPRESSION_NODE_LIST(DEFINE_VISIT) | |
516 #undef DEFINE_VISIT | |
517 | |
518 | |
519 void StatementCfgBuilder::VisitBlock(Block* stmt) { | |
520 VisitStatements(stmt->statements()); | |
521 } | |
522 | |
523 | |
524 void StatementCfgBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { | |
525 ExpressionCfgBuilder builder; | |
526 builder.Build(stmt->expression(), CfgGlobals::current()->nowhere()); | |
527 if (builder.graph() == NULL) { | |
528 BAILOUT("unsupported expression in expression statement"); | |
529 } | |
530 graph()->Append(new PositionInstr(stmt->statement_pos())); | |
531 graph()->Concatenate(builder.graph()); | |
532 } | |
533 | |
534 | |
535 void StatementCfgBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | |
536 // Nothing to do. | |
537 } | |
538 | |
539 | |
540 void StatementCfgBuilder::VisitIfStatement(IfStatement* stmt) { | |
541 BAILOUT("IfStatement"); | |
542 } | |
543 | |
544 | |
545 void StatementCfgBuilder::VisitContinueStatement(ContinueStatement* stmt) { | |
546 BAILOUT("ContinueStatement"); | |
547 } | |
548 | |
549 | |
550 void StatementCfgBuilder::VisitBreakStatement(BreakStatement* stmt) { | |
551 BAILOUT("BreakStatement"); | |
552 } | |
553 | |
554 | |
555 void StatementCfgBuilder::VisitReturnStatement(ReturnStatement* stmt) { | |
556 ExpressionCfgBuilder builder; | |
557 builder.Build(stmt->expression(), NULL); | |
558 if (builder.graph() == NULL) { | |
559 BAILOUT("unsupported expression in return statement"); | |
560 } | |
561 | |
562 graph()->Append(new PositionInstr(stmt->statement_pos())); | |
563 graph()->Concatenate(builder.graph()); | |
564 graph()->AppendReturnInstruction(builder.value()); | |
565 } | |
566 | |
567 | |
568 void StatementCfgBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
569 BAILOUT("WithEnterStatement"); | |
570 } | |
571 | |
572 | |
573 void StatementCfgBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | |
574 BAILOUT("WithExitStatement"); | |
575 } | |
576 | |
577 | |
578 void StatementCfgBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | |
579 BAILOUT("SwitchStatement"); | |
580 } | |
581 | |
582 | |
583 void StatementCfgBuilder::VisitLoopStatement(LoopStatement* stmt) { | |
584 BAILOUT("LoopStatement"); | |
585 } | |
586 | |
587 | |
588 void StatementCfgBuilder::VisitForInStatement(ForInStatement* stmt) { | |
589 BAILOUT("ForInStatement"); | |
590 } | |
591 | |
592 | |
593 void StatementCfgBuilder::VisitTryCatch(TryCatch* stmt) { | |
594 BAILOUT("TryCatch"); | |
595 } | |
596 | |
597 | |
598 void StatementCfgBuilder::VisitTryFinally(TryFinally* stmt) { | |
599 BAILOUT("TryFinally"); | |
600 } | |
601 | |
602 | |
603 void StatementCfgBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
604 BAILOUT("DebuggerStatement"); | |
605 } | |
606 | |
607 | |
608 #ifdef DEBUG | |
609 // CFG printing support (via depth-first, preorder block traversal). | |
610 | |
611 void Cfg::Print() { | |
612 entry_->Print(); | |
613 entry_->Unmark(); | |
614 } | |
615 | |
616 | |
617 void Constant::Print() { | |
618 PrintF("Constant "); | |
619 handle_->Print(); | |
620 } | |
621 | |
622 | |
623 void Nowhere::Print() { | |
624 PrintF("Nowhere"); | |
625 } | |
626 | |
627 | |
628 void SlotLocation::Print() { | |
629 PrintF("Slot "); | |
630 switch (type_) { | |
631 case Slot::PARAMETER: | |
632 PrintF("(PARAMETER, %d)", index_); | |
633 break; | |
634 case Slot::LOCAL: | |
635 PrintF("(LOCAL, %d)", index_); | |
636 break; | |
637 default: | |
638 UNREACHABLE(); | |
639 } | |
640 } | |
641 | |
642 | |
643 void TempLocation::Print() { | |
644 PrintF("Temp %d", number()); | |
645 } | |
646 | |
647 | |
648 void OneOperandInstruction::Print() { | |
649 PrintF("("); | |
650 location()->Print(); | |
651 PrintF(", "); | |
652 value_->Print(); | |
653 PrintF(")"); | |
654 } | |
655 | |
656 | |
657 void TwoOperandInstruction::Print() { | |
658 PrintF("("); | |
659 location()->Print(); | |
660 PrintF(", "); | |
661 value0_->Print(); | |
662 PrintF(", "); | |
663 value1_->Print(); | |
664 PrintF(")"); | |
665 } | |
666 | |
667 | |
668 void MoveInstr::Print() { | |
669 PrintF("Move "); | |
670 OneOperandInstruction::Print(); | |
671 PrintF("\n"); | |
672 } | |
673 | |
674 | |
675 void PropLoadInstr::Print() { | |
676 PrintF("PropLoad "); | |
677 TwoOperandInstruction::Print(); | |
678 PrintF("\n"); | |
679 } | |
680 | |
681 | |
682 void BinaryOpInstr::Print() { | |
683 switch (op()) { | |
684 case Token::OR: | |
685 // Two character operand. | |
686 PrintF("BinaryOp[OR] "); | |
687 break; | |
688 case Token::AND: | |
689 case Token::SHL: | |
690 case Token::SAR: | |
691 case Token::SHR: | |
692 case Token::ADD: | |
693 case Token::SUB: | |
694 case Token::MUL: | |
695 case Token::DIV: | |
696 case Token::MOD: | |
697 // Three character operands. | |
698 PrintF("BinaryOp[%s] ", Token::Name(op())); | |
699 break; | |
700 case Token::COMMA: | |
701 // Five character operand. | |
702 PrintF("BinaryOp[COMMA] "); | |
703 break; | |
704 case Token::BIT_OR: | |
705 // Six character operand. | |
706 PrintF("BinaryOp[BIT_OR] "); | |
707 break; | |
708 case Token::BIT_XOR: | |
709 case Token::BIT_AND: | |
710 // Seven character operands. | |
711 PrintF("BinaryOp[%s] ", Token::Name(op())); | |
712 break; | |
713 default: | |
714 UNREACHABLE(); | |
715 } | |
716 TwoOperandInstruction::Print(); | |
717 PrintF("\n"); | |
718 } | |
719 | |
720 | |
721 void ReturnInstr::Print() { | |
722 PrintF("Return "); | |
723 OneOperandInstruction::Print(); | |
724 PrintF("\n"); | |
725 } | |
726 | |
727 | |
728 void InstructionBlock::Print() { | |
729 if (!is_marked_) { | |
730 is_marked_ = true; | |
731 PrintF("L%d:\n", number()); | |
732 for (int i = 0, len = instructions_.length(); i < len; i++) { | |
733 instructions_[i]->Print(); | |
734 } | |
735 PrintF("Goto L%d\n\n", successor_->number()); | |
736 successor_->Print(); | |
737 } | |
738 } | |
739 | |
740 | |
741 void EntryNode::Print() { | |
742 if (!is_marked_) { | |
743 is_marked_ = true; | |
744 successor_->Print(); | |
745 } | |
746 } | |
747 | |
748 | |
749 void ExitNode::Print() { | |
750 if (!is_marked_) { | |
751 is_marked_ = true; | |
752 PrintF("L%d:\nExit\n\n", number()); | |
753 } | |
754 } | |
755 | |
756 #endif // DEBUG | |
757 | |
758 } } // namespace v8::internal | |
OLD | NEW |