Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 694 const Runtime::Function* function = node->function(); | 694 const Runtime::Function* function = node->function(); |
| 695 ASSERT(function != NULL); | 695 ASSERT(function != NULL); |
| 696 ASSERT(function->intrinsic_type == Runtime::INLINE); | 696 ASSERT(function->intrinsic_type == Runtime::INLINE); |
| 697 InlineFunctionGenerator generator = | 697 InlineFunctionGenerator generator = |
| 698 FindInlineFunctionGenerator(function->function_id); | 698 FindInlineFunctionGenerator(function->function_id); |
| 699 ((*this).*(generator))(args); | 699 ((*this).*(generator))(args); |
| 700 } | 700 } |
| 701 | 701 |
| 702 | 702 |
| 703 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 703 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 704 Comment cmnt(masm_, "[ BinaryOperation"); | 704 Comment cmnt(masm_, "[ BinaryOperation"); |
|
Kevin Millikin (Chromium)
2011/05/31 11:46:28
By moving this comment into VisitComma, VisitLogic
Sven Panne
2011/05/31 14:30:33
Done.
| |
| 705 Token::Value op = expr->op(); | 705 switch (expr->op()) { |
| 706 Expression* left = expr->left(); | 706 case Token::COMMA: return VisitComma(expr); |
| 707 Expression* right = expr->right(); | 707 case Token::OR: return VisitAndOr(expr, false); |
|
Kevin Millikin (Chromium)
2011/05/31 11:46:28
Let's not pass the flag here, since we can just us
Sven Panne
2011/05/31 14:30:33
Done, same for HGraphBuilder.
| |
| 708 | 708 case Token::AND: return VisitAndOr(expr, true); |
| 709 OverwriteMode mode = NO_OVERWRITE; | 709 default: return VisitCommon(expr); |
| 710 if (left->ResultOverwriteAllowed()) { | |
| 711 mode = OVERWRITE_LEFT; | |
| 712 } else if (right->ResultOverwriteAllowed()) { | |
| 713 mode = OVERWRITE_RIGHT; | |
| 714 } | |
| 715 | |
| 716 switch (op) { | |
| 717 case Token::COMMA: | |
| 718 VisitForEffect(left); | |
| 719 if (context()->IsTest()) ForwardBailoutToChild(expr); | |
| 720 context()->HandleExpression(right); | |
| 721 break; | |
| 722 | |
| 723 case Token::OR: | |
| 724 case Token::AND: | |
| 725 EmitLogicalOperation(expr); | |
| 726 break; | |
| 727 | |
| 728 case Token::ADD: | |
| 729 case Token::SUB: | |
| 730 case Token::DIV: | |
| 731 case Token::MOD: | |
| 732 case Token::MUL: | |
| 733 case Token::BIT_OR: | |
| 734 case Token::BIT_AND: | |
| 735 case Token::BIT_XOR: | |
| 736 case Token::SHL: | |
| 737 case Token::SHR: | |
| 738 case Token::SAR: { | |
| 739 // Load both operands. | |
| 740 VisitForStackValue(left); | |
| 741 VisitForAccumulatorValue(right); | |
| 742 | |
| 743 SetSourcePosition(expr->position()); | |
| 744 if (ShouldInlineSmiCase(op)) { | |
| 745 EmitInlineSmiBinaryOp(expr, op, mode, left, right); | |
| 746 } else { | |
| 747 EmitBinaryOp(expr, op, mode); | |
| 748 } | |
| 749 break; | |
| 750 } | |
| 751 | |
| 752 default: | |
| 753 UNREACHABLE(); | |
| 754 } | 710 } |
| 755 } | 711 } |
| 756 | 712 |
| 757 | 713 |
| 758 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 714 void FullCodeGenerator::VisitCommon(BinaryOperation* expr) { |
| 759 Label eval_right, done; | 715 Token::Value op = expr->op(); |
| 716 Expression* left = expr->left(); | |
| 717 Expression* right = expr->right(); | |
| 718 OverwriteMode mode = | |
| 719 left->ResultOverwriteAllowed() | |
| 720 ? OVERWRITE_LEFT | |
| 721 : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE); | |
| 760 | 722 |
| 761 context()->EmitLogicalLeft(expr, &eval_right, &done); | 723 VisitForStackValue(left); |
| 724 VisitForAccumulatorValue(right); | |
| 762 | 725 |
| 763 PrepareForBailoutForId(expr->RightId(), NO_REGISTERS); | 726 SetSourcePosition(expr->position()); |
| 764 __ bind(&eval_right); | 727 if (ShouldInlineSmiCase(op)) { |
| 728 EmitInlineSmiBinaryOp(expr, op, mode, left, right); | |
| 729 } else { | |
| 730 EmitBinaryOp(expr, op, mode); | |
| 731 } | |
| 732 } | |
| 733 | |
| 734 | |
| 735 void FullCodeGenerator::VisitComma(BinaryOperation* expr) { | |
| 736 VisitForEffect(expr->left()); | |
| 765 if (context()->IsTest()) ForwardBailoutToChild(expr); | 737 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 766 context()->HandleExpression(expr->right()); | 738 VisitInSameContext(expr->right()); |
| 739 } | |
| 767 | 740 |
| 741 | |
| 742 void FullCodeGenerator::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { | |
| 743 Expression* left = expr->left(); | |
| 744 Expression* right = expr->right(); | |
| 745 int rightId = expr->RightId(); | |
|
Kevin Millikin (Chromium)
2011/05/31 11:46:28
right_id
Sven Panne
2011/05/31 14:30:33
Done.
| |
| 746 Label done; | |
| 747 | |
| 748 if (context()->IsTest()) { | |
|
Kevin Millikin (Chromium)
2011/05/31 11:46:28
I did like having this code as virtual functions o
Sven Panne
2011/05/31 14:30:33
In principle I agree that the explicit IfFooContex
| |
| 749 Label eval_right; | |
| 750 const TestContext* test = TestContext::cast(context()); | |
| 751 if (is_logical_and) { | |
| 752 VisitForControl(left, &eval_right, test->false_label(), &eval_right); | |
| 753 } else { | |
| 754 VisitForControl(left, test->true_label(), &eval_right, &eval_right); | |
| 755 } | |
| 756 PrepareForBailoutForId(rightId, NO_REGISTERS); | |
| 757 __ bind(&eval_right); | |
| 758 ForwardBailoutToChild(expr); | |
| 759 | |
| 760 } else if (context()->IsAccumulatorValue()) { | |
| 761 VisitForAccumulatorValue(left); | |
| 762 // We want the value in the accumulator for the test, and on the stack in | |
| 763 // case we need it. | |
| 764 __ push(result_register()); | |
| 765 Label discard, restore; | |
| 766 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 767 if (is_logical_and) { | |
| 768 DoTest(&discard, &restore, &restore); | |
| 769 } else { | |
| 770 DoTest(&restore, &discard, &restore); | |
| 771 } | |
| 772 __ bind(&restore); | |
| 773 __ pop(result_register()); | |
| 774 __ jmp(&done); | |
| 775 __ bind(&discard); | |
| 776 __ Drop(1); | |
| 777 PrepareForBailoutForId(rightId, NO_REGISTERS); | |
| 778 | |
| 779 } else if (context()->IsStackValue()) { | |
| 780 VisitForAccumulatorValue(left); | |
| 781 // We want the value in the accumulator for the test, and on the stack in | |
| 782 // case we need it. | |
| 783 __ push(result_register()); | |
| 784 Label discard; | |
| 785 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 786 if (is_logical_and) { | |
| 787 DoTest(&discard, &done, &discard); | |
| 788 } else { | |
| 789 DoTest(&done, &discard, &discard); | |
| 790 } | |
| 791 __ bind(&discard); | |
| 792 __ Drop(1); | |
| 793 PrepareForBailoutForId(rightId, NO_REGISTERS); | |
| 794 | |
| 795 } else { | |
| 796 ASSERT(context()->IsEffect()); | |
| 797 Label eval_right; | |
| 798 if (is_logical_and) { | |
| 799 VisitForControl(left, &eval_right, &done, &eval_right); | |
| 800 } else { | |
| 801 VisitForControl(left, &done, &eval_right, &eval_right); | |
| 802 } | |
| 803 PrepareForBailoutForId(rightId, NO_REGISTERS); | |
| 804 __ bind(&eval_right); | |
| 805 } | |
| 806 | |
| 807 VisitInSameContext(right); | |
| 768 __ bind(&done); | 808 __ bind(&done); |
| 769 } | 809 } |
| 770 | 810 |
| 771 | 811 |
| 772 void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr, | |
| 773 Label* eval_right, | |
| 774 Label* done) const { | |
| 775 if (expr->op() == Token::OR) { | |
| 776 codegen()->VisitForControl(expr->left(), done, eval_right, eval_right); | |
| 777 } else { | |
| 778 ASSERT(expr->op() == Token::AND); | |
| 779 codegen()->VisitForControl(expr->left(), eval_right, done, eval_right); | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 | |
| 784 void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft( | |
| 785 BinaryOperation* expr, | |
| 786 Label* eval_right, | |
| 787 Label* done) const { | |
| 788 HandleExpression(expr->left()); | |
| 789 // We want the value in the accumulator for the test, and on the stack in case | |
| 790 // we need it. | |
| 791 __ push(result_register()); | |
| 792 Label discard, restore; | |
| 793 if (expr->op() == Token::OR) { | |
| 794 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 795 codegen()->DoTest(&restore, &discard, &restore); | |
| 796 } else { | |
| 797 ASSERT(expr->op() == Token::AND); | |
| 798 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 799 codegen()->DoTest(&discard, &restore, &restore); | |
| 800 } | |
| 801 __ bind(&restore); | |
| 802 __ pop(result_register()); | |
| 803 __ jmp(done); | |
| 804 __ bind(&discard); | |
| 805 __ Drop(1); | |
| 806 } | |
| 807 | |
| 808 | |
| 809 void FullCodeGenerator::StackValueContext::EmitLogicalLeft( | |
| 810 BinaryOperation* expr, | |
| 811 Label* eval_right, | |
| 812 Label* done) const { | |
| 813 codegen()->VisitForAccumulatorValue(expr->left()); | |
| 814 // We want the value in the accumulator for the test, and on the stack in case | |
| 815 // we need it. | |
| 816 __ push(result_register()); | |
| 817 Label discard; | |
| 818 if (expr->op() == Token::OR) { | |
| 819 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 820 codegen()->DoTest(done, &discard, &discard); | |
| 821 } else { | |
| 822 ASSERT(expr->op() == Token::AND); | |
| 823 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | |
| 824 codegen()->DoTest(&discard, done, &discard); | |
| 825 } | |
| 826 __ bind(&discard); | |
| 827 __ Drop(1); | |
| 828 } | |
| 829 | |
| 830 | |
| 831 void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr, | |
| 832 Label* eval_right, | |
| 833 Label* done) const { | |
| 834 if (expr->op() == Token::OR) { | |
| 835 codegen()->VisitForControl(expr->left(), | |
| 836 true_label_, eval_right, eval_right); | |
| 837 } else { | |
| 838 ASSERT(expr->op() == Token::AND); | |
| 839 codegen()->VisitForControl(expr->left(), | |
| 840 eval_right, false_label_, eval_right); | |
| 841 } | |
| 842 } | |
| 843 | |
| 844 | |
| 845 void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) { | 812 void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) { |
| 846 if (!info_->HasDeoptimizationSupport()) return; | 813 if (!info_->HasDeoptimizationSupport()) return; |
| 847 ASSERT(context()->IsTest()); | 814 ASSERT(context()->IsTest()); |
| 848 ASSERT(expr == forward_bailout_stack_->expr()); | 815 ASSERT(expr == forward_bailout_stack_->expr()); |
| 849 forward_bailout_pending_ = forward_bailout_stack_; | 816 forward_bailout_pending_ = forward_bailout_stack_; |
| 850 } | 817 } |
| 851 | 818 |
| 852 | 819 |
| 853 void FullCodeGenerator::EffectContext::HandleExpression( | 820 void FullCodeGenerator::VisitInSameContext(Expression* expr) { |
| 854 Expression* expr) const { | 821 if (context()->IsTest()) { |
| 855 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 822 ForwardBailoutStack stack(expr, forward_bailout_pending_); |
| 856 } | 823 ForwardBailoutStack* saved = forward_bailout_stack_; |
| 857 | 824 forward_bailout_pending_ = NULL; |
| 858 | 825 forward_bailout_stack_ = &stack; |
| 859 void FullCodeGenerator::AccumulatorValueContext::HandleExpression( | 826 AstVisitor::Visit(expr); |
|
Kevin Millikin (Chromium)
2011/05/31 11:46:28
This can just be Visit(expr), can't it?
Sven Panne
2011/05/31 14:30:33
Done.
| |
| 860 Expression* expr) const { | 827 forward_bailout_stack_ = saved; |
| 861 codegen()->HandleInNonTestContext(expr, TOS_REG); | 828 } else { |
| 862 } | 829 ASSERT(forward_bailout_pending_ == NULL); |
| 863 | 830 Visit(expr); |
| 864 | 831 State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS; |
| 865 void FullCodeGenerator::StackValueContext::HandleExpression( | 832 PrepareForBailout(expr, state); |
| 866 Expression* expr) const { | 833 // Forwarding bailouts to children is a one shot operation. It should have |
| 867 codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 834 // been processed at this point. |
| 868 } | 835 ASSERT(forward_bailout_pending_ == NULL); |
| 869 | 836 } |
| 870 | |
| 871 void FullCodeGenerator::TestContext::HandleExpression(Expression* expr) const { | |
| 872 codegen()->VisitInTestContext(expr); | |
| 873 } | |
| 874 | |
| 875 | |
| 876 void FullCodeGenerator::HandleInNonTestContext(Expression* expr, State state) { | |
| 877 ASSERT(forward_bailout_pending_ == NULL); | |
| 878 AstVisitor::Visit(expr); | |
| 879 PrepareForBailout(expr, state); | |
| 880 // Forwarding bailouts to children is a one shot operation. It | |
| 881 // should have been processed at this point. | |
| 882 ASSERT(forward_bailout_pending_ == NULL); | |
| 883 } | |
| 884 | |
| 885 | |
| 886 void FullCodeGenerator::VisitInTestContext(Expression* expr) { | |
| 887 ForwardBailoutStack stack(expr, forward_bailout_pending_); | |
| 888 ForwardBailoutStack* saved = forward_bailout_stack_; | |
| 889 forward_bailout_pending_ = NULL; | |
| 890 forward_bailout_stack_ = &stack; | |
| 891 AstVisitor::Visit(expr); | |
| 892 forward_bailout_stack_ = saved; | |
| 893 } | 837 } |
| 894 | 838 |
| 895 | 839 |
| 896 void FullCodeGenerator::VisitBlock(Block* stmt) { | 840 void FullCodeGenerator::VisitBlock(Block* stmt) { |
| 897 Comment cmnt(masm_, "[ Block"); | 841 Comment cmnt(masm_, "[ Block"); |
| 898 Breakable nested_statement(this, stmt); | 842 Breakable nested_statement(this, stmt); |
| 899 SetStatementPosition(stmt); | 843 SetStatementPosition(stmt); |
| 900 | 844 |
| 901 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 845 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 902 VisitStatements(stmt->statements()); | 846 VisitStatements(stmt->statements()); |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1280 __ bind(&true_case); | 1224 __ bind(&true_case); |
| 1281 SetExpressionPosition(expr->then_expression(), | 1225 SetExpressionPosition(expr->then_expression(), |
| 1282 expr->then_expression_position()); | 1226 expr->then_expression_position()); |
| 1283 if (context()->IsTest()) { | 1227 if (context()->IsTest()) { |
| 1284 const TestContext* for_test = TestContext::cast(context()); | 1228 const TestContext* for_test = TestContext::cast(context()); |
| 1285 VisitForControl(expr->then_expression(), | 1229 VisitForControl(expr->then_expression(), |
| 1286 for_test->true_label(), | 1230 for_test->true_label(), |
| 1287 for_test->false_label(), | 1231 for_test->false_label(), |
| 1288 NULL); | 1232 NULL); |
| 1289 } else { | 1233 } else { |
| 1290 context()->HandleExpression(expr->then_expression()); | 1234 VisitInSameContext(expr->then_expression()); |
| 1291 __ jmp(&done); | 1235 __ jmp(&done); |
| 1292 } | 1236 } |
| 1293 | 1237 |
| 1294 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); | 1238 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); |
| 1295 __ bind(&false_case); | 1239 __ bind(&false_case); |
| 1296 if (context()->IsTest()) ForwardBailoutToChild(expr); | 1240 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 1297 SetExpressionPosition(expr->else_expression(), | 1241 SetExpressionPosition(expr->else_expression(), |
| 1298 expr->else_expression_position()); | 1242 expr->else_expression_position()); |
| 1299 context()->HandleExpression(expr->else_expression()); | 1243 VisitInSameContext(expr->else_expression()); |
| 1300 // If control flow falls through Visit, merge it with true case here. | 1244 // If control flow falls through Visit, merge it with true case here. |
| 1301 if (!context()->IsTest()) { | 1245 if (!context()->IsTest()) { |
| 1302 __ bind(&done); | 1246 __ bind(&done); |
| 1303 } | 1247 } |
| 1304 } | 1248 } |
| 1305 | 1249 |
| 1306 | 1250 |
| 1307 void FullCodeGenerator::VisitLiteral(Literal* expr) { | 1251 void FullCodeGenerator::VisitLiteral(Literal* expr) { |
| 1308 Comment cmnt(masm_, "[ Literal"); | 1252 Comment cmnt(masm_, "[ Literal"); |
| 1309 context()->Plug(expr->handle()); | 1253 context()->Plug(expr->handle()); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1365 __ Drop(stack_depth); | 1309 __ Drop(stack_depth); |
| 1366 __ PopTryHandler(); | 1310 __ PopTryHandler(); |
| 1367 return 0; | 1311 return 0; |
| 1368 } | 1312 } |
| 1369 | 1313 |
| 1370 | 1314 |
| 1371 #undef __ | 1315 #undef __ |
| 1372 | 1316 |
| 1373 | 1317 |
| 1374 } } // namespace v8::internal | 1318 } } // namespace v8::internal |
| OLD | NEW |