Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 |
| (...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 680 // code by jumping to the return site. | 680 // code by jumping to the return site. |
| 681 function_return_.Jump(&return_value); | 681 function_return_.Jump(&return_value); |
| 682 } else { | 682 } else { |
| 683 function_return_.Bind(&return_value); | 683 function_return_.Bind(&return_value); |
| 684 GenerateReturnSequence(&return_value); | 684 GenerateReturnSequence(&return_value); |
| 685 } | 685 } |
| 686 } | 686 } |
| 687 } | 687 } |
| 688 | 688 |
| 689 | 689 |
| 690 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* a) { | 690 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 691 UNIMPLEMENTED(); | 691 ASSERT(!in_spilled_code()); |
| 692 } | 692 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 693 CodeForStatementPosition(node); | |
| 694 Load(node->expression()); | |
| 695 Result context; | |
| 696 if (node->is_catch_block()) { | |
| 697 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); | |
| 698 } else { | |
| 699 context = frame_->CallRuntime(Runtime::kPushContext, 1); | |
| 700 } | |
| 693 | 701 |
| 694 void CodeGenerator::VisitWithExitStatement(WithExitStatement* a) { | 702 // Update context local. |
| 695 UNIMPLEMENTED(); | 703 frame_->SaveContextRegister(); |
| 696 } | |
| 697 | 704 |
| 698 void CodeGenerator::VisitSwitchStatement(SwitchStatement* a) { | 705 // Verify that the runtime call result and esi agree. |
|
William Hesse
2009/06/26 08:25:18
rsi
| |
| 699 UNIMPLEMENTED(); | 706 if (FLAG_debug_code) { |
| 707 __ cmpq(context.reg(), rsi); | |
| 708 __ Assert(equal, "Runtime::NewContext should end up in rsi"); | |
| 709 } | |
| 700 } | 710 } |
| 701 | 711 |
| 702 | 712 |
| 713 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | |
| 714 ASSERT(!in_spilled_code()); | |
| 715 Comment cmnt(masm_, "[ WithExitStatement"); | |
| 716 CodeForStatementPosition(node); | |
| 717 // Pop context. | |
| 718 __ movq(rsi, ContextOperand(rsi, Context::PREVIOUS_INDEX)); | |
| 719 // Update context local. | |
| 720 frame_->SaveContextRegister(); | |
| 721 } | |
| 722 | |
| 723 | |
| 724 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | |
| 725 // TODO(X64): This code is completely generic and should be moved somewhere | |
| 726 // where it can be shared between architectures. | |
| 727 ASSERT(!in_spilled_code()); | |
| 728 Comment cmnt(masm_, "[ SwitchStatement"); | |
| 729 CodeForStatementPosition(node); | |
| 730 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | |
| 731 | |
| 732 // Compile the switch value. | |
| 733 Load(node->tag()); | |
| 734 | |
| 735 ZoneList<CaseClause*>* cases = node->cases(); | |
| 736 int length = cases->length(); | |
| 737 CaseClause* default_clause = NULL; | |
| 738 | |
| 739 JumpTarget next_test; | |
| 740 // Compile the case label expressions and comparisons. Exit early | |
| 741 // if a comparison is unconditionally true. The target next_test is | |
| 742 // bound before the loop in order to indicate control flow to the | |
| 743 // first comparison. | |
| 744 next_test.Bind(); | |
| 745 for (int i = 0; i < length && !next_test.is_unused(); i++) { | |
| 746 CaseClause* clause = cases->at(i); | |
| 747 // The default is not a test, but remember it for later. | |
| 748 if (clause->is_default()) { | |
| 749 default_clause = clause; | |
| 750 continue; | |
| 751 } | |
| 752 | |
| 753 Comment cmnt(masm_, "[ Case comparison"); | |
| 754 // We recycle the same target next_test for each test. Bind it if | |
| 755 // the previous test has not done so and then unuse it for the | |
| 756 // loop. | |
| 757 if (next_test.is_linked()) { | |
| 758 next_test.Bind(); | |
| 759 } | |
| 760 next_test.Unuse(); | |
| 761 | |
| 762 // Duplicate the switch value. | |
| 763 frame_->Dup(); | |
| 764 | |
| 765 // Compile the label expression. | |
| 766 Load(clause->label()); | |
| 767 | |
| 768 // Compare and branch to the body if true or the next test if | |
| 769 // false. Prefer the next test as a fall through. | |
| 770 ControlDestination dest(clause->body_target(), &next_test, false); | |
| 771 Comparison(equal, true, &dest); | |
| 772 | |
| 773 // If the comparison fell through to the true target, jump to the | |
| 774 // actual body. | |
| 775 if (dest.true_was_fall_through()) { | |
| 776 clause->body_target()->Unuse(); | |
| 777 clause->body_target()->Jump(); | |
| 778 } | |
| 779 } | |
| 780 | |
| 781 // If there was control flow to a next test from the last one | |
| 782 // compiled, compile a jump to the default or break target. | |
| 783 if (!next_test.is_unused()) { | |
| 784 if (next_test.is_linked()) { | |
| 785 next_test.Bind(); | |
| 786 } | |
| 787 // Drop the switch value. | |
| 788 frame_->Drop(); | |
| 789 if (default_clause != NULL) { | |
| 790 default_clause->body_target()->Jump(); | |
| 791 } else { | |
| 792 node->break_target()->Jump(); | |
| 793 } | |
| 794 } | |
| 795 | |
| 796 // The last instruction emitted was a jump, either to the default | |
| 797 // clause or the break target, or else to a case body from the loop | |
| 798 // that compiles the tests. | |
| 799 ASSERT(!has_valid_frame()); | |
| 800 // Compile case bodies as needed. | |
| 801 for (int i = 0; i < length; i++) { | |
| 802 CaseClause* clause = cases->at(i); | |
| 803 | |
| 804 // There are two ways to reach the body: from the corresponding | |
| 805 // test or as the fall through of the previous body. | |
| 806 if (clause->body_target()->is_linked() || has_valid_frame()) { | |
| 807 if (clause->body_target()->is_linked()) { | |
| 808 if (has_valid_frame()) { | |
| 809 // If we have both a jump to the test and a fall through, put | |
| 810 // a jump on the fall through path to avoid the dropping of | |
| 811 // the switch value on the test path. The exception is the | |
| 812 // default which has already had the switch value dropped. | |
| 813 if (clause->is_default()) { | |
| 814 clause->body_target()->Bind(); | |
| 815 } else { | |
| 816 JumpTarget body; | |
| 817 body.Jump(); | |
| 818 clause->body_target()->Bind(); | |
| 819 frame_->Drop(); | |
| 820 body.Bind(); | |
| 821 } | |
| 822 } else { | |
| 823 // No fall through to worry about. | |
| 824 clause->body_target()->Bind(); | |
| 825 if (!clause->is_default()) { | |
| 826 frame_->Drop(); | |
| 827 } | |
| 828 } | |
| 829 } else { | |
| 830 // Otherwise, we have only fall through. | |
| 831 ASSERT(has_valid_frame()); | |
| 832 } | |
| 833 | |
| 834 // We are now prepared to compile the body. | |
| 835 Comment cmnt(masm_, "[ Case body"); | |
| 836 VisitStatements(clause->statements()); | |
| 837 } | |
| 838 clause->body_target()->Unuse(); | |
| 839 } | |
| 840 | |
| 841 // We may not have a valid frame here so bind the break target only | |
| 842 // if needed. | |
| 843 if (node->break_target()->is_linked()) { | |
| 844 node->break_target()->Bind(); | |
| 845 } | |
| 846 node->break_target()->Unuse(); | |
| 847 } | |
| 848 | |
| 849 | |
| 703 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 850 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 704 ASSERT(!in_spilled_code()); | 851 ASSERT(!in_spilled_code()); |
| 705 Comment cmnt(masm_, "[ LoopStatement"); | 852 Comment cmnt(masm_, "[ LoopStatement"); |
| 706 CodeForStatementPosition(node); | 853 CodeForStatementPosition(node); |
| 707 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 854 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 708 | 855 |
| 709 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 856 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 710 // known result for the test expression, with no side effects. | 857 // known result for the test expression, with no side effects. |
| 711 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 858 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 712 if (node->cond() == NULL) { | 859 if (node->cond() == NULL) { |
| (...skipping 5297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6010 break; | 6157 break; |
| 6011 default: | 6158 default: |
| 6012 UNREACHABLE(); | 6159 UNREACHABLE(); |
| 6013 } | 6160 } |
| 6014 } | 6161 } |
| 6015 | 6162 |
| 6016 | 6163 |
| 6017 #undef __ | 6164 #undef __ |
| 6018 | 6165 |
| 6019 } } // namespace v8::internal | 6166 } } // namespace v8::internal |
| OLD | NEW |