| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "codegen-inl.h" | 30 #include "codegen-inl.h" |
| 31 #include "compiler.h" | 31 #include "compiler.h" |
| 32 #include "debug.h" |
| 32 #include "full-codegen.h" | 33 #include "full-codegen.h" |
| 34 #include "liveedit.h" |
| 33 #include "macro-assembler.h" | 35 #include "macro-assembler.h" |
| 36 #include "prettyprinter.h" |
| 34 #include "scopes.h" | 37 #include "scopes.h" |
| 35 #include "stub-cache.h" | 38 #include "stub-cache.h" |
| 36 #include "debug.h" | |
| 37 #include "liveedit.h" | |
| 38 | 39 |
| 39 namespace v8 { | 40 namespace v8 { |
| 40 namespace internal { | 41 namespace internal { |
| 41 | 42 |
| 42 void BreakableStatementChecker::Check(Statement* stmt) { | 43 void BreakableStatementChecker::Check(Statement* stmt) { |
| 43 Visit(stmt); | 44 Visit(stmt); |
| 44 } | 45 } |
| 45 | 46 |
| 46 | 47 |
| 47 void BreakableStatementChecker::Check(Expression* expr) { | 48 void BreakableStatementChecker::Check(Expression* expr) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 | 160 |
| 160 void BreakableStatementChecker::VisitSharedFunctionInfoLiteral( | 161 void BreakableStatementChecker::VisitSharedFunctionInfoLiteral( |
| 161 SharedFunctionInfoLiteral* expr) { | 162 SharedFunctionInfoLiteral* expr) { |
| 162 } | 163 } |
| 163 | 164 |
| 164 | 165 |
| 165 void BreakableStatementChecker::VisitConditional(Conditional* expr) { | 166 void BreakableStatementChecker::VisitConditional(Conditional* expr) { |
| 166 } | 167 } |
| 167 | 168 |
| 168 | 169 |
| 169 void BreakableStatementChecker::VisitSlot(Slot* expr) { | |
| 170 } | |
| 171 | |
| 172 | |
| 173 void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) { | 170 void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) { |
| 174 } | 171 } |
| 175 | 172 |
| 176 | 173 |
| 177 void BreakableStatementChecker::VisitLiteral(Literal* expr) { | 174 void BreakableStatementChecker::VisitLiteral(Literal* expr) { |
| 178 } | 175 } |
| 179 | 176 |
| 180 | 177 |
| 181 void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) { | 178 void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 182 } | 179 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 | 273 |
| 277 | 274 |
| 278 #define __ ACCESS_MASM(masm()) | 275 #define __ ACCESS_MASM(masm()) |
| 279 | 276 |
| 280 bool FullCodeGenerator::MakeCode(CompilationInfo* info) { | 277 bool FullCodeGenerator::MakeCode(CompilationInfo* info) { |
| 281 Handle<Script> script = info->script(); | 278 Handle<Script> script = info->script(); |
| 282 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | 279 if (!script->IsUndefined() && !script->source()->IsUndefined()) { |
| 283 int len = String::cast(script->source())->length(); | 280 int len = String::cast(script->source())->length(); |
| 284 COUNTERS->total_full_codegen_source_size()->Increment(len); | 281 COUNTERS->total_full_codegen_source_size()->Increment(len); |
| 285 } | 282 } |
| 283 if (FLAG_trace_codegen) { |
| 284 PrintF("Full Compiler - "); |
| 285 } |
| 286 CodeGenerator::MakeCodePrologue(info); | 286 CodeGenerator::MakeCodePrologue(info); |
| 287 const int kInitialBufferSize = 4 * KB; | 287 const int kInitialBufferSize = 4 * KB; |
| 288 MacroAssembler masm(NULL, kInitialBufferSize); | 288 MacroAssembler masm(NULL, kInitialBufferSize); |
| 289 | 289 |
| 290 FullCodeGenerator cgen(&masm); | 290 FullCodeGenerator cgen(&masm); |
| 291 cgen.Generate(info); | 291 cgen.Generate(info); |
| 292 if (cgen.HasStackOverflow()) { | 292 if (cgen.HasStackOverflow()) { |
| 293 ASSERT(!Isolate::Current()->has_pending_exception()); | 293 ASSERT(!Isolate::Current()->has_pending_exception()); |
| 294 return false; | 294 return false; |
| 295 } | 295 } |
| 296 unsigned table_offset = cgen.EmitStackCheckTable(); |
| 296 | 297 |
| 297 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); | 298 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); |
| 298 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); | 299 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); |
| 300 code->set_optimizable(info->IsOptimizable()); |
| 301 cgen.PopulateDeoptimizationData(code); |
| 302 code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); |
| 303 code->set_allow_osr_at_loop_nesting_level(0); |
| 304 code->set_stack_check_table_start(table_offset); |
| 305 CodeGenerator::PrintCode(code, info); |
| 299 info->SetCode(code); // may be an empty handle. | 306 info->SetCode(code); // may be an empty handle. |
| 300 return !code.is_null(); | 307 return !code.is_null(); |
| 301 } | 308 } |
| 302 | 309 |
| 303 | 310 |
| 311 unsigned 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 masm()->RecordComment("[ Stack check table"); |
| 317 unsigned offset = masm()->pc_offset(); |
| 318 unsigned length = stack_checks_.length(); |
| 319 __ dd(length); |
| 320 for (unsigned i = 0; i < length; ++i) { |
| 321 __ dd(stack_checks_[i].id); |
| 322 __ dd(stack_checks_[i].pc_and_state); |
| 323 } |
| 324 masm()->RecordComment("]"); |
| 325 return offset; |
| 326 } |
| 327 |
| 328 |
| 329 void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) { |
| 330 // Fill in the deoptimization information. |
| 331 ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty()); |
| 332 if (!info_->HasDeoptimizationSupport()) return; |
| 333 int length = bailout_entries_.length(); |
| 334 Handle<DeoptimizationOutputData> data = |
| 335 Isolate::Current()->factory()-> |
| 336 NewDeoptimizationOutputData(length, TENURED); |
| 337 for (int i = 0; i < length; i++) { |
| 338 data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id)); |
| 339 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state)); |
| 340 } |
| 341 code->set_deoptimization_data(*data); |
| 342 } |
| 343 |
| 344 |
| 345 void FullCodeGenerator::PrepareForBailout(AstNode* node, State state) { |
| 346 PrepareForBailoutForId(node->id(), state); |
| 347 } |
| 348 |
| 349 |
| 350 void FullCodeGenerator::RecordJSReturnSite(Call* call) { |
| 351 // We record the offset of the function return so we can rebuild the frame |
| 352 // if the function was inlined, i.e., this is the return address in the |
| 353 // inlined function's frame. |
| 354 // |
| 355 // The state is ignored. We defensively set it to TOS_REG, which is the |
| 356 // real state of the unoptimized code at the return site. |
| 357 PrepareForBailoutForId(call->ReturnId(), TOS_REG); |
| 358 #ifdef DEBUG |
| 359 // In debug builds, mark the return so we can verify that this function |
| 360 // was called. |
| 361 ASSERT(!call->return_is_recorded_); |
| 362 call->return_is_recorded_ = true; |
| 363 #endif |
| 364 } |
| 365 |
| 366 |
| 367 void FullCodeGenerator::PrepareForBailoutForId(int id, State state) { |
| 368 // There's no need to prepare this code for bailouts from already optimized |
| 369 // code or code that can't be optimized. |
| 370 if (!FLAG_deopt || !info_->HasDeoptimizationSupport()) return; |
| 371 unsigned pc_and_state = |
| 372 StateField::encode(state) | PcField::encode(masm_->pc_offset()); |
| 373 BailoutEntry entry = { id, pc_and_state }; |
| 374 #ifdef DEBUG |
| 375 // Assert that we don't have multiple bailout entries for the same node. |
| 376 for (int i = 0; i < bailout_entries_.length(); i++) { |
| 377 if (bailout_entries_.at(i).id == entry.id) { |
| 378 AstPrinter printer; |
| 379 PrintF("%s", printer.PrintProgram(info_->function())); |
| 380 UNREACHABLE(); |
| 381 } |
| 382 } |
| 383 #endif // DEBUG |
| 384 bailout_entries_.Add(entry); |
| 385 } |
| 386 |
| 387 |
| 388 void FullCodeGenerator::RecordStackCheck(int ast_id) { |
| 389 // The pc offset does not need to be encoded and packed together with a |
| 390 // state. |
| 391 BailoutEntry entry = { ast_id, masm_->pc_offset() }; |
| 392 stack_checks_.Add(entry); |
| 393 } |
| 394 |
| 395 |
| 304 int FullCodeGenerator::SlotOffset(Slot* slot) { | 396 int FullCodeGenerator::SlotOffset(Slot* slot) { |
| 305 ASSERT(slot != NULL); | 397 ASSERT(slot != NULL); |
| 306 // Offset is negative because higher indexes are at lower addresses. | 398 // Offset is negative because higher indexes are at lower addresses. |
| 307 int offset = -slot->index() * kPointerSize; | 399 int offset = -slot->index() * kPointerSize; |
| 308 // Adjust by a (parameter or local) base offset. | 400 // Adjust by a (parameter or local) base offset. |
| 309 switch (slot->type()) { | 401 switch (slot->type()) { |
| 310 case Slot::PARAMETER: | 402 case Slot::PARAMETER: |
| 311 offset += (scope()->num_parameters() + 1) * kPointerSize; | 403 offset += (scope()->num_parameters() + 1) * kPointerSize; |
| 312 break; | 404 break; |
| 313 case Slot::LOCAL: | 405 case Slot::LOCAL: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 328 if (FLAG_always_inline_smi_code) return true; | 420 if (FLAG_always_inline_smi_code) return true; |
| 329 return loop_depth_ > 0; | 421 return loop_depth_ > 0; |
| 330 } | 422 } |
| 331 | 423 |
| 332 | 424 |
| 333 void FullCodeGenerator::EffectContext::Plug(Register reg) const { | 425 void FullCodeGenerator::EffectContext::Plug(Register reg) const { |
| 334 } | 426 } |
| 335 | 427 |
| 336 | 428 |
| 337 void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { | 429 void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { |
| 338 // Move value into place. | |
| 339 __ Move(result_register(), reg); | 430 __ Move(result_register(), reg); |
| 340 } | 431 } |
| 341 | 432 |
| 342 | 433 |
| 343 void FullCodeGenerator::StackValueContext::Plug(Register reg) const { | 434 void FullCodeGenerator::StackValueContext::Plug(Register reg) const { |
| 344 // Move value into place. | |
| 345 __ push(reg); | 435 __ push(reg); |
| 346 } | 436 } |
| 347 | 437 |
| 348 | 438 |
| 349 void FullCodeGenerator::TestContext::Plug(Register reg) const { | 439 void FullCodeGenerator::TestContext::Plug(Register reg) const { |
| 350 // For simplicity we always test the accumulator register. | 440 // For simplicity we always test the accumulator register. |
| 351 __ Move(result_register(), reg); | 441 __ Move(result_register(), reg); |
| 442 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 352 codegen()->DoTest(true_label_, false_label_, fall_through_); | 443 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 353 } | 444 } |
| 354 | 445 |
| 355 | 446 |
| 356 void FullCodeGenerator::EffectContext::PlugTOS() const { | 447 void FullCodeGenerator::EffectContext::PlugTOS() const { |
| 357 __ Drop(1); | 448 __ Drop(1); |
| 358 } | 449 } |
| 359 | 450 |
| 360 | 451 |
| 361 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { | 452 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { |
| 362 __ pop(result_register()); | 453 __ pop(result_register()); |
| 363 } | 454 } |
| 364 | 455 |
| 365 | 456 |
| 366 void FullCodeGenerator::StackValueContext::PlugTOS() const { | 457 void FullCodeGenerator::StackValueContext::PlugTOS() const { |
| 367 } | 458 } |
| 368 | 459 |
| 369 | 460 |
| 370 void FullCodeGenerator::TestContext::PlugTOS() const { | 461 void FullCodeGenerator::TestContext::PlugTOS() const { |
| 371 // For simplicity we always test the accumulator register. | 462 // For simplicity we always test the accumulator register. |
| 372 __ pop(result_register()); | 463 __ pop(result_register()); |
| 464 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 373 codegen()->DoTest(true_label_, false_label_, fall_through_); | 465 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 374 } | 466 } |
| 375 | 467 |
| 376 | 468 |
| 377 void FullCodeGenerator::EffectContext::PrepareTest( | 469 void FullCodeGenerator::EffectContext::PrepareTest( |
| 378 Label* materialize_true, | 470 Label* materialize_true, |
| 379 Label* materialize_false, | 471 Label* materialize_false, |
| 380 Label** if_true, | 472 Label** if_true, |
| 381 Label** if_false, | 473 Label** if_false, |
| 382 Label** fall_through) const { | 474 Label** fall_through) const { |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 OverwriteMode mode = NO_OVERWRITE; | 699 OverwriteMode mode = NO_OVERWRITE; |
| 608 if (left->ResultOverwriteAllowed()) { | 700 if (left->ResultOverwriteAllowed()) { |
| 609 mode = OVERWRITE_LEFT; | 701 mode = OVERWRITE_LEFT; |
| 610 } else if (right->ResultOverwriteAllowed()) { | 702 } else if (right->ResultOverwriteAllowed()) { |
| 611 mode = OVERWRITE_RIGHT; | 703 mode = OVERWRITE_RIGHT; |
| 612 } | 704 } |
| 613 | 705 |
| 614 switch (op) { | 706 switch (op) { |
| 615 case Token::COMMA: | 707 case Token::COMMA: |
| 616 VisitForEffect(left); | 708 VisitForEffect(left); |
| 617 Visit(right); | 709 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 710 context()->HandleExpression(right); |
| 618 break; | 711 break; |
| 619 | 712 |
| 620 case Token::OR: | 713 case Token::OR: |
| 621 case Token::AND: | 714 case Token::AND: |
| 622 EmitLogicalOperation(expr); | 715 EmitLogicalOperation(expr); |
| 623 break; | 716 break; |
| 624 | 717 |
| 625 case Token::ADD: | 718 case Token::ADD: |
| 626 case Token::SUB: | 719 case Token::SUB: |
| 627 case Token::DIV: | 720 case Token::DIV: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 } | 756 } |
| 664 } | 757 } |
| 665 | 758 |
| 666 | 759 |
| 667 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 760 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
| 668 Label eval_right, done; | 761 Label eval_right, done; |
| 669 | 762 |
| 670 context()->EmitLogicalLeft(expr, &eval_right, &done); | 763 context()->EmitLogicalLeft(expr, &eval_right, &done); |
| 671 | 764 |
| 672 __ bind(&eval_right); | 765 __ bind(&eval_right); |
| 673 Visit(expr->right()); | 766 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 767 context()->HandleExpression(expr->right()); |
| 674 | 768 |
| 675 __ bind(&done); | 769 __ bind(&done); |
| 676 } | 770 } |
| 677 | 771 |
| 678 | 772 |
| 679 void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr, | 773 void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr, |
| 680 Label* eval_right, | 774 Label* eval_right, |
| 681 Label* done) const { | 775 Label* done) const { |
| 682 if (expr->op() == Token::OR) { | 776 if (expr->op() == Token::OR) { |
| 683 codegen()->VisitForControl(expr->left(), done, eval_right, eval_right); | 777 codegen()->VisitForControl(expr->left(), done, eval_right, eval_right); |
| 684 } else { | 778 } else { |
| 685 ASSERT(expr->op() == Token::AND); | 779 ASSERT(expr->op() == Token::AND); |
| 686 codegen()->VisitForControl(expr->left(), eval_right, done, eval_right); | 780 codegen()->VisitForControl(expr->left(), eval_right, done, eval_right); |
| 687 } | 781 } |
| 688 } | 782 } |
| 689 | 783 |
| 690 | 784 |
| 691 void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft( | 785 void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft( |
| 692 BinaryOperation* expr, | 786 BinaryOperation* expr, |
| 693 Label* eval_right, | 787 Label* eval_right, |
| 694 Label* done) const { | 788 Label* done) const { |
| 695 codegen()->Visit(expr->left()); | 789 HandleExpression(expr->left()); |
| 696 // We want the value in the accumulator for the test, and on the stack in case | 790 // We want the value in the accumulator for the test, and on the stack in case |
| 697 // we need it. | 791 // we need it. |
| 698 __ push(result_register()); | 792 __ push(result_register()); |
| 699 Label discard, restore; | 793 Label discard, restore; |
| 700 if (expr->op() == Token::OR) { | 794 if (expr->op() == Token::OR) { |
| 795 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 701 codegen()->DoTest(&restore, &discard, &restore); | 796 codegen()->DoTest(&restore, &discard, &restore); |
| 702 } else { | 797 } else { |
| 703 ASSERT(expr->op() == Token::AND); | 798 ASSERT(expr->op() == Token::AND); |
| 799 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 704 codegen()->DoTest(&discard, &restore, &restore); | 800 codegen()->DoTest(&discard, &restore, &restore); |
| 705 } | 801 } |
| 706 __ bind(&restore); | 802 __ bind(&restore); |
| 707 __ pop(result_register()); | 803 __ pop(result_register()); |
| 708 __ jmp(done); | 804 __ jmp(done); |
| 709 __ bind(&discard); | 805 __ bind(&discard); |
| 710 __ Drop(1); | 806 __ Drop(1); |
| 711 } | 807 } |
| 712 | 808 |
| 713 | 809 |
| 714 void FullCodeGenerator::StackValueContext::EmitLogicalLeft( | 810 void FullCodeGenerator::StackValueContext::EmitLogicalLeft( |
| 715 BinaryOperation* expr, | 811 BinaryOperation* expr, |
| 716 Label* eval_right, | 812 Label* eval_right, |
| 717 Label* done) const { | 813 Label* done) const { |
| 718 codegen()->VisitForAccumulatorValue(expr->left()); | 814 codegen()->VisitForAccumulatorValue(expr->left()); |
| 719 // We want the value in the accumulator for the test, and on the stack in case | 815 // We want the value in the accumulator for the test, and on the stack in case |
| 720 // we need it. | 816 // we need it. |
| 721 __ push(result_register()); | 817 __ push(result_register()); |
| 722 Label discard; | 818 Label discard; |
| 723 if (expr->op() == Token::OR) { | 819 if (expr->op() == Token::OR) { |
| 820 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 724 codegen()->DoTest(done, &discard, &discard); | 821 codegen()->DoTest(done, &discard, &discard); |
| 725 } else { | 822 } else { |
| 726 ASSERT(expr->op() == Token::AND); | 823 ASSERT(expr->op() == Token::AND); |
| 824 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 727 codegen()->DoTest(&discard, done, &discard); | 825 codegen()->DoTest(&discard, done, &discard); |
| 728 } | 826 } |
| 729 __ bind(&discard); | 827 __ bind(&discard); |
| 730 __ Drop(1); | 828 __ Drop(1); |
| 731 } | 829 } |
| 732 | 830 |
| 733 | 831 |
| 734 void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr, | 832 void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr, |
| 735 Label* eval_right, | 833 Label* eval_right, |
| 736 Label* done) const { | 834 Label* done) const { |
| 737 if (expr->op() == Token::OR) { | 835 if (expr->op() == Token::OR) { |
| 738 codegen()->VisitForControl(expr->left(), | 836 codegen()->VisitForControl(expr->left(), |
| 739 true_label_, eval_right, eval_right); | 837 true_label_, eval_right, eval_right); |
| 740 } else { | 838 } else { |
| 741 ASSERT(expr->op() == Token::AND); | 839 ASSERT(expr->op() == Token::AND); |
| 742 codegen()->VisitForControl(expr->left(), | 840 codegen()->VisitForControl(expr->left(), |
| 743 eval_right, false_label_, eval_right); | 841 eval_right, false_label_, eval_right); |
| 744 } | 842 } |
| 745 } | 843 } |
| 746 | 844 |
| 747 | 845 |
| 846 void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) { |
| 847 if (!info_->HasDeoptimizationSupport()) return; |
| 848 ASSERT(context()->IsTest()); |
| 849 ASSERT(expr == forward_bailout_stack_->expr()); |
| 850 forward_bailout_pending_ = forward_bailout_stack_; |
| 851 } |
| 852 |
| 853 |
| 854 void FullCodeGenerator::EffectContext::HandleExpression( |
| 855 Expression* expr) const { |
| 856 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); |
| 857 } |
| 858 |
| 859 |
| 860 void FullCodeGenerator::AccumulatorValueContext::HandleExpression( |
| 861 Expression* expr) const { |
| 862 codegen()->HandleInNonTestContext(expr, TOS_REG); |
| 863 } |
| 864 |
| 865 |
| 866 void FullCodeGenerator::StackValueContext::HandleExpression( |
| 867 Expression* expr) const { |
| 868 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); |
| 869 } |
| 870 |
| 871 |
| 872 void FullCodeGenerator::TestContext::HandleExpression(Expression* expr) const { |
| 873 codegen()->VisitInTestContext(expr); |
| 874 } |
| 875 |
| 876 |
| 877 void FullCodeGenerator::HandleInNonTestContext(Expression* expr, State state) { |
| 878 ASSERT(forward_bailout_pending_ == NULL); |
| 879 AstVisitor::Visit(expr); |
| 880 PrepareForBailout(expr, state); |
| 881 // Forwarding bailouts to children is a one shot operation. It |
| 882 // should have been processed at this point. |
| 883 ASSERT(forward_bailout_pending_ == NULL); |
| 884 } |
| 885 |
| 886 |
| 887 void FullCodeGenerator::VisitInTestContext(Expression* expr) { |
| 888 ForwardBailoutStack stack(expr, forward_bailout_pending_); |
| 889 ForwardBailoutStack* saved = forward_bailout_stack_; |
| 890 forward_bailout_pending_ = NULL; |
| 891 forward_bailout_stack_ = &stack; |
| 892 AstVisitor::Visit(expr); |
| 893 forward_bailout_stack_ = saved; |
| 894 } |
| 895 |
| 896 |
| 748 void FullCodeGenerator::VisitBlock(Block* stmt) { | 897 void FullCodeGenerator::VisitBlock(Block* stmt) { |
| 749 Comment cmnt(masm_, "[ Block"); | 898 Comment cmnt(masm_, "[ Block"); |
| 750 Breakable nested_statement(this, stmt); | 899 Breakable nested_statement(this, stmt); |
| 751 SetStatementPosition(stmt); | 900 SetStatementPosition(stmt); |
| 901 |
| 902 PrepareForBailoutForId(stmt->EntryId(), TOS_REG); |
| 752 VisitStatements(stmt->statements()); | 903 VisitStatements(stmt->statements()); |
| 753 __ bind(nested_statement.break_target()); | 904 __ bind(nested_statement.break_target()); |
| 905 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 754 } | 906 } |
| 755 | 907 |
| 756 | 908 |
| 757 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 909 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 758 Comment cmnt(masm_, "[ ExpressionStatement"); | 910 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 759 SetStatementPosition(stmt); | 911 SetStatementPosition(stmt); |
| 760 VisitForEffect(stmt->expression()); | 912 VisitForEffect(stmt->expression()); |
| 761 } | 913 } |
| 762 | 914 |
| 763 | 915 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 779 __ jmp(&done); | 931 __ jmp(&done); |
| 780 | 932 |
| 781 __ bind(&else_part); | 933 __ bind(&else_part); |
| 782 Visit(stmt->else_statement()); | 934 Visit(stmt->else_statement()); |
| 783 } else { | 935 } else { |
| 784 VisitForControl(stmt->condition(), &then_part, &done, &then_part); | 936 VisitForControl(stmt->condition(), &then_part, &done, &then_part); |
| 785 __ bind(&then_part); | 937 __ bind(&then_part); |
| 786 Visit(stmt->then_statement()); | 938 Visit(stmt->then_statement()); |
| 787 } | 939 } |
| 788 __ bind(&done); | 940 __ bind(&done); |
| 941 PrepareForBailoutForId(stmt->id(), NO_REGISTERS); |
| 789 } | 942 } |
| 790 | 943 |
| 791 | 944 |
| 792 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | 945 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| 793 Comment cmnt(masm_, "[ ContinueStatement"); | 946 Comment cmnt(masm_, "[ ContinueStatement"); |
| 794 SetStatementPosition(stmt); | 947 SetStatementPosition(stmt); |
| 795 NestedStatement* current = nesting_stack_; | 948 NestedStatement* current = nesting_stack_; |
| 796 int stack_depth = 0; | 949 int stack_depth = 0; |
| 797 while (!current->IsContinueTarget(stmt->target())) { | 950 while (!current->IsContinueTarget(stmt->target())) { |
| 798 stack_depth = current->Exit(stack_depth); | 951 stack_depth = current->Exit(stack_depth); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 // Pop context. | 1018 // Pop context. |
| 866 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 1019 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 867 // Update local stack frame context field. | 1020 // Update local stack frame context field. |
| 868 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | 1021 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
| 869 } | 1022 } |
| 870 | 1023 |
| 871 | 1024 |
| 872 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 1025 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 873 Comment cmnt(masm_, "[ DoWhileStatement"); | 1026 Comment cmnt(masm_, "[ DoWhileStatement"); |
| 874 SetStatementPosition(stmt); | 1027 SetStatementPosition(stmt); |
| 875 Label body, stack_limit_hit, stack_check_success, done; | 1028 Label body, stack_check; |
| 876 | 1029 |
| 877 Iteration loop_statement(this, stmt); | 1030 Iteration loop_statement(this, stmt); |
| 878 increment_loop_depth(); | 1031 increment_loop_depth(); |
| 879 | 1032 |
| 880 __ bind(&body); | 1033 __ bind(&body); |
| 881 Visit(stmt->body()); | 1034 Visit(stmt->body()); |
| 882 | 1035 |
| 883 // Check stack before looping. | |
| 884 __ bind(loop_statement.continue_target()); | |
| 885 __ StackLimitCheck(&stack_limit_hit); | |
| 886 __ bind(&stack_check_success); | |
| 887 | |
| 888 // Record the position of the do while condition and make sure it is | 1036 // Record the position of the do while condition and make sure it is |
| 889 // possible to break on the condition. | 1037 // possible to break on the condition. |
| 1038 __ bind(loop_statement.continue_target()); |
| 1039 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); |
| 890 SetExpressionPosition(stmt->cond(), stmt->condition_position()); | 1040 SetExpressionPosition(stmt->cond(), stmt->condition_position()); |
| 891 VisitForControl(stmt->cond(), | 1041 VisitForControl(stmt->cond(), |
| 1042 &stack_check, |
| 1043 loop_statement.break_target(), |
| 1044 &stack_check); |
| 1045 |
| 1046 // Check stack before looping. |
| 1047 __ bind(&stack_check); |
| 1048 EmitStackCheck(stmt); |
| 1049 __ jmp(&body); |
| 1050 |
| 1051 __ bind(loop_statement.break_target()); |
| 1052 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1053 decrement_loop_depth(); |
| 1054 } |
| 1055 |
| 1056 |
| 1057 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
| 1058 Comment cmnt(masm_, "[ WhileStatement"); |
| 1059 Label test, body; |
| 1060 |
| 1061 Iteration loop_statement(this, stmt); |
| 1062 increment_loop_depth(); |
| 1063 |
| 1064 // Emit the test at the bottom of the loop. |
| 1065 __ jmp(&test); |
| 1066 |
| 1067 __ bind(&body); |
| 1068 Visit(stmt->body()); |
| 1069 |
| 1070 // Emit the statement position here as this is where the while |
| 1071 // statement code starts. |
| 1072 __ bind(loop_statement.continue_target()); |
| 1073 SetStatementPosition(stmt); |
| 1074 |
| 1075 // Check stack before looping. |
| 1076 EmitStackCheck(stmt); |
| 1077 |
| 1078 __ bind(&test); |
| 1079 VisitForControl(stmt->cond(), |
| 892 &body, | 1080 &body, |
| 893 loop_statement.break_target(), | 1081 loop_statement.break_target(), |
| 894 loop_statement.break_target()); | 1082 loop_statement.break_target()); |
| 895 | 1083 |
| 896 __ bind(loop_statement.break_target()); | 1084 __ bind(loop_statement.break_target()); |
| 897 __ jmp(&done); | 1085 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 898 | |
| 899 __ bind(&stack_limit_hit); | |
| 900 StackCheckStub stack_stub; | |
| 901 __ CallStub(&stack_stub); | |
| 902 __ jmp(&stack_check_success); | |
| 903 | |
| 904 __ bind(&done); | |
| 905 decrement_loop_depth(); | |
| 906 } | |
| 907 | |
| 908 | |
| 909 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | |
| 910 Comment cmnt(masm_, "[ WhileStatement"); | |
| 911 Label body, stack_limit_hit, stack_check_success, done; | |
| 912 | |
| 913 Iteration loop_statement(this, stmt); | |
| 914 increment_loop_depth(); | |
| 915 | |
| 916 // Emit the test at the bottom of the loop. | |
| 917 __ jmp(loop_statement.continue_target()); | |
| 918 | |
| 919 __ bind(&body); | |
| 920 Visit(stmt->body()); | |
| 921 __ bind(loop_statement.continue_target()); | |
| 922 | |
| 923 // Emit the statement position here as this is where the while | |
| 924 // statement code starts. | |
| 925 SetStatementPosition(stmt); | |
| 926 | |
| 927 // Check stack before looping. | |
| 928 __ StackLimitCheck(&stack_limit_hit); | |
| 929 __ bind(&stack_check_success); | |
| 930 | |
| 931 VisitForControl(stmt->cond(), | |
| 932 &body, | |
| 933 loop_statement.break_target(), | |
| 934 loop_statement.break_target()); | |
| 935 | |
| 936 __ bind(loop_statement.break_target()); | |
| 937 __ jmp(&done); | |
| 938 | |
| 939 __ bind(&stack_limit_hit); | |
| 940 StackCheckStub stack_stub; | |
| 941 __ CallStub(&stack_stub); | |
| 942 __ jmp(&stack_check_success); | |
| 943 | |
| 944 __ bind(&done); | |
| 945 decrement_loop_depth(); | 1086 decrement_loop_depth(); |
| 946 } | 1087 } |
| 947 | 1088 |
| 948 | 1089 |
| 949 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { | 1090 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { |
| 950 Comment cmnt(masm_, "[ ForStatement"); | 1091 Comment cmnt(masm_, "[ ForStatement"); |
| 951 Label test, body, stack_limit_hit, stack_check_success; | 1092 Label test, body; |
| 952 | 1093 |
| 953 Iteration loop_statement(this, stmt); | 1094 Iteration loop_statement(this, stmt); |
| 954 if (stmt->init() != NULL) { | 1095 if (stmt->init() != NULL) { |
| 955 Visit(stmt->init()); | 1096 Visit(stmt->init()); |
| 956 } | 1097 } |
| 957 | 1098 |
| 958 increment_loop_depth(); | 1099 increment_loop_depth(); |
| 959 // Emit the test at the bottom of the loop (even if empty). | 1100 // Emit the test at the bottom of the loop (even if empty). |
| 960 __ jmp(&test); | 1101 __ jmp(&test); |
| 961 | 1102 |
| 962 __ bind(&stack_limit_hit); | |
| 963 StackCheckStub stack_stub; | |
| 964 __ CallStub(&stack_stub); | |
| 965 __ jmp(&stack_check_success); | |
| 966 | |
| 967 __ bind(&body); | 1103 __ bind(&body); |
| 968 Visit(stmt->body()); | 1104 Visit(stmt->body()); |
| 969 | 1105 |
| 970 __ bind(loop_statement.continue_target()); | 1106 __ bind(loop_statement.continue_target()); |
| 1107 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); |
| 971 | 1108 |
| 972 SetStatementPosition(stmt); | 1109 SetStatementPosition(stmt); |
| 973 if (stmt->next() != NULL) { | 1110 if (stmt->next() != NULL) { |
| 974 Visit(stmt->next()); | 1111 Visit(stmt->next()); |
| 975 } | 1112 } |
| 976 | 1113 |
| 977 __ bind(&test); | |
| 978 // Emit the statement position here as this is where the for | 1114 // Emit the statement position here as this is where the for |
| 979 // statement code starts. | 1115 // statement code starts. |
| 980 SetStatementPosition(stmt); | 1116 SetStatementPosition(stmt); |
| 981 | 1117 |
| 982 // Check stack before looping. | 1118 // Check stack before looping. |
| 983 __ StackLimitCheck(&stack_limit_hit); | 1119 EmitStackCheck(stmt); |
| 984 __ bind(&stack_check_success); | |
| 985 | 1120 |
| 1121 __ bind(&test); |
| 986 if (stmt->cond() != NULL) { | 1122 if (stmt->cond() != NULL) { |
| 987 VisitForControl(stmt->cond(), | 1123 VisitForControl(stmt->cond(), |
| 988 &body, | 1124 &body, |
| 989 loop_statement.break_target(), | 1125 loop_statement.break_target(), |
| 990 loop_statement.break_target()); | 1126 loop_statement.break_target()); |
| 991 } else { | 1127 } else { |
| 992 __ jmp(&body); | 1128 __ jmp(&body); |
| 993 } | 1129 } |
| 994 | 1130 |
| 995 __ bind(loop_statement.break_target()); | 1131 __ bind(loop_statement.break_target()); |
| 1132 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 996 decrement_loop_depth(); | 1133 decrement_loop_depth(); |
| 997 } | 1134 } |
| 998 | 1135 |
| 999 | 1136 |
| 1000 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1137 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 1001 Comment cmnt(masm_, "[ TryCatchStatement"); | 1138 Comment cmnt(masm_, "[ TryCatchStatement"); |
| 1002 SetStatementPosition(stmt); | 1139 SetStatementPosition(stmt); |
| 1003 // The try block adds a handler to the exception handler chain | 1140 // The try block adds a handler to the exception handler chain |
| 1004 // before entering, and removes it again when exiting normally. | 1141 // before entering, and removes it again when exiting normally. |
| 1005 // If an exception is thrown during execution of the try block, | 1142 // If an exception is thrown during execution of the try block, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 __ bind(&true_case); | 1260 __ bind(&true_case); |
| 1124 SetExpressionPosition(expr->then_expression(), | 1261 SetExpressionPosition(expr->then_expression(), |
| 1125 expr->then_expression_position()); | 1262 expr->then_expression_position()); |
| 1126 if (context()->IsTest()) { | 1263 if (context()->IsTest()) { |
| 1127 const TestContext* for_test = TestContext::cast(context()); | 1264 const TestContext* for_test = TestContext::cast(context()); |
| 1128 VisitForControl(expr->then_expression(), | 1265 VisitForControl(expr->then_expression(), |
| 1129 for_test->true_label(), | 1266 for_test->true_label(), |
| 1130 for_test->false_label(), | 1267 for_test->false_label(), |
| 1131 NULL); | 1268 NULL); |
| 1132 } else { | 1269 } else { |
| 1133 Visit(expr->then_expression()); | 1270 context()->HandleExpression(expr->then_expression()); |
| 1134 __ jmp(&done); | 1271 __ jmp(&done); |
| 1135 } | 1272 } |
| 1136 | 1273 |
| 1137 __ bind(&false_case); | 1274 __ bind(&false_case); |
| 1275 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 1138 SetExpressionPosition(expr->else_expression(), | 1276 SetExpressionPosition(expr->else_expression(), |
| 1139 expr->else_expression_position()); | 1277 expr->else_expression_position()); |
| 1140 Visit(expr->else_expression()); | 1278 context()->HandleExpression(expr->else_expression()); |
| 1141 // If control flow falls through Visit, merge it with true case here. | 1279 // If control flow falls through Visit, merge it with true case here. |
| 1142 if (!context()->IsTest()) { | 1280 if (!context()->IsTest()) { |
| 1143 __ bind(&done); | 1281 __ bind(&done); |
| 1144 } | 1282 } |
| 1145 } | 1283 } |
| 1146 | 1284 |
| 1147 | 1285 |
| 1148 void FullCodeGenerator::VisitSlot(Slot* expr) { | |
| 1149 // Slots do not appear directly in the AST. | |
| 1150 UNREACHABLE(); | |
| 1151 } | |
| 1152 | |
| 1153 | |
| 1154 void FullCodeGenerator::VisitLiteral(Literal* expr) { | 1286 void FullCodeGenerator::VisitLiteral(Literal* expr) { |
| 1155 Comment cmnt(masm_, "[ Literal"); | 1287 Comment cmnt(masm_, "[ Literal"); |
| 1156 context()->Plug(expr->handle()); | 1288 context()->Plug(expr->handle()); |
| 1157 } | 1289 } |
| 1158 | 1290 |
| 1159 | 1291 |
| 1160 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1292 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 1161 Comment cmnt(masm_, "[ FunctionLiteral"); | 1293 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 1162 | 1294 |
| 1163 // Build the function boilerplate and instantiate it. | 1295 // Build the function boilerplate and instantiate it. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1217 __ Drop(stack_depth); | 1349 __ Drop(stack_depth); |
| 1218 __ PopTryHandler(); | 1350 __ PopTryHandler(); |
| 1219 return 0; | 1351 return 0; |
| 1220 } | 1352 } |
| 1221 | 1353 |
| 1222 | 1354 |
| 1223 #undef __ | 1355 #undef __ |
| 1224 | 1356 |
| 1225 | 1357 |
| 1226 } } // namespace v8::internal | 1358 } } // namespace v8::internal |
| OLD | NEW |