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