1 // Copyright 2009 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 "codegen-inl.h" 31 #include "compiler.h" 32 #include "full-codegen.h" 33 #include "stub-cache.h" 34 #include "debug.h" 35 #include "liveedit.h" 36 37 namespace v8 { 38 namespace internal { 39 40 #define BAILOUT(reason) \ 41 do { \ 42 if (FLAG_trace_bailout) { \ 43 PrintF("%s\n", reason); \ 44 } \ 45 has_supported_syntax_ = false; \ 46 return; \ 47 } while (false) 48 49 50 #define CHECK_BAILOUT \ 51 do { \ 52 if (!has_supported_syntax_) return; \ 53 } while (false) 54 55 56 void FullCodeGenSyntaxChecker::Check(FunctionLiteral* fun) { 57 Scope* scope = fun->scope(); 58 VisitDeclarations(scope->declarations()); 59 CHECK_BAILOUT; 60 61 VisitStatements(fun->body()); 62 } 63 64 65 void FullCodeGenSyntaxChecker::VisitDeclarations( 66 ZoneList<Declaration*>* decls) { 67 for (int i = 0; i < decls->length(); i++) { 68 Visit(decls->at(i)); 69 CHECK_BAILOUT; 70 } 71 } 72 73 74 void FullCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) { 75 for (int i = 0, len = stmts->length(); i < len; i++) { 76 Visit(stmts->at(i)); 77 CHECK_BAILOUT; 78 } 79 } 80 81 82 void FullCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) { 83 Property* prop = decl->proxy()->AsProperty(); 84 if (prop != NULL) { 85 Visit(prop->obj()); 86 Visit(prop->key()); 87 } 88 89 if (decl->fun() != NULL) { 90 Visit(decl->fun()); 91 } 92 } 93 94 95 void FullCodeGenSyntaxChecker::VisitBlock(Block* stmt) { 96 VisitStatements(stmt->statements()); 97 } 98 99 100 void FullCodeGenSyntaxChecker::VisitExpressionStatement( 101 ExpressionStatement* stmt) { 102 Visit(stmt->expression()); 103 } 104 105 106 void FullCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) { 107 // Supported. 108 } 109 110 111 void FullCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) { 112 Visit(stmt->condition()); 113 CHECK_BAILOUT; 114 Visit(stmt->then_statement()); 115 CHECK_BAILOUT; 116 Visit(stmt->else_statement()); 117 } 118 119 120 void FullCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) { 121 // Supported. 122 } 123 124 125 void FullCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) { 126 // Supported. 127 } 128 129 130 void FullCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) { 131 Visit(stmt->expression()); 132 } 133 134 135 void FullCodeGenSyntaxChecker::VisitWithEnterStatement( 136 WithEnterStatement* stmt) { 137 Visit(stmt->expression()); 138 } 139 140 141 void FullCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) { 142 // Supported. 143 } 144 145 146 void FullCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) { 147 BAILOUT("SwitchStatement"); 148 } 149 150 151 void FullCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { 152 Visit(stmt->cond()); 153 CHECK_BAILOUT; 154 Visit(stmt->body()); 155 } 156 157 158 void FullCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) { 159 Visit(stmt->cond()); 160 CHECK_BAILOUT; 161 Visit(stmt->body()); 162 } 163 164 165 void FullCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) { 166 if (!FLAG_always_full_compiler) BAILOUT("ForStatement"); 167 if (stmt->init() != NULL) { 168 Visit(stmt->init()); 169 CHECK_BAILOUT; 170 } 171 if (stmt->cond() != NULL) { 172 Visit(stmt->cond()); 173 CHECK_BAILOUT; 174 } 175 Visit(stmt->body()); 176 if (stmt->next() != NULL) { 177 CHECK_BAILOUT; 178 Visit(stmt->next()); 179 } 180 } 181 182 183 void FullCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) { 184 BAILOUT("ForInStatement"); 185 } 186 187 188 void FullCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) { 189 Visit(stmt->try_block()); 190 CHECK_BAILOUT; 191 Visit(stmt->catch_block()); 192 } 193 194 195 void FullCodeGenSyntaxChecker::VisitTryFinallyStatement( 196 TryFinallyStatement* stmt) { 197 Visit(stmt->try_block()); 198 CHECK_BAILOUT; 199 Visit(stmt->finally_block()); 200 } 201 202 203 void FullCodeGenSyntaxChecker::VisitDebuggerStatement( 204 DebuggerStatement* stmt) { 205 // Supported. 206 } 207 208 209 void FullCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { 210 // Supported. 211 } 212 213 214 void FullCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral( 215 FunctionBoilerplateLiteral* expr) { 216 BAILOUT("FunctionBoilerplateLiteral"); 217 } 218 219 220 void FullCodeGenSyntaxChecker::VisitConditional(Conditional* expr) { 221 Visit(expr->condition()); 222 CHECK_BAILOUT; 223 Visit(expr->then_expression()); 224 CHECK_BAILOUT; 225 Visit(expr->else_expression()); 226 } 227 228 229 void FullCodeGenSyntaxChecker::VisitSlot(Slot* expr) { 230 UNREACHABLE(); 231 } 232 233 234 void FullCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { 235 // Supported. 236 } 237 238 239 void FullCodeGenSyntaxChecker::VisitLiteral(Literal* expr) { 240 // Supported. 241 } 242 243 244 void FullCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { 245 // Supported. 246 } 247 248 249 void FullCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { 250 ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); 251 252 for (int i = 0, len = properties->length(); i < len; i++) { 253 ObjectLiteral::Property* property = properties->at(i); 254 if (property->IsCompileTimeValue()) continue; 255 Visit(property->key()); 256 CHECK_BAILOUT; 257 Visit(property->value()); 258 CHECK_BAILOUT; 259 } 260 } 261 262 263 void FullCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { 264 ZoneList<Expression*>* subexprs = expr->values(); 265 for (int i = 0, len = subexprs->length(); i < len; i++) { 266 Expression* subexpr = subexprs->at(i); 267 if (subexpr->AsLiteral() != NULL) continue; 268 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 269 Visit(subexpr); 270 CHECK_BAILOUT; 271 } 272 } 273 274 275 void FullCodeGenSyntaxChecker::VisitCatchExtensionObject( 276 CatchExtensionObject* expr) { 277 Visit(expr->key()); 278 CHECK_BAILOUT; 279 Visit(expr->value()); 280 } 281 282 283 void FullCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) { 284 Token::Value op = expr->op(); 285 if (op == Token::INIT_CONST) BAILOUT("initialize constant"); 286 287 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); 288 Property* prop = expr->target()->AsProperty(); 289 ASSERT(var == NULL || prop == NULL); 290 if (var != NULL) { 291 if (var->mode() == Variable::CONST) BAILOUT("Assignment to const"); 292 // All other variables are supported. 293 } else if (prop != NULL) { 294 Visit(prop->obj()); 295 CHECK_BAILOUT; 296 Visit(prop->key()); 297 CHECK_BAILOUT; 298 } else { 299 // This is a throw reference error. 300 BAILOUT("non-variable/non-property assignment"); 301 } 302 303 Visit(expr->value()); 304 } 305 306 307 void FullCodeGenSyntaxChecker::VisitThrow(Throw* expr) { 308 Visit(expr->exception()); 309 } 310 311 312 void FullCodeGenSyntaxChecker::VisitProperty(Property* expr) { 313 Visit(expr->obj()); 314 CHECK_BAILOUT; 315 Visit(expr->key()); 316 } 317 318 319 void FullCodeGenSyntaxChecker::VisitCall(Call* expr) { 320 Expression* fun = expr->expression(); 321 ZoneList<Expression*>* args = expr->arguments(); 322 Variable* var = fun->AsVariableProxy()->AsVariable(); 323 324 // Check for supported calls 325 if (var != NULL && var->is_possibly_eval()) { 326 BAILOUT("call to the identifier 'eval'"); 327 } else if (var != NULL && !var->is_this() && var->is_global()) { 328 // Calls to global variables are supported. 329 } else if (var != NULL && var->slot() != NULL && 330 var->slot()->type() == Slot::LOOKUP) { 331 BAILOUT("call to a lookup slot"); 332 } else if (fun->AsProperty() != NULL) { 333 Property* prop = fun->AsProperty(); 334 Visit(prop->obj()); 335 CHECK_BAILOUT; 336 Visit(prop->key()); 337 CHECK_BAILOUT; 338 } else { 339 // Otherwise the call is supported if the function expression is. 340 Visit(fun); 341 } 342 // Check all arguments to the call. 343 for (int i = 0; i < args->length(); i++) { 344 Visit(args->at(i)); 345 CHECK_BAILOUT; 346 } 347 } 348 349 350 void FullCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) { 351 Visit(expr->expression()); 352 CHECK_BAILOUT; 353 ZoneList<Expression*>* args = expr->arguments(); 354 // Check all arguments to the call 355 for (int i = 0; i < args->length(); i++) { 356 Visit(args->at(i)); 357 CHECK_BAILOUT; 358 } 359 } 360 361 362 void FullCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { 363 // Check for inline runtime call 364 if (expr->name()->Get(0) == '_' && 365 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { 366 BAILOUT("inlined runtime call"); 367 } 368 // Check all arguments to the call. (Relies on TEMP meaning STACK.) 369 for (int i = 0; i < expr->arguments()->length(); i++) { 370 Visit(expr->arguments()->at(i)); 371 CHECK_BAILOUT; 372 } 373 } 374 375 376 void FullCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { 377 switch (expr->op()) { 378 case Token::ADD: 379 case Token::BIT_NOT: 380 case Token::NOT: 381 case Token::SUB: 382 case Token::TYPEOF: 383 case Token::VOID: 384 Visit(expr->expression()); 385 break; 386 case Token::DELETE: 387 BAILOUT("UnaryOperation: DELETE"); 388 default: 389 UNREACHABLE(); 390 } 391 } 392 393 394 void FullCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) { 395 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 396 Property* prop = expr->expression()->AsProperty(); 397 ASSERT(var == NULL || prop == NULL); 398 if (var != NULL) { 399 // All global variables are supported. 400 if (!var->is_global()) { 401 ASSERT(var->slot() != NULL); 402 Slot::Type type = var->slot()->type(); 403 if (type == Slot::LOOKUP) { 404 BAILOUT("CountOperation with lookup slot"); 405 } 406 } 407 } else if (prop != NULL) { 408 Visit(prop->obj()); 409 CHECK_BAILOUT; 410 Visit(prop->key()); 411 CHECK_BAILOUT; 412 } else { 413 // This is a throw reference error. 414 BAILOUT("CountOperation non-variable/non-property expression"); 415 } 416 } 417 418 419 void FullCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { 420 Visit(expr->left()); 421 CHECK_BAILOUT; 422 Visit(expr->right()); 423 } 424 425 426 void FullCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { 427 Visit(expr->left()); 428 CHECK_BAILOUT; 429 Visit(expr->right()); 430 } 431 432 433 void FullCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { 434 // Supported. 435 } 436 437 #undef BAILOUT 438 #undef CHECK_BAILOUT 439 440 441 #define __ ACCESS_MASM(masm()) 442 443 Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) { 444 Handle<Script> script = info->script(); 445 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 446 int len = String::cast(script->source())->length(); 447 Counters::total_full_codegen_source_size.Increment(len); 448 } 449 CodeGenerator::MakeCodePrologue(info); 450 const int kInitialBufferSize = 4 * KB; 451 MacroAssembler masm(NULL, kInitialBufferSize); 452 LiveEditFunctionTracker live_edit_tracker(info->function()); 453 454 FullCodeGenerator cgen(&masm); 455 cgen.Generate(info, PRIMARY); 456 if (cgen.HasStackOverflow()) { 457 ASSERT(!Top::has_pending_exception()); 458 return Handle<Code>::null(); 459 } 460 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); 461 Handle<Code> result = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); 462 live_edit_tracker.RecordFunctionCode(result); 463 return result; 464 } 465 466 467 int FullCodeGenerator::SlotOffset(Slot* slot) { 468 ASSERT(slot != NULL); 469 // Offset is negative because higher indexes are at lower addresses. 470 int offset = -slot->index() * kPointerSize; 471 // Adjust by a (parameter or local) base offset. 472 switch (slot->type()) { 473 case Slot::PARAMETER: 474 offset += (scope()->num_parameters() + 1) * kPointerSize; 475 break; 476 case Slot::LOCAL: 477 offset += JavaScriptFrameConstants::kLocal0Offset; 478 break; 479 case Slot::CONTEXT: 480 case Slot::LOOKUP: 481 UNREACHABLE(); 482 } 483 return offset; 484 } 485 486 487 void FullCodeGenerator::VisitDeclarations( 488 ZoneList<Declaration*>* declarations) { 489 int length = declarations->length(); 490 int globals = 0; 491 for (int i = 0; i < length; i++) { 492 Declaration* decl = declarations->at(i); 493 Variable* var = decl->proxy()->var(); 494 Slot* slot = var->slot(); 495 496 // If it was not possible to allocate the variable at compile 497 // time, we need to "declare" it at runtime to make sure it 498 // actually exists in the local context. 499 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { 500 VisitDeclaration(decl); 501 } else { 502 // Count global variables and functions for later processing 503 globals++; 504 } 505 } 506 507 // Compute array of global variable and function declarations. 508 // Do nothing in case of no declared global functions or variables. 509 if (globals > 0) { 510 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED); 511 for (int j = 0, i = 0; i < length; i++) { 512 Declaration* decl = declarations->at(i); 513 Variable* var = decl->proxy()->var(); 514 Slot* slot = var->slot(); 515 516 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) { 517 array->set(j++, *(var->name())); 518 if (decl->fun() == NULL) { 519 if (var->mode() == Variable::CONST) { 520 // In case this is const property use the hole. 521 array->set_the_hole(j++); 522 } else { 523 array->set_undefined(j++); 524 } 525 } else { 526 Handle<JSFunction> function = 527 Compiler::BuildBoilerplate(decl->fun(), script(), this); 528 // Check for stack-overflow exception. 529 if (HasStackOverflow()) return; 530 array->set(j++, *function); 531 } 532 } 533 } 534 // Invoke the platform-dependent code generator to do the actual 535 // declaration the global variables and functions. 536 DeclareGlobals(array); 537 } 538 } 539 540 541 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { 542 if (FLAG_debug_info) { 543 CodeGenerator::RecordPositions(masm_, fun->start_position()); 544 } 545 } 546 547 548 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { 549 if (FLAG_debug_info) { 550 CodeGenerator::RecordPositions(masm_, fun->end_position()); 551 } 552 } 553 554 555 void FullCodeGenerator::SetStatementPosition(Statement* stmt) { 556 if (FLAG_debug_info) { 557 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); 558 } 559 } 560 561 562 void FullCodeGenerator::SetStatementPosition(int pos) { 563 if (FLAG_debug_info) { 564 CodeGenerator::RecordPositions(masm_, pos); 565 } 566 } 567 568 569 void FullCodeGenerator::SetSourcePosition(int pos) { 570 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { 571 masm_->RecordPosition(pos); 572 } 573 } 574 575 576 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { 577 Label eval_right, done; 578 579 // Set up the appropriate context for the left subexpression based 580 // on the operation and our own context. Initially assume we can 581 // inherit both true and false labels from our context. 582 if (expr->op() == Token::OR) { 583 switch (context_) { 584 case Expression::kUninitialized: 585 UNREACHABLE(); 586 case Expression::kEffect: 587 VisitForControl(expr->left(), &done, &eval_right); 588 break; 589 case Expression::kValue: 590 VisitForValueControl(expr->left(), 591 location_, 592 &done, 593 &eval_right); 594 break; 595 case Expression::kTest: 596 VisitForControl(expr->left(), true_label_, &eval_right); 597 break; 598 case Expression::kValueTest: 599 VisitForValueControl(expr->left(), 600 location_, 601 true_label_, 602 &eval_right); 603 break; 604 case Expression::kTestValue: 605 VisitForControl(expr->left(), true_label_, &eval_right); 606 break; 607 } 608 } else { 609 ASSERT_EQ(Token::AND, expr->op()); 610 switch (context_) { 611 case Expression::kUninitialized: 612 UNREACHABLE(); 613 case Expression::kEffect: 614 VisitForControl(expr->left(), &eval_right, &done); 615 break; 616 case Expression::kValue: 617 VisitForControlValue(expr->left(), 618 location_, 619 &eval_right, 620 &done); 621 break; 622 case Expression::kTest: 623 VisitForControl(expr->left(), &eval_right, false_label_); 624 break; 625 case Expression::kValueTest: 626 VisitForControl(expr->left(), &eval_right, false_label_); 627 break; 628 case Expression::kTestValue: 629 VisitForControlValue(expr->left(), 630 location_, 631 &eval_right, 632 false_label_); 633 break; 634 } 635 } 636 637 __ bind(&eval_right); 638 Visit(expr->right()); 639 640 __ bind(&done); 641 } 642 643 644 void FullCodeGenerator::VisitBlock(Block* stmt) { 645 Comment cmnt(masm_, "[ Block"); 646 Breakable nested_statement(this, stmt); 647 SetStatementPosition(stmt); 648 VisitStatements(stmt->statements()); 649 __ bind(nested_statement.break_target()); 650 } 651 652 653 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 654 Comment cmnt(masm_, "[ ExpressionStatement"); 655 SetStatementPosition(stmt); 656 VisitForEffect(stmt->expression()); 657 } 658 659 660 void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { 661 Comment cmnt(masm_, "[ EmptyStatement"); 662 SetStatementPosition(stmt); 663 } 664 665 666 void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) { 667 Comment cmnt(masm_, "[ IfStatement"); 668 SetStatementPosition(stmt); 669 Label then_part, else_part, done; 670 671 // Do not worry about optimizing for empty then or else bodies. 672 VisitForControl(stmt->condition(), &then_part, &else_part); 673 674 __ bind(&then_part); 675 Visit(stmt->then_statement()); 676 __ jmp(&done); 677 678 __ bind(&else_part); 679 Visit(stmt->else_statement()); 680 681 __ bind(&done); 682 } 683 684 685 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 686 Comment cmnt(masm_, "[ ContinueStatement"); 687 SetStatementPosition(stmt); 688 NestedStatement* current = nesting_stack_; 689 int stack_depth = 0; 690 while (!current->IsContinueTarget(stmt->target())) { 691 stack_depth = current->Exit(stack_depth); 692 current = current->outer(); 693 } 694 __ Drop(stack_depth); 695 696 Iteration* loop = current->AsIteration(); 697 __ jmp(loop->continue_target()); 698 } 699 700 701 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 702 Comment cmnt(masm_, "[ BreakStatement"); 703 SetStatementPosition(stmt); 704 NestedStatement* current = nesting_stack_; 705 int stack_depth = 0; 706 while (!current->IsBreakTarget(stmt->target())) { 707 stack_depth = current->Exit(stack_depth); 708 current = current->outer(); 709 } 710 __ Drop(stack_depth); 711 712 Breakable* target = current->AsBreakable(); 713 __ jmp(target->break_target()); 714 } 715 716 717 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 718 Comment cmnt(masm_, "[ ReturnStatement"); 719 SetStatementPosition(stmt); 720 Expression* expr = stmt->expression(); 721 VisitForValue(expr, kAccumulator); 722 723 // Exit all nested statements. 724 NestedStatement* current = nesting_stack_; 725 int stack_depth = 0; 726 while (current != NULL) { 727 stack_depth = current->Exit(stack_depth); 728 current = current->outer(); 729 } 730 __ Drop(stack_depth); 731 732 EmitReturnSequence(stmt->statement_pos()); 733 } 734 735 736 void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { 737 Comment cmnt(masm_, "[ WithEnterStatement"); 738 SetStatementPosition(stmt); 739 740 VisitForValue(stmt->expression(), kStack); 741 if (stmt->is_catch_block()) { 742 __ CallRuntime(Runtime::kPushCatchContext, 1); 743 } else { 744 __ CallRuntime(Runtime::kPushContext, 1); 745 } 746 // Both runtime calls return the new context in both the context and the 747 // result registers. 748 749 // Update local stack frame context field. 750 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 751 } 752 753 754 void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { 755 Comment cmnt(masm_, "[ WithExitStatement"); 756 SetStatementPosition(stmt); 757 758 // Pop context. 759 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 760 // Update local stack frame context field. 761 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 762 } 763 764 765 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 766 UNREACHABLE(); 767 } 768 769 770 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 771 Comment cmnt(masm_, "[ DoWhileStatement"); 772 SetStatementPosition(stmt); 773 Label body, stack_limit_hit, stack_check_success; 774 775 Iteration loop_statement(this, stmt); 776 increment_loop_depth(); 777 778 __ bind(&body); 779 Visit(stmt->body()); 780 781 // Check stack before looping. 782 __ StackLimitCheck(&stack_limit_hit); 783 __ bind(&stack_check_success); 784 785 __ bind(loop_statement.continue_target()); 786 SetStatementPosition(stmt->condition_position()); 787 VisitForControl(stmt->cond(), &body, loop_statement.break_target()); 788 789 __ bind(&stack_limit_hit); 790 StackCheckStub stack_stub; 791 __ CallStub(&stack_stub); 792 __ jmp(&stack_check_success); 793 794 __ bind(loop_statement.break_target()); 795 796 decrement_loop_depth(); 797 } 798 799 800 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 801 Comment cmnt(masm_, "[ WhileStatement"); 802 SetStatementPosition(stmt); 803 Label body, stack_limit_hit, stack_check_success; 804 805 Iteration loop_statement(this, stmt); 806 increment_loop_depth(); 807 808 // Emit the test at the bottom of the loop. 809 __ jmp(loop_statement.continue_target()); 810 811 __ bind(&body); 812 Visit(stmt->body()); 813 814 __ bind(loop_statement.continue_target()); 815 // Check stack before looping. 816 __ StackLimitCheck(&stack_limit_hit); 817 __ bind(&stack_check_success); 818 819 VisitForControl(stmt->cond(), &body, loop_statement.break_target()); 820 821 __ bind(&stack_limit_hit); 822 StackCheckStub stack_stub; 823 __ CallStub(&stack_stub); 824 __ jmp(&stack_check_success); 825 826 __ bind(loop_statement.break_target()); 827 decrement_loop_depth(); 828 } 829 830 831 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { 832 Comment cmnt(masm_, "[ ForStatement"); 833 SetStatementPosition(stmt); 834 Label test, body, stack_limit_hit, stack_check_success; 835 836 Iteration loop_statement(this, stmt); 837 if (stmt->init() != NULL) { 838 Visit(stmt->init()); 839 } 840 841 increment_loop_depth(); 842 // Emit the test at the bottom of the loop (even if empty). 843 __ jmp(&test); 844 845 __ bind(&body); 846 Visit(stmt->body()); 847 848 __ bind(loop_statement.continue_target()); 849 850 SetStatementPosition(stmt); 851 if (stmt->next() != NULL) { 852 Visit(stmt->next()); 853 } 854 855 __ bind(&test); 856 857 // Check stack before looping. 858 __ StackLimitCheck(&stack_limit_hit); 859 __ bind(&stack_check_success); 860 861 if (stmt->cond() != NULL) { 862 VisitForControl(stmt->cond(), &body, loop_statement.break_target()); 863 } else { 864 __ jmp(&body); 865 } 866 867 __ bind(&stack_limit_hit); 868 StackCheckStub stack_stub; 869 __ CallStub(&stack_stub); 870 __ jmp(&stack_check_success); 871 872 __ bind(loop_statement.break_target()); 873 decrement_loop_depth(); 874 } 875 876 877 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 878 UNREACHABLE(); 879 } 880 881 882 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 883 Comment cmnt(masm_, "[ TryCatchStatement"); 884 SetStatementPosition(stmt); 885 // The try block adds a handler to the exception handler chain 886 // before entering, and removes it again when exiting normally. 887 // If an exception is thrown during execution of the try block, 888 // control is passed to the handler, which also consumes the handler. 889 // At this point, the exception is in a register, and store it in 890 // the temporary local variable (prints as ".catch-var") before 891 // executing the catch block. The catch block has been rewritten 892 // to introduce a new scope to bind the catch variable and to remove 893 // that scope again afterwards. 894 895 Label try_handler_setup, catch_entry, done; 896 __ Call(&try_handler_setup); 897 // Try handler code, exception in result register. 898 899 // Store exception in local .catch variable before executing catch block. 900 { 901 // The catch variable is *always* a variable proxy for a local variable. 902 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable(); 903 ASSERT_NOT_NULL(catch_var); 904 Slot* variable_slot = catch_var->slot(); 905 ASSERT_NOT_NULL(variable_slot); 906 ASSERT_EQ(Slot::LOCAL, variable_slot->type()); 907 StoreToFrameField(SlotOffset(variable_slot), result_register()); 908 } 909 910 Visit(stmt->catch_block()); 911 __ jmp(&done); 912 913 // Try block code. Sets up the exception handler chain. 914 __ bind(&try_handler_setup); 915 { 916 TryCatch try_block(this, &catch_entry); 917 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); 918 Visit(stmt->try_block()); 919 __ PopTryHandler(); 920 } 921 __ bind(&done); 922 } 923 924 925 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 926 Comment cmnt(masm_, "[ TryFinallyStatement"); 927 SetStatementPosition(stmt); 928 // Try finally is compiled by setting up a try-handler on the stack while 929 // executing the try body, and removing it again afterwards. 930 // 931 // The try-finally construct can enter the finally block in three ways: 932 // 1. By exiting the try-block normally. This removes the try-handler and 933 // calls the finally block code before continuing. 934 // 2. By exiting the try-block with a function-local control flow transfer 935 // (break/continue/return). The site of the, e.g., break removes the 936 // try handler and calls the finally block code before continuing 937 // its outward control transfer. 938 // 3. by exiting the try-block with a thrown exception. 939 // This can happen in nested function calls. It traverses the try-handler 940 // chain and consumes the try-handler entry before jumping to the 941 // handler code. The handler code then calls the finally-block before 942 // rethrowing the exception. 943 // 944 // The finally block must assume a return address on top of the stack 945 // (or in the link register on ARM chips) and a value (return value or 946 // exception) in the result register (rax/eax/r0), both of which must 947 // be preserved. The return address isn't GC-safe, so it should be 948 // cooked before GC. 949 Label finally_entry; 950 Label try_handler_setup; 951 952 // Setup the try-handler chain. Use a call to 953 // Jump to try-handler setup and try-block code. Use call to put try-handler 954 // address on stack. 955 __ Call(&try_handler_setup); 956 // Try handler code. Return address of call is pushed on handler stack. 957 { 958 // This code is only executed during stack-handler traversal when an 959 // exception is thrown. The execption is in the result register, which 960 // is retained by the finally block. 961 // Call the finally block and then rethrow the exception. 962 __ Call(&finally_entry); 963 __ push(result_register()); 964 __ CallRuntime(Runtime::kReThrow, 1); 965 } 966 967 __ bind(&finally_entry); 968 { 969 // Finally block implementation. 970 Finally finally_block(this); 971 EnterFinallyBlock(); 972 Visit(stmt->finally_block()); 973 ExitFinallyBlock(); // Return to the calling code. 974 } 975 976 __ bind(&try_handler_setup); 977 { 978 // Setup try handler (stack pointer registers). 979 TryFinally try_block(this, &finally_entry); 980 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); 981 Visit(stmt->try_block()); 982 __ PopTryHandler(); 983 } 984 // Execute the finally block on the way out. 985 __ Call(&finally_entry); 986 } 987 988 989 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 990 #ifdef ENABLE_DEBUGGER_SUPPORT 991 Comment cmnt(masm_, "[ DebuggerStatement"); 992 SetStatementPosition(stmt); 993 994 __ DebugBreak(); 995 // Ignore the return value. 996 #endif 997 } 998 999 1000 void FullCodeGenerator::VisitFunctionBoilerplateLiteral( 1001 FunctionBoilerplateLiteral* expr) { 1002 UNREACHABLE(); 1003 } 1004 1005 1006 void FullCodeGenerator::VisitConditional(Conditional* expr) { 1007 Comment cmnt(masm_, "[ Conditional"); 1008 Label true_case, false_case, done; 1009 VisitForControl(expr->condition(), &true_case, &false_case); 1010 1011 __ bind(&true_case); 1012 Visit(expr->then_expression()); 1013 // If control flow falls through Visit, jump to done. 1014 if (context_ == Expression::kEffect || context_ == Expression::kValue) { 1015 __ jmp(&done); 1016 } 1017 1018 __ bind(&false_case); 1019 Visit(expr->else_expression()); 1020 // If control flow falls through Visit, merge it with true case here. 1021 if (context_ == Expression::kEffect || context_ == Expression::kValue) { 1022 __ bind(&done); 1023 } 1024 } 1025 1026 1027 void FullCodeGenerator::VisitSlot(Slot* expr) { 1028 // Slots do not appear directly in the AST. 1029 UNREACHABLE(); 1030 } 1031 1032 1033 void FullCodeGenerator::VisitLiteral(Literal* expr) { 1034 Comment cmnt(masm_, "[ Literal"); 1035 Apply(context_, expr); 1036 } 1037 1038 1039 void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { 1040 // Call runtime routine to allocate the catch extension object and 1041 // assign the exception value to the catch variable. 1042 Comment cmnt(masm_, "[ CatchExtensionObject"); 1043 VisitForValue(expr->key(), kStack); 1044 VisitForValue(expr->value(), kStack); 1045 // Create catch extension object. 1046 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2); 1047 Apply(context_, result_register()); 1048 } 1049 1050 1051 void FullCodeGenerator::VisitThrow(Throw* expr) { 1052 Comment cmnt(masm_, "[ Throw"); 1053 VisitForValue(expr->exception(), kStack); 1054 __ CallRuntime(Runtime::kThrow, 1); 1055 // Never returns here. 1056 } 1057 1058 1059 int FullCodeGenerator::TryFinally::Exit(int stack_depth) { 1060 // The macros used here must preserve the result register. 1061 __ Drop(stack_depth); 1062 __ PopTryHandler(); 1063 __ Call(finally_entry_); 1064 return 0; 1065 } 1066 1067 1068 int FullCodeGenerator::TryCatch::Exit(int stack_depth) { 1069 // The macros used here must preserve the result register. 1070 __ Drop(stack_depth); 1071 __ PopTryHandler(); 1072 return 0; 1073 } 1074 1075 #undef __ 1076 1077 1078 } } // namespace v8::internal 1079