Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 661 case Token::SHR: | 661 case Token::SHR: |
| 662 case Token::SAR: { | 662 case Token::SAR: { |
| 663 frame_->EmitPop(r0); // r0 : y | 663 frame_->EmitPop(r0); // r0 : y |
| 664 frame_->EmitPop(r1); // r1 : x | 664 frame_->EmitPop(r1); // r1 : x |
| 665 GenericBinaryOpStub stub(op); | 665 GenericBinaryOpStub stub(op); |
| 666 frame_->CallStub(&stub, 0); | 666 frame_->CallStub(&stub, 0); |
| 667 break; | 667 break; |
| 668 } | 668 } |
| 669 | 669 |
| 670 case Token::DIV: { | 670 case Token::DIV: { |
| 671 __ mov(r0, Operand(1)); | 671 Result arg_count = allocator_->Allocate(r0); |
| 672 frame_->InvokeBuiltin(Builtins::DIV, CALL_JS, 2); | 672 ASSERT(arg_count.is_valid()); |
| 673 __ mov(arg_count.reg(), Operand(1)); | |
| 674 frame_->InvokeBuiltin(Builtins::DIV, CALL_JS, &arg_count, 2); | |
| 673 break; | 675 break; |
| 674 } | 676 } |
| 675 | 677 |
| 676 case Token::MOD: { | 678 case Token::MOD: { |
| 677 __ mov(r0, Operand(1)); | 679 Result arg_count = allocator_->Allocate(r0); |
| 678 frame_->InvokeBuiltin(Builtins::MOD, CALL_JS, 2); | 680 ASSERT(arg_count.is_valid()); |
| 681 __ mov(arg_count.reg(), Operand(1)); | |
| 682 frame_->InvokeBuiltin(Builtins::MOD, CALL_JS, &arg_count, 2); | |
| 679 break; | 683 break; |
| 680 } | 684 } |
| 681 | 685 |
| 682 case Token::COMMA: | 686 case Token::COMMA: |
| 683 frame_->EmitPop(r0); | 687 frame_->EmitPop(r0); |
| 684 // simply discard left value | 688 // simply discard left value |
| 685 frame_->Drop(); | 689 frame_->Drop(); |
| 686 break; | 690 break; |
| 687 | 691 |
| 688 default: | 692 default: |
| 689 // Other cases should have been handled before this point. | 693 // Other cases should have been handled before this point. |
| 690 UNREACHABLE(); | 694 UNREACHABLE(); |
| 691 break; | 695 break; |
| 692 } | 696 } |
| 693 } | 697 } |
| 694 | 698 |
| 695 | 699 |
| 696 class DeferredInlinedSmiOperation: public DeferredCode { | 700 class DeferredInlineSmiOperation: public DeferredCode { |
| 697 public: | 701 public: |
| 698 DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op, | 702 DeferredInlineSmiOperation(CodeGenerator* generator, |
| 699 int value, bool reversed) : | 703 Token::Value op, |
| 700 DeferredCode(generator), op_(op), value_(value), reversed_(reversed) { | 704 int value, |
| 705 bool reversed) | |
| 706 : DeferredCode(generator), | |
| 707 op_(op), | |
| 708 value_(value), | |
| 709 reversed_(reversed) { | |
| 701 set_comment("[ DeferredInlinedSmiOperation"); | 710 set_comment("[ DeferredInlinedSmiOperation"); |
| 702 } | 711 } |
| 703 | 712 |
| 704 virtual void Generate() { | 713 virtual void Generate(); |
| 705 switch (op_) { | |
| 706 case Token::ADD: { | |
| 707 if (reversed_) { | |
| 708 // revert optimistic add | |
| 709 __ sub(r0, r0, Operand(Smi::FromInt(value_))); | |
| 710 __ mov(r1, Operand(Smi::FromInt(value_))); // x | |
| 711 } else { | |
| 712 // revert optimistic add | |
| 713 __ sub(r1, r0, Operand(Smi::FromInt(value_))); | |
| 714 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 715 } | |
| 716 break; | |
| 717 } | |
| 718 | |
| 719 case Token::SUB: { | |
| 720 if (reversed_) { | |
| 721 // revert optimistic sub | |
| 722 __ rsb(r0, r0, Operand(Smi::FromInt(value_))); | |
| 723 __ mov(r1, Operand(Smi::FromInt(value_))); | |
| 724 } else { | |
| 725 __ add(r1, r0, Operand(Smi::FromInt(value_))); | |
| 726 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 727 } | |
| 728 break; | |
| 729 } | |
| 730 | |
| 731 case Token::BIT_OR: | |
| 732 case Token::BIT_XOR: | |
| 733 case Token::BIT_AND: { | |
| 734 if (reversed_) { | |
| 735 __ mov(r1, Operand(Smi::FromInt(value_))); | |
| 736 } else { | |
| 737 __ mov(r1, Operand(r0)); | |
| 738 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 739 } | |
| 740 break; | |
| 741 } | |
| 742 | |
| 743 case Token::SHL: | |
| 744 case Token::SHR: | |
| 745 case Token::SAR: { | |
| 746 if (!reversed_) { | |
| 747 __ mov(r1, Operand(r0)); | |
| 748 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 749 } else { | |
| 750 UNREACHABLE(); // should have been handled in SmiOperation | |
| 751 } | |
| 752 break; | |
| 753 } | |
| 754 | |
| 755 default: | |
| 756 // other cases should have been handled before this point. | |
| 757 UNREACHABLE(); | |
| 758 break; | |
| 759 } | |
| 760 | |
| 761 GenericBinaryOpStub igostub(op_); | |
| 762 __ CallStub(&igostub); | |
| 763 } | |
| 764 | 714 |
| 765 private: | 715 private: |
| 766 Token::Value op_; | 716 Token::Value op_; |
| 767 int value_; | 717 int value_; |
| 768 bool reversed_; | 718 bool reversed_; |
| 769 }; | 719 }; |
| 770 | 720 |
| 771 | 721 |
| 722 void DeferredInlineSmiOperation::Generate() { | |
| 723 enter()->Bind(); | |
| 724 VirtualFrame::SpilledScope spilled_scope(generator()); | |
| 725 | |
| 726 switch (op_) { | |
| 727 case Token::ADD: { | |
| 728 if (reversed_) { | |
| 729 // revert optimistic add | |
| 730 __ sub(r0, r0, Operand(Smi::FromInt(value_))); | |
| 731 __ mov(r1, Operand(Smi::FromInt(value_))); // x | |
|
Mads Ager (chromium)
2009/02/17 08:01:20
This comment seems old and out of context here. R
Kevin Millikin (Chromium)
2009/02/17 08:08:44
Done.
| |
| 732 } else { | |
| 733 // revert optimistic add | |
| 734 __ sub(r1, r0, Operand(Smi::FromInt(value_))); | |
| 735 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 736 } | |
| 737 break; | |
| 738 } | |
| 739 | |
| 740 case Token::SUB: { | |
| 741 if (reversed_) { | |
| 742 // revert optimistic sub | |
| 743 __ rsb(r0, r0, Operand(Smi::FromInt(value_))); | |
| 744 __ mov(r1, Operand(Smi::FromInt(value_))); | |
| 745 } else { | |
| 746 __ add(r1, r0, Operand(Smi::FromInt(value_))); | |
| 747 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 748 } | |
| 749 break; | |
| 750 } | |
| 751 | |
| 752 case Token::BIT_OR: | |
| 753 case Token::BIT_XOR: | |
| 754 case Token::BIT_AND: { | |
| 755 if (reversed_) { | |
| 756 __ mov(r1, Operand(Smi::FromInt(value_))); | |
| 757 } else { | |
| 758 __ mov(r1, Operand(r0)); | |
| 759 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 760 } | |
| 761 break; | |
| 762 } | |
| 763 | |
| 764 case Token::SHL: | |
| 765 case Token::SHR: | |
| 766 case Token::SAR: { | |
| 767 if (!reversed_) { | |
| 768 __ mov(r1, Operand(r0)); | |
| 769 __ mov(r0, Operand(Smi::FromInt(value_))); | |
| 770 } else { | |
| 771 UNREACHABLE(); // should have been handled in SmiOperation | |
| 772 } | |
| 773 break; | |
| 774 } | |
| 775 | |
| 776 default: | |
| 777 // other cases should have been handled before this point. | |
| 778 UNREACHABLE(); | |
| 779 break; | |
| 780 } | |
| 781 | |
| 782 GenericBinaryOpStub igostub(op_); | |
| 783 Result arg0 = generator()->allocator()->Allocate(r0); | |
| 784 ASSERT(arg0.is_valid()); | |
| 785 Result arg1 = generator()->allocator()->Allocate(r1); | |
| 786 ASSERT(arg1.is_valid()); | |
| 787 generator()->frame()->CallStub(&igostub, &arg0, &arg1, 0); | |
| 788 exit()->Jump(); | |
| 789 } | |
| 790 | |
| 791 | |
| 772 void CodeGenerator::SmiOperation(Token::Value op, | 792 void CodeGenerator::SmiOperation(Token::Value op, |
| 773 Handle<Object> value, | 793 Handle<Object> value, |
| 774 bool reversed) { | 794 bool reversed) { |
| 775 VirtualFrame::SpilledScope spilled_scope(this); | 795 VirtualFrame::SpilledScope spilled_scope(this); |
| 776 // NOTE: This is an attempt to inline (a bit) more of the code for | 796 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 777 // some possible smi operations (like + and -) when (at least) one | 797 // some possible smi operations (like + and -) when (at least) one |
| 778 // of the operands is a literal smi. With this optimization, the | 798 // of the operands is a literal smi. With this optimization, the |
| 779 // performance of the system is increased by ~15%, and the generated | 799 // performance of the system is increased by ~15%, and the generated |
| 780 // code size is increased by ~1% (measured on a combination of | 800 // code size is increased by ~1% (measured on a combination of |
| 781 // different benchmarks). | 801 // different benchmarks). |
| 782 | 802 |
| 783 // sp[0] : operand | 803 // sp[0] : operand |
| 784 | 804 |
| 785 int int_value = Smi::cast(*value)->value(); | 805 int int_value = Smi::cast(*value)->value(); |
| 786 | 806 |
| 787 JumpTarget exit(this); | 807 JumpTarget exit(this); |
| 788 frame_->EmitPop(r0); | 808 frame_->EmitPop(r0); |
| 789 | 809 |
| 790 switch (op) { | 810 switch (op) { |
| 791 case Token::ADD: { | 811 case Token::ADD: { |
| 792 DeferredCode* deferred = | 812 DeferredCode* deferred = |
| 793 new DeferredInlinedSmiOperation(this, op, int_value, reversed); | 813 new DeferredInlineSmiOperation(this, op, int_value, reversed); |
| 794 | 814 |
| 795 __ add(r0, r0, Operand(value), SetCC); | 815 __ add(r0, r0, Operand(value), SetCC); |
| 796 deferred->enter()->Branch(vs); | 816 deferred->enter()->Branch(vs); |
| 797 __ tst(r0, Operand(kSmiTagMask)); | 817 __ tst(r0, Operand(kSmiTagMask)); |
| 798 deferred->enter()->Branch(ne); | 818 deferred->enter()->Branch(ne); |
| 799 deferred->exit()->Bind(); | 819 deferred->exit()->Bind(); |
| 800 break; | 820 break; |
| 801 } | 821 } |
| 802 | 822 |
| 803 case Token::SUB: { | 823 case Token::SUB: { |
| 804 DeferredCode* deferred = | 824 DeferredCode* deferred = |
| 805 new DeferredInlinedSmiOperation(this, op, int_value, reversed); | 825 new DeferredInlineSmiOperation(this, op, int_value, reversed); |
| 806 | 826 |
| 807 if (!reversed) { | 827 if (!reversed) { |
| 808 __ sub(r0, r0, Operand(value), SetCC); | 828 __ sub(r0, r0, Operand(value), SetCC); |
| 809 } else { | 829 } else { |
| 810 __ rsb(r0, r0, Operand(value), SetCC); | 830 __ rsb(r0, r0, Operand(value), SetCC); |
| 811 } | 831 } |
| 812 deferred->enter()->Branch(vs); | 832 deferred->enter()->Branch(vs); |
| 813 __ tst(r0, Operand(kSmiTagMask)); | 833 __ tst(r0, Operand(kSmiTagMask)); |
| 814 deferred->enter()->Branch(ne); | 834 deferred->enter()->Branch(ne); |
| 815 deferred->exit()->Bind(); | 835 deferred->exit()->Bind(); |
| 816 break; | 836 break; |
| 817 } | 837 } |
| 818 | 838 |
| 819 case Token::BIT_OR: | 839 case Token::BIT_OR: |
| 820 case Token::BIT_XOR: | 840 case Token::BIT_XOR: |
| 821 case Token::BIT_AND: { | 841 case Token::BIT_AND: { |
| 822 DeferredCode* deferred = | 842 DeferredCode* deferred = |
| 823 new DeferredInlinedSmiOperation(this, op, int_value, reversed); | 843 new DeferredInlineSmiOperation(this, op, int_value, reversed); |
| 824 __ tst(r0, Operand(kSmiTagMask)); | 844 __ tst(r0, Operand(kSmiTagMask)); |
| 825 deferred->enter()->Branch(ne); | 845 deferred->enter()->Branch(ne); |
| 826 switch (op) { | 846 switch (op) { |
| 827 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; | 847 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; |
| 828 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; | 848 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; |
| 829 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; | 849 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; |
| 830 default: UNREACHABLE(); | 850 default: UNREACHABLE(); |
| 831 } | 851 } |
| 832 deferred->exit()->Bind(); | 852 deferred->exit()->Bind(); |
| 833 break; | 853 break; |
| 834 } | 854 } |
| 835 | 855 |
| 836 case Token::SHL: | 856 case Token::SHL: |
| 837 case Token::SHR: | 857 case Token::SHR: |
| 838 case Token::SAR: { | 858 case Token::SAR: { |
| 839 if (reversed) { | 859 if (reversed) { |
| 840 __ mov(ip, Operand(value)); | 860 __ mov(ip, Operand(value)); |
| 841 frame_->EmitPush(ip); | 861 frame_->EmitPush(ip); |
| 842 frame_->EmitPush(r0); | 862 frame_->EmitPush(r0); |
| 843 GenericBinaryOperation(op); | 863 GenericBinaryOperation(op); |
| 844 | 864 |
| 845 } else { | 865 } else { |
| 846 int shift_value = int_value & 0x1f; // least significant 5 bits | 866 int shift_value = int_value & 0x1f; // least significant 5 bits |
| 847 DeferredCode* deferred = | 867 DeferredCode* deferred = |
| 848 new DeferredInlinedSmiOperation(this, op, shift_value, false); | 868 new DeferredInlineSmiOperation(this, op, shift_value, false); |
| 849 __ tst(r0, Operand(kSmiTagMask)); | 869 __ tst(r0, Operand(kSmiTagMask)); |
| 850 deferred->enter()->Branch(ne); | 870 deferred->enter()->Branch(ne); |
| 851 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags | 871 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags |
| 852 switch (op) { | 872 switch (op) { |
| 853 case Token::SHL: { | 873 case Token::SHL: { |
| 854 __ mov(r2, Operand(r2, LSL, shift_value)); | 874 __ mov(r2, Operand(r2, LSL, shift_value)); |
| 855 // check that the *unsigned* result fits in a smi | 875 // check that the *unsigned* result fits in a smi |
| 856 __ add(r3, r2, Operand(0x40000000), SetCC); | 876 __ add(r3, r2, Operand(0x40000000), SetCC); |
| 857 deferred->enter()->Branch(mi); | 877 deferred->enter()->Branch(mi); |
| 858 break; | 878 break; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 947 ncr = LESS; | 967 ncr = LESS; |
| 948 } | 968 } |
| 949 frame_->EmitPush(r0); | 969 frame_->EmitPush(r0); |
| 950 arg_count++; | 970 arg_count++; |
| 951 __ mov(r0, Operand(Smi::FromInt(ncr))); | 971 __ mov(r0, Operand(Smi::FromInt(ncr))); |
| 952 } | 972 } |
| 953 | 973 |
| 954 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 974 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 955 // tagged as a small integer. | 975 // tagged as a small integer. |
| 956 frame_->EmitPush(r0); | 976 frame_->EmitPush(r0); |
| 957 __ mov(r0, Operand(arg_count)); | 977 Result arg_count_register = allocator_->Allocate(r0); |
| 958 frame_->InvokeBuiltin(native, CALL_JS, arg_count + 1); | 978 ASSERT(arg_count_register.is_valid()); |
| 959 __ cmp(r0, Operand(0)); | 979 __ mov(arg_count_register.reg(), Operand(arg_count)); |
| 980 Result result = frame_->InvokeBuiltin(native, | |
| 981 CALL_JS, | |
| 982 &arg_count_register, | |
| 983 arg_count + 1); | |
| 984 __ cmp(result.reg(), Operand(0)); | |
| 985 result.Unuse(); | |
| 960 exit.Jump(); | 986 exit.Jump(); |
| 961 | 987 |
| 962 // test smi equality by pointer comparison. | 988 // test smi equality by pointer comparison. |
| 963 smi.Bind(); | 989 smi.Bind(); |
| 964 __ cmp(r1, Operand(r0)); | 990 __ cmp(r1, Operand(r0)); |
| 965 | 991 |
| 966 exit.Bind(); | 992 exit.Bind(); |
| 967 cc_reg_ = cc; | 993 cc_reg_ = cc; |
| 968 } | 994 } |
| 969 | 995 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1036 } | 1062 } |
| 1037 | 1063 |
| 1038 | 1064 |
| 1039 void CodeGenerator::VisitBlock(Block* node) { | 1065 void CodeGenerator::VisitBlock(Block* node) { |
| 1040 VirtualFrame::SpilledScope spilled_scope(this); | 1066 VirtualFrame::SpilledScope spilled_scope(this); |
| 1041 Comment cmnt(masm_, "[ Block"); | 1067 Comment cmnt(masm_, "[ Block"); |
| 1042 CodeForStatementPosition(node); | 1068 CodeForStatementPosition(node); |
| 1043 node->set_break_stack_height(break_stack_height_); | 1069 node->set_break_stack_height(break_stack_height_); |
| 1044 node->break_target()->Initialize(this); | 1070 node->break_target()->Initialize(this); |
| 1045 VisitStatementsAndSpill(node->statements()); | 1071 VisitStatementsAndSpill(node->statements()); |
| 1046 node->break_target()->Bind(); | 1072 if (node->break_target()->is_linked()) { |
| 1073 node->break_target()->Bind(); | |
| 1074 } | |
| 1047 } | 1075 } |
| 1048 | 1076 |
| 1049 | 1077 |
| 1050 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1078 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1051 VirtualFrame::SpilledScope spilled_scope(this); | 1079 VirtualFrame::SpilledScope spilled_scope(this); |
| 1052 __ mov(r0, Operand(pairs)); | 1080 __ mov(r0, Operand(pairs)); |
| 1053 frame_->EmitPush(r0); | 1081 frame_->EmitPush(r0); |
| 1054 frame_->EmitPush(cp); | 1082 frame_->EmitPush(cp); |
| 1055 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1083 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1056 frame_->EmitPush(r0); | 1084 frame_->EmitPush(r0); |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1455 } | 1483 } |
| 1456 } | 1484 } |
| 1457 | 1485 |
| 1458 | 1486 |
| 1459 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1487 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1460 VirtualFrame::SpilledScope spilled_scope(this); | 1488 VirtualFrame::SpilledScope spilled_scope(this); |
| 1461 Comment cmnt(masm_, "[ LoopStatement"); | 1489 Comment cmnt(masm_, "[ LoopStatement"); |
| 1462 CodeForStatementPosition(node); | 1490 CodeForStatementPosition(node); |
| 1463 node->set_break_stack_height(break_stack_height_); | 1491 node->set_break_stack_height(break_stack_height_); |
| 1464 node->break_target()->Initialize(this); | 1492 node->break_target()->Initialize(this); |
| 1465 node->continue_target()->Initialize(this); | |
| 1466 | 1493 |
| 1467 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1494 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1468 // known result for the test expression, with no side effects. | 1495 // known result for the test expression, with no side effects. |
| 1469 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1496 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1470 if (node->cond() == NULL) { | 1497 if (node->cond() == NULL) { |
| 1471 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1498 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1472 info = ALWAYS_TRUE; | 1499 info = ALWAYS_TRUE; |
| 1473 } else { | 1500 } else { |
| 1474 Literal* lit = node->cond()->AsLiteral(); | 1501 Literal* lit = node->cond()->AsLiteral(); |
| 1475 if (lit != NULL) { | 1502 if (lit != NULL) { |
| 1476 if (lit->IsTrue()) { | 1503 if (lit->IsTrue()) { |
| 1477 info = ALWAYS_TRUE; | 1504 info = ALWAYS_TRUE; |
| 1478 } else if (lit->IsFalse()) { | 1505 } else if (lit->IsFalse()) { |
| 1479 info = ALWAYS_FALSE; | 1506 info = ALWAYS_FALSE; |
| 1480 } | 1507 } |
| 1481 } | 1508 } |
| 1482 } | 1509 } |
| 1483 | 1510 |
| 1484 switch (node->type()) { | 1511 switch (node->type()) { |
| 1485 case LoopStatement::DO_LOOP: { | 1512 case LoopStatement::DO_LOOP: { |
| 1486 JumpTarget body(this); | 1513 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
| 1487 // Label the body. | 1514 |
| 1515 // Label the top of the loop for the backward CFG edge. If the test | |
| 1516 // is always true we can use the continue target, and if the test is | |
| 1517 // always false there is no need. | |
| 1488 if (info == ALWAYS_TRUE) { | 1518 if (info == ALWAYS_TRUE) { |
| 1519 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | |
| 1489 node->continue_target()->Bind(); | 1520 node->continue_target()->Bind(); |
| 1490 } else if (info == ALWAYS_FALSE) { | 1521 } else if (info == ALWAYS_FALSE) { |
| 1491 // There is no need, we will never jump back. | 1522 node->continue_target()->Initialize(this); |
| 1492 } else { | 1523 } else { |
| 1493 ASSERT(info == DONT_KNOW); | 1524 ASSERT(info == DONT_KNOW); |
| 1525 node->continue_target()->Initialize(this); | |
| 1494 body.Bind(); | 1526 body.Bind(); |
| 1495 } | 1527 } |
| 1528 | |
| 1496 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1529 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1497 VisitAndSpill(node->body()); | 1530 VisitAndSpill(node->body()); |
| 1498 | 1531 |
| 1499 // Compile the "test". | 1532 // Compile the test. |
| 1500 if (info == ALWAYS_TRUE) { | 1533 if (info == ALWAYS_TRUE) { |
| 1501 if (frame_ != NULL) { | 1534 if (has_valid_frame()) { |
| 1502 // If control can fall off the end of the body, jump back to the | 1535 // If control can fall off the end of the body, jump back to the |
| 1503 // top. | 1536 // top. |
| 1504 node->continue_target()->Jump(); | 1537 node->continue_target()->Jump(); |
| 1505 } | 1538 } |
| 1506 } else if (info == ALWAYS_FALSE) { | 1539 } else if (info == ALWAYS_FALSE) { |
| 1507 // If we have a continue in the body, we only have to bind its jump | 1540 // If we have a continue in the body, we only have to bind its jump |
| 1508 // target. | 1541 // target. |
| 1509 if (node->continue_target()->is_linked()) { | 1542 if (node->continue_target()->is_linked()) { |
| 1510 node->continue_target()->Bind(); | 1543 node->continue_target()->Bind(); |
| 1511 } | 1544 } |
| 1512 } else { | 1545 } else { |
| 1513 ASSERT(info == DONT_KNOW); | 1546 ASSERT(info == DONT_KNOW); |
| 1514 // We have to compile the test expression if it can be reached by | 1547 // We have to compile the test expression if it can be reached by |
| 1515 // control flow falling out of the body or via continue. | 1548 // control flow falling out of the body or via continue. |
| 1516 if (frame_ != NULL || node->continue_target()->is_linked()) { | 1549 if (node->continue_target()->is_linked()) { |
| 1517 node->continue_target()->Bind(); | 1550 node->continue_target()->Bind(); |
| 1551 } | |
| 1552 if (has_valid_frame()) { | |
| 1518 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1553 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1519 &body, node->break_target(), true); | 1554 &body, node->break_target(), true); |
| 1520 if (frame_ != NULL) { | 1555 if (has_valid_frame()) { |
| 1521 // A NULL frame here indicates that control did not fall out of | 1556 // A invalid frame here indicates that control did not |
| 1522 // the test expression. | 1557 // fall out of the test expression. |
| 1523 Branch(true, &body); | 1558 Branch(true, &body); |
| 1524 } | 1559 } |
| 1525 } | 1560 } |
| 1526 } | 1561 } |
| 1527 break; | 1562 break; |
| 1528 } | 1563 } |
| 1529 | 1564 |
| 1530 case LoopStatement::WHILE_LOOP: { | 1565 case LoopStatement::WHILE_LOOP: { |
| 1531 JumpTarget body(this); | 1566 // If the test is never true and has no side effects there is no need |
| 1532 // Generate the loop header. | 1567 // to compile the test or body. |
| 1533 if (info == ALWAYS_TRUE) { | 1568 if (info == ALWAYS_FALSE) break; |
| 1534 // Merely label the body with the continue target. | 1569 |
| 1535 node->continue_target()->Bind(); | 1570 // Label the top of the loop with the continue target for the backward |
| 1536 } else if (info == ALWAYS_FALSE) { | 1571 // CFG edge. |
| 1537 // There is no need to even compile the test or body. | 1572 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 1538 break; | 1573 node->continue_target()->Bind(); |
| 1539 } else { | 1574 |
| 1540 // Compile the test labeled with the continue target and label the | 1575 if (info == DONT_KNOW) { |
| 1541 // body with the body target. | 1576 JumpTarget body(this); |
| 1542 ASSERT(info == DONT_KNOW); | |
| 1543 node->continue_target()->Bind(); | |
| 1544 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1577 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1545 &body, node->break_target(), true); | 1578 &body, node->break_target(), true); |
| 1546 if (frame_ != NULL) { | 1579 if (has_valid_frame()) { |
| 1547 // A NULL frame indicates that control did not fall out of the | 1580 // A NULL frame indicates that control did not fall out of the |
| 1548 // test expression. | 1581 // test expression. |
| 1549 Branch(false, node->break_target()); | 1582 Branch(false, node->break_target()); |
| 1550 } | 1583 } |
| 1551 if (frame_ != NULL || body.is_linked()) { | 1584 if (has_valid_frame() || body.is_linked()) { |
| 1552 body.Bind(); | 1585 body.Bind(); |
| 1553 } | 1586 } |
| 1554 } | 1587 } |
| 1555 if (frame_ != NULL) { | 1588 |
| 1589 if (has_valid_frame()) { | |
| 1556 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1590 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1557 VisitAndSpill(node->body()); | 1591 VisitAndSpill(node->body()); |
| 1558 | 1592 |
| 1559 // If control flow can fall out of the body, jump back to the top. | 1593 // If control flow can fall out of the body, jump back to the top. |
| 1560 if (frame_ != NULL) { | 1594 if (has_valid_frame()) { |
| 1561 node->continue_target()->Jump(); | 1595 node->continue_target()->Jump(); |
| 1562 } | 1596 } |
| 1563 } | 1597 } |
| 1564 break; | 1598 break; |
| 1565 } | 1599 } |
| 1566 | 1600 |
| 1567 case LoopStatement::FOR_LOOP: { | 1601 case LoopStatement::FOR_LOOP: { |
| 1568 JumpTarget loop(this); | 1602 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); |
| 1569 JumpTarget body(this); | 1603 |
| 1570 if (node->init() != NULL) { | 1604 if (node->init() != NULL) { |
| 1571 VisitAndSpill(node->init()); | 1605 VisitAndSpill(node->init()); |
| 1572 } | 1606 } |
| 1573 | 1607 |
| 1574 // There is no need to compile the test or body. | 1608 // There is no need to compile the test or body. |
| 1575 if (info == ALWAYS_FALSE) break; | 1609 if (info == ALWAYS_FALSE) break; |
| 1576 | 1610 |
| 1577 // If there is no update statement, label the top of the loop with the | 1611 // If there is no update statement, label the top of the loop with the |
| 1578 // continue target, otherwise with the loop target. | 1612 // continue target, otherwise with the loop target. |
| 1579 if (node->next() == NULL) { | 1613 if (node->next() == NULL) { |
| 1614 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | |
| 1580 node->continue_target()->Bind(); | 1615 node->continue_target()->Bind(); |
| 1581 } else { | 1616 } else { |
| 1617 node->continue_target()->Initialize(this); | |
| 1582 loop.Bind(); | 1618 loop.Bind(); |
| 1583 } | 1619 } |
| 1584 | 1620 |
| 1585 // If the test is always true, there is no need to compile it. | 1621 // If the test is always true, there is no need to compile it. |
| 1586 if (info == DONT_KNOW) { | 1622 if (info == DONT_KNOW) { |
| 1623 JumpTarget body(this); | |
| 1587 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1624 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1588 &body, node->break_target(), true); | 1625 &body, node->break_target(), true); |
| 1589 if (frame_ != NULL) { | 1626 if (has_valid_frame()) { |
| 1590 Branch(false, node->break_target()); | 1627 Branch(false, node->break_target()); |
| 1591 } | 1628 } |
| 1592 if (frame_ != NULL || body.is_linked()) { | 1629 if (has_valid_frame() || body.is_linked()) { |
| 1593 body.Bind(); | 1630 body.Bind(); |
| 1594 } | 1631 } |
| 1595 } | 1632 } |
| 1596 | 1633 |
| 1597 if (frame_ != NULL) { | 1634 if (has_valid_frame()) { |
| 1598 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1635 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1599 VisitAndSpill(node->body()); | 1636 VisitAndSpill(node->body()); |
| 1600 | 1637 |
| 1601 if (node->next() == NULL) { | 1638 if (node->next() == NULL) { |
| 1602 // If there is no update statement and control flow can fall out | 1639 // If there is no update statement and control flow can fall out |
| 1603 // of the loop, jump directly to the continue label. | 1640 // of the loop, jump directly to the continue label. |
| 1604 if (frame_ != NULL) { | 1641 if (has_valid_frame()) { |
| 1605 node->continue_target()->Jump(); | 1642 node->continue_target()->Jump(); |
| 1606 } | 1643 } |
| 1607 } else { | 1644 } else { |
| 1608 // If there is an update statement and control flow can reach it | 1645 // If there is an update statement and control flow can reach it |
| 1609 // via falling out of the body of the loop or continuing, we | 1646 // via falling out of the body of the loop or continuing, we |
| 1610 // compile the update statement. | 1647 // compile the update statement. |
| 1611 if (frame_ != NULL || node->continue_target()->is_linked()) { | 1648 if (node->continue_target()->is_linked()) { |
| 1612 node->continue_target()->Bind(); | 1649 node->continue_target()->Bind(); |
| 1650 } | |
| 1651 if (has_valid_frame()) { | |
| 1613 // Record source position of the statement as this code which is | 1652 // Record source position of the statement as this code which is |
| 1614 // after the code for the body actually belongs to the loop | 1653 // after the code for the body actually belongs to the loop |
| 1615 // statement and not the body. | 1654 // statement and not the body. |
| 1616 CodeForStatementPosition(node); | 1655 CodeForStatementPosition(node); |
| 1617 | |
| 1618 VisitAndSpill(node->next()); | 1656 VisitAndSpill(node->next()); |
| 1619 loop.Jump(); | 1657 loop.Jump(); |
| 1620 } | 1658 } |
| 1621 } | 1659 } |
| 1622 } | 1660 } |
| 1623 break; | 1661 break; |
| 1624 } | 1662 } |
| 1625 } | 1663 } |
| 1626 | 1664 |
| 1627 if (node->break_target()->is_linked()) { | 1665 if (node->break_target()->is_linked()) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1673 // Check if enumerable is already a JSObject | 1711 // Check if enumerable is already a JSObject |
| 1674 __ tst(r0, Operand(kSmiTagMask)); | 1712 __ tst(r0, Operand(kSmiTagMask)); |
| 1675 primitive.Branch(eq); | 1713 primitive.Branch(eq); |
| 1676 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 1714 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 1677 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 1715 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 1678 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 1716 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
| 1679 jsobject.Branch(hs); | 1717 jsobject.Branch(hs); |
| 1680 | 1718 |
| 1681 primitive.Bind(); | 1719 primitive.Bind(); |
| 1682 frame_->EmitPush(r0); | 1720 frame_->EmitPush(r0); |
| 1683 __ mov(r0, Operand(0)); | 1721 Result arg_count = allocator_->Allocate(r0); |
| 1684 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS, 1); | 1722 ASSERT(arg_count.is_valid()); |
| 1723 __ mov(arg_count.reg(), Operand(0)); | |
| 1724 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS, &arg_count, 1); | |
| 1685 | 1725 |
| 1686 | 1726 |
| 1687 jsobject.Bind(); | 1727 jsobject.Bind(); |
| 1688 | 1728 |
| 1689 // Get the set of properties (as a FixedArray or Map). | 1729 // Get the set of properties (as a FixedArray or Map). |
| 1690 frame_->EmitPush(r0); // duplicate the object being enumerated | 1730 frame_->EmitPush(r0); // duplicate the object being enumerated |
| 1691 frame_->EmitPush(r0); | 1731 frame_->EmitPush(r0); |
| 1692 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1732 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 1693 | 1733 |
| 1694 // If we got a Map, we can do a fast modification check. | 1734 // If we got a Map, we can do a fast modification check. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1754 // If not, we have to filter the key. | 1794 // If not, we have to filter the key. |
| 1755 __ ldr(r1, frame_->ElementAt(4)); | 1795 __ ldr(r1, frame_->ElementAt(4)); |
| 1756 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 1796 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1757 __ cmp(r1, Operand(r2)); | 1797 __ cmp(r1, Operand(r2)); |
| 1758 end_del_check.Branch(eq); | 1798 end_del_check.Branch(eq); |
| 1759 | 1799 |
| 1760 // Convert the entry to a string (or null if it isn't a property anymore). | 1800 // Convert the entry to a string (or null if it isn't a property anymore). |
| 1761 __ ldr(r0, frame_->ElementAt(4)); // push enumerable | 1801 __ ldr(r0, frame_->ElementAt(4)); // push enumerable |
| 1762 frame_->EmitPush(r0); | 1802 frame_->EmitPush(r0); |
| 1763 frame_->EmitPush(r3); // push entry | 1803 frame_->EmitPush(r3); // push entry |
| 1764 __ mov(r0, Operand(1)); | 1804 Result arg_count_register = allocator_->Allocate(r0); |
| 1765 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS, 2); | 1805 ASSERT(arg_count_register.is_valid()); |
| 1766 __ mov(r3, Operand(r0)); | 1806 __ mov(arg_count_register.reg(), Operand(1)); |
| 1807 Result result = frame_->InvokeBuiltin(Builtins::FILTER_KEY, | |
| 1808 CALL_JS, | |
| 1809 &arg_count_register, | |
| 1810 2); | |
| 1811 __ mov(r3, Operand(result.reg())); | |
| 1812 result.Unuse(); | |
| 1767 | 1813 |
| 1768 // If the property has been removed while iterating, we just skip it. | 1814 // If the property has been removed while iterating, we just skip it. |
| 1769 __ cmp(r3, Operand(Factory::null_value())); | 1815 __ cmp(r3, Operand(Factory::null_value())); |
| 1770 node->continue_target()->Branch(eq); | 1816 node->continue_target()->Branch(eq); |
| 1771 | 1817 |
| 1772 end_del_check.Bind(); | 1818 end_del_check.Bind(); |
| 1773 // Store the entry in the 'each' expression and take another spin in the | 1819 // Store the entry in the 'each' expression and take another spin in the |
| 1774 // loop. r3: i'th entry of the enum cache (or string there of) | 1820 // loop. r3: i'th entry of the enum cache (or string there of) |
| 1775 frame_->EmitPush(r3); // push entry | 1821 frame_->EmitPush(r3); // push entry |
| 1776 { Reference each(this, node->each()); | 1822 { Reference each(this, node->each()); |
| (...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2264 // This deferred code stub will be used for creating the boilerplate | 2310 // This deferred code stub will be used for creating the boilerplate |
| 2265 // by calling Runtime_CreateObjectLiteral. | 2311 // by calling Runtime_CreateObjectLiteral. |
| 2266 // Each created boilerplate is stored in the JSFunction and they are | 2312 // Each created boilerplate is stored in the JSFunction and they are |
| 2267 // therefore context dependent. | 2313 // therefore context dependent. |
| 2268 class ObjectLiteralDeferred: public DeferredCode { | 2314 class ObjectLiteralDeferred: public DeferredCode { |
| 2269 public: | 2315 public: |
| 2270 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node) | 2316 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node) |
| 2271 : DeferredCode(generator), node_(node) { | 2317 : DeferredCode(generator), node_(node) { |
| 2272 set_comment("[ ObjectLiteralDeferred"); | 2318 set_comment("[ ObjectLiteralDeferred"); |
| 2273 } | 2319 } |
| 2320 | |
| 2274 virtual void Generate(); | 2321 virtual void Generate(); |
| 2322 | |
| 2275 private: | 2323 private: |
| 2276 ObjectLiteral* node_; | 2324 ObjectLiteral* node_; |
| 2277 }; | 2325 }; |
| 2278 | 2326 |
| 2279 | 2327 |
| 2280 void ObjectLiteralDeferred::Generate() { | 2328 void ObjectLiteralDeferred::Generate() { |
| 2329 // Argument is passed in r1. | |
| 2330 enter()->Bind(); | |
| 2331 VirtualFrame::SpilledScope spilled_scope(generator()); | |
| 2332 | |
| 2281 // If the entry is undefined we call the runtime system to computed | 2333 // If the entry is undefined we call the runtime system to computed |
| 2282 // the literal. | 2334 // the literal. |
| 2283 | 2335 |
| 2336 VirtualFrame* frame = generator()->frame(); | |
| 2284 // Literal array (0). | 2337 // Literal array (0). |
| 2285 __ push(r1); | 2338 frame->Push(r1); |
| 2286 // Literal index (1). | 2339 // Literal index (1). |
| 2287 __ mov(r0, Operand(Smi::FromInt(node_->literal_index()))); | 2340 __ mov(r0, Operand(Smi::FromInt(node_->literal_index()))); |
| 2288 __ push(r0); | 2341 frame->Push(r0); |
| 2289 // Constant properties (2). | 2342 // Constant properties (2). |
| 2290 __ mov(r0, Operand(node_->constant_properties())); | 2343 __ mov(r0, Operand(node_->constant_properties())); |
| 2291 __ push(r0); | 2344 frame->Push(r0); |
| 2292 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2345 Result boilerplate = |
| 2293 __ mov(r2, Operand(r0)); | 2346 frame->CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 2347 __ mov(r2, Operand(boilerplate.reg())); | |
| 2348 // Result is returned in r2. | |
| 2349 exit()->Jump(); | |
| 2294 } | 2350 } |
| 2295 | 2351 |
| 2296 | 2352 |
| 2297 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2353 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2298 VirtualFrame::SpilledScope spilled_scope(this); | 2354 VirtualFrame::SpilledScope spilled_scope(this); |
| 2299 Comment cmnt(masm_, "[ ObjectLiteral"); | 2355 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2300 | 2356 |
| 2301 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2357 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2302 | 2358 |
| 2303 // Retrieve the literal array and check the allocated entry. | 2359 // Retrieve the literal array and check the allocated entry. |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2709 LoadGlobal(); | 2765 LoadGlobal(); |
| 2710 | 2766 |
| 2711 // Push the arguments ("left-to-right") on the stack. | 2767 // Push the arguments ("left-to-right") on the stack. |
| 2712 ZoneList<Expression*>* args = node->arguments(); | 2768 ZoneList<Expression*>* args = node->arguments(); |
| 2713 int arg_count = args->length(); | 2769 int arg_count = args->length(); |
| 2714 for (int i = 0; i < arg_count; i++) { | 2770 for (int i = 0; i < arg_count; i++) { |
| 2715 LoadAndSpill(args->at(i)); | 2771 LoadAndSpill(args->at(i)); |
| 2716 } | 2772 } |
| 2717 | 2773 |
| 2718 // r0: the number of arguments. | 2774 // r0: the number of arguments. |
| 2719 __ mov(r0, Operand(arg_count)); | 2775 Result num_args = allocator_->Allocate(r0); |
| 2776 ASSERT(num_args.is_valid()); | |
| 2777 __ mov(num_args.reg(), Operand(arg_count)); | |
| 2720 | 2778 |
| 2721 // Load the function into r1 as per calling convention. | 2779 // Load the function into r1 as per calling convention. |
| 2722 __ ldr(r1, frame_->ElementAt(arg_count + 1)); | 2780 Result function = allocator_->Allocate(r1); |
| 2781 ASSERT(function.is_valid()); | |
| 2782 __ ldr(function.reg(), frame_->ElementAt(arg_count + 1)); | |
| 2723 | 2783 |
| 2724 // Call the construct call builtin that handles allocation and | 2784 // Call the construct call builtin that handles allocation and |
| 2725 // constructor invocation. | 2785 // constructor invocation. |
| 2726 CodeForSourcePosition(node->position()); | 2786 CodeForSourcePosition(node->position()); |
| 2727 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 2787 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2728 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1); | 2788 Result result = frame_->CallCodeObject(ic, |
| 2789 RelocInfo::CONSTRUCT_CALL, | |
| 2790 &num_args, | |
| 2791 &function, | |
| 2792 arg_count + 1); | |
| 2729 | 2793 |
| 2730 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 2794 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
| 2731 __ str(r0, frame_->Top()); | 2795 __ str(r0, frame_->Top()); |
| 2732 } | 2796 } |
| 2733 | 2797 |
| 2734 | 2798 |
| 2735 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2799 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 2736 VirtualFrame::SpilledScope spilled_scope(this); | 2800 VirtualFrame::SpilledScope spilled_scope(this); |
| 2737 ASSERT(args->length() == 1); | 2801 ASSERT(args->length() == 1); |
| 2738 JumpTarget leave(this); | 2802 JumpTarget leave(this); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2955 true_target(), | 3019 true_target(), |
| 2956 true); | 3020 true); |
| 2957 cc_reg_ = NegateCondition(cc_reg_); | 3021 cc_reg_ = NegateCondition(cc_reg_); |
| 2958 | 3022 |
| 2959 } else if (op == Token::DELETE) { | 3023 } else if (op == Token::DELETE) { |
| 2960 Property* property = node->expression()->AsProperty(); | 3024 Property* property = node->expression()->AsProperty(); |
| 2961 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3025 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 2962 if (property != NULL) { | 3026 if (property != NULL) { |
| 2963 LoadAndSpill(property->obj()); | 3027 LoadAndSpill(property->obj()); |
| 2964 LoadAndSpill(property->key()); | 3028 LoadAndSpill(property->key()); |
| 2965 __ mov(r0, Operand(1)); // not counting receiver | 3029 Result arg_count = allocator_->Allocate(r0); |
| 2966 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2); | 3030 ASSERT(arg_count.is_valid()); |
| 3031 __ mov(arg_count.reg(), Operand(1)); // not counting receiver | |
| 3032 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2); | |
| 2967 | 3033 |
| 2968 } else if (variable != NULL) { | 3034 } else if (variable != NULL) { |
| 2969 Slot* slot = variable->slot(); | 3035 Slot* slot = variable->slot(); |
| 2970 if (variable->is_global()) { | 3036 if (variable->is_global()) { |
| 2971 LoadGlobal(); | 3037 LoadGlobal(); |
| 2972 __ mov(r0, Operand(variable->name())); | 3038 __ mov(r0, Operand(variable->name())); |
| 2973 frame_->EmitPush(r0); | 3039 frame_->EmitPush(r0); |
| 2974 __ mov(r0, Operand(1)); // not counting receiver | 3040 Result arg_count = allocator_->Allocate(r0); |
| 2975 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2); | 3041 ASSERT(arg_count.is_valid()); |
| 3042 __ mov(arg_count.reg(), Operand(1)); // not counting receiver | |
| 3043 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2); | |
| 2976 | 3044 |
| 2977 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 3045 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 2978 // lookup the context holding the named variable | 3046 // lookup the context holding the named variable |
| 2979 frame_->EmitPush(cp); | 3047 frame_->EmitPush(cp); |
| 2980 __ mov(r0, Operand(variable->name())); | 3048 __ mov(r0, Operand(variable->name())); |
| 2981 frame_->EmitPush(r0); | 3049 frame_->EmitPush(r0); |
| 2982 frame_->CallRuntime(Runtime::kLookupContext, 2); | 3050 frame_->CallRuntime(Runtime::kLookupContext, 2); |
| 2983 // r0: context | 3051 // r0: context |
| 2984 frame_->EmitPush(r0); | 3052 frame_->EmitPush(r0); |
| 2985 __ mov(r0, Operand(variable->name())); | 3053 __ mov(r0, Operand(variable->name())); |
| 2986 frame_->EmitPush(r0); | 3054 frame_->EmitPush(r0); |
| 2987 __ mov(r0, Operand(1)); // not counting receiver | 3055 Result arg_count = allocator_->Allocate(r0); |
| 2988 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2); | 3056 ASSERT(arg_count.is_valid()); |
| 3057 __ mov(arg_count.reg(), Operand(1)); // not counting receiver | |
| 3058 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2); | |
| 2989 | 3059 |
| 2990 } else { | 3060 } else { |
| 2991 // Default: Result of deleting non-global, not dynamically | 3061 // Default: Result of deleting non-global, not dynamically |
| 2992 // introduced variables is false. | 3062 // introduced variables is false. |
| 2993 __ mov(r0, Operand(Factory::false_value())); | 3063 __ mov(r0, Operand(Factory::false_value())); |
| 2994 } | 3064 } |
| 2995 | 3065 |
| 2996 } else { | 3066 } else { |
| 2997 // Default: Result of deleting expressions is true. | 3067 // Default: Result of deleting expressions is true. |
| 2998 LoadAndSpill(node->expression()); // may have side-effects | 3068 LoadAndSpill(node->expression()); // may have side-effects |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 3025 } | 3095 } |
| 3026 | 3096 |
| 3027 case Token::BIT_NOT: { | 3097 case Token::BIT_NOT: { |
| 3028 // smi check | 3098 // smi check |
| 3029 JumpTarget smi_label(this); | 3099 JumpTarget smi_label(this); |
| 3030 JumpTarget continue_label(this); | 3100 JumpTarget continue_label(this); |
| 3031 __ tst(r0, Operand(kSmiTagMask)); | 3101 __ tst(r0, Operand(kSmiTagMask)); |
| 3032 smi_label.Branch(eq); | 3102 smi_label.Branch(eq); |
| 3033 | 3103 |
| 3034 frame_->EmitPush(r0); | 3104 frame_->EmitPush(r0); |
| 3035 __ mov(r0, Operand(0)); // not counting receiver | 3105 Result arg_count = allocator_->Allocate(r0); |
| 3036 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, 1); | 3106 ASSERT(arg_count.is_valid()); |
| 3107 __ mov(arg_count.reg(), Operand(0)); // not counting receiver | |
| 3108 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, &arg_count, 1); | |
| 3037 | 3109 |
| 3038 continue_label.Jump(); | 3110 continue_label.Jump(); |
| 3039 smi_label.Bind(); | 3111 smi_label.Bind(); |
| 3040 __ mvn(r0, Operand(r0)); | 3112 __ mvn(r0, Operand(r0)); |
| 3041 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag | 3113 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag |
| 3042 continue_label.Bind(); | 3114 continue_label.Bind(); |
| 3043 break; | 3115 break; |
| 3044 } | 3116 } |
| 3045 | 3117 |
| 3046 case Token::VOID: | 3118 case Token::VOID: |
| 3047 // since the stack top is cached in r0, popping and then | 3119 // since the stack top is cached in r0, popping and then |
| 3048 // pushing a value can be done by just writing to r0. | 3120 // pushing a value can be done by just writing to r0. |
| 3049 __ mov(r0, Operand(Factory::undefined_value())); | 3121 __ mov(r0, Operand(Factory::undefined_value())); |
| 3050 break; | 3122 break; |
| 3051 | 3123 |
| 3052 case Token::ADD: { | 3124 case Token::ADD: { |
| 3053 // Smi check. | 3125 // Smi check. |
| 3054 JumpTarget continue_label(this); | 3126 JumpTarget continue_label(this); |
| 3055 __ tst(r0, Operand(kSmiTagMask)); | 3127 __ tst(r0, Operand(kSmiTagMask)); |
| 3056 continue_label.Branch(eq); | 3128 continue_label.Branch(eq); |
| 3057 frame_->EmitPush(r0); | 3129 frame_->EmitPush(r0); |
| 3058 __ mov(r0, Operand(0)); // not counting receiver | 3130 Result arg_count = allocator_->Allocate(r0); |
| 3059 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1); | 3131 ASSERT(arg_count.is_valid()); |
| 3132 __ mov(arg_count.reg(), Operand(0)); // not counting receiver | |
| 3133 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, &arg_count, 1); | |
| 3060 continue_label.Bind(); | 3134 continue_label.Bind(); |
| 3061 break; | 3135 break; |
| 3062 } | 3136 } |
| 3063 default: | 3137 default: |
| 3064 UNREACHABLE(); | 3138 UNREACHABLE(); |
| 3065 } | 3139 } |
| 3066 frame_->EmitPush(r0); // r0 has result | 3140 frame_->EmitPush(r0); // r0 has result |
| 3067 } | 3141 } |
| 3068 } | 3142 } |
| 3069 | 3143 |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3453 break; | 3527 break; |
| 3454 | 3528 |
| 3455 case Token::GTE: | 3529 case Token::GTE: |
| 3456 Comparison(ge); | 3530 Comparison(ge); |
| 3457 break; | 3531 break; |
| 3458 | 3532 |
| 3459 case Token::EQ_STRICT: | 3533 case Token::EQ_STRICT: |
| 3460 Comparison(eq, true); | 3534 Comparison(eq, true); |
| 3461 break; | 3535 break; |
| 3462 | 3536 |
| 3463 case Token::IN: | 3537 case Token::IN: { |
| 3464 __ mov(r0, Operand(1)); // not counting receiver | 3538 Result arg_count = allocator_->Allocate(r0); |
| 3465 frame_->InvokeBuiltin(Builtins::IN, CALL_JS, 2); | 3539 ASSERT(arg_count.is_valid()); |
| 3466 frame_->EmitPush(r0); | 3540 __ mov(arg_count.reg(), Operand(1)); // not counting receiver |
| 3541 Result result = frame_->InvokeBuiltin(Builtins::IN, | |
| 3542 CALL_JS, | |
| 3543 &arg_count, | |
| 3544 2); | |
| 3545 frame_->EmitPush(result.reg()); | |
| 3467 break; | 3546 break; |
| 3547 } | |
| 3468 | 3548 |
| 3469 case Token::INSTANCEOF: | 3549 case Token::INSTANCEOF: { |
| 3470 __ mov(r0, Operand(1)); // not counting receiver | 3550 Result arg_count = allocator_->Allocate(r0); |
| 3471 frame_->InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS, 2); | 3551 ASSERT(arg_count.is_valid()); |
| 3472 __ tst(r0, Operand(r0)); | 3552 __ mov(arg_count.reg(), Operand(1)); // not counting receiver |
| 3553 Result result = frame_->InvokeBuiltin(Builtins::INSTANCE_OF, | |
| 3554 CALL_JS, | |
| 3555 &arg_count, | |
| 3556 2); | |
| 3557 __ tst(result.reg(), Operand(result.reg())); | |
| 3473 cc_reg_ = eq; | 3558 cc_reg_ = eq; |
| 3474 break; | 3559 break; |
| 3560 } | |
| 3475 | 3561 |
| 3476 default: | 3562 default: |
| 3477 UNREACHABLE(); | 3563 UNREACHABLE(); |
| 3478 } | 3564 } |
| 3479 } | 3565 } |
| 3480 | 3566 |
| 3481 | 3567 |
| 3482 #ifdef DEBUG | 3568 #ifdef DEBUG |
| 3483 bool CodeGenerator::HasValidEntryRegisters() { return true; } | 3569 bool CodeGenerator::HasValidEntryRegisters() { return true; } |
| 3484 #endif | 3570 #endif |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3669 exit.Bind(); | 3755 exit.Bind(); |
| 3670 } | 3756 } |
| 3671 } | 3757 } |
| 3672 break; | 3758 break; |
| 3673 } | 3759 } |
| 3674 | 3760 |
| 3675 case NAMED: { | 3761 case NAMED: { |
| 3676 Comment cmnt(masm, "[ Store to named Property"); | 3762 Comment cmnt(masm, "[ Store to named Property"); |
| 3677 // Call the appropriate IC code. | 3763 // Call the appropriate IC code. |
| 3678 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3764 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3679 frame->EmitPop(r0); // value | 3765 Handle<String> name(GetName()); |
| 3766 | |
| 3767 Result value = cgen_->allocator()->Allocate(r0); | |
| 3768 ASSERT(value.is_valid()); | |
| 3769 frame->EmitPop(value.reg()); | |
| 3770 | |
| 3680 // Setup the name register. | 3771 // Setup the name register. |
| 3681 Handle<String> name(GetName()); | 3772 Result property_name = cgen_->allocator()->Allocate(r2); |
| 3682 __ mov(r2, Operand(name)); | 3773 ASSERT(property_name.is_valid()); |
| 3683 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3774 __ mov(property_name.reg(), Operand(name)); |
| 3684 frame->EmitPush(r0); | 3775 Result answer = frame->CallCodeObject(ic, |
| 3776 RelocInfo::CODE_TARGET, | |
| 3777 &value, | |
| 3778 &property_name, | |
| 3779 0); | |
| 3780 frame->EmitPush(answer.reg()); | |
| 3685 break; | 3781 break; |
| 3686 } | 3782 } |
| 3687 | 3783 |
| 3688 case KEYED: { | 3784 case KEYED: { |
| 3689 Comment cmnt(masm, "[ Store to keyed Property"); | 3785 Comment cmnt(masm, "[ Store to keyed Property"); |
| 3690 Property* property = expression_->AsProperty(); | 3786 Property* property = expression_->AsProperty(); |
| 3691 ASSERT(property != NULL); | 3787 ASSERT(property != NULL); |
| 3692 cgen_->CodeForSourcePosition(property->position()); | 3788 cgen_->CodeForSourcePosition(property->position()); |
| 3693 | 3789 |
| 3694 // Call IC code. | 3790 // Call IC code. |
| 3695 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3791 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3696 // TODO(1222589): Make the IC grab the values from the stack. | 3792 // TODO(1222589): Make the IC grab the values from the stack. |
| 3697 frame->EmitPop(r0); // value | 3793 Result value = cgen_->allocator()->Allocate(r0); |
| 3698 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3794 ASSERT(value.is_valid()); |
| 3699 frame->EmitPush(r0); | 3795 frame->EmitPop(value.reg()); // value |
| 3796 Result result = | |
| 3797 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, &value, 0); | |
| 3798 frame->EmitPush(result.reg()); | |
| 3700 break; | 3799 break; |
| 3701 } | 3800 } |
| 3702 | 3801 |
| 3703 default: | 3802 default: |
| 3704 UNREACHABLE(); | 3803 UNREACHABLE(); |
| 3705 } | 3804 } |
| 3706 } | 3805 } |
| 3707 | 3806 |
| 3708 | 3807 |
| 3709 void GetPropertyStub::Generate(MacroAssembler* masm) { | 3808 void GetPropertyStub::Generate(MacroAssembler* masm) { |
| (...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4608 __ mov(r2, Operand(0)); | 4707 __ mov(r2, Operand(0)); |
| 4609 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 4708 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 4610 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 4709 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 4611 RelocInfo::CODE_TARGET); | 4710 RelocInfo::CODE_TARGET); |
| 4612 } | 4711 } |
| 4613 | 4712 |
| 4614 | 4713 |
| 4615 #undef __ | 4714 #undef __ |
| 4616 | 4715 |
| 4617 } } // namespace v8::internal | 4716 } } // namespace v8::internal |
| OLD | NEW |