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 15namespace v8 { 16namespace internal { 17 18CallPrinter::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 29Handle<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 37void 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 51void CallPrinter::Print(const char* str) { 52 if (!found_ || done_) return; 53 num_prints_++; 54 builder_.AppendCString(str); 55} 56 57void CallPrinter::Print(Handle<String> str) { 58 if (!found_ || done_) return; 59 num_prints_++; 60 builder_.AppendString(str); 61} 62 63void CallPrinter::VisitBlock(Block* node) { 64 FindStatements(node->statements()); 65} 66 67 68void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {} 69 70 71void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {} 72 73 74void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) { 75 Find(node->expression()); 76} 77 78 79void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {} 80 81 82void CallPrinter::VisitSloppyBlockFunctionStatement( 83 SloppyBlockFunctionStatement* node) { 84 Find(node->statement()); 85} 86 87 88void 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 97void CallPrinter::VisitContinueStatement(ContinueStatement* node) {} 98 99 100void CallPrinter::VisitBreakStatement(BreakStatement* node) {} 101 102 103void CallPrinter::VisitReturnStatement(ReturnStatement* node) { 104 Find(node->expression()); 105} 106 107 108void CallPrinter::VisitWithStatement(WithStatement* node) { 109 Find(node->expression()); 110 Find(node->statement()); 111} 112 113 114void 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 121void CallPrinter::VisitCaseClause(CaseClause* clause) { 122 if (!clause->is_default()) { 123 Find(clause->label()); 124 } 125 FindStatements(clause->statements()); 126} 127 128 129void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) { 130 Find(node->body()); 131 Find(node->cond()); 132} 133 134 135void CallPrinter::VisitWhileStatement(WhileStatement* node) { 136 Find(node->cond()); 137 Find(node->body()); 138} 139 140 141void 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 151void CallPrinter::VisitForInStatement(ForInStatement* node) { 152 Find(node->each()); 153 Find(node->enumerable()); 154 Find(node->body()); 155} 156 157 158void 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 167void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) { 168 Find(node->try_block()); 169 Find(node->catch_block()); 170} 171 172 173void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 174 Find(node->try_block()); 175 Find(node->finally_block()); 176} 177 178 179void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} 180 181 182void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { 183 FindStatements(node->body()); 184} 185 186 187void 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 195void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} 196 197 198void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); } 199 200 201void CallPrinter::VisitConditional(Conditional* node) { 202 Find(node->condition()); 203 Find(node->then_expression()); 204 Find(node->else_expression()); 205} 206 207 208void CallPrinter::VisitLiteral(Literal* node) { 209 PrintLiteral(node->value(), true); 210} 211 212 213void 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 225void 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 232void 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 242void 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 252void CallPrinter::VisitAssignment(Assignment* node) { 253 Find(node->target()); 254 Find(node->value()); 255} 256 257 258void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } 259 260 261void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } 262 263 264void 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 280void 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 298void 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 315void CallPrinter::VisitCallRuntime(CallRuntime* node) { 316 FindArguments(node->arguments()); 317} 318 319 320void 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 332void 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 341void 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 352void 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 363void CallPrinter::VisitSpread(Spread* node) { 364 Print("(..."); 365 Find(node->expression(), true); 366 Print(")"); 367} 368 369 370void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 371 UNREACHABLE(); 372} 373 374void CallPrinter::VisitGetIterator(GetIterator* node) { 375 Print("GetIterator("); 376 Find(node->iterable(), true); 377 Print(")"); 378} 379 380void CallPrinter::VisitThisFunction(ThisFunction* node) {} 381 382 383void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} 384 385 386void CallPrinter::VisitSuperCallReference(SuperCallReference* node) { 387 Print("super"); 388} 389 390 391void CallPrinter::VisitRewritableExpression(RewritableExpression* node) { 392 Find(node->expression()); 393} 394 395 396void 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 404void 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 411void 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 433void 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. 444static 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 453const char* AstPrinter::Print(AstNode* node) { 454 Init(); 455 Visit(node); 456 return output_; 457} 458 459void 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 470void 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 496void 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 505void 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 555void AstPrinter::PrintLiteral(const AstRawString* value, bool quote) { 556 PrintLiteral(value->string(), quote); 557} 558 559 560//----------------------------------------------------------------------------- 561 562class IndentedScope BASE_EMBEDDED { 563 public: 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 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 578 virtual ~IndentedScope() { 579 ast_printer_->dec_indent(); 580 } 581 582 private: 583 AstPrinter* ast_printer_; 584}; 585 586 587//----------------------------------------------------------------------------- 588 589AstPrinter::AstPrinter(Isolate* isolate) 590 : isolate_(isolate), output_(nullptr), size_(0), pos_(0), indent_(0) { 591 InitializeAstVisitor(isolate); 592} 593 594AstPrinter::~AstPrinter() { 595 DCHECK(indent_ == 0); 596 DeleteArray(output_); 597} 598 599 600void AstPrinter::PrintIndented(const char* txt) { 601 for (int i = 0; i < indent_; i++) { 602 Print(". "); 603 } 604 Print("%s", txt); 605} 606 607 608void 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 618void 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 633void 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 641void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { 642 IndentedScope indent(this, s, node->position()); 643 Visit(node); 644} 645 646 647const 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 664void AstPrinter::PrintOut(Isolate* isolate, AstNode* node) { 665 AstPrinter printer(isolate); 666 printer.Init(); 667 printer.Visit(node); 668 PrintF("%s", printer.output_); 669} 670 671void 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 678void 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 689void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) { 690 for (int i = 0; i < statements->length(); i++) { 691 Visit(statements->at(i)); 692 } 693} 694 695 696void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) { 697 for (int i = 0; i < arguments->length(); i++) { 698 Visit(arguments->at(i)); 699 } 700} 701 702 703void 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. 712void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { 713 PrintLiteralWithModeIndented("VARIABLE", node->proxy()->var(), 714 node->proxy()->name()); 715} 716 717 718// TODO(svenpanne) Start with IndentedScope. 719void 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 728void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) { 729 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position()); 730 Visit(node->expression()); 731} 732 733 734void AstPrinter::VisitEmptyStatement(EmptyStatement* node) { 735 IndentedScope indent(this, "EMPTY", node->position()); 736} 737 738 739void AstPrinter::VisitSloppyBlockFunctionStatement( 740 SloppyBlockFunctionStatement* node) { 741 Visit(node->statement()); 742} 743 744 745void 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 755void AstPrinter::VisitContinueStatement(ContinueStatement* node) { 756 IndentedScope indent(this, "CONTINUE", node->position()); 757 PrintLabelsIndented(node->target()->labels()); 758} 759 760 761void AstPrinter::VisitBreakStatement(BreakStatement* node) { 762 IndentedScope indent(this, "BREAK", node->position()); 763 PrintLabelsIndented(node->target()->labels()); 764} 765 766 767void AstPrinter::VisitReturnStatement(ReturnStatement* node) { 768 IndentedScope indent(this, "RETURN", node->position()); 769 Visit(node->expression()); 770} 771 772 773void AstPrinter::VisitWithStatement(WithStatement* node) { 774 IndentedScope indent(this, "WITH", node->position()); 775 PrintIndentedVisit("OBJECT", node->expression()); 776 PrintIndentedVisit("BODY", node->statement()); 777} 778 779 780void 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 790void 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 802void 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 812void 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 822void 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 834void 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 844void 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 856void 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 866void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 867 IndentedScope indent(this, "TRY FINALLY", node->position()); 868 PrintTryStatement(node); 869 PrintIndentedVisit("FINALLY", node->finally_block()); 870} 871 872void 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 897void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { 898 IndentedScope indent(this, "DEBUGGER", node->position()); 899} 900 901 902void 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 914void 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 923void 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 952void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { 953 IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); 954 PrintLiteralIndented("NAME", node->name(), false); 955} 956 957 958void AstPrinter::VisitDoExpression(DoExpression* node) { 959 IndentedScope indent(this, "DO EXPRESSION", node->position()); 960 PrintStatements(node->block()->statements()); 961} 962 963 964void 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. 973void AstPrinter::VisitLiteral(Literal* node) { 974 PrintLiteralIndented("LITERAL", node->value(), true); 975} 976 977 978void 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 997void 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 1005void 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 1042void 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 1057void 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 1092void 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 1099void 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 1107void AstPrinter::VisitThrow(Throw* node) { 1108 IndentedScope indent(this, "THROW", node->position()); 1109 Visit(node->exception()); 1110} 1111 1112 1113void 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 1128void 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 1140void AstPrinter::VisitCallNew(CallNew* node) { 1141 IndentedScope indent(this, "CALL NEW", node->position()); 1142 Visit(node->expression()); 1143 PrintArguments(node->arguments()); 1144} 1145 1146 1147void 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 1162void AstPrinter::VisitUnaryOperation(UnaryOperation* node) { 1163 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1164 Visit(node->expression()); 1165} 1166 1167 1168void 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 1177void 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 1184void 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 1191void AstPrinter::VisitSpread(Spread* node) { 1192 IndentedScope indent(this, "...", node->position()); 1193 Visit(node->expression()); 1194} 1195 1196 1197void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 1198 IndentedScope indent(this, "()", node->position()); 1199} 1200 1201void AstPrinter::VisitGetIterator(GetIterator* node) { 1202 IndentedScope indent(this, "GET-ITERATOR", node->position()); 1203 Visit(node->iterable()); 1204} 1205 1206void AstPrinter::VisitThisFunction(ThisFunction* node) { 1207 IndentedScope indent(this, "THIS-FUNCTION", node->position()); 1208} 1209 1210 1211void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { 1212 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); 1213} 1214 1215 1216void AstPrinter::VisitSuperCallReference(SuperCallReference* node) { 1217 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position()); 1218} 1219 1220 1221void AstPrinter::VisitRewritableExpression(RewritableExpression* node) { 1222 Visit(node->expression()); 1223} 1224 1225 1226#endif // DEBUG 1227 1228} // namespace internal 1229} // namespace v8 1230