1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/ast/prettyprinter.h"
6
7 #include <stdarg.h>
8
9 #include "src/ast/ast-value-factory.h"
10 #include "src/ast/scopes.h"
11 #include "src/base/platform/platform.h"
12 #include "src/globals.h"
13
14 namespace v8 {
15 namespace internal {
16
CallPrinter(Isolate * isolate,bool is_builtin)17 CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin)
18 : builder_(isolate) {
19 isolate_ = isolate;
20 position_ = 0;
21 num_prints_ = 0;
22 found_ = false;
23 done_ = false;
24 is_builtin_ = is_builtin;
25 InitializeAstVisitor(isolate);
26 }
27
Print(FunctionLiteral * program,int position)28 Handle<String> CallPrinter::Print(FunctionLiteral* program, int position) {
29 num_prints_ = 0;
30 position_ = position;
31 Find(program);
32 return builder_.Finish().ToHandleChecked();
33 }
34
35
Find(AstNode * node,bool print)36 void CallPrinter::Find(AstNode* node, bool print) {
37 if (done_) return;
38 if (found_) {
39 if (print) {
40 int prev_num_prints = num_prints_;
41 Visit(node);
42 if (prev_num_prints != num_prints_) return;
43 }
44 Print("(intermediate value)");
45 } else {
46 Visit(node);
47 }
48 }
49
Print(const char * str)50 void CallPrinter::Print(const char* str) {
51 if (!found_ || done_) return;
52 num_prints_++;
53 builder_.AppendCString(str);
54 }
55
Print(Handle<String> str)56 void CallPrinter::Print(Handle<String> str) {
57 if (!found_ || done_) return;
58 num_prints_++;
59 builder_.AppendString(str);
60 }
61
VisitBlock(Block * node)62 void CallPrinter::VisitBlock(Block* node) {
63 FindStatements(node->statements());
64 }
65
66
VisitVariableDeclaration(VariableDeclaration * node)67 void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {}
68
69
VisitFunctionDeclaration(FunctionDeclaration * node)70 void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {}
71
72
VisitExpressionStatement(ExpressionStatement * node)73 void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) {
74 Find(node->expression());
75 }
76
77
VisitEmptyStatement(EmptyStatement * node)78 void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {}
79
80
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * node)81 void CallPrinter::VisitSloppyBlockFunctionStatement(
82 SloppyBlockFunctionStatement* node) {
83 Find(node->statement());
84 }
85
86
VisitIfStatement(IfStatement * node)87 void CallPrinter::VisitIfStatement(IfStatement* node) {
88 Find(node->condition());
89 Find(node->then_statement());
90 if (node->HasElseStatement()) {
91 Find(node->else_statement());
92 }
93 }
94
95
VisitContinueStatement(ContinueStatement * node)96 void CallPrinter::VisitContinueStatement(ContinueStatement* node) {}
97
98
VisitBreakStatement(BreakStatement * node)99 void CallPrinter::VisitBreakStatement(BreakStatement* node) {}
100
101
VisitReturnStatement(ReturnStatement * node)102 void CallPrinter::VisitReturnStatement(ReturnStatement* node) {
103 Find(node->expression());
104 }
105
106
VisitWithStatement(WithStatement * node)107 void CallPrinter::VisitWithStatement(WithStatement* node) {
108 Find(node->expression());
109 Find(node->statement());
110 }
111
112
VisitSwitchStatement(SwitchStatement * node)113 void CallPrinter::VisitSwitchStatement(SwitchStatement* node) {
114 Find(node->tag());
115 ZoneList<CaseClause*>* cases = node->cases();
116 for (int i = 0; i < cases->length(); i++) Find(cases->at(i));
117 }
118
119
VisitCaseClause(CaseClause * clause)120 void CallPrinter::VisitCaseClause(CaseClause* clause) {
121 if (!clause->is_default()) {
122 Find(clause->label());
123 }
124 FindStatements(clause->statements());
125 }
126
127
VisitDoWhileStatement(DoWhileStatement * node)128 void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
129 Find(node->body());
130 Find(node->cond());
131 }
132
133
VisitWhileStatement(WhileStatement * node)134 void CallPrinter::VisitWhileStatement(WhileStatement* node) {
135 Find(node->cond());
136 Find(node->body());
137 }
138
139
VisitForStatement(ForStatement * node)140 void CallPrinter::VisitForStatement(ForStatement* node) {
141 if (node->init() != NULL) {
142 Find(node->init());
143 }
144 if (node->cond() != NULL) Find(node->cond());
145 if (node->next() != NULL) Find(node->next());
146 Find(node->body());
147 }
148
149
VisitForInStatement(ForInStatement * node)150 void CallPrinter::VisitForInStatement(ForInStatement* node) {
151 Find(node->each());
152 Find(node->enumerable());
153 Find(node->body());
154 }
155
156
VisitForOfStatement(ForOfStatement * node)157 void CallPrinter::VisitForOfStatement(ForOfStatement* node) {
158 Find(node->assign_iterator());
159 Find(node->next_result());
160 Find(node->result_done());
161 Find(node->assign_each());
162 Find(node->body());
163 }
164
165
VisitTryCatchStatement(TryCatchStatement * node)166 void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
167 Find(node->try_block());
168 Find(node->catch_block());
169 }
170
171
VisitTryFinallyStatement(TryFinallyStatement * node)172 void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
173 Find(node->try_block());
174 Find(node->finally_block());
175 }
176
177
VisitDebuggerStatement(DebuggerStatement * node)178 void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {}
179
180
VisitFunctionLiteral(FunctionLiteral * node)181 void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
182 FindStatements(node->body());
183 }
184
185
VisitClassLiteral(ClassLiteral * node)186 void CallPrinter::VisitClassLiteral(ClassLiteral* node) {
187 if (node->extends()) Find(node->extends());
188 for (int i = 0; i < node->properties()->length(); i++) {
189 Find(node->properties()->at(i)->value());
190 }
191 }
192
193
VisitNativeFunctionLiteral(NativeFunctionLiteral * node)194 void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {}
195
196
VisitDoExpression(DoExpression * node)197 void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); }
198
199
VisitConditional(Conditional * node)200 void CallPrinter::VisitConditional(Conditional* node) {
201 Find(node->condition());
202 Find(node->then_expression());
203 Find(node->else_expression());
204 }
205
206
VisitLiteral(Literal * node)207 void CallPrinter::VisitLiteral(Literal* node) {
208 PrintLiteral(node->value(), true);
209 }
210
211
VisitRegExpLiteral(RegExpLiteral * node)212 void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
213 Print("/");
214 PrintLiteral(node->pattern(), false);
215 Print("/");
216 if (node->flags() & RegExp::kGlobal) Print("g");
217 if (node->flags() & RegExp::kIgnoreCase) Print("i");
218 if (node->flags() & RegExp::kMultiline) Print("m");
219 if (node->flags() & RegExp::kUnicode) Print("u");
220 if (node->flags() & RegExp::kSticky) Print("y");
221 }
222
223
VisitObjectLiteral(ObjectLiteral * node)224 void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) {
225 for (int i = 0; i < node->properties()->length(); i++) {
226 Find(node->properties()->at(i)->value());
227 }
228 }
229
230
VisitArrayLiteral(ArrayLiteral * node)231 void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) {
232 Print("[");
233 for (int i = 0; i < node->values()->length(); i++) {
234 if (i != 0) Print(",");
235 Find(node->values()->at(i), true);
236 }
237 Print("]");
238 }
239
240
VisitVariableProxy(VariableProxy * node)241 void CallPrinter::VisitVariableProxy(VariableProxy* node) {
242 if (is_builtin_) {
243 // Variable names of builtins are meaningless due to minification.
244 Print("(var)");
245 } else {
246 PrintLiteral(node->name(), false);
247 }
248 }
249
250
VisitAssignment(Assignment * node)251 void CallPrinter::VisitAssignment(Assignment* node) {
252 Find(node->target());
253 Find(node->value());
254 }
255
256
VisitYield(Yield * node)257 void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
258
259
VisitThrow(Throw * node)260 void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
261
262
VisitProperty(Property * node)263 void CallPrinter::VisitProperty(Property* node) {
264 Expression* key = node->key();
265 Literal* literal = key->AsLiteral();
266 if (literal != NULL && literal->value()->IsInternalizedString()) {
267 Find(node->obj(), true);
268 Print(".");
269 PrintLiteral(literal->value(), false);
270 } else {
271 Find(node->obj(), true);
272 Print("[");
273 Find(key, true);
274 Print("]");
275 }
276 }
277
278
VisitCall(Call * node)279 void CallPrinter::VisitCall(Call* node) {
280 bool was_found = !found_ && node->position() == position_;
281 if (was_found) {
282 // Bail out if the error is caused by a direct call to a variable in builtin
283 // code. The variable name is meaningless due to minification.
284 if (is_builtin_ && node->expression()->IsVariableProxy()) {
285 done_ = true;
286 return;
287 }
288 found_ = true;
289 }
290 Find(node->expression(), true);
291 if (!was_found) Print("(...)");
292 FindArguments(node->arguments());
293 if (was_found) done_ = true;
294 }
295
296
VisitCallNew(CallNew * node)297 void CallPrinter::VisitCallNew(CallNew* node) {
298 bool was_found = !found_ && node->position() == position_;
299 if (was_found) {
300 // Bail out if the error is caused by a direct call to a variable in builtin
301 // code. The variable name is meaningless due to minification.
302 if (is_builtin_ && node->expression()->IsVariableProxy()) {
303 done_ = true;
304 return;
305 }
306 found_ = true;
307 }
308 Find(node->expression(), was_found);
309 FindArguments(node->arguments());
310 if (was_found) done_ = true;
311 }
312
313
VisitCallRuntime(CallRuntime * node)314 void CallPrinter::VisitCallRuntime(CallRuntime* node) {
315 FindArguments(node->arguments());
316 }
317
318
VisitUnaryOperation(UnaryOperation * node)319 void CallPrinter::VisitUnaryOperation(UnaryOperation* node) {
320 Token::Value op = node->op();
321 bool needsSpace =
322 op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID;
323 Print("(");
324 Print(Token::String(op));
325 if (needsSpace) Print(" ");
326 Find(node->expression(), true);
327 Print(")");
328 }
329
330
VisitCountOperation(CountOperation * node)331 void CallPrinter::VisitCountOperation(CountOperation* node) {
332 Print("(");
333 if (node->is_prefix()) Print(Token::String(node->op()));
334 Find(node->expression(), true);
335 if (node->is_postfix()) Print(Token::String(node->op()));
336 Print(")");
337 }
338
339
VisitBinaryOperation(BinaryOperation * node)340 void CallPrinter::VisitBinaryOperation(BinaryOperation* node) {
341 Print("(");
342 Find(node->left(), true);
343 Print(" ");
344 Print(Token::String(node->op()));
345 Print(" ");
346 Find(node->right(), true);
347 Print(")");
348 }
349
350
VisitCompareOperation(CompareOperation * node)351 void CallPrinter::VisitCompareOperation(CompareOperation* node) {
352 Print("(");
353 Find(node->left(), true);
354 Print(" ");
355 Print(Token::String(node->op()));
356 Print(" ");
357 Find(node->right(), true);
358 Print(")");
359 }
360
361
VisitSpread(Spread * node)362 void CallPrinter::VisitSpread(Spread* node) {
363 Print("(...");
364 Find(node->expression(), true);
365 Print(")");
366 }
367
368
VisitEmptyParentheses(EmptyParentheses * node)369 void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
370 UNREACHABLE();
371 }
372
373
VisitThisFunction(ThisFunction * node)374 void CallPrinter::VisitThisFunction(ThisFunction* node) {}
375
376
VisitSuperPropertyReference(SuperPropertyReference * node)377 void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {}
378
379
VisitSuperCallReference(SuperCallReference * node)380 void CallPrinter::VisitSuperCallReference(SuperCallReference* node) {
381 Print("super");
382 }
383
384
VisitRewritableExpression(RewritableExpression * node)385 void CallPrinter::VisitRewritableExpression(RewritableExpression* node) {
386 Find(node->expression());
387 }
388
389
FindStatements(ZoneList<Statement * > * statements)390 void CallPrinter::FindStatements(ZoneList<Statement*>* statements) {
391 if (statements == NULL) return;
392 for (int i = 0; i < statements->length(); i++) {
393 Find(statements->at(i));
394 }
395 }
396
397
FindArguments(ZoneList<Expression * > * arguments)398 void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) {
399 if (found_) return;
400 for (int i = 0; i < arguments->length(); i++) {
401 Find(arguments->at(i));
402 }
403 }
404
PrintLiteral(Handle<Object> value,bool quote)405 void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) {
406 if (value->IsString()) {
407 if (quote) Print("\"");
408 Print(Handle<String>::cast(value));
409 if (quote) Print("\"");
410 } else if (value->IsNull(isolate_)) {
411 Print("null");
412 } else if (value->IsTrue(isolate_)) {
413 Print("true");
414 } else if (value->IsFalse(isolate_)) {
415 Print("false");
416 } else if (value->IsUndefined(isolate_)) {
417 Print("undefined");
418 } else if (value->IsNumber()) {
419 Print(isolate_->factory()->NumberToString(value));
420 } else if (value->IsSymbol()) {
421 // Symbols can only occur as literals if they were inserted by the parser.
422 PrintLiteral(handle(Handle<Symbol>::cast(value)->name(), isolate_), false);
423 }
424 }
425
426
PrintLiteral(const AstRawString * value,bool quote)427 void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) {
428 PrintLiteral(value->string(), quote);
429 }
430
431
432 //-----------------------------------------------------------------------------
433
434
435 #ifdef DEBUG
436
437 // A helper for ast nodes that use FeedbackVectorSlots.
FormatSlotNode(Vector<char> * buf,Expression * node,const char * node_name,FeedbackVectorSlot slot)438 static int FormatSlotNode(Vector<char>* buf, Expression* node,
439 const char* node_name, FeedbackVectorSlot slot) {
440 int pos = SNPrintF(*buf, "%s", node_name);
441 if (!slot.IsInvalid()) {
442 pos += SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt());
443 }
444 return pos;
445 }
446
Print(AstNode * node)447 const char* AstPrinter::Print(AstNode* node) {
448 Init();
449 Visit(node);
450 return output_;
451 }
452
Init()453 void AstPrinter::Init() {
454 if (size_ == 0) {
455 DCHECK(output_ == NULL);
456 const int initial_size = 256;
457 output_ = NewArray<char>(initial_size);
458 size_ = initial_size;
459 }
460 output_[0] = '\0';
461 pos_ = 0;
462 }
463
Print(const char * format,...)464 void AstPrinter::Print(const char* format, ...) {
465 for (;;) {
466 va_list arguments;
467 va_start(arguments, format);
468 int n = VSNPrintF(Vector<char>(output_, size_) + pos_,
469 format,
470 arguments);
471 va_end(arguments);
472
473 if (n >= 0) {
474 // there was enough space - we are done
475 pos_ += n;
476 return;
477 } else {
478 // there was not enough space - allocate more and try again
479 const int slack = 32;
480 int new_size = size_ + (size_ >> 1) + slack;
481 char* new_output = NewArray<char>(new_size);
482 MemCopy(new_output, output_, pos_);
483 DeleteArray(output_);
484 output_ = new_output;
485 size_ = new_size;
486 }
487 }
488 }
489
PrintLabels(ZoneList<const AstRawString * > * labels)490 void AstPrinter::PrintLabels(ZoneList<const AstRawString*>* labels) {
491 if (labels != NULL) {
492 for (int i = 0; i < labels->length(); i++) {
493 PrintLiteral(labels->at(i), false);
494 Print(": ");
495 }
496 }
497 }
498
PrintLiteral(Handle<Object> value,bool quote)499 void AstPrinter::PrintLiteral(Handle<Object> value, bool quote) {
500 Object* object = *value;
501 if (object->IsString()) {
502 String* string = String::cast(object);
503 if (quote) Print("\"");
504 for (int i = 0; i < string->length(); i++) {
505 Print("%c", string->Get(i));
506 }
507 if (quote) Print("\"");
508 } else if (object->IsNull(isolate_)) {
509 Print("null");
510 } else if (object->IsTrue(isolate_)) {
511 Print("true");
512 } else if (object->IsFalse(isolate_)) {
513 Print("false");
514 } else if (object->IsUndefined(isolate_)) {
515 Print("undefined");
516 } else if (object->IsNumber()) {
517 Print("%g", object->Number());
518 } else if (object->IsJSObject()) {
519 // regular expression
520 if (object->IsJSFunction()) {
521 Print("JS-Function");
522 } else if (object->IsJSArray()) {
523 Print("JS-array[%u]",
524 Smi::cast(JSArray::cast(object)->length())->value());
525 } else if (object->IsJSObject()) {
526 Print("JS-Object");
527 } else {
528 Print("?UNKNOWN?");
529 }
530 } else if (object->IsFixedArray()) {
531 Print("FixedArray");
532 } else if (object->IsSymbol()) {
533 // Symbols can only occur as literals if they were inserted by the parser.
534 Symbol* symbol = Symbol::cast(object);
535 if (symbol->name()->IsString()) {
536 int length = 0;
537 String* string = String::cast(symbol->name());
538 std::unique_ptr<char[]> desc = string->ToCString(
539 ALLOW_NULLS, FAST_STRING_TRAVERSAL, 0, string->length(), &length);
540 Print("Symbol(%*s)", length, desc.get());
541 } else {
542 Print("Symbol()");
543 }
544 } else {
545 Print("<unknown literal %p>", static_cast<void*>(object));
546 }
547 }
548
PrintLiteral(const AstRawString * value,bool quote)549 void AstPrinter::PrintLiteral(const AstRawString* value, bool quote) {
550 PrintLiteral(value->string(), quote);
551 }
552
553
554 //-----------------------------------------------------------------------------
555
556 class IndentedScope BASE_EMBEDDED {
557 public:
IndentedScope(AstPrinter * printer,const char * txt)558 IndentedScope(AstPrinter* printer, const char* txt)
559 : ast_printer_(printer) {
560 ast_printer_->PrintIndented(txt);
561 ast_printer_->Print("\n");
562 ast_printer_->inc_indent();
563 }
564
IndentedScope(AstPrinter * printer,const char * txt,int pos)565 IndentedScope(AstPrinter* printer, const char* txt, int pos)
566 : ast_printer_(printer) {
567 ast_printer_->PrintIndented(txt);
568 ast_printer_->Print(" at %d\n", pos);
569 ast_printer_->inc_indent();
570 }
571
~IndentedScope()572 virtual ~IndentedScope() {
573 ast_printer_->dec_indent();
574 }
575
576 private:
577 AstPrinter* ast_printer_;
578 };
579
580
581 //-----------------------------------------------------------------------------
582
AstPrinter(Isolate * isolate)583 AstPrinter::AstPrinter(Isolate* isolate)
584 : isolate_(isolate), output_(nullptr), size_(0), pos_(0), indent_(0) {
585 InitializeAstVisitor(isolate);
586 }
587
~AstPrinter()588 AstPrinter::~AstPrinter() {
589 DCHECK(indent_ == 0);
590 DeleteArray(output_);
591 }
592
593
PrintIndented(const char * txt)594 void AstPrinter::PrintIndented(const char* txt) {
595 for (int i = 0; i < indent_; i++) {
596 Print(". ");
597 }
598 Print("%s", txt);
599 }
600
601
PrintLiteralIndented(const char * info,Handle<Object> value,bool quote)602 void AstPrinter::PrintLiteralIndented(const char* info,
603 Handle<Object> value,
604 bool quote) {
605 PrintIndented(info);
606 Print(" ");
607 PrintLiteral(value, quote);
608 Print("\n");
609 }
610
611
PrintLiteralWithModeIndented(const char * info,Variable * var,Handle<Object> value)612 void AstPrinter::PrintLiteralWithModeIndented(const char* info,
613 Variable* var,
614 Handle<Object> value) {
615 if (var == NULL) {
616 PrintLiteralIndented(info, value, true);
617 } else {
618 EmbeddedVector<char, 256> buf;
619 int pos =
620 SNPrintF(buf, "%s (mode = %s", info, VariableMode2String(var->mode()));
621 SNPrintF(buf + pos, ")");
622 PrintLiteralIndented(buf.start(), value, true);
623 }
624 }
625
626
PrintLabelsIndented(ZoneList<const AstRawString * > * labels)627 void AstPrinter::PrintLabelsIndented(ZoneList<const AstRawString*>* labels) {
628 if (labels == NULL || labels->length() == 0) return;
629 PrintIndented("LABELS ");
630 PrintLabels(labels);
631 Print("\n");
632 }
633
634
PrintIndentedVisit(const char * s,AstNode * node)635 void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) {
636 IndentedScope indent(this, s, node->position());
637 Visit(node);
638 }
639
640
PrintProgram(FunctionLiteral * program)641 const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
642 Init();
643 { IndentedScope indent(this, "FUNC", program->position());
644 PrintIndented("KIND");
645 Print(" %d\n", program->kind());
646 PrintIndented("YIELD COUNT");
647 Print(" %d\n", program->yield_count());
648 PrintLiteralIndented("NAME", program->name(), true);
649 PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
650 PrintParameters(program->scope());
651 PrintDeclarations(program->scope()->declarations());
652 PrintStatements(program->body());
653 }
654 return output_;
655 }
656
657
PrintOut(Isolate * isolate,AstNode * node)658 void AstPrinter::PrintOut(Isolate* isolate, AstNode* node) {
659 AstPrinter printer(isolate);
660 printer.Init();
661 printer.Visit(node);
662 PrintF("%s", printer.output_);
663 }
664
PrintDeclarations(Declaration::List * declarations)665 void AstPrinter::PrintDeclarations(Declaration::List* declarations) {
666 if (!declarations->is_empty()) {
667 IndentedScope indent(this, "DECLS");
668 for (Declaration* decl : *declarations) Visit(decl);
669 }
670 }
671
PrintParameters(DeclarationScope * scope)672 void AstPrinter::PrintParameters(DeclarationScope* scope) {
673 if (scope->num_parameters() > 0) {
674 IndentedScope indent(this, "PARAMS");
675 for (int i = 0; i < scope->num_parameters(); i++) {
676 PrintLiteralWithModeIndented("VAR", scope->parameter(i),
677 scope->parameter(i)->name());
678 }
679 }
680 }
681
682
PrintStatements(ZoneList<Statement * > * statements)683 void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) {
684 for (int i = 0; i < statements->length(); i++) {
685 Visit(statements->at(i));
686 }
687 }
688
689
PrintArguments(ZoneList<Expression * > * arguments)690 void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
691 for (int i = 0; i < arguments->length(); i++) {
692 Visit(arguments->at(i));
693 }
694 }
695
696
VisitBlock(Block * node)697 void AstPrinter::VisitBlock(Block* node) {
698 const char* block_txt =
699 node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK";
700 IndentedScope indent(this, block_txt, node->position());
701 PrintStatements(node->statements());
702 }
703
704
705 // TODO(svenpanne) Start with IndentedScope.
VisitVariableDeclaration(VariableDeclaration * node)706 void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) {
707 PrintLiteralWithModeIndented("VARIABLE", node->proxy()->var(),
708 node->proxy()->name());
709 }
710
711
712 // TODO(svenpanne) Start with IndentedScope.
VisitFunctionDeclaration(FunctionDeclaration * node)713 void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {
714 PrintIndented("FUNCTION ");
715 PrintLiteral(node->proxy()->name(), true);
716 Print(" = function ");
717 PrintLiteral(node->fun()->name(), false);
718 Print("\n");
719 }
720
721
VisitExpressionStatement(ExpressionStatement * node)722 void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) {
723 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position());
724 Visit(node->expression());
725 }
726
727
VisitEmptyStatement(EmptyStatement * node)728 void AstPrinter::VisitEmptyStatement(EmptyStatement* node) {
729 IndentedScope indent(this, "EMPTY", node->position());
730 }
731
732
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * node)733 void AstPrinter::VisitSloppyBlockFunctionStatement(
734 SloppyBlockFunctionStatement* node) {
735 Visit(node->statement());
736 }
737
738
VisitIfStatement(IfStatement * node)739 void AstPrinter::VisitIfStatement(IfStatement* node) {
740 IndentedScope indent(this, "IF", node->position());
741 PrintIndentedVisit("CONDITION", node->condition());
742 PrintIndentedVisit("THEN", node->then_statement());
743 if (node->HasElseStatement()) {
744 PrintIndentedVisit("ELSE", node->else_statement());
745 }
746 }
747
748
VisitContinueStatement(ContinueStatement * node)749 void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
750 IndentedScope indent(this, "CONTINUE", node->position());
751 PrintLabelsIndented(node->target()->labels());
752 }
753
754
VisitBreakStatement(BreakStatement * node)755 void AstPrinter::VisitBreakStatement(BreakStatement* node) {
756 IndentedScope indent(this, "BREAK", node->position());
757 PrintLabelsIndented(node->target()->labels());
758 }
759
760
VisitReturnStatement(ReturnStatement * node)761 void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
762 IndentedScope indent(this, "RETURN", node->position());
763 Visit(node->expression());
764 }
765
766
VisitWithStatement(WithStatement * node)767 void AstPrinter::VisitWithStatement(WithStatement* node) {
768 IndentedScope indent(this, "WITH", node->position());
769 PrintIndentedVisit("OBJECT", node->expression());
770 PrintIndentedVisit("BODY", node->statement());
771 }
772
773
VisitSwitchStatement(SwitchStatement * node)774 void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
775 IndentedScope indent(this, "SWITCH", node->position());
776 PrintLabelsIndented(node->labels());
777 PrintIndentedVisit("TAG", node->tag());
778 for (int i = 0; i < node->cases()->length(); i++) {
779 Visit(node->cases()->at(i));
780 }
781 }
782
783
VisitCaseClause(CaseClause * clause)784 void AstPrinter::VisitCaseClause(CaseClause* clause) {
785 if (clause->is_default()) {
786 IndentedScope indent(this, "DEFAULT", clause->position());
787 PrintStatements(clause->statements());
788 } else {
789 IndentedScope indent(this, "CASE", clause->position());
790 Visit(clause->label());
791 PrintStatements(clause->statements());
792 }
793 }
794
795
VisitDoWhileStatement(DoWhileStatement * node)796 void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
797 IndentedScope indent(this, "DO", node->position());
798 PrintIndented("YIELD COUNT");
799 Print(" %d\n", node->yield_count());
800 PrintLabelsIndented(node->labels());
801 PrintIndentedVisit("BODY", node->body());
802 PrintIndentedVisit("COND", node->cond());
803 }
804
805
VisitWhileStatement(WhileStatement * node)806 void AstPrinter::VisitWhileStatement(WhileStatement* node) {
807 IndentedScope indent(this, "WHILE", node->position());
808 PrintIndented("YIELD COUNT");
809 Print(" %d\n", node->yield_count());
810 PrintLabelsIndented(node->labels());
811 PrintIndentedVisit("COND", node->cond());
812 PrintIndentedVisit("BODY", node->body());
813 }
814
815
VisitForStatement(ForStatement * node)816 void AstPrinter::VisitForStatement(ForStatement* node) {
817 IndentedScope indent(this, "FOR", node->position());
818 PrintIndented("YIELD COUNT");
819 Print(" %d\n", node->yield_count());
820 PrintLabelsIndented(node->labels());
821 if (node->init()) PrintIndentedVisit("INIT", node->init());
822 if (node->cond()) PrintIndentedVisit("COND", node->cond());
823 PrintIndentedVisit("BODY", node->body());
824 if (node->next()) PrintIndentedVisit("NEXT", node->next());
825 }
826
827
VisitForInStatement(ForInStatement * node)828 void AstPrinter::VisitForInStatement(ForInStatement* node) {
829 IndentedScope indent(this, "FOR IN", node->position());
830 PrintIndented("YIELD COUNT");
831 Print(" %d\n", node->yield_count());
832 PrintIndentedVisit("FOR", node->each());
833 PrintIndentedVisit("IN", node->enumerable());
834 PrintIndentedVisit("BODY", node->body());
835 }
836
837
VisitForOfStatement(ForOfStatement * node)838 void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
839 IndentedScope indent(this, "FOR OF", node->position());
840 PrintIndented("YIELD COUNT");
841 Print(" %d\n", node->yield_count());
842 PrintIndentedVisit("INIT", node->assign_iterator());
843 PrintIndentedVisit("NEXT", node->next_result());
844 PrintIndentedVisit("DONE", node->result_done());
845 PrintIndentedVisit("EACH", node->assign_each());
846 PrintIndentedVisit("BODY", node->body());
847 }
848
849
VisitTryCatchStatement(TryCatchStatement * node)850 void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
851 IndentedScope indent(this, "TRY CATCH", node->position());
852 PrintTryStatement(node);
853 PrintLiteralWithModeIndented("CATCHVAR",
854 node->variable(),
855 node->variable()->name());
856 PrintIndentedVisit("CATCH", node->catch_block());
857 }
858
859
VisitTryFinallyStatement(TryFinallyStatement * node)860 void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
861 IndentedScope indent(this, "TRY FINALLY", node->position());
862 PrintTryStatement(node);
863 PrintIndentedVisit("FINALLY", node->finally_block());
864 }
865
PrintTryStatement(TryStatement * node)866 void AstPrinter::PrintTryStatement(TryStatement* node) {
867 PrintIndentedVisit("TRY", node->try_block());
868 PrintIndented("CATCH PREDICTION");
869 const char* prediction = "";
870 switch (node->catch_prediction()) {
871 case HandlerTable::UNCAUGHT:
872 prediction = "UNCAUGHT";
873 break;
874 case HandlerTable::CAUGHT:
875 prediction = "CAUGHT";
876 break;
877 case HandlerTable::PROMISE:
878 prediction = "PROMISE";
879 break;
880 case HandlerTable::DESUGARING:
881 prediction = "DESUGARING";
882 break;
883 case HandlerTable::ASYNC_AWAIT:
884 prediction = "ASYNC_AWAIT";
885 break;
886 }
887 Print(" %s\n", prediction);
888 }
889
VisitDebuggerStatement(DebuggerStatement * node)890 void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
891 IndentedScope indent(this, "DEBUGGER", node->position());
892 }
893
894
VisitFunctionLiteral(FunctionLiteral * node)895 void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
896 IndentedScope indent(this, "FUNC LITERAL", node->position());
897 PrintLiteralIndented("NAME", node->name(), false);
898 PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
899 PrintParameters(node->scope());
900 // We don't want to see the function literal in this case: it
901 // will be printed via PrintProgram when the code for it is
902 // generated.
903 // PrintStatements(node->body());
904 }
905
906
VisitClassLiteral(ClassLiteral * node)907 void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
908 IndentedScope indent(this, "CLASS LITERAL", node->position());
909 PrintLiteralIndented("NAME", node->constructor()->name(), false);
910 if (node->extends() != nullptr) {
911 PrintIndentedVisit("EXTENDS", node->extends());
912 }
913 PrintClassProperties(node->properties());
914 }
915
PrintClassProperties(ZoneList<ClassLiteral::Property * > * properties)916 void AstPrinter::PrintClassProperties(
917 ZoneList<ClassLiteral::Property*>* properties) {
918 for (int i = 0; i < properties->length(); i++) {
919 ClassLiteral::Property* property = properties->at(i);
920 const char* prop_kind = nullptr;
921 switch (property->kind()) {
922 case ClassLiteral::Property::METHOD:
923 prop_kind = "METHOD";
924 break;
925 case ClassLiteral::Property::GETTER:
926 prop_kind = "GETTER";
927 break;
928 case ClassLiteral::Property::SETTER:
929 prop_kind = "SETTER";
930 break;
931 case ClassLiteral::Property::FIELD:
932 prop_kind = "FIELD";
933 break;
934 }
935 EmbeddedVector<char, 128> buf;
936 SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "",
937 prop_kind);
938 IndentedScope prop(this, buf.start());
939 PrintIndentedVisit("KEY", properties->at(i)->key());
940 PrintIndentedVisit("VALUE", properties->at(i)->value());
941 }
942 }
943
944
VisitNativeFunctionLiteral(NativeFunctionLiteral * node)945 void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
946 IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position());
947 PrintLiteralIndented("NAME", node->name(), false);
948 }
949
950
VisitDoExpression(DoExpression * node)951 void AstPrinter::VisitDoExpression(DoExpression* node) {
952 IndentedScope indent(this, "DO EXPRESSION", node->position());
953 PrintStatements(node->block()->statements());
954 }
955
956
VisitConditional(Conditional * node)957 void AstPrinter::VisitConditional(Conditional* node) {
958 IndentedScope indent(this, "CONDITIONAL", node->position());
959 PrintIndentedVisit("CONDITION", node->condition());
960 PrintIndentedVisit("THEN", node->then_expression());
961 PrintIndentedVisit("ELSE", node->else_expression());
962 }
963
964
965 // TODO(svenpanne) Start with IndentedScope.
VisitLiteral(Literal * node)966 void AstPrinter::VisitLiteral(Literal* node) {
967 PrintLiteralIndented("LITERAL", node->value(), true);
968 }
969
970
VisitRegExpLiteral(RegExpLiteral * node)971 void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
972 IndentedScope indent(this, "REGEXP LITERAL", node->position());
973 EmbeddedVector<char, 128> buf;
974 SNPrintF(buf, "literal_index = %d\n", node->literal_index());
975 PrintIndented(buf.start());
976 PrintLiteralIndented("PATTERN", node->pattern(), false);
977 int i = 0;
978 if (node->flags() & RegExp::kGlobal) buf[i++] = 'g';
979 if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i';
980 if (node->flags() & RegExp::kMultiline) buf[i++] = 'm';
981 if (node->flags() & RegExp::kUnicode) buf[i++] = 'u';
982 if (node->flags() & RegExp::kSticky) buf[i++] = 'y';
983 buf[i] = '\0';
984 PrintIndented("FLAGS ");
985 Print("%s", buf.start());
986 Print("\n");
987 }
988
989
VisitObjectLiteral(ObjectLiteral * node)990 void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
991 IndentedScope indent(this, "OBJ LITERAL", node->position());
992 EmbeddedVector<char, 128> buf;
993 SNPrintF(buf, "literal_index = %d\n", node->literal_index());
994 PrintIndented(buf.start());
995 PrintObjectProperties(node->properties());
996 }
997
PrintObjectProperties(ZoneList<ObjectLiteral::Property * > * properties)998 void AstPrinter::PrintObjectProperties(
999 ZoneList<ObjectLiteral::Property*>* properties) {
1000 for (int i = 0; i < properties->length(); i++) {
1001 ObjectLiteral::Property* property = properties->at(i);
1002 const char* prop_kind = nullptr;
1003 switch (property->kind()) {
1004 case ObjectLiteral::Property::CONSTANT:
1005 prop_kind = "CONSTANT";
1006 break;
1007 case ObjectLiteral::Property::COMPUTED:
1008 prop_kind = "COMPUTED";
1009 break;
1010 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1011 prop_kind = "MATERIALIZED_LITERAL";
1012 break;
1013 case ObjectLiteral::Property::PROTOTYPE:
1014 prop_kind = "PROTOTYPE";
1015 break;
1016 case ObjectLiteral::Property::GETTER:
1017 prop_kind = "GETTER";
1018 break;
1019 case ObjectLiteral::Property::SETTER:
1020 prop_kind = "SETTER";
1021 break;
1022 }
1023 EmbeddedVector<char, 128> buf;
1024 SNPrintF(buf, "PROPERTY - %s", prop_kind);
1025 IndentedScope prop(this, buf.start());
1026 PrintIndentedVisit("KEY", properties->at(i)->key());
1027 PrintIndentedVisit("VALUE", properties->at(i)->value());
1028 }
1029 }
1030
1031
VisitArrayLiteral(ArrayLiteral * node)1032 void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
1033 IndentedScope indent(this, "ARRAY LITERAL", node->position());
1034
1035 EmbeddedVector<char, 128> buf;
1036 SNPrintF(buf, "literal_index = %d\n", node->literal_index());
1037 PrintIndented(buf.start());
1038 if (node->values()->length() > 0) {
1039 IndentedScope indent(this, "VALUES", node->position());
1040 for (int i = 0; i < node->values()->length(); i++) {
1041 Visit(node->values()->at(i));
1042 }
1043 }
1044 }
1045
1046
VisitVariableProxy(VariableProxy * node)1047 void AstPrinter::VisitVariableProxy(VariableProxy* node) {
1048 EmbeddedVector<char, 128> buf;
1049 int pos =
1050 FormatSlotNode(&buf, node, "VAR PROXY", node->VariableFeedbackSlot());
1051
1052 if (!node->is_resolved()) {
1053 SNPrintF(buf + pos, " unresolved");
1054 PrintLiteralWithModeIndented(buf.start(), nullptr, node->name());
1055 } else {
1056 Variable* var = node->var();
1057 switch (var->location()) {
1058 case VariableLocation::UNALLOCATED:
1059 SNPrintF(buf + pos, " unallocated");
1060 break;
1061 case VariableLocation::PARAMETER:
1062 SNPrintF(buf + pos, " parameter[%d]", var->index());
1063 break;
1064 case VariableLocation::LOCAL:
1065 SNPrintF(buf + pos, " local[%d]", var->index());
1066 break;
1067 case VariableLocation::CONTEXT:
1068 SNPrintF(buf + pos, " context[%d]", var->index());
1069 break;
1070 case VariableLocation::LOOKUP:
1071 SNPrintF(buf + pos, " lookup");
1072 break;
1073 case VariableLocation::MODULE:
1074 SNPrintF(buf + pos, " module");
1075 break;
1076 }
1077 PrintLiteralWithModeIndented(buf.start(), var, node->name());
1078 }
1079 }
1080
1081
VisitAssignment(Assignment * node)1082 void AstPrinter::VisitAssignment(Assignment* node) {
1083 IndentedScope indent(this, Token::Name(node->op()), node->position());
1084 Visit(node->target());
1085 Visit(node->value());
1086 }
1087
1088
VisitYield(Yield * node)1089 void AstPrinter::VisitYield(Yield* node) {
1090 EmbeddedVector<char, 128> buf;
1091 SNPrintF(buf, "YIELD id %d", node->yield_id());
1092 IndentedScope indent(this, buf.start(), node->position());
1093 Visit(node->expression());
1094 }
1095
1096
VisitThrow(Throw * node)1097 void AstPrinter::VisitThrow(Throw* node) {
1098 IndentedScope indent(this, "THROW", node->position());
1099 Visit(node->exception());
1100 }
1101
1102
VisitProperty(Property * node)1103 void AstPrinter::VisitProperty(Property* node) {
1104 EmbeddedVector<char, 128> buf;
1105 FormatSlotNode(&buf, node, "PROPERTY", node->PropertyFeedbackSlot());
1106 IndentedScope indent(this, buf.start(), node->position());
1107
1108 Visit(node->obj());
1109 Literal* literal = node->key()->AsLiteral();
1110 if (literal != NULL && literal->value()->IsInternalizedString()) {
1111 PrintLiteralIndented("NAME", literal->value(), false);
1112 } else {
1113 PrintIndentedVisit("KEY", node->key());
1114 }
1115 }
1116
1117
VisitCall(Call * node)1118 void AstPrinter::VisitCall(Call* node) {
1119 EmbeddedVector<char, 128> buf;
1120 const char* name =
1121 node->tail_call_mode() == TailCallMode::kAllow ? "TAIL CALL" : "CALL";
1122 FormatSlotNode(&buf, node, name, node->CallFeedbackICSlot());
1123 IndentedScope indent(this, buf.start());
1124
1125 Visit(node->expression());
1126 PrintArguments(node->arguments());
1127 }
1128
1129
VisitCallNew(CallNew * node)1130 void AstPrinter::VisitCallNew(CallNew* node) {
1131 IndentedScope indent(this, "CALL NEW", node->position());
1132 Visit(node->expression());
1133 PrintArguments(node->arguments());
1134 }
1135
1136
VisitCallRuntime(CallRuntime * node)1137 void AstPrinter::VisitCallRuntime(CallRuntime* node) {
1138 EmbeddedVector<char, 128> buf;
1139 SNPrintF(buf, "CALL RUNTIME %s", node->debug_name());
1140 IndentedScope indent(this, buf.start(), node->position());
1141 PrintArguments(node->arguments());
1142 }
1143
1144
VisitUnaryOperation(UnaryOperation * node)1145 void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
1146 IndentedScope indent(this, Token::Name(node->op()), node->position());
1147 Visit(node->expression());
1148 }
1149
1150
VisitCountOperation(CountOperation * node)1151 void AstPrinter::VisitCountOperation(CountOperation* node) {
1152 EmbeddedVector<char, 128> buf;
1153 SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
1154 Token::Name(node->op()));
1155 IndentedScope indent(this, buf.start(), node->position());
1156 Visit(node->expression());
1157 }
1158
1159
VisitBinaryOperation(BinaryOperation * node)1160 void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
1161 IndentedScope indent(this, Token::Name(node->op()), node->position());
1162 Visit(node->left());
1163 Visit(node->right());
1164 }
1165
1166
VisitCompareOperation(CompareOperation * node)1167 void AstPrinter::VisitCompareOperation(CompareOperation* node) {
1168 IndentedScope indent(this, Token::Name(node->op()), node->position());
1169 Visit(node->left());
1170 Visit(node->right());
1171 }
1172
1173
VisitSpread(Spread * node)1174 void AstPrinter::VisitSpread(Spread* node) {
1175 IndentedScope indent(this, "...", node->position());
1176 Visit(node->expression());
1177 }
1178
1179
VisitEmptyParentheses(EmptyParentheses * node)1180 void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
1181 IndentedScope indent(this, "()", node->position());
1182 }
1183
1184
VisitThisFunction(ThisFunction * node)1185 void AstPrinter::VisitThisFunction(ThisFunction* node) {
1186 IndentedScope indent(this, "THIS-FUNCTION", node->position());
1187 }
1188
1189
VisitSuperPropertyReference(SuperPropertyReference * node)1190 void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
1191 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position());
1192 }
1193
1194
VisitSuperCallReference(SuperCallReference * node)1195 void AstPrinter::VisitSuperCallReference(SuperCallReference* node) {
1196 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position());
1197 }
1198
1199
VisitRewritableExpression(RewritableExpression * node)1200 void AstPrinter::VisitRewritableExpression(RewritableExpression* node) {
1201 Visit(node->expression());
1202 }
1203
1204
1205 #endif // DEBUG
1206
1207 } // namespace internal
1208 } // namespace v8
1209