1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "ast.h" 31 #include "func-name-inferrer.h" 32 #include "scopes.h" 33 #include "rewriter.h" 34 35 namespace v8 { 36 namespace internal { 37 38 39 class AstOptimizer: public AstVisitor { 40 public: 41 explicit AstOptimizer() : has_function_literal_(false) {} 42 explicit AstOptimizer(Handle<String> enclosing_name) 43 : has_function_literal_(false) { 44 func_name_inferrer_.PushEnclosingName(enclosing_name); 45 } 46 47 void Optimize(ZoneList<Statement*>* statements); 48 49 private: 50 // Used for loop condition analysis. Cleared before visiting a loop 51 // condition, set when a function literal is visited. 52 bool has_function_literal_; 53 // Helper object for function name inferring. 54 FuncNameInferrer func_name_inferrer_; 55 56 // Helpers 57 void OptimizeArguments(ZoneList<Expression*>* arguments); 58 59 // Node visitors. 60 #define DEF_VISIT(type) \ 61 virtual void Visit##type(type* node); 62 AST_NODE_LIST(DEF_VISIT) 63 #undef DEF_VISIT 64 65 DISALLOW_COPY_AND_ASSIGN(AstOptimizer); 66 }; 67 68 69 void AstOptimizer::Optimize(ZoneList<Statement*>* statements) { 70 int len = statements->length(); 71 for (int i = 0; i < len; i++) { 72 Visit(statements->at(i)); 73 } 74 } 75 76 77 void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) { 78 for (int i = 0; i < arguments->length(); i++) { 79 Visit(arguments->at(i)); 80 } 81 } 82 83 84 void AstOptimizer::VisitBlock(Block* node) { 85 Optimize(node->statements()); 86 } 87 88 89 void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) { 90 Visit(node->expression()); 91 } 92 93 94 void AstOptimizer::VisitIfStatement(IfStatement* node) { 95 Visit(node->condition()); 96 Visit(node->then_statement()); 97 if (node->HasElseStatement()) { 98 Visit(node->else_statement()); 99 } 100 } 101 102 103 void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) { 104 Visit(node->cond()); 105 Visit(node->body()); 106 } 107 108 109 void AstOptimizer::VisitWhileStatement(WhileStatement* node) { 110 has_function_literal_ = false; 111 Visit(node->cond()); 112 node->may_have_function_literal_ = has_function_literal_; 113 Visit(node->body()); 114 } 115 116 117 void AstOptimizer::VisitForStatement(ForStatement* node) { 118 if (node->init() != NULL) { 119 Visit(node->init()); 120 } 121 if (node->cond() != NULL) { 122 has_function_literal_ = false; 123 Visit(node->cond()); 124 node->may_have_function_literal_ = has_function_literal_; 125 } 126 Visit(node->body()); 127 if (node->next() != NULL) { 128 Visit(node->next()); 129 } 130 } 131 132 133 void AstOptimizer::VisitForInStatement(ForInStatement* node) { 134 Visit(node->each()); 135 Visit(node->enumerable()); 136 Visit(node->body()); 137 } 138 139 140 void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) { 141 Visit(node->try_block()); 142 Visit(node->catch_var()); 143 Visit(node->catch_block()); 144 } 145 146 147 void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) { 148 Visit(node->try_block()); 149 Visit(node->finally_block()); 150 } 151 152 153 void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) { 154 Visit(node->tag()); 155 for (int i = 0; i < node->cases()->length(); i++) { 156 CaseClause* clause = node->cases()->at(i); 157 if (!clause->is_default()) { 158 Visit(clause->label()); 159 } 160 Optimize(clause->statements()); 161 } 162 } 163 164 165 void AstOptimizer::VisitContinueStatement(ContinueStatement* node) { 166 USE(node); 167 } 168 169 170 void AstOptimizer::VisitBreakStatement(BreakStatement* node) { 171 USE(node); 172 } 173 174 175 void AstOptimizer::VisitDeclaration(Declaration* node) { 176 // Will not be reached by the current optimizations. 177 USE(node); 178 } 179 180 181 void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) { 182 USE(node); 183 } 184 185 186 void AstOptimizer::VisitReturnStatement(ReturnStatement* node) { 187 Visit(node->expression()); 188 } 189 190 191 void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) { 192 Visit(node->expression()); 193 } 194 195 196 void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) { 197 USE(node); 198 } 199 200 201 void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) { 202 USE(node); 203 } 204 205 206 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { 207 has_function_literal_ = true; 208 209 if (node->name()->length() == 0) { 210 // Anonymous function. 211 func_name_inferrer_.AddFunction(node); 212 } 213 } 214 215 216 void AstOptimizer::VisitFunctionBoilerplateLiteral( 217 FunctionBoilerplateLiteral* node) { 218 USE(node); 219 } 220 221 222 void AstOptimizer::VisitConditional(Conditional* node) { 223 Visit(node->condition()); 224 Visit(node->then_expression()); 225 Visit(node->else_expression()); 226 } 227 228 229 void AstOptimizer::VisitSlot(Slot* node) { 230 USE(node); 231 } 232 233 234 void AstOptimizer::VisitVariableProxy(VariableProxy* node) { 235 Variable* var = node->AsVariable(); 236 if (var != NULL) { 237 if (var->type()->IsKnown()) { 238 node->type()->CopyFrom(var->type()); 239 } else if (node->type()->IsLikelySmi()) { 240 var->type()->SetAsLikelySmi(); 241 } 242 243 if (!var->is_this() && 244 !Heap::result_symbol()->Equals(*var->name())) { 245 func_name_inferrer_.PushName(var->name()); 246 } 247 } 248 } 249 250 251 void AstOptimizer::VisitLiteral(Literal* node) { 252 Handle<Object> literal = node->handle(); 253 if (literal->IsSmi()) { 254 node->type()->SetAsLikelySmi(); 255 } else if (literal->IsString()) { 256 Handle<String> lit_str(Handle<String>::cast(literal)); 257 if (!Heap::prototype_symbol()->Equals(*lit_str)) { 258 func_name_inferrer_.PushName(lit_str); 259 } 260 } 261 } 262 263 264 void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) { 265 USE(node); 266 } 267 268 269 void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) { 270 for (int i = 0; i < node->values()->length(); i++) { 271 Visit(node->values()->at(i)); 272 } 273 } 274 275 void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) { 276 for (int i = 0; i < node->properties()->length(); i++) { 277 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_); 278 scoped_fni.Enter(); 279 Visit(node->properties()->at(i)->key()); 280 Visit(node->properties()->at(i)->value()); 281 } 282 } 283 284 285 void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) { 286 Visit(node->key()); 287 Visit(node->value()); 288 } 289 290 291 void AstOptimizer::VisitAssignment(Assignment* node) { 292 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_); 293 switch (node->op()) { 294 case Token::INIT_VAR: 295 case Token::INIT_CONST: 296 case Token::ASSIGN: 297 // No type can be infered from the general assignment. 298 299 // Don't infer if it is "a = function(){...}();"-like expression. 300 if (node->value()->AsCall() == NULL) { 301 scoped_fni.Enter(); 302 } 303 break; 304 case Token::ASSIGN_BIT_OR: 305 case Token::ASSIGN_BIT_XOR: 306 case Token::ASSIGN_BIT_AND: 307 case Token::ASSIGN_SHL: 308 case Token::ASSIGN_SAR: 309 case Token::ASSIGN_SHR: 310 node->type()->SetAsLikelySmiIfUnknown(); 311 node->target()->type()->SetAsLikelySmiIfUnknown(); 312 node->value()->type()->SetAsLikelySmiIfUnknown(); 313 break; 314 case Token::ASSIGN_ADD: 315 case Token::ASSIGN_SUB: 316 case Token::ASSIGN_MUL: 317 case Token::ASSIGN_DIV: 318 case Token::ASSIGN_MOD: 319 if (node->type()->IsLikelySmi()) { 320 node->target()->type()->SetAsLikelySmiIfUnknown(); 321 node->value()->type()->SetAsLikelySmiIfUnknown(); 322 } 323 break; 324 default: 325 UNREACHABLE(); 326 break; 327 } 328 329 Visit(node->target()); 330 Visit(node->value()); 331 332 switch (node->op()) { 333 case Token::INIT_VAR: 334 case Token::INIT_CONST: 335 case Token::ASSIGN: 336 // Pure assignment copies the type from the value. 337 node->type()->CopyFrom(node->value()->type()); 338 break; 339 case Token::ASSIGN_BIT_OR: 340 case Token::ASSIGN_BIT_XOR: 341 case Token::ASSIGN_BIT_AND: 342 case Token::ASSIGN_SHL: 343 case Token::ASSIGN_SAR: 344 case Token::ASSIGN_SHR: 345 // Should have been setup above already. 346 break; 347 case Token::ASSIGN_ADD: 348 case Token::ASSIGN_SUB: 349 case Token::ASSIGN_MUL: 350 case Token::ASSIGN_DIV: 351 case Token::ASSIGN_MOD: 352 if (node->type()->IsUnknown()) { 353 if (node->target()->type()->IsLikelySmi() || 354 node->value()->type()->IsLikelySmi()) { 355 node->type()->SetAsLikelySmi(); 356 } 357 } 358 break; 359 default: 360 UNREACHABLE(); 361 break; 362 } 363 364 // Since this is an assignment. We have to propagate this node's type to the 365 // variable. 366 VariableProxy* proxy = node->target()->AsVariableProxy(); 367 if (proxy != NULL) { 368 Variable* var = proxy->AsVariable(); 369 if (var != NULL) { 370 StaticType* var_type = var->type(); 371 if (var_type->IsUnknown()) { 372 var_type->CopyFrom(node->type()); 373 } else if (var_type->IsLikelySmi()) { 374 // We do not reset likely types to Unknown. 375 } 376 } 377 } 378 } 379 380 381 void AstOptimizer::VisitThrow(Throw* node) { 382 Visit(node->exception()); 383 } 384 385 386 void AstOptimizer::VisitProperty(Property* node) { 387 Visit(node->obj()); 388 Visit(node->key()); 389 } 390 391 392 void AstOptimizer::VisitCall(Call* node) { 393 Visit(node->expression()); 394 OptimizeArguments(node->arguments()); 395 } 396 397 398 void AstOptimizer::VisitCallNew(CallNew* node) { 399 Visit(node->expression()); 400 OptimizeArguments(node->arguments()); 401 } 402 403 404 void AstOptimizer::VisitCallRuntime(CallRuntime* node) { 405 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_); 406 if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) && 407 node->arguments()->length() >= 2 && 408 node->arguments()->at(1)->AsFunctionLiteral() != NULL) { 409 scoped_fni.Enter(); 410 } 411 OptimizeArguments(node->arguments()); 412 } 413 414 415 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) { 416 Visit(node->expression()); 417 } 418 419 420 void AstOptimizer::VisitCountOperation(CountOperation* node) { 421 // Count operations assume that they work on Smis. 422 node->type()->SetAsLikelySmiIfUnknown(); 423 node->expression()->type()->SetAsLikelySmiIfUnknown(); 424 Visit(node->expression()); 425 } 426 427 428 void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) { 429 // Depending on the operation we can propagate this node's type down the 430 // AST nodes. 431 switch (node->op()) { 432 case Token::COMMA: 433 case Token::OR: 434 case Token::AND: 435 break; 436 case Token::BIT_OR: 437 case Token::BIT_XOR: 438 case Token::BIT_AND: 439 case Token::SHL: 440 case Token::SAR: 441 case Token::SHR: 442 node->type()->SetAsLikelySmiIfUnknown(); 443 node->left()->type()->SetAsLikelySmiIfUnknown(); 444 node->right()->type()->SetAsLikelySmiIfUnknown(); 445 break; 446 case Token::ADD: 447 case Token::SUB: 448 case Token::MUL: 449 case Token::DIV: 450 case Token::MOD: 451 if (node->type()->IsLikelySmi()) { 452 node->left()->type()->SetAsLikelySmiIfUnknown(); 453 node->right()->type()->SetAsLikelySmiIfUnknown(); 454 } 455 break; 456 default: 457 UNREACHABLE(); 458 break; 459 } 460 461 Visit(node->left()); 462 Visit(node->right()); 463 464 // After visiting the operand nodes we have to check if this node's type 465 // can be updated. If it does, then we can push that information down 466 // towards the leafs again if the new information is an upgrade over the 467 // previous type of the operand nodes. 468 if (node->type()->IsUnknown()) { 469 if (node->left()->type()->IsLikelySmi() || 470 node->right()->type()->IsLikelySmi()) { 471 node->type()->SetAsLikelySmi(); 472 } 473 if (node->type()->IsLikelySmi()) { 474 // The type of this node changed to LIKELY_SMI. Propagate this knowledge 475 // down through the nodes. 476 if (node->left()->type()->IsUnknown()) { 477 node->left()->type()->SetAsLikelySmi(); 478 Visit(node->left()); 479 } 480 if (node->right()->type()->IsUnknown()) { 481 node->right()->type()->SetAsLikelySmi(); 482 Visit(node->right()); 483 } 484 } 485 } 486 } 487 488 489 void AstOptimizer::VisitCompareOperation(CompareOperation* node) { 490 if (node->type()->IsKnown()) { 491 // Propagate useful information down towards the leafs. 492 node->left()->type()->SetAsLikelySmiIfUnknown(); 493 node->right()->type()->SetAsLikelySmiIfUnknown(); 494 } 495 496 Visit(node->left()); 497 Visit(node->right()); 498 499 // After visiting the operand nodes we have to check if this node's type 500 // can be updated. If it does, then we can push that information down 501 // towards the leafs again if the new information is an upgrade over the 502 // previous type of the operand nodes. 503 if (node->type()->IsUnknown()) { 504 if (node->left()->type()->IsLikelySmi() || 505 node->right()->type()->IsLikelySmi()) { 506 node->type()->SetAsLikelySmi(); 507 } 508 if (node->type()->IsLikelySmi()) { 509 // The type of this node changed to LIKELY_SMI. Propagate this knowledge 510 // down through the nodes. 511 if (node->left()->type()->IsUnknown()) { 512 node->left()->type()->SetAsLikelySmi(); 513 Visit(node->left()); 514 } 515 if (node->right()->type()->IsUnknown()) { 516 node->right()->type()->SetAsLikelySmi(); 517 Visit(node->right()); 518 } 519 } 520 } 521 } 522 523 524 void AstOptimizer::VisitThisFunction(ThisFunction* node) { 525 USE(node); 526 } 527 528 529 class Processor: public AstVisitor { 530 public: 531 explicit Processor(VariableProxy* result) 532 : result_(result), 533 result_assigned_(false), 534 is_set_(false), 535 in_try_(false) { 536 } 537 538 void Process(ZoneList<Statement*>* statements); 539 bool result_assigned() const { return result_assigned_; } 540 541 private: 542 VariableProxy* result_; 543 544 // We are not tracking result usage via the result_'s use 545 // counts (we leave the accurate computation to the 546 // usage analyzer). Instead we simple remember if 547 // there was ever an assignment to result_. 548 bool result_assigned_; 549 550 // To avoid storing to .result all the time, we eliminate some of 551 // the stores by keeping track of whether or not we're sure .result 552 // will be overwritten anyway. This is a bit more tricky than what I 553 // was hoping for 554 bool is_set_; 555 bool in_try_; 556 557 Expression* SetResult(Expression* value) { 558 result_assigned_ = true; 559 return new Assignment(Token::ASSIGN, result_, value, 560 RelocInfo::kNoPosition); 561 } 562 563 // Node visitors. 564 #define DEF_VISIT(type) \ 565 virtual void Visit##type(type* node); 566 AST_NODE_LIST(DEF_VISIT) 567 #undef DEF_VISIT 568 569 void VisitIterationStatement(IterationStatement* stmt); 570 }; 571 572 573 void Processor::Process(ZoneList<Statement*>* statements) { 574 for (int i = statements->length() - 1; i >= 0; --i) { 575 Visit(statements->at(i)); 576 } 577 } 578 579 580 void Processor::VisitBlock(Block* node) { 581 // An initializer block is the rewritten form of a variable declaration 582 // with initialization expressions. The initializer block contains the 583 // list of assignments corresponding to the initialization expressions. 584 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of 585 // a variable declaration with initialization expression is 'undefined' 586 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) 587 // returns 'undefined'. To obtain the same behavior with v8, we need 588 // to prevent rewriting in that case. 589 if (!node->is_initializer_block()) Process(node->statements()); 590 } 591 592 593 void Processor::VisitExpressionStatement(ExpressionStatement* node) { 594 // Rewrite : <x>; -> .result = <x>; 595 if (!is_set_) { 596 node->set_expression(SetResult(node->expression())); 597 if (!in_try_) is_set_ = true; 598 } 599 } 600 601 602 void Processor::VisitIfStatement(IfStatement* node) { 603 // Rewrite both then and else parts (reversed). 604 bool save = is_set_; 605 Visit(node->else_statement()); 606 bool set_after_then = is_set_; 607 is_set_ = save; 608 Visit(node->then_statement()); 609 is_set_ = is_set_ && set_after_then; 610 } 611 612 613 void Processor::VisitIterationStatement(IterationStatement* node) { 614 // Rewrite the body. 615 bool set_after_loop = is_set_; 616 Visit(node->body()); 617 is_set_ = is_set_ && set_after_loop; 618 } 619 620 621 void Processor::VisitDoWhileStatement(DoWhileStatement* node) { 622 VisitIterationStatement(node); 623 } 624 625 626 void Processor::VisitWhileStatement(WhileStatement* node) { 627 VisitIterationStatement(node); 628 } 629 630 631 void Processor::VisitForStatement(ForStatement* node) { 632 VisitIterationStatement(node); 633 } 634 635 636 void Processor::VisitForInStatement(ForInStatement* node) { 637 VisitIterationStatement(node); 638 } 639 640 641 void Processor::VisitTryCatchStatement(TryCatchStatement* node) { 642 // Rewrite both try and catch blocks (reversed order). 643 bool set_after_catch = is_set_; 644 Visit(node->catch_block()); 645 is_set_ = is_set_ && set_after_catch; 646 bool save = in_try_; 647 in_try_ = true; 648 Visit(node->try_block()); 649 in_try_ = save; 650 } 651 652 653 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { 654 // Rewrite both try and finally block (reversed order). 655 Visit(node->finally_block()); 656 bool save = in_try_; 657 in_try_ = true; 658 Visit(node->try_block()); 659 in_try_ = save; 660 } 661 662 663 void Processor::VisitSwitchStatement(SwitchStatement* node) { 664 // Rewrite statements in all case clauses in reversed order. 665 ZoneList<CaseClause*>* clauses = node->cases(); 666 bool set_after_switch = is_set_; 667 for (int i = clauses->length() - 1; i >= 0; --i) { 668 CaseClause* clause = clauses->at(i); 669 Process(clause->statements()); 670 } 671 is_set_ = is_set_ && set_after_switch; 672 } 673 674 675 void Processor::VisitContinueStatement(ContinueStatement* node) { 676 is_set_ = false; 677 } 678 679 680 void Processor::VisitBreakStatement(BreakStatement* node) { 681 is_set_ = false; 682 } 683 684 685 // Do nothing: 686 void Processor::VisitDeclaration(Declaration* node) {} 687 void Processor::VisitEmptyStatement(EmptyStatement* node) {} 688 void Processor::VisitReturnStatement(ReturnStatement* node) {} 689 void Processor::VisitWithEnterStatement(WithEnterStatement* node) {} 690 void Processor::VisitWithExitStatement(WithExitStatement* node) {} 691 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} 692 693 694 // Expressions are never visited yet. 695 void Processor::VisitFunctionLiteral(FunctionLiteral* node) { 696 USE(node); 697 UNREACHABLE(); 698 } 699 700 701 void Processor::VisitFunctionBoilerplateLiteral( 702 FunctionBoilerplateLiteral* node) { 703 USE(node); 704 UNREACHABLE(); 705 } 706 707 708 void Processor::VisitConditional(Conditional* node) { 709 USE(node); 710 UNREACHABLE(); 711 } 712 713 714 void Processor::VisitSlot(Slot* node) { 715 USE(node); 716 UNREACHABLE(); 717 } 718 719 720 void Processor::VisitVariableProxy(VariableProxy* node) { 721 USE(node); 722 UNREACHABLE(); 723 } 724 725 726 void Processor::VisitLiteral(Literal* node) { 727 USE(node); 728 UNREACHABLE(); 729 } 730 731 732 void Processor::VisitRegExpLiteral(RegExpLiteral* node) { 733 USE(node); 734 UNREACHABLE(); 735 } 736 737 738 void Processor::VisitArrayLiteral(ArrayLiteral* node) { 739 USE(node); 740 UNREACHABLE(); 741 } 742 743 744 void Processor::VisitObjectLiteral(ObjectLiteral* node) { 745 USE(node); 746 UNREACHABLE(); 747 } 748 749 750 void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) { 751 USE(node); 752 UNREACHABLE(); 753 } 754 755 756 void Processor::VisitAssignment(Assignment* node) { 757 USE(node); 758 UNREACHABLE(); 759 } 760 761 762 void Processor::VisitThrow(Throw* node) { 763 USE(node); 764 UNREACHABLE(); 765 } 766 767 768 void Processor::VisitProperty(Property* node) { 769 USE(node); 770 UNREACHABLE(); 771 } 772 773 774 void Processor::VisitCall(Call* node) { 775 USE(node); 776 UNREACHABLE(); 777 } 778 779 780 void Processor::VisitCallNew(CallNew* node) { 781 USE(node); 782 UNREACHABLE(); 783 } 784 785 786 void Processor::VisitCallRuntime(CallRuntime* node) { 787 USE(node); 788 UNREACHABLE(); 789 } 790 791 792 void Processor::VisitUnaryOperation(UnaryOperation* node) { 793 USE(node); 794 UNREACHABLE(); 795 } 796 797 798 void Processor::VisitCountOperation(CountOperation* node) { 799 USE(node); 800 UNREACHABLE(); 801 } 802 803 804 void Processor::VisitBinaryOperation(BinaryOperation* node) { 805 USE(node); 806 UNREACHABLE(); 807 } 808 809 810 void Processor::VisitCompareOperation(CompareOperation* node) { 811 USE(node); 812 UNREACHABLE(); 813 } 814 815 816 void Processor::VisitThisFunction(ThisFunction* node) { 817 USE(node); 818 UNREACHABLE(); 819 } 820 821 822 bool Rewriter::Process(FunctionLiteral* function) { 823 HistogramTimerScope timer(&Counters::rewriting); 824 Scope* scope = function->scope(); 825 if (scope->is_function_scope()) return true; 826 827 ZoneList<Statement*>* body = function->body(); 828 if (body->is_empty()) return true; 829 830 VariableProxy* result = scope->NewTemporary(Factory::result_symbol()); 831 Processor processor(result); 832 processor.Process(body); 833 if (processor.HasStackOverflow()) return false; 834 835 if (processor.result_assigned()) body->Add(new ReturnStatement(result)); 836 return true; 837 } 838 839 840 bool Rewriter::Optimize(FunctionLiteral* function) { 841 ZoneList<Statement*>* body = function->body(); 842 843 if (FLAG_optimize_ast && !body->is_empty()) { 844 HistogramTimerScope timer(&Counters::ast_optimization); 845 AstOptimizer optimizer(function->name()); 846 optimizer.Optimize(body); 847 if (optimizer.HasStackOverflow()) { 848 return false; 849 } 850 } 851 return true; 852 } 853 854 855 } } // namespace v8::internal 856