full-codegen.cc revision 592a9fc1d8ea420377a2e7efd0600e20b058be2b
1// Copyright 2011 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.h" 31#include "compiler.h" 32#include "debug.h" 33#include "full-codegen.h" 34#include "liveedit.h" 35#include "macro-assembler.h" 36#include "prettyprinter.h" 37#include "scopes.h" 38#include "scopeinfo.h" 39#include "stub-cache.h" 40 41namespace v8 { 42namespace internal { 43 44void BreakableStatementChecker::Check(Statement* stmt) { 45 Visit(stmt); 46} 47 48 49void BreakableStatementChecker::Check(Expression* expr) { 50 Visit(expr); 51} 52 53 54void BreakableStatementChecker::VisitDeclaration(Declaration* decl) { 55} 56 57 58void BreakableStatementChecker::VisitBlock(Block* stmt) { 59} 60 61 62void BreakableStatementChecker::VisitExpressionStatement( 63 ExpressionStatement* stmt) { 64 // Check if expression is breakable. 65 Visit(stmt->expression()); 66} 67 68 69void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) { 70} 71 72 73void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) { 74 // If the condition is breakable the if statement is breakable. 75 Visit(stmt->condition()); 76} 77 78 79void BreakableStatementChecker::VisitContinueStatement( 80 ContinueStatement* stmt) { 81} 82 83 84void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) { 85} 86 87 88void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) { 89 // Return is breakable if the expression is. 90 Visit(stmt->expression()); 91} 92 93 94void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) { 95 Visit(stmt->expression()); 96} 97 98 99void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) { 100 // Switch statements breakable if the tag expression is. 101 Visit(stmt->tag()); 102} 103 104 105void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { 106 // Mark do while as breakable to avoid adding a break slot in front of it. 107 is_breakable_ = true; 108} 109 110 111void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) { 112 // Mark while statements breakable if the condition expression is. 113 Visit(stmt->cond()); 114} 115 116 117void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) { 118 // Mark for statements breakable if the condition expression is. 119 if (stmt->cond() != NULL) { 120 Visit(stmt->cond()); 121 } 122} 123 124 125void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) { 126 // Mark for in statements breakable if the enumerable expression is. 127 Visit(stmt->enumerable()); 128} 129 130 131void BreakableStatementChecker::VisitTryCatchStatement( 132 TryCatchStatement* stmt) { 133 // Mark try catch as breakable to avoid adding a break slot in front of it. 134 is_breakable_ = true; 135} 136 137 138void BreakableStatementChecker::VisitTryFinallyStatement( 139 TryFinallyStatement* stmt) { 140 // Mark try finally as breakable to avoid adding a break slot in front of it. 141 is_breakable_ = true; 142} 143 144 145void BreakableStatementChecker::VisitDebuggerStatement( 146 DebuggerStatement* stmt) { 147 // The debugger statement is breakable. 148 is_breakable_ = true; 149} 150 151 152void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) { 153} 154 155 156void BreakableStatementChecker::VisitSharedFunctionInfoLiteral( 157 SharedFunctionInfoLiteral* expr) { 158} 159 160 161void BreakableStatementChecker::VisitConditional(Conditional* expr) { 162} 163 164 165void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) { 166} 167 168 169void BreakableStatementChecker::VisitLiteral(Literal* expr) { 170} 171 172 173void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) { 174} 175 176 177void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) { 178} 179 180 181void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { 182} 183 184 185void BreakableStatementChecker::VisitAssignment(Assignment* expr) { 186 // If assigning to a property (including a global property) the assignment is 187 // breakable. 188 VariableProxy* proxy = expr->target()->AsVariableProxy(); 189 Property* prop = expr->target()->AsProperty(); 190 if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) { 191 is_breakable_ = true; 192 return; 193 } 194 195 // Otherwise the assignment is breakable if the assigned value is. 196 Visit(expr->value()); 197} 198 199 200void BreakableStatementChecker::VisitThrow(Throw* expr) { 201 // Throw is breakable if the expression is. 202 Visit(expr->exception()); 203} 204 205 206void BreakableStatementChecker::VisitProperty(Property* expr) { 207 // Property load is breakable. 208 is_breakable_ = true; 209} 210 211 212void BreakableStatementChecker::VisitCall(Call* expr) { 213 // Function calls both through IC and call stub are breakable. 214 is_breakable_ = true; 215} 216 217 218void BreakableStatementChecker::VisitCallNew(CallNew* expr) { 219 // Function calls through new are breakable. 220 is_breakable_ = true; 221} 222 223 224void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) { 225} 226 227 228void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) { 229 Visit(expr->expression()); 230} 231 232 233void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) { 234 Visit(expr->expression()); 235} 236 237 238void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) { 239 Visit(expr->left()); 240 if (expr->op() != Token::AND && 241 expr->op() != Token::OR) { 242 Visit(expr->right()); 243 } 244} 245 246 247void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) { 248 Visit(expr->left()); 249 Visit(expr->right()); 250} 251 252 253void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) { 254} 255 256 257#define __ ACCESS_MASM(masm()) 258 259bool FullCodeGenerator::MakeCode(CompilationInfo* info) { 260 Isolate* isolate = info->isolate(); 261 Handle<Script> script = info->script(); 262 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 263 int len = String::cast(script->source())->length(); 264 isolate->counters()->total_full_codegen_source_size()->Increment(len); 265 } 266 if (FLAG_trace_codegen) { 267 PrintF("Full Compiler - "); 268 } 269 CodeGenerator::MakeCodePrologue(info); 270 const int kInitialBufferSize = 4 * KB; 271 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize); 272#ifdef ENABLE_GDB_JIT_INTERFACE 273 masm.positions_recorder()->StartGDBJITLineInfoRecording(); 274#endif 275 276 FullCodeGenerator cgen(&masm); 277 cgen.Generate(info); 278 if (cgen.HasStackOverflow()) { 279 ASSERT(!isolate->has_pending_exception()); 280 return false; 281 } 282 unsigned table_offset = cgen.EmitStackCheckTable(); 283 284 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); 285 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); 286 code->set_optimizable(info->IsOptimizable()); 287 cgen.PopulateDeoptimizationData(code); 288 code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); 289 code->set_handler_table(*cgen.handler_table()); 290#ifdef ENABLE_DEBUGGER_SUPPORT 291 code->set_has_debug_break_slots( 292 info->isolate()->debugger()->IsDebuggerActive()); 293 code->set_compiled_optimizable(info->IsOptimizable()); 294#endif // ENABLE_DEBUGGER_SUPPORT 295 code->set_allow_osr_at_loop_nesting_level(0); 296 code->set_stack_check_table_offset(table_offset); 297 CodeGenerator::PrintCode(code, info); 298 info->SetCode(code); // May be an empty handle. 299#ifdef ENABLE_GDB_JIT_INTERFACE 300 if (FLAG_gdbjit && !code.is_null()) { 301 GDBJITLineInfo* lineinfo = 302 masm.positions_recorder()->DetachGDBJITLineInfo(); 303 304 GDBJIT(RegisterDetailedLineInfo(*code, lineinfo)); 305 } 306#endif 307 return !code.is_null(); 308} 309 310 311unsigned FullCodeGenerator::EmitStackCheckTable() { 312 // The stack check table consists of a length (in number of entries) 313 // field, and then a sequence of entries. Each entry is a pair of AST id 314 // and code-relative pc offset. 315 masm()->Align(kIntSize); 316 unsigned offset = masm()->pc_offset(); 317 unsigned length = stack_checks_.length(); 318 __ dd(length); 319 for (unsigned i = 0; i < length; ++i) { 320 __ dd(stack_checks_[i].id); 321 __ dd(stack_checks_[i].pc_and_state); 322 } 323 return offset; 324} 325 326 327void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) { 328 // Fill in the deoptimization information. 329 ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty()); 330 if (!info_->HasDeoptimizationSupport()) return; 331 int length = bailout_entries_.length(); 332 Handle<DeoptimizationOutputData> data = 333 isolate()->factory()-> 334 NewDeoptimizationOutputData(length, TENURED); 335 for (int i = 0; i < length; i++) { 336 data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id)); 337 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state)); 338 } 339 code->set_deoptimization_data(*data); 340} 341 342 343void FullCodeGenerator::PrepareForBailout(Expression* node, State state) { 344 PrepareForBailoutForId(node->id(), state); 345} 346 347 348void FullCodeGenerator::RecordJSReturnSite(Call* call) { 349 // We record the offset of the function return so we can rebuild the frame 350 // if the function was inlined, i.e., this is the return address in the 351 // inlined function's frame. 352 // 353 // The state is ignored. We defensively set it to TOS_REG, which is the 354 // real state of the unoptimized code at the return site. 355 PrepareForBailoutForId(call->ReturnId(), TOS_REG); 356#ifdef DEBUG 357 // In debug builds, mark the return so we can verify that this function 358 // was called. 359 ASSERT(!call->return_is_recorded_); 360 call->return_is_recorded_ = true; 361#endif 362} 363 364 365void FullCodeGenerator::PrepareForBailoutForId(unsigned id, State state) { 366 // There's no need to prepare this code for bailouts from already optimized 367 // code or code that can't be optimized. 368 if (!FLAG_deopt || !info_->HasDeoptimizationSupport()) return; 369 unsigned pc_and_state = 370 StateField::encode(state) | PcField::encode(masm_->pc_offset()); 371 BailoutEntry entry = { id, pc_and_state }; 372#ifdef DEBUG 373 // Assert that we don't have multiple bailout entries for the same node. 374 for (int i = 0; i < bailout_entries_.length(); i++) { 375 if (bailout_entries_.at(i).id == entry.id) { 376 AstPrinter printer; 377 PrintF("%s", printer.PrintProgram(info_->function())); 378 UNREACHABLE(); 379 } 380 } 381#endif // DEBUG 382 bailout_entries_.Add(entry); 383} 384 385 386void FullCodeGenerator::RecordStackCheck(unsigned ast_id) { 387 // The pc offset does not need to be encoded and packed together with a 388 // state. 389 ASSERT(masm_->pc_offset() > 0); 390 BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) }; 391 stack_checks_.Add(entry); 392} 393 394 395bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { 396 // Inline smi case inside loops, but not division and modulo which 397 // are too complicated and take up too much space. 398 if (op == Token::DIV ||op == Token::MOD) return false; 399 if (FLAG_always_inline_smi_code) return true; 400 return loop_depth_ > 0; 401} 402 403 404void FullCodeGenerator::EffectContext::Plug(Register reg) const { 405} 406 407 408void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { 409 __ Move(result_register(), reg); 410} 411 412 413void FullCodeGenerator::StackValueContext::Plug(Register reg) const { 414 __ push(reg); 415} 416 417 418void FullCodeGenerator::TestContext::Plug(Register reg) const { 419 // For simplicity we always test the accumulator register. 420 __ Move(result_register(), reg); 421 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 422 codegen()->DoTest(this); 423} 424 425 426void FullCodeGenerator::EffectContext::PlugTOS() const { 427 __ Drop(1); 428} 429 430 431void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { 432 __ pop(result_register()); 433} 434 435 436void FullCodeGenerator::StackValueContext::PlugTOS() const { 437} 438 439 440void FullCodeGenerator::TestContext::PlugTOS() const { 441 // For simplicity we always test the accumulator register. 442 __ pop(result_register()); 443 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 444 codegen()->DoTest(this); 445} 446 447 448void FullCodeGenerator::EffectContext::PrepareTest( 449 Label* materialize_true, 450 Label* materialize_false, 451 Label** if_true, 452 Label** if_false, 453 Label** fall_through) const { 454 // In an effect context, the true and the false case branch to the 455 // same label. 456 *if_true = *if_false = *fall_through = materialize_true; 457} 458 459 460void FullCodeGenerator::AccumulatorValueContext::PrepareTest( 461 Label* materialize_true, 462 Label* materialize_false, 463 Label** if_true, 464 Label** if_false, 465 Label** fall_through) const { 466 *if_true = *fall_through = materialize_true; 467 *if_false = materialize_false; 468} 469 470 471void FullCodeGenerator::StackValueContext::PrepareTest( 472 Label* materialize_true, 473 Label* materialize_false, 474 Label** if_true, 475 Label** if_false, 476 Label** fall_through) const { 477 *if_true = *fall_through = materialize_true; 478 *if_false = materialize_false; 479} 480 481 482void FullCodeGenerator::TestContext::PrepareTest( 483 Label* materialize_true, 484 Label* materialize_false, 485 Label** if_true, 486 Label** if_false, 487 Label** fall_through) const { 488 *if_true = true_label_; 489 *if_false = false_label_; 490 *fall_through = fall_through_; 491} 492 493 494void FullCodeGenerator::DoTest(const TestContext* context) { 495 DoTest(context->condition(), 496 context->true_label(), 497 context->false_label(), 498 context->fall_through()); 499} 500 501 502void FullCodeGenerator::VisitDeclarations( 503 ZoneList<Declaration*>* declarations) { 504 int length = declarations->length(); 505 int global_count = 0; 506 for (int i = 0; i < length; i++) { 507 Declaration* decl = declarations->at(i); 508 EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count); 509 } 510 511 // Batch declare global functions and variables. 512 if (global_count > 0) { 513 Handle<FixedArray> array = 514 isolate()->factory()->NewFixedArray(2 * global_count, TENURED); 515 for (int j = 0, i = 0; i < length; i++) { 516 Declaration* decl = declarations->at(i); 517 Variable* var = decl->proxy()->var(); 518 519 if (var->IsUnallocated()) { 520 array->set(j++, *(var->name())); 521 if (decl->fun() == NULL) { 522 if (var->binding_needs_init()) { 523 // In case this binding needs initialization use the hole. 524 array->set_the_hole(j++); 525 } else { 526 array->set_undefined(j++); 527 } 528 } else { 529 Handle<SharedFunctionInfo> function = 530 Compiler::BuildFunctionInfo(decl->fun(), script()); 531 // Check for stack-overflow exception. 532 if (function.is_null()) { 533 SetStackOverflow(); 534 return; 535 } 536 array->set(j++, *function); 537 } 538 } 539 } 540 // Invoke the platform-dependent code generator to do the actual 541 // declaration the global functions and variables. 542 DeclareGlobals(array); 543 } 544} 545 546 547int FullCodeGenerator::DeclareGlobalsFlags() { 548 ASSERT(DeclareGlobalsLanguageMode::is_valid(language_mode())); 549 return DeclareGlobalsEvalFlag::encode(is_eval()) | 550 DeclareGlobalsNativeFlag::encode(is_native()) | 551 DeclareGlobalsLanguageMode::encode(language_mode()); 552} 553 554 555void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { 556 CodeGenerator::RecordPositions(masm_, fun->start_position()); 557} 558 559 560void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { 561 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1); 562} 563 564 565void FullCodeGenerator::SetStatementPosition(Statement* stmt) { 566#ifdef ENABLE_DEBUGGER_SUPPORT 567 if (!isolate()->debugger()->IsDebuggerActive()) { 568 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); 569 } else { 570 // Check if the statement will be breakable without adding a debug break 571 // slot. 572 BreakableStatementChecker checker; 573 checker.Check(stmt); 574 // Record the statement position right here if the statement is not 575 // breakable. For breakable statements the actual recording of the 576 // position will be postponed to the breakable code (typically an IC). 577 bool position_recorded = CodeGenerator::RecordPositions( 578 masm_, stmt->statement_pos(), !checker.is_breakable()); 579 // If the position recording did record a new position generate a debug 580 // break slot to make the statement breakable. 581 if (position_recorded) { 582 Debug::GenerateSlot(masm_); 583 } 584 } 585#else 586 CodeGenerator::RecordPositions(masm_, stmt->statement_pos()); 587#endif 588} 589 590 591void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) { 592#ifdef ENABLE_DEBUGGER_SUPPORT 593 if (!isolate()->debugger()->IsDebuggerActive()) { 594 CodeGenerator::RecordPositions(masm_, pos); 595 } else { 596 // Check if the expression will be breakable without adding a debug break 597 // slot. 598 BreakableStatementChecker checker; 599 checker.Check(expr); 600 // Record a statement position right here if the expression is not 601 // breakable. For breakable expressions the actual recording of the 602 // position will be postponed to the breakable code (typically an IC). 603 // NOTE this will record a statement position for something which might 604 // not be a statement. As stepping in the debugger will only stop at 605 // statement positions this is used for e.g. the condition expression of 606 // a do while loop. 607 bool position_recorded = CodeGenerator::RecordPositions( 608 masm_, pos, !checker.is_breakable()); 609 // If the position recording did record a new position generate a debug 610 // break slot to make the statement breakable. 611 if (position_recorded) { 612 Debug::GenerateSlot(masm_); 613 } 614 } 615#else 616 CodeGenerator::RecordPositions(masm_, pos); 617#endif 618} 619 620 621void FullCodeGenerator::SetStatementPosition(int pos) { 622 CodeGenerator::RecordPositions(masm_, pos); 623} 624 625 626void FullCodeGenerator::SetSourcePosition(int pos) { 627 if (pos != RelocInfo::kNoPosition) { 628 masm_->positions_recorder()->RecordPosition(pos); 629 } 630} 631 632 633// Lookup table for code generators for special runtime calls which are 634// generated inline. 635#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ 636 &FullCodeGenerator::Emit##Name, 637 638const FullCodeGenerator::InlineFunctionGenerator 639 FullCodeGenerator::kInlineFunctionGenerators[] = { 640 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 641 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 642 }; 643#undef INLINE_FUNCTION_GENERATOR_ADDRESS 644 645 646FullCodeGenerator::InlineFunctionGenerator 647 FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) { 648 int lookup_index = 649 static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction); 650 ASSERT(lookup_index >= 0); 651 ASSERT(static_cast<size_t>(lookup_index) < 652 ARRAY_SIZE(kInlineFunctionGenerators)); 653 return kInlineFunctionGenerators[lookup_index]; 654} 655 656 657void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) { 658 const Runtime::Function* function = expr->function(); 659 ASSERT(function != NULL); 660 ASSERT(function->intrinsic_type == Runtime::INLINE); 661 InlineFunctionGenerator generator = 662 FindInlineFunctionGenerator(function->function_id); 663 ((*this).*(generator))(expr); 664} 665 666 667void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { 668 switch (expr->op()) { 669 case Token::COMMA: 670 return VisitComma(expr); 671 case Token::OR: 672 case Token::AND: 673 return VisitLogicalExpression(expr); 674 default: 675 return VisitArithmeticExpression(expr); 676 } 677} 678 679 680void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) { 681 if (context()->IsEffect()) { 682 VisitForEffect(expr); 683 } else if (context()->IsAccumulatorValue()) { 684 VisitForAccumulatorValue(expr); 685 } else if (context()->IsStackValue()) { 686 VisitForStackValue(expr); 687 } else if (context()->IsTest()) { 688 const TestContext* test = TestContext::cast(context()); 689 VisitForControl(expr, test->true_label(), test->false_label(), 690 test->fall_through()); 691 } 692} 693 694 695void FullCodeGenerator::VisitComma(BinaryOperation* expr) { 696 Comment cmnt(masm_, "[ Comma"); 697 VisitForEffect(expr->left()); 698 VisitInDuplicateContext(expr->right()); 699} 700 701 702void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { 703 bool is_logical_and = expr->op() == Token::AND; 704 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR"); 705 Expression* left = expr->left(); 706 Expression* right = expr->right(); 707 int right_id = expr->RightId(); 708 Label done; 709 710 if (context()->IsTest()) { 711 Label eval_right; 712 const TestContext* test = TestContext::cast(context()); 713 if (is_logical_and) { 714 VisitForControl(left, &eval_right, test->false_label(), &eval_right); 715 } else { 716 VisitForControl(left, test->true_label(), &eval_right, &eval_right); 717 } 718 PrepareForBailoutForId(right_id, NO_REGISTERS); 719 __ bind(&eval_right); 720 721 } else if (context()->IsAccumulatorValue()) { 722 VisitForAccumulatorValue(left); 723 // We want the value in the accumulator for the test, and on the stack in 724 // case we need it. 725 __ push(result_register()); 726 Label discard, restore; 727 if (is_logical_and) { 728 DoTest(left, &discard, &restore, &restore); 729 } else { 730 DoTest(left, &restore, &discard, &restore); 731 } 732 __ bind(&restore); 733 __ pop(result_register()); 734 __ jmp(&done); 735 __ bind(&discard); 736 __ Drop(1); 737 PrepareForBailoutForId(right_id, NO_REGISTERS); 738 739 } else if (context()->IsStackValue()) { 740 VisitForAccumulatorValue(left); 741 // We want the value in the accumulator for the test, and on the stack in 742 // case we need it. 743 __ push(result_register()); 744 Label discard; 745 if (is_logical_and) { 746 DoTest(left, &discard, &done, &discard); 747 } else { 748 DoTest(left, &done, &discard, &discard); 749 } 750 __ bind(&discard); 751 __ Drop(1); 752 PrepareForBailoutForId(right_id, NO_REGISTERS); 753 754 } else { 755 ASSERT(context()->IsEffect()); 756 Label eval_right; 757 if (is_logical_and) { 758 VisitForControl(left, &eval_right, &done, &eval_right); 759 } else { 760 VisitForControl(left, &done, &eval_right, &eval_right); 761 } 762 PrepareForBailoutForId(right_id, NO_REGISTERS); 763 __ bind(&eval_right); 764 } 765 766 VisitInDuplicateContext(right); 767 __ bind(&done); 768} 769 770 771void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { 772 Token::Value op = expr->op(); 773 Comment cmnt(masm_, "[ ArithmeticExpression"); 774 Expression* left = expr->left(); 775 Expression* right = expr->right(); 776 OverwriteMode mode = 777 left->ResultOverwriteAllowed() 778 ? OVERWRITE_LEFT 779 : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE); 780 781 VisitForStackValue(left); 782 VisitForAccumulatorValue(right); 783 784 SetSourcePosition(expr->position()); 785 if (ShouldInlineSmiCase(op)) { 786 EmitInlineSmiBinaryOp(expr, op, mode, left, right); 787 } else { 788 EmitBinaryOp(expr, op, mode); 789 } 790} 791 792 793void FullCodeGenerator::VisitBlock(Block* stmt) { 794 Comment cmnt(masm_, "[ Block"); 795 NestedBlock nested_block(this, stmt); 796 SetStatementPosition(stmt); 797 798 Scope* saved_scope = scope(); 799 // Push a block context when entering a block with block scoped variables. 800 if (stmt->block_scope() != NULL) { 801 { Comment cmnt(masm_, "[ Extend block context"); 802 scope_ = stmt->block_scope(); 803 Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); 804 int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; 805 __ Push(scope_info); 806 PushFunctionArgumentForContextAllocation(); 807 if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) { 808 FastNewBlockContextStub stub(heap_slots); 809 __ CallStub(&stub); 810 } else { 811 __ CallRuntime(Runtime::kPushBlockContext, 2); 812 } 813 814 // Replace the context stored in the frame. 815 StoreToFrameField(StandardFrameConstants::kContextOffset, 816 context_register()); 817 } 818 { Comment cmnt(masm_, "[ Declarations"); 819 VisitDeclarations(scope_->declarations()); 820 } 821 } 822 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 823 VisitStatements(stmt->statements()); 824 scope_ = saved_scope; 825 __ bind(nested_block.break_label()); 826 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 827 828 // Pop block context if necessary. 829 if (stmt->block_scope() != NULL) { 830 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 831 // Update local stack frame context field. 832 StoreToFrameField(StandardFrameConstants::kContextOffset, 833 context_register()); 834 } 835} 836 837 838void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 839 Comment cmnt(masm_, "[ ExpressionStatement"); 840 SetStatementPosition(stmt); 841 VisitForEffect(stmt->expression()); 842} 843 844 845void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { 846 Comment cmnt(masm_, "[ EmptyStatement"); 847 SetStatementPosition(stmt); 848} 849 850 851void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) { 852 Comment cmnt(masm_, "[ IfStatement"); 853 SetStatementPosition(stmt); 854 Label then_part, else_part, done; 855 856 if (stmt->HasElseStatement()) { 857 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part); 858 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); 859 __ bind(&then_part); 860 Visit(stmt->then_statement()); 861 __ jmp(&done); 862 863 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); 864 __ bind(&else_part); 865 Visit(stmt->else_statement()); 866 } else { 867 VisitForControl(stmt->condition(), &then_part, &done, &then_part); 868 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); 869 __ bind(&then_part); 870 Visit(stmt->then_statement()); 871 872 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); 873 } 874 __ bind(&done); 875 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS); 876} 877 878 879void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 880 Comment cmnt(masm_, "[ ContinueStatement"); 881 SetStatementPosition(stmt); 882 NestedStatement* current = nesting_stack_; 883 int stack_depth = 0; 884 int context_length = 0; 885 // When continuing, we clobber the unpredictable value in the accumulator 886 // with one that's safe for GC. If we hit an exit from the try block of 887 // try...finally on our way out, we will unconditionally preserve the 888 // accumulator on the stack. 889 ClearAccumulator(); 890 while (!current->IsContinueTarget(stmt->target())) { 891 current = current->Exit(&stack_depth, &context_length); 892 } 893 __ Drop(stack_depth); 894 if (context_length > 0) { 895 while (context_length > 0) { 896 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 897 --context_length; 898 } 899 StoreToFrameField(StandardFrameConstants::kContextOffset, 900 context_register()); 901 } 902 903 __ jmp(current->AsIteration()->continue_label()); 904} 905 906 907void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 908 Comment cmnt(masm_, "[ BreakStatement"); 909 SetStatementPosition(stmt); 910 NestedStatement* current = nesting_stack_; 911 int stack_depth = 0; 912 int context_length = 0; 913 // When breaking, we clobber the unpredictable value in the accumulator 914 // with one that's safe for GC. If we hit an exit from the try block of 915 // try...finally on our way out, we will unconditionally preserve the 916 // accumulator on the stack. 917 ClearAccumulator(); 918 while (!current->IsBreakTarget(stmt->target())) { 919 current = current->Exit(&stack_depth, &context_length); 920 } 921 __ Drop(stack_depth); 922 if (context_length > 0) { 923 while (context_length > 0) { 924 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 925 --context_length; 926 } 927 StoreToFrameField(StandardFrameConstants::kContextOffset, 928 context_register()); 929 } 930 931 __ jmp(current->AsBreakable()->break_label()); 932} 933 934 935void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 936 Comment cmnt(masm_, "[ ReturnStatement"); 937 SetStatementPosition(stmt); 938 Expression* expr = stmt->expression(); 939 VisitForAccumulatorValue(expr); 940 941 // Exit all nested statements. 942 NestedStatement* current = nesting_stack_; 943 int stack_depth = 0; 944 int context_length = 0; 945 while (current != NULL) { 946 current = current->Exit(&stack_depth, &context_length); 947 } 948 __ Drop(stack_depth); 949 950 EmitReturnSequence(); 951} 952 953 954void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { 955 Comment cmnt(masm_, "[ WithStatement"); 956 SetStatementPosition(stmt); 957 958 VisitForStackValue(stmt->expression()); 959 PushFunctionArgumentForContextAllocation(); 960 __ CallRuntime(Runtime::kPushWithContext, 2); 961 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 962 963 { WithOrCatch body(this); 964 Visit(stmt->statement()); 965 } 966 967 // Pop context. 968 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 969 // Update local stack frame context field. 970 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 971} 972 973 974void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 975 Comment cmnt(masm_, "[ DoWhileStatement"); 976 SetStatementPosition(stmt); 977 Label body, stack_check; 978 979 Iteration loop_statement(this, stmt); 980 increment_loop_depth(); 981 982 __ bind(&body); 983 Visit(stmt->body()); 984 985 // Record the position of the do while condition and make sure it is 986 // possible to break on the condition. 987 __ bind(loop_statement.continue_label()); 988 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); 989 SetExpressionPosition(stmt->cond(), stmt->condition_position()); 990 VisitForControl(stmt->cond(), 991 &stack_check, 992 loop_statement.break_label(), 993 &stack_check); 994 995 // Check stack before looping. 996 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); 997 __ bind(&stack_check); 998 EmitStackCheck(stmt); 999 __ jmp(&body); 1000 1001 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1002 __ bind(loop_statement.break_label()); 1003 decrement_loop_depth(); 1004} 1005 1006 1007void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 1008 Comment cmnt(masm_, "[ WhileStatement"); 1009 Label test, body; 1010 1011 Iteration loop_statement(this, stmt); 1012 increment_loop_depth(); 1013 1014 // Emit the test at the bottom of the loop. 1015 __ jmp(&test); 1016 1017 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1018 __ bind(&body); 1019 Visit(stmt->body()); 1020 1021 // Emit the statement position here as this is where the while 1022 // statement code starts. 1023 __ bind(loop_statement.continue_label()); 1024 SetStatementPosition(stmt); 1025 1026 // Check stack before looping. 1027 EmitStackCheck(stmt); 1028 1029 __ bind(&test); 1030 VisitForControl(stmt->cond(), 1031 &body, 1032 loop_statement.break_label(), 1033 loop_statement.break_label()); 1034 1035 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1036 __ bind(loop_statement.break_label()); 1037 decrement_loop_depth(); 1038} 1039 1040 1041void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { 1042 Comment cmnt(masm_, "[ ForStatement"); 1043 Label test, body; 1044 1045 Iteration loop_statement(this, stmt); 1046 if (stmt->init() != NULL) { 1047 Visit(stmt->init()); 1048 } 1049 1050 increment_loop_depth(); 1051 // Emit the test at the bottom of the loop (even if empty). 1052 __ jmp(&test); 1053 1054 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1055 __ bind(&body); 1056 Visit(stmt->body()); 1057 1058 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); 1059 __ bind(loop_statement.continue_label()); 1060 SetStatementPosition(stmt); 1061 if (stmt->next() != NULL) { 1062 Visit(stmt->next()); 1063 } 1064 1065 // Emit the statement position here as this is where the for 1066 // statement code starts. 1067 SetStatementPosition(stmt); 1068 1069 // Check stack before looping. 1070 EmitStackCheck(stmt); 1071 1072 __ bind(&test); 1073 if (stmt->cond() != NULL) { 1074 VisitForControl(stmt->cond(), 1075 &body, 1076 loop_statement.break_label(), 1077 loop_statement.break_label()); 1078 } else { 1079 __ jmp(&body); 1080 } 1081 1082 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1083 __ bind(loop_statement.break_label()); 1084 decrement_loop_depth(); 1085} 1086 1087 1088void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 1089 Comment cmnt(masm_, "[ TryCatchStatement"); 1090 SetStatementPosition(stmt); 1091 // The try block adds a handler to the exception handler chain before 1092 // entering, and removes it again when exiting normally. If an exception 1093 // is thrown during execution of the try block, the handler is consumed 1094 // and control is passed to the catch block with the exception in the 1095 // result register. 1096 1097 Label try_entry, handler_entry, exit; 1098 __ jmp(&try_entry); 1099 __ bind(&handler_entry); 1100 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos())); 1101 // Exception handler code, the exception is in the result register. 1102 // Extend the context before executing the catch block. 1103 { Comment cmnt(masm_, "[ Extend catch context"); 1104 __ Push(stmt->variable()->name()); 1105 __ push(result_register()); 1106 PushFunctionArgumentForContextAllocation(); 1107 __ CallRuntime(Runtime::kPushCatchContext, 3); 1108 StoreToFrameField(StandardFrameConstants::kContextOffset, 1109 context_register()); 1110 } 1111 1112 Scope* saved_scope = scope(); 1113 scope_ = stmt->scope(); 1114 ASSERT(scope_->declarations()->is_empty()); 1115 { WithOrCatch catch_body(this); 1116 Visit(stmt->catch_block()); 1117 } 1118 // Restore the context. 1119 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 1120 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 1121 scope_ = saved_scope; 1122 __ jmp(&exit); 1123 1124 // Try block code. Sets up the exception handler chain. 1125 __ bind(&try_entry); 1126 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER, stmt->index()); 1127 { TryCatch try_body(this); 1128 Visit(stmt->try_block()); 1129 } 1130 __ PopTryHandler(); 1131 __ bind(&exit); 1132} 1133 1134 1135void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1136 Comment cmnt(masm_, "[ TryFinallyStatement"); 1137 SetStatementPosition(stmt); 1138 // Try finally is compiled by setting up a try-handler on the stack while 1139 // executing the try body, and removing it again afterwards. 1140 // 1141 // The try-finally construct can enter the finally block in three ways: 1142 // 1. By exiting the try-block normally. This removes the try-handler and 1143 // calls the finally block code before continuing. 1144 // 2. By exiting the try-block with a function-local control flow transfer 1145 // (break/continue/return). The site of the, e.g., break removes the 1146 // try handler and calls the finally block code before continuing 1147 // its outward control transfer. 1148 // 3. By exiting the try-block with a thrown exception. 1149 // This can happen in nested function calls. It traverses the try-handler 1150 // chain and consumes the try-handler entry before jumping to the 1151 // handler code. The handler code then calls the finally-block before 1152 // rethrowing the exception. 1153 // 1154 // The finally block must assume a return address on top of the stack 1155 // (or in the link register on ARM chips) and a value (return value or 1156 // exception) in the result register (rax/eax/r0), both of which must 1157 // be preserved. The return address isn't GC-safe, so it should be 1158 // cooked before GC. 1159 Label try_entry, handler_entry, finally_entry; 1160 1161 // Jump to try-handler setup and try-block code. 1162 __ jmp(&try_entry); 1163 __ bind(&handler_entry); 1164 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos())); 1165 // Exception handler code. This code is only executed when an exception 1166 // is thrown. The exception is in the result register, and must be 1167 // preserved by the finally block. Call the finally block and then 1168 // rethrow the exception if it returns. 1169 __ Call(&finally_entry); 1170 __ push(result_register()); 1171 __ CallRuntime(Runtime::kReThrow, 1); 1172 1173 // Finally block implementation. 1174 __ bind(&finally_entry); 1175 EnterFinallyBlock(); 1176 { Finally finally_body(this); 1177 Visit(stmt->finally_block()); 1178 } 1179 ExitFinallyBlock(); // Return to the calling code. 1180 1181 // Setup try handler. 1182 __ bind(&try_entry); 1183 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER, stmt->index()); 1184 { TryFinally try_body(this, &finally_entry); 1185 Visit(stmt->try_block()); 1186 } 1187 __ PopTryHandler(); 1188 // Execute the finally block on the way out. Clobber the unpredictable 1189 // value in the result register with one that's safe for GC because the 1190 // finally block will unconditionally preserve the result register on the 1191 // stack. 1192 ClearAccumulator(); 1193 __ Call(&finally_entry); 1194} 1195 1196 1197void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 1198#ifdef ENABLE_DEBUGGER_SUPPORT 1199 Comment cmnt(masm_, "[ DebuggerStatement"); 1200 SetStatementPosition(stmt); 1201 1202 __ DebugBreak(); 1203 // Ignore the return value. 1204#endif 1205} 1206 1207 1208void FullCodeGenerator::VisitConditional(Conditional* expr) { 1209 Comment cmnt(masm_, "[ Conditional"); 1210 Label true_case, false_case, done; 1211 VisitForControl(expr->condition(), &true_case, &false_case, &true_case); 1212 1213 PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS); 1214 __ bind(&true_case); 1215 SetExpressionPosition(expr->then_expression(), 1216 expr->then_expression_position()); 1217 if (context()->IsTest()) { 1218 const TestContext* for_test = TestContext::cast(context()); 1219 VisitForControl(expr->then_expression(), 1220 for_test->true_label(), 1221 for_test->false_label(), 1222 NULL); 1223 } else { 1224 VisitInDuplicateContext(expr->then_expression()); 1225 __ jmp(&done); 1226 } 1227 1228 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); 1229 __ bind(&false_case); 1230 SetExpressionPosition(expr->else_expression(), 1231 expr->else_expression_position()); 1232 VisitInDuplicateContext(expr->else_expression()); 1233 // If control flow falls through Visit, merge it with true case here. 1234 if (!context()->IsTest()) { 1235 __ bind(&done); 1236 } 1237} 1238 1239 1240void FullCodeGenerator::VisitLiteral(Literal* expr) { 1241 Comment cmnt(masm_, "[ Literal"); 1242 context()->Plug(expr->handle()); 1243} 1244 1245 1246void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 1247 Comment cmnt(masm_, "[ FunctionLiteral"); 1248 1249 // Build the function boilerplate and instantiate it. 1250 Handle<SharedFunctionInfo> function_info = 1251 Compiler::BuildFunctionInfo(expr, script()); 1252 if (function_info.is_null()) { 1253 SetStackOverflow(); 1254 return; 1255 } 1256 EmitNewClosure(function_info, expr->pretenure()); 1257} 1258 1259 1260void FullCodeGenerator::VisitSharedFunctionInfoLiteral( 1261 SharedFunctionInfoLiteral* expr) { 1262 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); 1263 EmitNewClosure(expr->shared_function_info(), false); 1264} 1265 1266 1267void FullCodeGenerator::VisitThrow(Throw* expr) { 1268 Comment cmnt(masm_, "[ Throw"); 1269 VisitForStackValue(expr->exception()); 1270 __ CallRuntime(Runtime::kThrow, 1); 1271 // Never returns here. 1272} 1273 1274 1275FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( 1276 int* stack_depth, 1277 int* context_length) { 1278 // The macros used here must preserve the result register. 1279 __ Drop(*stack_depth); 1280 __ PopTryHandler(); 1281 *stack_depth = 0; 1282 return previous_; 1283} 1284 1285 1286bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { 1287 Expression *sub_expr; 1288 Handle<String> check; 1289 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 1290 EmitLiteralCompareTypeof(expr, sub_expr, check); 1291 return true; 1292 } 1293 1294 if (expr->IsLiteralCompareUndefined(&sub_expr)) { 1295 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue); 1296 return true; 1297 } 1298 1299 if (expr->IsLiteralCompareNull(&sub_expr)) { 1300 EmitLiteralCompareNil(expr, sub_expr, kNullValue); 1301 return true; 1302 } 1303 1304 return false; 1305} 1306 1307 1308#undef __ 1309 1310 1311} } // namespace v8::internal 1312