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