| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/ast/ast.h" | 9 #include "src/ast/ast.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 #undef SIMD128_GEN_ASM | 653 #undef SIMD128_GEN_ASM |
| 654 | 654 |
| 655 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 655 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
| 656 compiler::Node* value = assembler->Parameter(0); | 656 compiler::Node* value = assembler->Parameter(0); |
| 657 compiler::Node* string = assembler->LoadJSValueValue(value); | 657 compiler::Node* string = assembler->LoadJSValueValue(value); |
| 658 compiler::Node* result = assembler->LoadStringLength(string); | 658 compiler::Node* result = assembler->LoadStringLength(string); |
| 659 assembler->Return(result); | 659 assembler->Return(result); |
| 660 } | 660 } |
| 661 | 661 |
| 662 // static | 662 // static |
| 663 compiler::Node* AddStub::Generate(CodeStubAssembler* assembler, | |
| 664 compiler::Node* left, compiler::Node* right, | |
| 665 compiler::Node* context) { | |
| 666 typedef CodeStubAssembler::Label Label; | |
| 667 typedef compiler::Node Node; | |
| 668 typedef CodeStubAssembler::Variable Variable; | |
| 669 | |
| 670 // Shared entry for floating point addition. | |
| 671 Label do_fadd(assembler); | |
| 672 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), | |
| 673 var_fadd_rhs(assembler, MachineRepresentation::kFloat64); | |
| 674 | |
| 675 // We might need to loop several times due to ToPrimitive, ToString and/or | |
| 676 // ToNumber conversions. | |
| 677 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
| 678 var_rhs(assembler, MachineRepresentation::kTagged), | |
| 679 var_result(assembler, MachineRepresentation::kTagged); | |
| 680 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
| 681 Label loop(assembler, 2, loop_vars), end(assembler), | |
| 682 string_add_convert_left(assembler, Label::kDeferred), | |
| 683 string_add_convert_right(assembler, Label::kDeferred); | |
| 684 var_lhs.Bind(left); | |
| 685 var_rhs.Bind(right); | |
| 686 assembler->Goto(&loop); | |
| 687 assembler->Bind(&loop); | |
| 688 { | |
| 689 // Load the current {lhs} and {rhs} values. | |
| 690 Node* lhs = var_lhs.value(); | |
| 691 Node* rhs = var_rhs.value(); | |
| 692 | |
| 693 // Check if the {lhs} is a Smi or a HeapObject. | |
| 694 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
| 695 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
| 696 | |
| 697 assembler->Bind(&if_lhsissmi); | |
| 698 { | |
| 699 // Check if the {rhs} is also a Smi. | |
| 700 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 701 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 702 &if_rhsisnotsmi); | |
| 703 | |
| 704 assembler->Bind(&if_rhsissmi); | |
| 705 { | |
| 706 // Try fast Smi addition first. | |
| 707 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); | |
| 708 Node* overflow = assembler->Projection(1, pair); | |
| 709 | |
| 710 // Check if the Smi additon overflowed. | |
| 711 Label if_overflow(assembler), if_notoverflow(assembler); | |
| 712 assembler->Branch(overflow, &if_overflow, &if_notoverflow); | |
| 713 | |
| 714 assembler->Bind(&if_overflow); | |
| 715 { | |
| 716 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 717 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
| 718 assembler->Goto(&do_fadd); | |
| 719 } | |
| 720 | |
| 721 assembler->Bind(&if_notoverflow); | |
| 722 var_result.Bind(assembler->Projection(0, pair)); | |
| 723 assembler->Goto(&end); | |
| 724 } | |
| 725 | |
| 726 assembler->Bind(&if_rhsisnotsmi); | |
| 727 { | |
| 728 // Load the map of {rhs}. | |
| 729 Node* rhs_map = assembler->LoadMap(rhs); | |
| 730 | |
| 731 // Check if the {rhs} is a HeapNumber. | |
| 732 Label if_rhsisnumber(assembler), | |
| 733 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 734 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
| 735 &if_rhsisnotnumber); | |
| 736 | |
| 737 assembler->Bind(&if_rhsisnumber); | |
| 738 { | |
| 739 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 740 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 741 assembler->Goto(&do_fadd); | |
| 742 } | |
| 743 | |
| 744 assembler->Bind(&if_rhsisnotnumber); | |
| 745 { | |
| 746 // Load the instance type of {rhs}. | |
| 747 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
| 748 | |
| 749 // Check if the {rhs} is a String. | |
| 750 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 751 if_rhsisnotstring(assembler, Label::kDeferred); | |
| 752 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), | |
| 753 &if_rhsisstring, &if_rhsisnotstring); | |
| 754 | |
| 755 assembler->Bind(&if_rhsisstring); | |
| 756 { | |
| 757 var_lhs.Bind(lhs); | |
| 758 var_rhs.Bind(rhs); | |
| 759 assembler->Goto(&string_add_convert_left); | |
| 760 } | |
| 761 | |
| 762 assembler->Bind(&if_rhsisnotstring); | |
| 763 { | |
| 764 // Check if {rhs} is a JSReceiver. | |
| 765 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
| 766 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
| 767 assembler->Branch( | |
| 768 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 769 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 770 | |
| 771 assembler->Bind(&if_rhsisreceiver); | |
| 772 { | |
| 773 // Convert {rhs} to a primitive first passing no hint. | |
| 774 Callable callable = | |
| 775 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
| 776 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 777 assembler->Goto(&loop); | |
| 778 } | |
| 779 | |
| 780 assembler->Bind(&if_rhsisnotreceiver); | |
| 781 { | |
| 782 // Convert {rhs} to a Number first. | |
| 783 Callable callable = | |
| 784 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 785 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 786 assembler->Goto(&loop); | |
| 787 } | |
| 788 } | |
| 789 } | |
| 790 } | |
| 791 } | |
| 792 | |
| 793 assembler->Bind(&if_lhsisnotsmi); | |
| 794 { | |
| 795 // Load the map and instance type of {lhs}. | |
| 796 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | |
| 797 | |
| 798 // Check if {lhs} is a String. | |
| 799 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); | |
| 800 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
| 801 &if_lhsisstring, &if_lhsisnotstring); | |
| 802 | |
| 803 assembler->Bind(&if_lhsisstring); | |
| 804 { | |
| 805 var_lhs.Bind(lhs); | |
| 806 var_rhs.Bind(rhs); | |
| 807 assembler->Goto(&string_add_convert_right); | |
| 808 } | |
| 809 | |
| 810 assembler->Bind(&if_lhsisnotstring); | |
| 811 { | |
| 812 // Check if {rhs} is a Smi. | |
| 813 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 814 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 815 &if_rhsisnotsmi); | |
| 816 | |
| 817 assembler->Bind(&if_rhsissmi); | |
| 818 { | |
| 819 // Check if {lhs} is a Number. | |
| 820 Label if_lhsisnumber(assembler), | |
| 821 if_lhsisnotnumber(assembler, Label::kDeferred); | |
| 822 assembler->Branch(assembler->Word32Equal( | |
| 823 lhs_instance_type, | |
| 824 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
| 825 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 826 | |
| 827 assembler->Bind(&if_lhsisnumber); | |
| 828 { | |
| 829 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. | |
| 830 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 831 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
| 832 assembler->Goto(&do_fadd); | |
| 833 } | |
| 834 | |
| 835 assembler->Bind(&if_lhsisnotnumber); | |
| 836 { | |
| 837 // The {lhs} is neither a Number nor a String, and the {rhs} is a | |
| 838 // Smi. | |
| 839 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
| 840 if_lhsisnotreceiver(assembler, Label::kDeferred); | |
| 841 assembler->Branch( | |
| 842 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
| 843 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
| 844 | |
| 845 assembler->Bind(&if_lhsisreceiver); | |
| 846 { | |
| 847 // Convert {lhs} to a primitive first passing no hint. | |
| 848 Callable callable = | |
| 849 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
| 850 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 851 assembler->Goto(&loop); | |
| 852 } | |
| 853 | |
| 854 assembler->Bind(&if_lhsisnotreceiver); | |
| 855 { | |
| 856 // Convert {lhs} to a Number first. | |
| 857 Callable callable = | |
| 858 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 859 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 860 assembler->Goto(&loop); | |
| 861 } | |
| 862 } | |
| 863 } | |
| 864 | |
| 865 assembler->Bind(&if_rhsisnotsmi); | |
| 866 { | |
| 867 // Load the instance type of {rhs}. | |
| 868 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
| 869 | |
| 870 // Check if {rhs} is a String. | |
| 871 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); | |
| 872 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), | |
| 873 &if_rhsisstring, &if_rhsisnotstring); | |
| 874 | |
| 875 assembler->Bind(&if_rhsisstring); | |
| 876 { | |
| 877 var_lhs.Bind(lhs); | |
| 878 var_rhs.Bind(rhs); | |
| 879 assembler->Goto(&string_add_convert_left); | |
| 880 } | |
| 881 | |
| 882 assembler->Bind(&if_rhsisnotstring); | |
| 883 { | |
| 884 // Check if {lhs} is a HeapNumber. | |
| 885 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
| 886 assembler->Branch(assembler->Word32Equal( | |
| 887 lhs_instance_type, | |
| 888 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
| 889 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 890 | |
| 891 assembler->Bind(&if_lhsisnumber); | |
| 892 { | |
| 893 // Check if {rhs} is also a HeapNumber. | |
| 894 Label if_rhsisnumber(assembler), | |
| 895 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 896 assembler->Branch(assembler->Word32Equal( | |
| 897 rhs_instance_type, | |
| 898 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
| 899 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 900 | |
| 901 assembler->Bind(&if_rhsisnumber); | |
| 902 { | |
| 903 // Perform a floating point addition. | |
| 904 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 905 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 906 assembler->Goto(&do_fadd); | |
| 907 } | |
| 908 | |
| 909 assembler->Bind(&if_rhsisnotnumber); | |
| 910 { | |
| 911 // Check if {rhs} is a JSReceiver. | |
| 912 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
| 913 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
| 914 assembler->Branch( | |
| 915 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 916 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 917 | |
| 918 assembler->Bind(&if_rhsisreceiver); | |
| 919 { | |
| 920 // Convert {rhs} to a primitive first passing no hint. | |
| 921 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
| 922 assembler->isolate()); | |
| 923 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 924 assembler->Goto(&loop); | |
| 925 } | |
| 926 | |
| 927 assembler->Bind(&if_rhsisnotreceiver); | |
| 928 { | |
| 929 // Convert {rhs} to a Number first. | |
| 930 Callable callable = | |
| 931 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 932 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 933 assembler->Goto(&loop); | |
| 934 } | |
| 935 } | |
| 936 } | |
| 937 | |
| 938 assembler->Bind(&if_lhsisnotnumber); | |
| 939 { | |
| 940 // Check if {lhs} is a JSReceiver. | |
| 941 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
| 942 if_lhsisnotreceiver(assembler); | |
| 943 assembler->Branch( | |
| 944 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
| 945 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
| 946 | |
| 947 assembler->Bind(&if_lhsisreceiver); | |
| 948 { | |
| 949 // Convert {lhs} to a primitive first passing no hint. | |
| 950 Callable callable = | |
| 951 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
| 952 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 953 assembler->Goto(&loop); | |
| 954 } | |
| 955 | |
| 956 assembler->Bind(&if_lhsisnotreceiver); | |
| 957 { | |
| 958 // Check if {rhs} is a JSReceiver. | |
| 959 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
| 960 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
| 961 assembler->Branch( | |
| 962 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 963 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 964 | |
| 965 assembler->Bind(&if_rhsisreceiver); | |
| 966 { | |
| 967 // Convert {rhs} to a primitive first passing no hint. | |
| 968 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
| 969 assembler->isolate()); | |
| 970 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 971 assembler->Goto(&loop); | |
| 972 } | |
| 973 | |
| 974 assembler->Bind(&if_rhsisnotreceiver); | |
| 975 { | |
| 976 // Convert {lhs} to a Number first. | |
| 977 Callable callable = | |
| 978 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 979 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 980 assembler->Goto(&loop); | |
| 981 } | |
| 982 } | |
| 983 } | |
| 984 } | |
| 985 } | |
| 986 } | |
| 987 } | |
| 988 } | |
| 989 assembler->Bind(&string_add_convert_left); | |
| 990 { | |
| 991 // Convert {lhs}, which is a Smi, to a String and concatenate the | |
| 992 // resulting string with the String {rhs}. | |
| 993 Callable callable = CodeFactory::StringAdd( | |
| 994 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); | |
| 995 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), | |
| 996 var_rhs.value())); | |
| 997 assembler->Goto(&end); | |
| 998 } | |
| 999 | |
| 1000 assembler->Bind(&string_add_convert_right); | |
| 1001 { | |
| 1002 // Convert {lhs}, which is a Smi, to a String and concatenate the | |
| 1003 // resulting string with the String {rhs}. | |
| 1004 Callable callable = CodeFactory::StringAdd( | |
| 1005 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); | |
| 1006 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), | |
| 1007 var_rhs.value())); | |
| 1008 assembler->Goto(&end); | |
| 1009 } | |
| 1010 | |
| 1011 assembler->Bind(&do_fadd); | |
| 1012 { | |
| 1013 Node* lhs_value = var_fadd_lhs.value(); | |
| 1014 Node* rhs_value = var_fadd_rhs.value(); | |
| 1015 Node* value = assembler->Float64Add(lhs_value, rhs_value); | |
| 1016 Node* result = assembler->ChangeFloat64ToTagged(value); | |
| 1017 var_result.Bind(result); | |
| 1018 assembler->Goto(&end); | |
| 1019 } | |
| 1020 assembler->Bind(&end); | |
| 1021 return var_result.value(); | |
| 1022 } | |
| 1023 | |
| 1024 // static | |
| 1025 compiler::Node* AddWithFeedbackStub::Generate( | 663 compiler::Node* AddWithFeedbackStub::Generate( |
| 1026 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 664 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
| 1027 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 665 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
| 1028 compiler::Node* context) { | 666 compiler::Node* context) { |
| 1029 typedef CodeStubAssembler::Label Label; | 667 typedef CodeStubAssembler::Label Label; |
| 1030 typedef compiler::Node Node; | 668 typedef compiler::Node Node; |
| 1031 typedef CodeStubAssembler::Variable Variable; | 669 typedef CodeStubAssembler::Variable Variable; |
| 1032 | 670 |
| 1033 // Shared entry for floating point addition. | 671 // Shared entry for floating point addition. |
| 1034 Label do_fadd(assembler), end(assembler), | 672 Label do_fadd(assembler), end(assembler), |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1144 assembler->Goto(&end); | 782 assembler->Goto(&end); |
| 1145 } | 783 } |
| 1146 | 784 |
| 1147 assembler->Bind(&end); | 785 assembler->Bind(&end); |
| 1148 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 786 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
| 1149 slot_id); | 787 slot_id); |
| 1150 return var_result.value(); | 788 return var_result.value(); |
| 1151 } | 789 } |
| 1152 | 790 |
| 1153 // static | 791 // static |
| 1154 compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler, | |
| 1155 compiler::Node* left, | |
| 1156 compiler::Node* right, | |
| 1157 compiler::Node* context) { | |
| 1158 typedef CodeStubAssembler::Label Label; | |
| 1159 typedef compiler::Node Node; | |
| 1160 typedef CodeStubAssembler::Variable Variable; | |
| 1161 | |
| 1162 // Shared entry for floating point subtraction. | |
| 1163 Label do_fsub(assembler), end(assembler); | |
| 1164 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), | |
| 1165 var_fsub_rhs(assembler, MachineRepresentation::kFloat64); | |
| 1166 | |
| 1167 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
| 1168 // conversions. | |
| 1169 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
| 1170 var_rhs(assembler, MachineRepresentation::kTagged), | |
| 1171 var_result(assembler, MachineRepresentation::kTagged); | |
| 1172 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
| 1173 Label loop(assembler, 2, loop_vars); | |
| 1174 var_lhs.Bind(left); | |
| 1175 var_rhs.Bind(right); | |
| 1176 assembler->Goto(&loop); | |
| 1177 assembler->Bind(&loop); | |
| 1178 { | |
| 1179 // Load the current {lhs} and {rhs} values. | |
| 1180 Node* lhs = var_lhs.value(); | |
| 1181 Node* rhs = var_rhs.value(); | |
| 1182 | |
| 1183 // Check if the {lhs} is a Smi or a HeapObject. | |
| 1184 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
| 1185 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
| 1186 | |
| 1187 assembler->Bind(&if_lhsissmi); | |
| 1188 { | |
| 1189 // Check if the {rhs} is also a Smi. | |
| 1190 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 1191 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 1192 &if_rhsisnotsmi); | |
| 1193 | |
| 1194 assembler->Bind(&if_rhsissmi); | |
| 1195 { | |
| 1196 // Try a fast Smi subtraction first. | |
| 1197 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); | |
| 1198 Node* overflow = assembler->Projection(1, pair); | |
| 1199 | |
| 1200 // Check if the Smi subtraction overflowed. | |
| 1201 Label if_overflow(assembler), if_notoverflow(assembler); | |
| 1202 assembler->Branch(overflow, &if_overflow, &if_notoverflow); | |
| 1203 | |
| 1204 assembler->Bind(&if_overflow); | |
| 1205 { | |
| 1206 // The result doesn't fit into Smi range. | |
| 1207 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 1208 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
| 1209 assembler->Goto(&do_fsub); | |
| 1210 } | |
| 1211 | |
| 1212 assembler->Bind(&if_notoverflow); | |
| 1213 var_result.Bind(assembler->Projection(0, pair)); | |
| 1214 assembler->Goto(&end); | |
| 1215 } | |
| 1216 | |
| 1217 assembler->Bind(&if_rhsisnotsmi); | |
| 1218 { | |
| 1219 // Load the map of the {rhs}. | |
| 1220 Node* rhs_map = assembler->LoadMap(rhs); | |
| 1221 | |
| 1222 // Check if {rhs} is a HeapNumber. | |
| 1223 Label if_rhsisnumber(assembler), | |
| 1224 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 1225 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
| 1226 &if_rhsisnotnumber); | |
| 1227 | |
| 1228 assembler->Bind(&if_rhsisnumber); | |
| 1229 { | |
| 1230 // Perform a floating point subtraction. | |
| 1231 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 1232 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 1233 assembler->Goto(&do_fsub); | |
| 1234 } | |
| 1235 | |
| 1236 assembler->Bind(&if_rhsisnotnumber); | |
| 1237 { | |
| 1238 // Convert the {rhs} to a Number first. | |
| 1239 Callable callable = | |
| 1240 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1241 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 1242 assembler->Goto(&loop); | |
| 1243 } | |
| 1244 } | |
| 1245 } | |
| 1246 | |
| 1247 assembler->Bind(&if_lhsisnotsmi); | |
| 1248 { | |
| 1249 // Load the map of the {lhs}. | |
| 1250 Node* lhs_map = assembler->LoadMap(lhs); | |
| 1251 | |
| 1252 // Check if the {lhs} is a HeapNumber. | |
| 1253 Label if_lhsisnumber(assembler), | |
| 1254 if_lhsisnotnumber(assembler, Label::kDeferred); | |
| 1255 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 1256 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
| 1257 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 1258 | |
| 1259 assembler->Bind(&if_lhsisnumber); | |
| 1260 { | |
| 1261 // Check if the {rhs} is a Smi. | |
| 1262 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 1263 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 1264 &if_rhsisnotsmi); | |
| 1265 | |
| 1266 assembler->Bind(&if_rhsissmi); | |
| 1267 { | |
| 1268 // Perform a floating point subtraction. | |
| 1269 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 1270 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
| 1271 assembler->Goto(&do_fsub); | |
| 1272 } | |
| 1273 | |
| 1274 assembler->Bind(&if_rhsisnotsmi); | |
| 1275 { | |
| 1276 // Load the map of the {rhs}. | |
| 1277 Node* rhs_map = assembler->LoadMap(rhs); | |
| 1278 | |
| 1279 // Check if the {rhs} is a HeapNumber. | |
| 1280 Label if_rhsisnumber(assembler), | |
| 1281 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 1282 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 1283 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 1284 | |
| 1285 assembler->Bind(&if_rhsisnumber); | |
| 1286 { | |
| 1287 // Perform a floating point subtraction. | |
| 1288 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 1289 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 1290 assembler->Goto(&do_fsub); | |
| 1291 } | |
| 1292 | |
| 1293 assembler->Bind(&if_rhsisnotnumber); | |
| 1294 { | |
| 1295 // Convert the {rhs} to a Number first. | |
| 1296 Callable callable = | |
| 1297 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1298 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 1299 assembler->Goto(&loop); | |
| 1300 } | |
| 1301 } | |
| 1302 } | |
| 1303 | |
| 1304 assembler->Bind(&if_lhsisnotnumber); | |
| 1305 { | |
| 1306 // Convert the {lhs} to a Number first. | |
| 1307 Callable callable = | |
| 1308 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1309 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 1310 assembler->Goto(&loop); | |
| 1311 } | |
| 1312 } | |
| 1313 } | |
| 1314 | |
| 1315 assembler->Bind(&do_fsub); | |
| 1316 { | |
| 1317 Node* lhs_value = var_fsub_lhs.value(); | |
| 1318 Node* rhs_value = var_fsub_rhs.value(); | |
| 1319 Node* value = assembler->Float64Sub(lhs_value, rhs_value); | |
| 1320 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
| 1321 assembler->Goto(&end); | |
| 1322 } | |
| 1323 assembler->Bind(&end); | |
| 1324 return var_result.value(); | |
| 1325 } | |
| 1326 | |
| 1327 // static | |
| 1328 compiler::Node* SubtractWithFeedbackStub::Generate( | 792 compiler::Node* SubtractWithFeedbackStub::Generate( |
| 1329 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 793 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
| 1330 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 794 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
| 1331 compiler::Node* context) { | 795 compiler::Node* context) { |
| 1332 typedef CodeStubAssembler::Label Label; | 796 typedef CodeStubAssembler::Label Label; |
| 1333 typedef compiler::Node Node; | 797 typedef compiler::Node Node; |
| 1334 typedef CodeStubAssembler::Variable Variable; | 798 typedef CodeStubAssembler::Variable Variable; |
| 1335 | 799 |
| 1336 // Shared entry for floating point subtraction. | 800 // Shared entry for floating point subtraction. |
| 1337 Label do_fsub(assembler), end(assembler), | 801 Label do_fsub(assembler), end(assembler), |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1450 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | 914 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); |
| 1451 assembler->Goto(&end); | 915 assembler->Goto(&end); |
| 1452 } | 916 } |
| 1453 | 917 |
| 1454 assembler->Bind(&end); | 918 assembler->Bind(&end); |
| 1455 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 919 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
| 1456 slot_id); | 920 slot_id); |
| 1457 return var_result.value(); | 921 return var_result.value(); |
| 1458 } | 922 } |
| 1459 | 923 |
| 1460 // static | |
| 1461 compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler, | |
| 1462 compiler::Node* left, | |
| 1463 compiler::Node* right, | |
| 1464 compiler::Node* context) { | |
| 1465 using compiler::Node; | |
| 1466 typedef CodeStubAssembler::Label Label; | |
| 1467 typedef CodeStubAssembler::Variable Variable; | |
| 1468 | |
| 1469 // Shared entry point for floating point multiplication. | |
| 1470 Label do_fmul(assembler), return_result(assembler); | |
| 1471 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), | |
| 1472 var_rhs_float64(assembler, MachineRepresentation::kFloat64); | |
| 1473 | |
| 1474 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 1475 | |
| 1476 // We might need to loop one or two times due to ToNumber conversions. | |
| 1477 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
| 1478 var_rhs(assembler, MachineRepresentation::kTagged), | |
| 1479 var_result(assembler, MachineRepresentation::kTagged); | |
| 1480 Variable* loop_variables[] = {&var_lhs, &var_rhs}; | |
| 1481 Label loop(assembler, 2, loop_variables); | |
| 1482 var_lhs.Bind(left); | |
| 1483 var_rhs.Bind(right); | |
| 1484 assembler->Goto(&loop); | |
| 1485 assembler->Bind(&loop); | |
| 1486 { | |
| 1487 Node* lhs = var_lhs.value(); | |
| 1488 Node* rhs = var_rhs.value(); | |
| 1489 | |
| 1490 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); | |
| 1491 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); | |
| 1492 | |
| 1493 assembler->Bind(&lhs_is_smi); | |
| 1494 { | |
| 1495 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); | |
| 1496 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, | |
| 1497 &rhs_is_not_smi); | |
| 1498 | |
| 1499 assembler->Bind(&rhs_is_smi); | |
| 1500 { | |
| 1501 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, | |
| 1502 // in case of overflow. | |
| 1503 var_result.Bind(assembler->SmiMul(lhs, rhs)); | |
| 1504 assembler->Goto(&return_result); | |
| 1505 } | |
| 1506 | |
| 1507 assembler->Bind(&rhs_is_not_smi); | |
| 1508 { | |
| 1509 Node* rhs_map = assembler->LoadMap(rhs); | |
| 1510 | |
| 1511 // Check if {rhs} is a HeapNumber. | |
| 1512 Label rhs_is_number(assembler), | |
| 1513 rhs_is_not_number(assembler, Label::kDeferred); | |
| 1514 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 1515 &rhs_is_number, &rhs_is_not_number); | |
| 1516 | |
| 1517 assembler->Bind(&rhs_is_number); | |
| 1518 { | |
| 1519 // Convert {lhs} to a double and multiply it with the value of {rhs}. | |
| 1520 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); | |
| 1521 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 1522 assembler->Goto(&do_fmul); | |
| 1523 } | |
| 1524 | |
| 1525 assembler->Bind(&rhs_is_not_number); | |
| 1526 { | |
| 1527 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | |
| 1528 var_lhs.Bind(rhs); | |
| 1529 var_rhs.Bind(lhs); | |
| 1530 assembler->Goto(&loop); | |
| 1531 } | |
| 1532 } | |
| 1533 } | |
| 1534 | |
| 1535 assembler->Bind(&lhs_is_not_smi); | |
| 1536 { | |
| 1537 Node* lhs_map = assembler->LoadMap(lhs); | |
| 1538 | |
| 1539 // Check if {lhs} is a HeapNumber. | |
| 1540 Label lhs_is_number(assembler), | |
| 1541 lhs_is_not_number(assembler, Label::kDeferred); | |
| 1542 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
| 1543 &lhs_is_number, &lhs_is_not_number); | |
| 1544 | |
| 1545 assembler->Bind(&lhs_is_number); | |
| 1546 { | |
| 1547 // Check if {rhs} is a Smi. | |
| 1548 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); | |
| 1549 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, | |
| 1550 &rhs_is_not_smi); | |
| 1551 | |
| 1552 assembler->Bind(&rhs_is_smi); | |
| 1553 { | |
| 1554 // Convert {rhs} to a double and multiply it with the value of {lhs}. | |
| 1555 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 1556 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); | |
| 1557 assembler->Goto(&do_fmul); | |
| 1558 } | |
| 1559 | |
| 1560 assembler->Bind(&rhs_is_not_smi); | |
| 1561 { | |
| 1562 Node* rhs_map = assembler->LoadMap(rhs); | |
| 1563 | |
| 1564 // Check if {rhs} is a HeapNumber. | |
| 1565 Label rhs_is_number(assembler), | |
| 1566 rhs_is_not_number(assembler, Label::kDeferred); | |
| 1567 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 1568 &rhs_is_number, &rhs_is_not_number); | |
| 1569 | |
| 1570 assembler->Bind(&rhs_is_number); | |
| 1571 { | |
| 1572 // Both {lhs} and {rhs} are HeapNumbers. Load their values and | |
| 1573 // multiply them. | |
| 1574 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 1575 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 1576 assembler->Goto(&do_fmul); | |
| 1577 } | |
| 1578 | |
| 1579 assembler->Bind(&rhs_is_not_number); | |
| 1580 { | |
| 1581 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | |
| 1582 var_lhs.Bind(rhs); | |
| 1583 var_rhs.Bind(lhs); | |
| 1584 assembler->Goto(&loop); | |
| 1585 } | |
| 1586 } | |
| 1587 } | |
| 1588 | |
| 1589 assembler->Bind(&lhs_is_not_number); | |
| 1590 { | |
| 1591 // Convert {lhs} to a Number and loop. | |
| 1592 Callable callable = | |
| 1593 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1594 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 1595 assembler->Goto(&loop); | |
| 1596 } | |
| 1597 } | |
| 1598 } | |
| 1599 | |
| 1600 assembler->Bind(&do_fmul); | |
| 1601 { | |
| 1602 Node* value = | |
| 1603 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); | |
| 1604 Node* result = assembler->ChangeFloat64ToTagged(value); | |
| 1605 var_result.Bind(result); | |
| 1606 assembler->Goto(&return_result); | |
| 1607 } | |
| 1608 | |
| 1609 assembler->Bind(&return_result); | |
| 1610 return var_result.value(); | |
| 1611 } | |
| 1612 | 924 |
| 1613 // static | 925 // static |
| 1614 compiler::Node* MultiplyWithFeedbackStub::Generate( | 926 compiler::Node* MultiplyWithFeedbackStub::Generate( |
| 1615 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 927 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
| 1616 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 928 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
| 1617 compiler::Node* context) { | 929 compiler::Node* context) { |
| 1618 using compiler::Node; | 930 using compiler::Node; |
| 1619 typedef CodeStubAssembler::Label Label; | 931 typedef CodeStubAssembler::Label Label; |
| 1620 typedef CodeStubAssembler::Variable Variable; | 932 typedef CodeStubAssembler::Variable Variable; |
| 1621 | 933 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1720 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | 1032 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); |
| 1721 assembler->Goto(&end); | 1033 assembler->Goto(&end); |
| 1722 } | 1034 } |
| 1723 | 1035 |
| 1724 assembler->Bind(&end); | 1036 assembler->Bind(&end); |
| 1725 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1037 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
| 1726 slot_id); | 1038 slot_id); |
| 1727 return var_result.value(); | 1039 return var_result.value(); |
| 1728 } | 1040 } |
| 1729 | 1041 |
| 1730 // static | |
| 1731 compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, | |
| 1732 compiler::Node* left, | |
| 1733 compiler::Node* right, | |
| 1734 compiler::Node* context) { | |
| 1735 using compiler::Node; | |
| 1736 typedef CodeStubAssembler::Label Label; | |
| 1737 typedef CodeStubAssembler::Variable Variable; | |
| 1738 | |
| 1739 // Shared entry point for floating point division. | |
| 1740 Label do_fdiv(assembler), end(assembler); | |
| 1741 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), | |
| 1742 var_divisor_float64(assembler, MachineRepresentation::kFloat64); | |
| 1743 | |
| 1744 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 1745 | |
| 1746 // We might need to loop one or two times due to ToNumber conversions. | |
| 1747 Variable var_dividend(assembler, MachineRepresentation::kTagged), | |
| 1748 var_divisor(assembler, MachineRepresentation::kTagged), | |
| 1749 var_result(assembler, MachineRepresentation::kTagged); | |
| 1750 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | |
| 1751 Label loop(assembler, 2, loop_variables); | |
| 1752 var_dividend.Bind(left); | |
| 1753 var_divisor.Bind(right); | |
| 1754 assembler->Goto(&loop); | |
| 1755 assembler->Bind(&loop); | |
| 1756 { | |
| 1757 Node* dividend = var_dividend.value(); | |
| 1758 Node* divisor = var_divisor.value(); | |
| 1759 | |
| 1760 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); | |
| 1761 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, | |
| 1762 ÷nd_is_not_smi); | |
| 1763 | |
| 1764 assembler->Bind(÷nd_is_smi); | |
| 1765 { | |
| 1766 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
| 1767 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
| 1768 &divisor_is_not_smi); | |
| 1769 | |
| 1770 assembler->Bind(&divisor_is_smi); | |
| 1771 { | |
| 1772 Label bailout(assembler); | |
| 1773 | |
| 1774 // Do floating point division if {divisor} is zero. | |
| 1775 assembler->GotoIf( | |
| 1776 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)), | |
| 1777 &bailout); | |
| 1778 | |
| 1779 // Do floating point division {dividend} is zero and {divisor} is | |
| 1780 // negative. | |
| 1781 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler); | |
| 1782 assembler->Branch( | |
| 1783 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)), | |
| 1784 ÷nd_is_zero, ÷nd_is_not_zero); | |
| 1785 | |
| 1786 assembler->Bind(÷nd_is_zero); | |
| 1787 { | |
| 1788 assembler->GotoIf( | |
| 1789 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)), | |
| 1790 &bailout); | |
| 1791 assembler->Goto(÷nd_is_not_zero); | |
| 1792 } | |
| 1793 assembler->Bind(÷nd_is_not_zero); | |
| 1794 | |
| 1795 Node* untagged_divisor = assembler->SmiUntag(divisor); | |
| 1796 Node* untagged_dividend = assembler->SmiUntag(dividend); | |
| 1797 | |
| 1798 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 | |
| 1799 // if the Smi size is 31) and {divisor} is -1. | |
| 1800 Label divisor_is_minus_one(assembler), | |
| 1801 divisor_is_not_minus_one(assembler); | |
| 1802 assembler->Branch(assembler->Word32Equal(untagged_divisor, | |
| 1803 assembler->Int32Constant(-1)), | |
| 1804 &divisor_is_minus_one, &divisor_is_not_minus_one); | |
| 1805 | |
| 1806 assembler->Bind(&divisor_is_minus_one); | |
| 1807 { | |
| 1808 assembler->GotoIf( | |
| 1809 assembler->Word32Equal( | |
| 1810 untagged_dividend, | |
| 1811 assembler->Int32Constant( | |
| 1812 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), | |
| 1813 &bailout); | |
| 1814 assembler->Goto(&divisor_is_not_minus_one); | |
| 1815 } | |
| 1816 assembler->Bind(&divisor_is_not_minus_one); | |
| 1817 | |
| 1818 // TODO(epertoso): consider adding a machine instruction that returns | |
| 1819 // both the result and the remainder. | |
| 1820 Node* untagged_result = | |
| 1821 assembler->Int32Div(untagged_dividend, untagged_divisor); | |
| 1822 Node* truncated = | |
| 1823 assembler->Int32Mul(untagged_result, untagged_divisor); | |
| 1824 // Do floating point division if the remainder is not 0. | |
| 1825 assembler->GotoIf( | |
| 1826 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout); | |
| 1827 var_result.Bind(assembler->SmiTag(untagged_result)); | |
| 1828 assembler->Goto(&end); | |
| 1829 | |
| 1830 // Bailout: convert {dividend} and {divisor} to double and do double | |
| 1831 // division. | |
| 1832 assembler->Bind(&bailout); | |
| 1833 { | |
| 1834 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
| 1835 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
| 1836 assembler->Goto(&do_fdiv); | |
| 1837 } | |
| 1838 } | |
| 1839 | |
| 1840 assembler->Bind(&divisor_is_not_smi); | |
| 1841 { | |
| 1842 Node* divisor_map = assembler->LoadMap(divisor); | |
| 1843 | |
| 1844 // Check if {divisor} is a HeapNumber. | |
| 1845 Label divisor_is_number(assembler), | |
| 1846 divisor_is_not_number(assembler, Label::kDeferred); | |
| 1847 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
| 1848 &divisor_is_number, &divisor_is_not_number); | |
| 1849 | |
| 1850 assembler->Bind(&divisor_is_number); | |
| 1851 { | |
| 1852 // Convert {dividend} to a double and divide it with the value of | |
| 1853 // {divisor}. | |
| 1854 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
| 1855 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
| 1856 assembler->Goto(&do_fdiv); | |
| 1857 } | |
| 1858 | |
| 1859 assembler->Bind(&divisor_is_not_number); | |
| 1860 { | |
| 1861 // Convert {divisor} to a number and loop. | |
| 1862 Callable callable = | |
| 1863 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1864 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
| 1865 assembler->Goto(&loop); | |
| 1866 } | |
| 1867 } | |
| 1868 } | |
| 1869 | |
| 1870 assembler->Bind(÷nd_is_not_smi); | |
| 1871 { | |
| 1872 Node* dividend_map = assembler->LoadMap(dividend); | |
| 1873 | |
| 1874 // Check if {dividend} is a HeapNumber. | |
| 1875 Label dividend_is_number(assembler), | |
| 1876 dividend_is_not_number(assembler, Label::kDeferred); | |
| 1877 assembler->Branch(assembler->WordEqual(dividend_map, number_map), | |
| 1878 ÷nd_is_number, ÷nd_is_not_number); | |
| 1879 | |
| 1880 assembler->Bind(÷nd_is_number); | |
| 1881 { | |
| 1882 // Check if {divisor} is a Smi. | |
| 1883 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
| 1884 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
| 1885 &divisor_is_not_smi); | |
| 1886 | |
| 1887 assembler->Bind(&divisor_is_smi); | |
| 1888 { | |
| 1889 // Convert {divisor} to a double and use it for a floating point | |
| 1890 // division. | |
| 1891 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
| 1892 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
| 1893 assembler->Goto(&do_fdiv); | |
| 1894 } | |
| 1895 | |
| 1896 assembler->Bind(&divisor_is_not_smi); | |
| 1897 { | |
| 1898 Node* divisor_map = assembler->LoadMap(divisor); | |
| 1899 | |
| 1900 // Check if {divisor} is a HeapNumber. | |
| 1901 Label divisor_is_number(assembler), | |
| 1902 divisor_is_not_number(assembler, Label::kDeferred); | |
| 1903 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
| 1904 &divisor_is_number, &divisor_is_not_number); | |
| 1905 | |
| 1906 assembler->Bind(&divisor_is_number); | |
| 1907 { | |
| 1908 // Both {dividend} and {divisor} are HeapNumbers. Load their values | |
| 1909 // and divide them. | |
| 1910 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
| 1911 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
| 1912 assembler->Goto(&do_fdiv); | |
| 1913 } | |
| 1914 | |
| 1915 assembler->Bind(&divisor_is_not_number); | |
| 1916 { | |
| 1917 // Convert {divisor} to a number and loop. | |
| 1918 Callable callable = | |
| 1919 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1920 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
| 1921 assembler->Goto(&loop); | |
| 1922 } | |
| 1923 } | |
| 1924 } | |
| 1925 | |
| 1926 assembler->Bind(÷nd_is_not_number); | |
| 1927 { | |
| 1928 // Convert {dividend} to a Number and loop. | |
| 1929 Callable callable = | |
| 1930 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 1931 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); | |
| 1932 assembler->Goto(&loop); | |
| 1933 } | |
| 1934 } | |
| 1935 } | |
| 1936 | |
| 1937 assembler->Bind(&do_fdiv); | |
| 1938 { | |
| 1939 Node* value = assembler->Float64Div(var_dividend_float64.value(), | |
| 1940 var_divisor_float64.value()); | |
| 1941 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
| 1942 assembler->Goto(&end); | |
| 1943 } | |
| 1944 assembler->Bind(&end); | |
| 1945 return var_result.value(); | |
| 1946 } | |
| 1947 | 1042 |
| 1948 // static | 1043 // static |
| 1949 compiler::Node* DivideWithFeedbackStub::Generate( | 1044 compiler::Node* DivideWithFeedbackStub::Generate( |
| 1950 CodeStubAssembler* assembler, compiler::Node* dividend, | 1045 CodeStubAssembler* assembler, compiler::Node* dividend, |
| 1951 compiler::Node* divisor, compiler::Node* slot_id, | 1046 compiler::Node* divisor, compiler::Node* slot_id, |
| 1952 compiler::Node* type_feedback_vector, compiler::Node* context) { | 1047 compiler::Node* type_feedback_vector, compiler::Node* context) { |
| 1953 using compiler::Node; | 1048 using compiler::Node; |
| 1954 typedef CodeStubAssembler::Label Label; | 1049 typedef CodeStubAssembler::Label Label; |
| 1955 typedef CodeStubAssembler::Variable Variable; | 1050 typedef CodeStubAssembler::Variable Variable; |
| 1956 | 1051 |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2115 assembler->Goto(&end); | 1210 assembler->Goto(&end); |
| 2116 } | 1211 } |
| 2117 | 1212 |
| 2118 assembler->Bind(&end); | 1213 assembler->Bind(&end); |
| 2119 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1214 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
| 2120 slot_id); | 1215 slot_id); |
| 2121 return var_result.value(); | 1216 return var_result.value(); |
| 2122 } | 1217 } |
| 2123 | 1218 |
| 2124 // static | 1219 // static |
| 2125 compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler, | |
| 2126 compiler::Node* left, | |
| 2127 compiler::Node* right, | |
| 2128 compiler::Node* context) { | |
| 2129 using compiler::Node; | |
| 2130 typedef CodeStubAssembler::Label Label; | |
| 2131 typedef CodeStubAssembler::Variable Variable; | |
| 2132 | |
| 2133 Variable var_result(assembler, MachineRepresentation::kTagged); | |
| 2134 Label return_result(assembler, &var_result); | |
| 2135 | |
| 2136 // Shared entry point for floating point modulus. | |
| 2137 Label do_fmod(assembler); | |
| 2138 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), | |
| 2139 var_divisor_float64(assembler, MachineRepresentation::kFloat64); | |
| 2140 | |
| 2141 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 2142 | |
| 2143 // We might need to loop one or two times due to ToNumber conversions. | |
| 2144 Variable var_dividend(assembler, MachineRepresentation::kTagged), | |
| 2145 var_divisor(assembler, MachineRepresentation::kTagged); | |
| 2146 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | |
| 2147 Label loop(assembler, 2, loop_variables); | |
| 2148 var_dividend.Bind(left); | |
| 2149 var_divisor.Bind(right); | |
| 2150 assembler->Goto(&loop); | |
| 2151 assembler->Bind(&loop); | |
| 2152 { | |
| 2153 Node* dividend = var_dividend.value(); | |
| 2154 Node* divisor = var_divisor.value(); | |
| 2155 | |
| 2156 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); | |
| 2157 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, | |
| 2158 ÷nd_is_not_smi); | |
| 2159 | |
| 2160 assembler->Bind(÷nd_is_smi); | |
| 2161 { | |
| 2162 Label dividend_is_not_zero(assembler); | |
| 2163 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
| 2164 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
| 2165 &divisor_is_not_smi); | |
| 2166 | |
| 2167 assembler->Bind(&divisor_is_smi); | |
| 2168 { | |
| 2169 // Compute the modulus of two Smis. | |
| 2170 var_result.Bind(assembler->SmiMod(dividend, divisor)); | |
| 2171 assembler->Goto(&return_result); | |
| 2172 } | |
| 2173 | |
| 2174 assembler->Bind(&divisor_is_not_smi); | |
| 2175 { | |
| 2176 Node* divisor_map = assembler->LoadMap(divisor); | |
| 2177 | |
| 2178 // Check if {divisor} is a HeapNumber. | |
| 2179 Label divisor_is_number(assembler), | |
| 2180 divisor_is_not_number(assembler, Label::kDeferred); | |
| 2181 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
| 2182 &divisor_is_number, &divisor_is_not_number); | |
| 2183 | |
| 2184 assembler->Bind(&divisor_is_number); | |
| 2185 { | |
| 2186 // Convert {dividend} to a double and compute its modulus with the | |
| 2187 // value of {dividend}. | |
| 2188 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
| 2189 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
| 2190 assembler->Goto(&do_fmod); | |
| 2191 } | |
| 2192 | |
| 2193 assembler->Bind(&divisor_is_not_number); | |
| 2194 { | |
| 2195 // Convert {divisor} to a number and loop. | |
| 2196 Callable callable = | |
| 2197 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 2198 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
| 2199 assembler->Goto(&loop); | |
| 2200 } | |
| 2201 } | |
| 2202 } | |
| 2203 | |
| 2204 assembler->Bind(÷nd_is_not_smi); | |
| 2205 { | |
| 2206 Node* dividend_map = assembler->LoadMap(dividend); | |
| 2207 | |
| 2208 // Check if {dividend} is a HeapNumber. | |
| 2209 Label dividend_is_number(assembler), | |
| 2210 dividend_is_not_number(assembler, Label::kDeferred); | |
| 2211 assembler->Branch(assembler->WordEqual(dividend_map, number_map), | |
| 2212 ÷nd_is_number, ÷nd_is_not_number); | |
| 2213 | |
| 2214 assembler->Bind(÷nd_is_number); | |
| 2215 { | |
| 2216 // Check if {divisor} is a Smi. | |
| 2217 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
| 2218 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
| 2219 &divisor_is_not_smi); | |
| 2220 | |
| 2221 assembler->Bind(&divisor_is_smi); | |
| 2222 { | |
| 2223 // Convert {divisor} to a double and compute {dividend}'s modulus with | |
| 2224 // it. | |
| 2225 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
| 2226 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
| 2227 assembler->Goto(&do_fmod); | |
| 2228 } | |
| 2229 | |
| 2230 assembler->Bind(&divisor_is_not_smi); | |
| 2231 { | |
| 2232 Node* divisor_map = assembler->LoadMap(divisor); | |
| 2233 | |
| 2234 // Check if {divisor} is a HeapNumber. | |
| 2235 Label divisor_is_number(assembler), | |
| 2236 divisor_is_not_number(assembler, Label::kDeferred); | |
| 2237 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
| 2238 &divisor_is_number, &divisor_is_not_number); | |
| 2239 | |
| 2240 assembler->Bind(&divisor_is_number); | |
| 2241 { | |
| 2242 // Both {dividend} and {divisor} are HeapNumbers. Load their values | |
| 2243 // and compute their modulus. | |
| 2244 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
| 2245 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
| 2246 assembler->Goto(&do_fmod); | |
| 2247 } | |
| 2248 | |
| 2249 assembler->Bind(&divisor_is_not_number); | |
| 2250 { | |
| 2251 // Convert {divisor} to a number and loop. | |
| 2252 Callable callable = | |
| 2253 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 2254 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
| 2255 assembler->Goto(&loop); | |
| 2256 } | |
| 2257 } | |
| 2258 } | |
| 2259 | |
| 2260 assembler->Bind(÷nd_is_not_number); | |
| 2261 { | |
| 2262 // Convert {dividend} to a Number and loop. | |
| 2263 Callable callable = | |
| 2264 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 2265 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); | |
| 2266 assembler->Goto(&loop); | |
| 2267 } | |
| 2268 } | |
| 2269 } | |
| 2270 | |
| 2271 assembler->Bind(&do_fmod); | |
| 2272 { | |
| 2273 Node* value = assembler->Float64Mod(var_dividend_float64.value(), | |
| 2274 var_divisor_float64.value()); | |
| 2275 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
| 2276 assembler->Goto(&return_result); | |
| 2277 } | |
| 2278 | |
| 2279 assembler->Bind(&return_result); | |
| 2280 return var_result.value(); | |
| 2281 } | |
| 2282 | |
| 2283 // static | |
| 2284 compiler::Node* ModulusWithFeedbackStub::Generate( | 1220 compiler::Node* ModulusWithFeedbackStub::Generate( |
| 2285 CodeStubAssembler* assembler, compiler::Node* dividend, | 1221 CodeStubAssembler* assembler, compiler::Node* dividend, |
| 2286 compiler::Node* divisor, compiler::Node* slot_id, | 1222 compiler::Node* divisor, compiler::Node* slot_id, |
| 2287 compiler::Node* type_feedback_vector, compiler::Node* context) { | 1223 compiler::Node* type_feedback_vector, compiler::Node* context) { |
| 2288 using compiler::Node; | 1224 using compiler::Node; |
| 2289 typedef CodeStubAssembler::Label Label; | 1225 typedef CodeStubAssembler::Label Label; |
| 2290 typedef CodeStubAssembler::Variable Variable; | 1226 typedef CodeStubAssembler::Variable Variable; |
| 2291 | 1227 |
| 2292 // Shared entry point for floating point division. | 1228 // Shared entry point for floating point division. |
| 2293 Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); | 1229 Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2389 Callable callable = CodeFactory::Modulus(assembler->isolate()); | 1325 Callable callable = CodeFactory::Modulus(assembler->isolate()); |
| 2390 var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); | 1326 var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); |
| 2391 assembler->Goto(&end); | 1327 assembler->Goto(&end); |
| 2392 } | 1328 } |
| 2393 | 1329 |
| 2394 assembler->Bind(&end); | 1330 assembler->Bind(&end); |
| 2395 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1331 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
| 2396 slot_id); | 1332 slot_id); |
| 2397 return var_result.value(); | 1333 return var_result.value(); |
| 2398 } | 1334 } |
| 2399 // static | |
| 2400 compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler, | |
| 2401 compiler::Node* left, | |
| 2402 compiler::Node* right, | |
| 2403 compiler::Node* context) { | |
| 2404 using compiler::Node; | |
| 2405 | |
| 2406 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2407 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2408 Node* shift_count = | |
| 2409 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
| 2410 Node* value = assembler->Word32Shl(lhs_value, shift_count); | |
| 2411 Node* result = assembler->ChangeInt32ToTagged(value); | |
| 2412 return result; | |
| 2413 } | |
| 2414 | |
| 2415 // static | |
| 2416 compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler, | |
| 2417 compiler::Node* left, | |
| 2418 compiler::Node* right, | |
| 2419 compiler::Node* context) { | |
| 2420 using compiler::Node; | |
| 2421 | |
| 2422 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2423 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2424 Node* shift_count = | |
| 2425 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
| 2426 Node* value = assembler->Word32Sar(lhs_value, shift_count); | |
| 2427 Node* result = assembler->ChangeInt32ToTagged(value); | |
| 2428 return result; | |
| 2429 } | |
| 2430 | |
| 2431 // static | |
| 2432 compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler, | |
| 2433 compiler::Node* left, | |
| 2434 compiler::Node* right, | |
| 2435 compiler::Node* context) { | |
| 2436 using compiler::Node; | |
| 2437 | |
| 2438 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2439 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2440 Node* shift_count = | |
| 2441 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
| 2442 Node* value = assembler->Word32Shr(lhs_value, shift_count); | |
| 2443 Node* result = assembler->ChangeUint32ToTagged(value); | |
| 2444 return result; | |
| 2445 } | |
| 2446 | |
| 2447 // static | |
| 2448 compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler, | |
| 2449 compiler::Node* left, | |
| 2450 compiler::Node* right, | |
| 2451 compiler::Node* context) { | |
| 2452 using compiler::Node; | |
| 2453 | |
| 2454 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2455 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2456 Node* value = assembler->Word32And(lhs_value, rhs_value); | |
| 2457 Node* result = assembler->ChangeInt32ToTagged(value); | |
| 2458 return result; | |
| 2459 } | |
| 2460 | |
| 2461 // static | |
| 2462 compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler, | |
| 2463 compiler::Node* left, | |
| 2464 compiler::Node* right, | |
| 2465 compiler::Node* context) { | |
| 2466 using compiler::Node; | |
| 2467 | |
| 2468 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2469 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2470 Node* value = assembler->Word32Or(lhs_value, rhs_value); | |
| 2471 Node* result = assembler->ChangeInt32ToTagged(value); | |
| 2472 return result; | |
| 2473 } | |
| 2474 | |
| 2475 // static | |
| 2476 compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler, | |
| 2477 compiler::Node* left, | |
| 2478 compiler::Node* right, | |
| 2479 compiler::Node* context) { | |
| 2480 using compiler::Node; | |
| 2481 | |
| 2482 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
| 2483 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
| 2484 Node* value = assembler->Word32Xor(lhs_value, rhs_value); | |
| 2485 Node* result = assembler->ChangeInt32ToTagged(value); | |
| 2486 return result; | |
| 2487 } | |
| 2488 | 1335 |
| 2489 // static | 1336 // static |
| 2490 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, | 1337 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, |
| 2491 compiler::Node* value, | 1338 compiler::Node* value, |
| 2492 compiler::Node* context, | 1339 compiler::Node* context, |
| 2493 compiler::Node* type_feedback_vector, | 1340 compiler::Node* type_feedback_vector, |
| 2494 compiler::Node* slot_id) { | 1341 compiler::Node* slot_id) { |
| 2495 typedef CodeStubAssembler::Label Label; | 1342 typedef CodeStubAssembler::Label Label; |
| 2496 typedef compiler::Node Node; | 1343 typedef compiler::Node Node; |
| 2497 typedef CodeStubAssembler::Variable Variable; | 1344 typedef CodeStubAssembler::Variable Variable; |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2694 | 1541 |
| 2695 // ES6 section 21.1.3.19 String.prototype.substring ( start, end ) | 1542 // ES6 section 21.1.3.19 String.prototype.substring ( start, end ) |
| 2696 compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, | 1543 compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, |
| 2697 compiler::Node* string, | 1544 compiler::Node* string, |
| 2698 compiler::Node* from, | 1545 compiler::Node* from, |
| 2699 compiler::Node* to, | 1546 compiler::Node* to, |
| 2700 compiler::Node* context) { | 1547 compiler::Node* context) { |
| 2701 return assembler->SubString(context, string, from, to); | 1548 return assembler->SubString(context, string, from, to); |
| 2702 } | 1549 } |
| 2703 | 1550 |
| 2704 // ES6 section 7.1.13 ToObject (argument) | |
| 2705 void ToObjectStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
| 2706 typedef compiler::Node Node; | |
| 2707 typedef CodeStubAssembler::Label Label; | |
| 2708 typedef CodeStubAssembler::Variable Variable; | |
| 2709 | |
| 2710 Label if_number(assembler, Label::kDeferred), if_notsmi(assembler), | |
| 2711 if_jsreceiver(assembler), if_noconstructor(assembler, Label::kDeferred), | |
| 2712 if_wrapjsvalue(assembler); | |
| 2713 | |
| 2714 Node* object = assembler->Parameter(Descriptor::kArgument); | |
| 2715 Node* context = assembler->Parameter(Descriptor::kContext); | |
| 2716 | |
| 2717 Variable constructor_function_index_var(assembler, | |
| 2718 MachineType::PointerRepresentation()); | |
| 2719 | |
| 2720 assembler->Branch(assembler->WordIsSmi(object), &if_number, &if_notsmi); | |
| 2721 | |
| 2722 assembler->Bind(&if_notsmi); | |
| 2723 Node* map = assembler->LoadMap(object); | |
| 2724 | |
| 2725 assembler->GotoIf(assembler->IsHeapNumberMap(map), &if_number); | |
| 2726 | |
| 2727 Node* instance_type = assembler->LoadMapInstanceType(map); | |
| 2728 assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), | |
| 2729 &if_jsreceiver); | |
| 2730 | |
| 2731 Node* constructor_function_index = | |
| 2732 assembler->LoadMapConstructorFunctionIndex(map); | |
| 2733 assembler->GotoIf(assembler->WordEqual(constructor_function_index, | |
| 2734 assembler->IntPtrConstant( | |
| 2735 Map::kNoConstructorFunctionIndex)), | |
| 2736 &if_noconstructor); | |
| 2737 constructor_function_index_var.Bind(constructor_function_index); | |
| 2738 assembler->Goto(&if_wrapjsvalue); | |
| 2739 | |
| 2740 assembler->Bind(&if_number); | |
| 2741 constructor_function_index_var.Bind( | |
| 2742 assembler->IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); | |
| 2743 assembler->Goto(&if_wrapjsvalue); | |
| 2744 | |
| 2745 assembler->Bind(&if_wrapjsvalue); | |
| 2746 Node* native_context = assembler->LoadNativeContext(context); | |
| 2747 Node* constructor = assembler->LoadFixedArrayElement( | |
| 2748 native_context, constructor_function_index_var.value(), 0, | |
| 2749 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 2750 Node* initial_map = assembler->LoadObjectField( | |
| 2751 constructor, JSFunction::kPrototypeOrInitialMapOffset); | |
| 2752 Node* js_value = assembler->Allocate(JSValue::kSize); | |
| 2753 assembler->StoreMapNoWriteBarrier(js_value, initial_map); | |
| 2754 assembler->StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, | |
| 2755 Heap::kEmptyFixedArrayRootIndex); | |
| 2756 assembler->StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, | |
| 2757 Heap::kEmptyFixedArrayRootIndex); | |
| 2758 assembler->StoreObjectField(js_value, JSValue::kValueOffset, object); | |
| 2759 assembler->Return(js_value); | |
| 2760 | |
| 2761 assembler->Bind(&if_noconstructor); | |
| 2762 assembler->TailCallRuntime( | |
| 2763 Runtime::kThrowUndefinedOrNullToObject, context, | |
| 2764 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | |
| 2765 "ToObject", TENURED))); | |
| 2766 | |
| 2767 assembler->Bind(&if_jsreceiver); | |
| 2768 assembler->Return(object); | |
| 2769 } | |
| 2770 | |
| 2771 // static | |
| 2772 // ES6 section 12.5.5 typeof operator | |
| 2773 compiler::Node* TypeofStub::Generate(CodeStubAssembler* assembler, | |
| 2774 compiler::Node* value, | |
| 2775 compiler::Node* context) { | |
| 2776 typedef compiler::Node Node; | |
| 2777 typedef CodeStubAssembler::Label Label; | |
| 2778 typedef CodeStubAssembler::Variable Variable; | |
| 2779 | |
| 2780 Variable result_var(assembler, MachineRepresentation::kTagged); | |
| 2781 | |
| 2782 Label return_number(assembler, Label::kDeferred), if_oddball(assembler), | |
| 2783 return_function(assembler), return_undefined(assembler), | |
| 2784 return_object(assembler), return_string(assembler), | |
| 2785 return_result(assembler); | |
| 2786 | |
| 2787 assembler->GotoIf(assembler->WordIsSmi(value), &return_number); | |
| 2788 | |
| 2789 Node* map = assembler->LoadMap(value); | |
| 2790 | |
| 2791 assembler->GotoIf(assembler->IsHeapNumberMap(map), &return_number); | |
| 2792 | |
| 2793 Node* instance_type = assembler->LoadMapInstanceType(map); | |
| 2794 | |
| 2795 assembler->GotoIf(assembler->Word32Equal( | |
| 2796 instance_type, assembler->Int32Constant(ODDBALL_TYPE)), | |
| 2797 &if_oddball); | |
| 2798 | |
| 2799 Node* callable_or_undetectable_mask = | |
| 2800 assembler->Word32And(assembler->LoadMapBitField(map), | |
| 2801 assembler->Int32Constant(1 << Map::kIsCallable | | |
| 2802 1 << Map::kIsUndetectable)); | |
| 2803 | |
| 2804 assembler->GotoIf( | |
| 2805 assembler->Word32Equal(callable_or_undetectable_mask, | |
| 2806 assembler->Int32Constant(1 << Map::kIsCallable)), | |
| 2807 &return_function); | |
| 2808 | |
| 2809 assembler->GotoUnless(assembler->Word32Equal(callable_or_undetectable_mask, | |
| 2810 assembler->Int32Constant(0)), | |
| 2811 &return_undefined); | |
| 2812 | |
| 2813 assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), | |
| 2814 &return_object); | |
| 2815 | |
| 2816 assembler->GotoIf(assembler->IsStringInstanceType(instance_type), | |
| 2817 &return_string); | |
| 2818 | |
| 2819 #define SIMD128_BRANCH(TYPE, Type, type, lane_count, lane_type) \ | |
| 2820 Label return_##type(assembler); \ | |
| 2821 Node* type##_map = \ | |
| 2822 assembler->HeapConstant(assembler->factory()->type##_map()); \ | |
| 2823 assembler->GotoIf(assembler->WordEqual(map, type##_map), &return_##type); | |
| 2824 SIMD128_TYPES(SIMD128_BRANCH) | |
| 2825 #undef SIMD128_BRANCH | |
| 2826 | |
| 2827 assembler->Assert(assembler->Word32Equal( | |
| 2828 instance_type, assembler->Int32Constant(SYMBOL_TYPE))); | |
| 2829 result_var.Bind(assembler->HeapConstant( | |
| 2830 assembler->isolate()->factory()->symbol_string())); | |
| 2831 assembler->Goto(&return_result); | |
| 2832 | |
| 2833 assembler->Bind(&return_number); | |
| 2834 { | |
| 2835 result_var.Bind(assembler->HeapConstant( | |
| 2836 assembler->isolate()->factory()->number_string())); | |
| 2837 assembler->Goto(&return_result); | |
| 2838 } | |
| 2839 | |
| 2840 assembler->Bind(&if_oddball); | |
| 2841 { | |
| 2842 Node* type = assembler->LoadObjectField(value, Oddball::kTypeOfOffset); | |
| 2843 result_var.Bind(type); | |
| 2844 assembler->Goto(&return_result); | |
| 2845 } | |
| 2846 | |
| 2847 assembler->Bind(&return_function); | |
| 2848 { | |
| 2849 result_var.Bind(assembler->HeapConstant( | |
| 2850 assembler->isolate()->factory()->function_string())); | |
| 2851 assembler->Goto(&return_result); | |
| 2852 } | |
| 2853 | |
| 2854 assembler->Bind(&return_undefined); | |
| 2855 { | |
| 2856 result_var.Bind(assembler->HeapConstant( | |
| 2857 assembler->isolate()->factory()->undefined_string())); | |
| 2858 assembler->Goto(&return_result); | |
| 2859 } | |
| 2860 | |
| 2861 assembler->Bind(&return_object); | |
| 2862 { | |
| 2863 result_var.Bind(assembler->HeapConstant( | |
| 2864 assembler->isolate()->factory()->object_string())); | |
| 2865 assembler->Goto(&return_result); | |
| 2866 } | |
| 2867 | |
| 2868 assembler->Bind(&return_string); | |
| 2869 { | |
| 2870 result_var.Bind(assembler->HeapConstant( | |
| 2871 assembler->isolate()->factory()->string_string())); | |
| 2872 assembler->Goto(&return_result); | |
| 2873 } | |
| 2874 | |
| 2875 #define SIMD128_BIND_RETURN(TYPE, Type, type, lane_count, lane_type) \ | |
| 2876 assembler->Bind(&return_##type); \ | |
| 2877 { \ | |
| 2878 result_var.Bind(assembler->HeapConstant( \ | |
| 2879 assembler->isolate()->factory()->type##_string())); \ | |
| 2880 assembler->Goto(&return_result); \ | |
| 2881 } | |
| 2882 SIMD128_TYPES(SIMD128_BIND_RETURN) | |
| 2883 #undef SIMD128_BIND_RETURN | |
| 2884 | |
| 2885 assembler->Bind(&return_result); | |
| 2886 return result_var.value(); | |
| 2887 } | |
| 2888 | |
| 2889 // static | |
| 2890 compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler, | |
| 2891 compiler::Node* object, | |
| 2892 compiler::Node* callable, | |
| 2893 compiler::Node* context) { | |
| 2894 typedef CodeStubAssembler::Label Label; | |
| 2895 typedef CodeStubAssembler::Variable Variable; | |
| 2896 | |
| 2897 Label return_runtime(assembler, Label::kDeferred), end(assembler); | |
| 2898 Variable result(assembler, MachineRepresentation::kTagged); | |
| 2899 | |
| 2900 // Check if no one installed @@hasInstance somewhere. | |
| 2901 assembler->GotoUnless( | |
| 2902 assembler->WordEqual( | |
| 2903 assembler->LoadObjectField( | |
| 2904 assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex), | |
| 2905 PropertyCell::kValueOffset), | |
| 2906 assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), | |
| 2907 &return_runtime); | |
| 2908 | |
| 2909 // Check if {callable} is a valid receiver. | |
| 2910 assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime); | |
| 2911 assembler->GotoIf( | |
| 2912 assembler->Word32Equal( | |
| 2913 assembler->Word32And( | |
| 2914 assembler->LoadMapBitField(assembler->LoadMap(callable)), | |
| 2915 assembler->Int32Constant(1 << Map::kIsCallable)), | |
| 2916 assembler->Int32Constant(0)), | |
| 2917 &return_runtime); | |
| 2918 | |
| 2919 // Use the inline OrdinaryHasInstance directly. | |
| 2920 result.Bind(assembler->OrdinaryHasInstance(context, callable, object)); | |
| 2921 assembler->Goto(&end); | |
| 2922 | |
| 2923 // TODO(bmeurer): Use GetPropertyStub here once available. | |
| 2924 assembler->Bind(&return_runtime); | |
| 2925 { | |
| 2926 result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object, | |
| 2927 callable)); | |
| 2928 assembler->Goto(&end); | |
| 2929 } | |
| 2930 | |
| 2931 assembler->Bind(&end); | |
| 2932 return result.value(); | |
| 2933 } | |
| 2934 | |
| 2935 namespace { | |
| 2936 | |
| 2937 enum RelationalComparisonMode { | |
| 2938 kLessThan, | |
| 2939 kLessThanOrEqual, | |
| 2940 kGreaterThan, | |
| 2941 kGreaterThanOrEqual | |
| 2942 }; | |
| 2943 | |
| 2944 compiler::Node* GenerateAbstractRelationalComparison( | |
| 2945 CodeStubAssembler* assembler, RelationalComparisonMode mode, | |
| 2946 compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) { | |
| 2947 typedef CodeStubAssembler::Label Label; | |
| 2948 typedef compiler::Node Node; | |
| 2949 typedef CodeStubAssembler::Variable Variable; | |
| 2950 | |
| 2951 Label return_true(assembler), return_false(assembler), end(assembler); | |
| 2952 Variable result(assembler, MachineRepresentation::kTagged); | |
| 2953 | |
| 2954 // Shared entry for floating point comparison. | |
| 2955 Label do_fcmp(assembler); | |
| 2956 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), | |
| 2957 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); | |
| 2958 | |
| 2959 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
| 2960 // conversions. | |
| 2961 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
| 2962 var_rhs(assembler, MachineRepresentation::kTagged); | |
| 2963 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
| 2964 Label loop(assembler, 2, loop_vars); | |
| 2965 var_lhs.Bind(lhs); | |
| 2966 var_rhs.Bind(rhs); | |
| 2967 assembler->Goto(&loop); | |
| 2968 assembler->Bind(&loop); | |
| 2969 { | |
| 2970 // Load the current {lhs} and {rhs} values. | |
| 2971 lhs = var_lhs.value(); | |
| 2972 rhs = var_rhs.value(); | |
| 2973 | |
| 2974 // Check if the {lhs} is a Smi or a HeapObject. | |
| 2975 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
| 2976 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
| 2977 | |
| 2978 assembler->Bind(&if_lhsissmi); | |
| 2979 { | |
| 2980 // Check if {rhs} is a Smi or a HeapObject. | |
| 2981 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 2982 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 2983 &if_rhsisnotsmi); | |
| 2984 | |
| 2985 assembler->Bind(&if_rhsissmi); | |
| 2986 { | |
| 2987 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. | |
| 2988 switch (mode) { | |
| 2989 case kLessThan: | |
| 2990 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true, | |
| 2991 &return_false); | |
| 2992 break; | |
| 2993 case kLessThanOrEqual: | |
| 2994 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, | |
| 2995 &return_false); | |
| 2996 break; | |
| 2997 case kGreaterThan: | |
| 2998 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true, | |
| 2999 &return_false); | |
| 3000 break; | |
| 3001 case kGreaterThanOrEqual: | |
| 3002 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, | |
| 3003 &return_false); | |
| 3004 break; | |
| 3005 } | |
| 3006 } | |
| 3007 | |
| 3008 assembler->Bind(&if_rhsisnotsmi); | |
| 3009 { | |
| 3010 // Load the map of {rhs}. | |
| 3011 Node* rhs_map = assembler->LoadMap(rhs); | |
| 3012 | |
| 3013 // Check if the {rhs} is a HeapNumber. | |
| 3014 Label if_rhsisnumber(assembler), | |
| 3015 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 3016 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
| 3017 &if_rhsisnotnumber); | |
| 3018 | |
| 3019 assembler->Bind(&if_rhsisnumber); | |
| 3020 { | |
| 3021 // Convert the {lhs} and {rhs} to floating point values, and | |
| 3022 // perform a floating point comparison. | |
| 3023 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 3024 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 3025 assembler->Goto(&do_fcmp); | |
| 3026 } | |
| 3027 | |
| 3028 assembler->Bind(&if_rhsisnotnumber); | |
| 3029 { | |
| 3030 // Convert the {rhs} to a Number; we don't need to perform the | |
| 3031 // dedicated ToPrimitive(rhs, hint Number) operation, as the | |
| 3032 // ToNumber(rhs) will by itself already invoke ToPrimitive with | |
| 3033 // a Number hint. | |
| 3034 Callable callable = | |
| 3035 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 3036 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3037 assembler->Goto(&loop); | |
| 3038 } | |
| 3039 } | |
| 3040 } | |
| 3041 | |
| 3042 assembler->Bind(&if_lhsisnotsmi); | |
| 3043 { | |
| 3044 // Load the HeapNumber map for later comparisons. | |
| 3045 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 3046 | |
| 3047 // Load the map of {lhs}. | |
| 3048 Node* lhs_map = assembler->LoadMap(lhs); | |
| 3049 | |
| 3050 // Check if {rhs} is a Smi or a HeapObject. | |
| 3051 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 3052 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 3053 &if_rhsisnotsmi); | |
| 3054 | |
| 3055 assembler->Bind(&if_rhsissmi); | |
| 3056 { | |
| 3057 // Check if the {lhs} is a HeapNumber. | |
| 3058 Label if_lhsisnumber(assembler), | |
| 3059 if_lhsisnotnumber(assembler, Label::kDeferred); | |
| 3060 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
| 3061 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 3062 | |
| 3063 assembler->Bind(&if_lhsisnumber); | |
| 3064 { | |
| 3065 // Convert the {lhs} and {rhs} to floating point values, and | |
| 3066 // perform a floating point comparison. | |
| 3067 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 3068 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
| 3069 assembler->Goto(&do_fcmp); | |
| 3070 } | |
| 3071 | |
| 3072 assembler->Bind(&if_lhsisnotnumber); | |
| 3073 { | |
| 3074 // Convert the {lhs} to a Number; we don't need to perform the | |
| 3075 // dedicated ToPrimitive(lhs, hint Number) operation, as the | |
| 3076 // ToNumber(lhs) will by itself already invoke ToPrimitive with | |
| 3077 // a Number hint. | |
| 3078 Callable callable = | |
| 3079 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 3080 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 3081 assembler->Goto(&loop); | |
| 3082 } | |
| 3083 } | |
| 3084 | |
| 3085 assembler->Bind(&if_rhsisnotsmi); | |
| 3086 { | |
| 3087 // Load the map of {rhs}. | |
| 3088 Node* rhs_map = assembler->LoadMap(rhs); | |
| 3089 | |
| 3090 // Check if {lhs} is a HeapNumber. | |
| 3091 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
| 3092 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
| 3093 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 3094 | |
| 3095 assembler->Bind(&if_lhsisnumber); | |
| 3096 { | |
| 3097 // Check if {rhs} is also a HeapNumber. | |
| 3098 Label if_rhsisnumber(assembler), | |
| 3099 if_rhsisnotnumber(assembler, Label::kDeferred); | |
| 3100 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), | |
| 3101 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 3102 | |
| 3103 assembler->Bind(&if_rhsisnumber); | |
| 3104 { | |
| 3105 // Convert the {lhs} and {rhs} to floating point values, and | |
| 3106 // perform a floating point comparison. | |
| 3107 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 3108 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 3109 assembler->Goto(&do_fcmp); | |
| 3110 } | |
| 3111 | |
| 3112 assembler->Bind(&if_rhsisnotnumber); | |
| 3113 { | |
| 3114 // Convert the {rhs} to a Number; we don't need to perform | |
| 3115 // dedicated ToPrimitive(rhs, hint Number) operation, as the | |
| 3116 // ToNumber(rhs) will by itself already invoke ToPrimitive with | |
| 3117 // a Number hint. | |
| 3118 Callable callable = | |
| 3119 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 3120 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3121 assembler->Goto(&loop); | |
| 3122 } | |
| 3123 } | |
| 3124 | |
| 3125 assembler->Bind(&if_lhsisnotnumber); | |
| 3126 { | |
| 3127 // Load the instance type of {lhs}. | |
| 3128 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
| 3129 | |
| 3130 // Check if {lhs} is a String. | |
| 3131 Label if_lhsisstring(assembler), | |
| 3132 if_lhsisnotstring(assembler, Label::kDeferred); | |
| 3133 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
| 3134 &if_lhsisstring, &if_lhsisnotstring); | |
| 3135 | |
| 3136 assembler->Bind(&if_lhsisstring); | |
| 3137 { | |
| 3138 // Load the instance type of {rhs}. | |
| 3139 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
| 3140 | |
| 3141 // Check if {rhs} is also a String. | |
| 3142 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 3143 if_rhsisnotstring(assembler, Label::kDeferred); | |
| 3144 assembler->Branch( | |
| 3145 assembler->IsStringInstanceType(rhs_instance_type), | |
| 3146 &if_rhsisstring, &if_rhsisnotstring); | |
| 3147 | |
| 3148 assembler->Bind(&if_rhsisstring); | |
| 3149 { | |
| 3150 // Both {lhs} and {rhs} are strings. | |
| 3151 switch (mode) { | |
| 3152 case kLessThan: | |
| 3153 result.Bind(assembler->CallStub( | |
| 3154 CodeFactory::StringLessThan(assembler->isolate()), | |
| 3155 context, lhs, rhs)); | |
| 3156 assembler->Goto(&end); | |
| 3157 break; | |
| 3158 case kLessThanOrEqual: | |
| 3159 result.Bind(assembler->CallStub( | |
| 3160 CodeFactory::StringLessThanOrEqual(assembler->isolate()), | |
| 3161 context, lhs, rhs)); | |
| 3162 assembler->Goto(&end); | |
| 3163 break; | |
| 3164 case kGreaterThan: | |
| 3165 result.Bind(assembler->CallStub( | |
| 3166 CodeFactory::StringGreaterThan(assembler->isolate()), | |
| 3167 context, lhs, rhs)); | |
| 3168 assembler->Goto(&end); | |
| 3169 break; | |
| 3170 case kGreaterThanOrEqual: | |
| 3171 result.Bind( | |
| 3172 assembler->CallStub(CodeFactory::StringGreaterThanOrEqual( | |
| 3173 assembler->isolate()), | |
| 3174 context, lhs, rhs)); | |
| 3175 assembler->Goto(&end); | |
| 3176 break; | |
| 3177 } | |
| 3178 } | |
| 3179 | |
| 3180 assembler->Bind(&if_rhsisnotstring); | |
| 3181 { | |
| 3182 // The {lhs} is a String, while {rhs} is neither a Number nor a | |
| 3183 // String, so we need to call ToPrimitive(rhs, hint Number) if | |
| 3184 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the | |
| 3185 // other cases. | |
| 3186 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
| 3187 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
| 3188 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
| 3189 assembler->Branch( | |
| 3190 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3191 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3192 | |
| 3193 assembler->Bind(&if_rhsisreceiver); | |
| 3194 { | |
| 3195 // Convert {rhs} to a primitive first passing Number hint. | |
| 3196 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
| 3197 assembler->isolate(), ToPrimitiveHint::kNumber); | |
| 3198 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3199 assembler->Goto(&loop); | |
| 3200 } | |
| 3201 | |
| 3202 assembler->Bind(&if_rhsisnotreceiver); | |
| 3203 { | |
| 3204 // Convert both {lhs} and {rhs} to Number. | |
| 3205 Callable callable = CodeFactory::ToNumber(assembler->isolate()); | |
| 3206 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 3207 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3208 assembler->Goto(&loop); | |
| 3209 } | |
| 3210 } | |
| 3211 } | |
| 3212 | |
| 3213 assembler->Bind(&if_lhsisnotstring); | |
| 3214 { | |
| 3215 // The {lhs} is neither a Number nor a String, so we need to call | |
| 3216 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or | |
| 3217 // ToNumber(lhs) and ToNumber(rhs) in the other cases. | |
| 3218 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
| 3219 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
| 3220 if_lhsisnotreceiver(assembler, Label::kDeferred); | |
| 3221 assembler->Branch( | |
| 3222 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
| 3223 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
| 3224 | |
| 3225 assembler->Bind(&if_lhsisreceiver); | |
| 3226 { | |
| 3227 // Convert {lhs} to a primitive first passing Number hint. | |
| 3228 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
| 3229 assembler->isolate(), ToPrimitiveHint::kNumber); | |
| 3230 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 3231 assembler->Goto(&loop); | |
| 3232 } | |
| 3233 | |
| 3234 assembler->Bind(&if_lhsisnotreceiver); | |
| 3235 { | |
| 3236 // Convert both {lhs} and {rhs} to Number. | |
| 3237 Callable callable = CodeFactory::ToNumber(assembler->isolate()); | |
| 3238 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 3239 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3240 assembler->Goto(&loop); | |
| 3241 } | |
| 3242 } | |
| 3243 } | |
| 3244 } | |
| 3245 } | |
| 3246 } | |
| 3247 | |
| 3248 assembler->Bind(&do_fcmp); | |
| 3249 { | |
| 3250 // Load the {lhs} and {rhs} floating point values. | |
| 3251 Node* lhs = var_fcmp_lhs.value(); | |
| 3252 Node* rhs = var_fcmp_rhs.value(); | |
| 3253 | |
| 3254 // Perform a fast floating point comparison. | |
| 3255 switch (mode) { | |
| 3256 case kLessThan: | |
| 3257 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true, | |
| 3258 &return_false); | |
| 3259 break; | |
| 3260 case kLessThanOrEqual: | |
| 3261 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, | |
| 3262 &return_false); | |
| 3263 break; | |
| 3264 case kGreaterThan: | |
| 3265 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true, | |
| 3266 &return_false); | |
| 3267 break; | |
| 3268 case kGreaterThanOrEqual: | |
| 3269 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, | |
| 3270 &return_false); | |
| 3271 break; | |
| 3272 } | |
| 3273 } | |
| 3274 | |
| 3275 assembler->Bind(&return_true); | |
| 3276 { | |
| 3277 result.Bind(assembler->BooleanConstant(true)); | |
| 3278 assembler->Goto(&end); | |
| 3279 } | |
| 3280 | |
| 3281 assembler->Bind(&return_false); | |
| 3282 { | |
| 3283 result.Bind(assembler->BooleanConstant(false)); | |
| 3284 assembler->Goto(&end); | |
| 3285 } | |
| 3286 | |
| 3287 assembler->Bind(&end); | |
| 3288 return result.value(); | |
| 3289 } | |
| 3290 | |
| 3291 enum ResultMode { kDontNegateResult, kNegateResult }; | |
| 3292 | |
| 3293 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, | |
| 3294 CodeStubAssembler::Label* if_equal, | |
| 3295 CodeStubAssembler::Label* if_notequal) { | |
| 3296 // In case of abstract or strict equality checks, we need additional checks | |
| 3297 // for NaN values because they are not considered equal, even if both the | |
| 3298 // left and the right hand side reference exactly the same value. | |
| 3299 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it | |
| 3300 // seems to be what is tested in the current SIMD.js testsuite. | |
| 3301 | |
| 3302 typedef CodeStubAssembler::Label Label; | |
| 3303 typedef compiler::Node Node; | |
| 3304 | |
| 3305 // Check if {value} is a Smi or a HeapObject. | |
| 3306 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | |
| 3307 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, | |
| 3308 &if_valueisnotsmi); | |
| 3309 | |
| 3310 assembler->Bind(&if_valueisnotsmi); | |
| 3311 { | |
| 3312 // Load the map of {value}. | |
| 3313 Node* value_map = assembler->LoadMap(value); | |
| 3314 | |
| 3315 // Check if {value} (and therefore {rhs}) is a HeapNumber. | |
| 3316 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); | |
| 3317 assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber, | |
| 3318 &if_valueisnotnumber); | |
| 3319 | |
| 3320 assembler->Bind(&if_valueisnumber); | |
| 3321 { | |
| 3322 // Convert {value} (and therefore {rhs}) to floating point value. | |
| 3323 Node* value_value = assembler->LoadHeapNumberValue(value); | |
| 3324 | |
| 3325 // Check if the HeapNumber value is a NaN. | |
| 3326 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); | |
| 3327 } | |
| 3328 | |
| 3329 assembler->Bind(&if_valueisnotnumber); | |
| 3330 assembler->Goto(if_equal); | |
| 3331 } | |
| 3332 | |
| 3333 assembler->Bind(&if_valueissmi); | |
| 3334 assembler->Goto(if_equal); | |
| 3335 } | |
| 3336 | |
| 3337 void GenerateEqual_Simd128Value_HeapObject( | |
| 3338 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, | |
| 3339 compiler::Node* rhs, compiler::Node* rhs_map, | |
| 3340 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { | |
| 3341 assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal, | |
| 3342 if_notequal); | |
| 3343 } | |
| 3344 | |
| 3345 // ES6 section 7.2.12 Abstract Equality Comparison | |
| 3346 compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode, | |
| 3347 compiler::Node* lhs, compiler::Node* rhs, | |
| 3348 compiler::Node* context) { | |
| 3349 // This is a slightly optimized version of Object::Equals represented as | |
| 3350 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you | |
| 3351 // change something functionality wise in here, remember to update the | |
| 3352 // Object::Equals method as well. | |
| 3353 typedef CodeStubAssembler::Label Label; | |
| 3354 typedef compiler::Node Node; | |
| 3355 typedef CodeStubAssembler::Variable Variable; | |
| 3356 | |
| 3357 Label if_equal(assembler), if_notequal(assembler), | |
| 3358 do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler); | |
| 3359 Variable result(assembler, MachineRepresentation::kTagged); | |
| 3360 | |
| 3361 // Shared entry for floating point comparison. | |
| 3362 Label do_fcmp(assembler); | |
| 3363 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), | |
| 3364 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); | |
| 3365 | |
| 3366 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
| 3367 // conversions. | |
| 3368 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
| 3369 var_rhs(assembler, MachineRepresentation::kTagged); | |
| 3370 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
| 3371 Label loop(assembler, 2, loop_vars); | |
| 3372 var_lhs.Bind(lhs); | |
| 3373 var_rhs.Bind(rhs); | |
| 3374 assembler->Goto(&loop); | |
| 3375 assembler->Bind(&loop); | |
| 3376 { | |
| 3377 // Load the current {lhs} and {rhs} values. | |
| 3378 lhs = var_lhs.value(); | |
| 3379 rhs = var_rhs.value(); | |
| 3380 | |
| 3381 // Check if {lhs} and {rhs} refer to the same object. | |
| 3382 Label if_same(assembler), if_notsame(assembler); | |
| 3383 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
| 3384 | |
| 3385 assembler->Bind(&if_same); | |
| 3386 { | |
| 3387 // The {lhs} and {rhs} reference the exact same value, yet we need special | |
| 3388 // treatment for HeapNumber, as NaN is not equal to NaN. | |
| 3389 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | |
| 3390 } | |
| 3391 | |
| 3392 assembler->Bind(&if_notsame); | |
| 3393 { | |
| 3394 // Check if {lhs} is a Smi or a HeapObject. | |
| 3395 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
| 3396 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, | |
| 3397 &if_lhsisnotsmi); | |
| 3398 | |
| 3399 assembler->Bind(&if_lhsissmi); | |
| 3400 { | |
| 3401 // Check if {rhs} is a Smi or a HeapObject. | |
| 3402 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 3403 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 3404 &if_rhsisnotsmi); | |
| 3405 | |
| 3406 assembler->Bind(&if_rhsissmi); | |
| 3407 // We have already checked for {lhs} and {rhs} being the same value, so | |
| 3408 // if both are Smis when we get here they must not be equal. | |
| 3409 assembler->Goto(&if_notequal); | |
| 3410 | |
| 3411 assembler->Bind(&if_rhsisnotsmi); | |
| 3412 { | |
| 3413 // Load the map of {rhs}. | |
| 3414 Node* rhs_map = assembler->LoadMap(rhs); | |
| 3415 | |
| 3416 // Check if {rhs} is a HeapNumber. | |
| 3417 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 3418 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
| 3419 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 3420 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 3421 | |
| 3422 assembler->Bind(&if_rhsisnumber); | |
| 3423 { | |
| 3424 // Convert {lhs} and {rhs} to floating point values, and | |
| 3425 // perform a floating point comparison. | |
| 3426 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
| 3427 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 3428 assembler->Goto(&do_fcmp); | |
| 3429 } | |
| 3430 | |
| 3431 assembler->Bind(&if_rhsisnotnumber); | |
| 3432 { | |
| 3433 // Load the instance type of the {rhs}. | |
| 3434 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
| 3435 | |
| 3436 // Check if the {rhs} is a String. | |
| 3437 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 3438 if_rhsisnotstring(assembler); | |
| 3439 assembler->Branch( | |
| 3440 assembler->IsStringInstanceType(rhs_instance_type), | |
| 3441 &if_rhsisstring, &if_rhsisnotstring); | |
| 3442 | |
| 3443 assembler->Bind(&if_rhsisstring); | |
| 3444 { | |
| 3445 // The {rhs} is a String and the {lhs} is a Smi; we need | |
| 3446 // to convert the {rhs} to a Number and compare the output to | |
| 3447 // the Number on the {lhs}. | |
| 3448 assembler->Goto(&do_rhsstringtonumber); | |
| 3449 } | |
| 3450 | |
| 3451 assembler->Bind(&if_rhsisnotstring); | |
| 3452 { | |
| 3453 // Check if the {rhs} is a Boolean. | |
| 3454 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); | |
| 3455 assembler->Branch(assembler->IsBooleanMap(rhs_map), | |
| 3456 &if_rhsisboolean, &if_rhsisnotboolean); | |
| 3457 | |
| 3458 assembler->Bind(&if_rhsisboolean); | |
| 3459 { | |
| 3460 // The {rhs} is a Boolean, load its number value. | |
| 3461 var_rhs.Bind( | |
| 3462 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); | |
| 3463 assembler->Goto(&loop); | |
| 3464 } | |
| 3465 | |
| 3466 assembler->Bind(&if_rhsisnotboolean); | |
| 3467 { | |
| 3468 // Check if the {rhs} is a Receiver. | |
| 3469 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
| 3470 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
| 3471 if_rhsisnotreceiver(assembler); | |
| 3472 assembler->Branch( | |
| 3473 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3474 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3475 | |
| 3476 assembler->Bind(&if_rhsisreceiver); | |
| 3477 { | |
| 3478 // Convert {rhs} to a primitive first (passing no hint). | |
| 3479 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
| 3480 assembler->isolate()); | |
| 3481 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3482 assembler->Goto(&loop); | |
| 3483 } | |
| 3484 | |
| 3485 assembler->Bind(&if_rhsisnotreceiver); | |
| 3486 assembler->Goto(&if_notequal); | |
| 3487 } | |
| 3488 } | |
| 3489 } | |
| 3490 } | |
| 3491 } | |
| 3492 | |
| 3493 assembler->Bind(&if_lhsisnotsmi); | |
| 3494 { | |
| 3495 // Check if {rhs} is a Smi or a HeapObject. | |
| 3496 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 3497 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 3498 &if_rhsisnotsmi); | |
| 3499 | |
| 3500 assembler->Bind(&if_rhsissmi); | |
| 3501 { | |
| 3502 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} | |
| 3503 // and {rhs} is not observable and doesn't matter for the result, so | |
| 3504 // we can just swap them and use the Smi handling above (for {lhs} | |
| 3505 // being a Smi). | |
| 3506 var_lhs.Bind(rhs); | |
| 3507 var_rhs.Bind(lhs); | |
| 3508 assembler->Goto(&loop); | |
| 3509 } | |
| 3510 | |
| 3511 assembler->Bind(&if_rhsisnotsmi); | |
| 3512 { | |
| 3513 Label if_lhsisstring(assembler), if_lhsisnumber(assembler), | |
| 3514 if_lhsissymbol(assembler), if_lhsissimd128value(assembler), | |
| 3515 if_lhsisoddball(assembler), if_lhsisreceiver(assembler); | |
| 3516 | |
| 3517 // Both {lhs} and {rhs} are HeapObjects, load their maps | |
| 3518 // and their instance types. | |
| 3519 Node* lhs_map = assembler->LoadMap(lhs); | |
| 3520 Node* rhs_map = assembler->LoadMap(rhs); | |
| 3521 | |
| 3522 // Load the instance types of {lhs} and {rhs}. | |
| 3523 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
| 3524 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
| 3525 | |
| 3526 // Dispatch based on the instance type of {lhs}. | |
| 3527 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; | |
| 3528 Label* case_labels[kNumCases]; | |
| 3529 int32_t case_values[kNumCases]; | |
| 3530 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { | |
| 3531 case_labels[i] = new Label(assembler); | |
| 3532 case_values[i] = i; | |
| 3533 } | |
| 3534 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; | |
| 3535 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; | |
| 3536 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; | |
| 3537 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; | |
| 3538 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; | |
| 3539 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; | |
| 3540 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; | |
| 3541 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; | |
| 3542 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values, | |
| 3543 case_labels, arraysize(case_values)); | |
| 3544 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { | |
| 3545 assembler->Bind(case_labels[i]); | |
| 3546 assembler->Goto(&if_lhsisstring); | |
| 3547 delete case_labels[i]; | |
| 3548 } | |
| 3549 | |
| 3550 assembler->Bind(&if_lhsisstring); | |
| 3551 { | |
| 3552 // Check if {rhs} is also a String. | |
| 3553 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 3554 if_rhsisnotstring(assembler); | |
| 3555 assembler->Branch( | |
| 3556 assembler->IsStringInstanceType(rhs_instance_type), | |
| 3557 &if_rhsisstring, &if_rhsisnotstring); | |
| 3558 | |
| 3559 assembler->Bind(&if_rhsisstring); | |
| 3560 { | |
| 3561 // Both {lhs} and {rhs} are of type String, just do the | |
| 3562 // string comparison then. | |
| 3563 Callable callable = | |
| 3564 (mode == kDontNegateResult) | |
| 3565 ? CodeFactory::StringEqual(assembler->isolate()) | |
| 3566 : CodeFactory::StringNotEqual(assembler->isolate()); | |
| 3567 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | |
| 3568 assembler->Goto(&end); | |
| 3569 } | |
| 3570 | |
| 3571 assembler->Bind(&if_rhsisnotstring); | |
| 3572 { | |
| 3573 // The {lhs} is a String and the {rhs} is some other HeapObject. | |
| 3574 // Swapping {lhs} and {rhs} is not observable and doesn't matter | |
| 3575 // for the result, so we can just swap them and use the String | |
| 3576 // handling below (for {rhs} being a String). | |
| 3577 var_lhs.Bind(rhs); | |
| 3578 var_rhs.Bind(lhs); | |
| 3579 assembler->Goto(&loop); | |
| 3580 } | |
| 3581 } | |
| 3582 | |
| 3583 assembler->Bind(&if_lhsisnumber); | |
| 3584 { | |
| 3585 // Check if {rhs} is also a HeapNumber. | |
| 3586 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
| 3587 assembler->Branch( | |
| 3588 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), | |
| 3589 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 3590 | |
| 3591 assembler->Bind(&if_rhsisnumber); | |
| 3592 { | |
| 3593 // Convert {lhs} and {rhs} to floating point values, and | |
| 3594 // perform a floating point comparison. | |
| 3595 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
| 3596 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
| 3597 assembler->Goto(&do_fcmp); | |
| 3598 } | |
| 3599 | |
| 3600 assembler->Bind(&if_rhsisnotnumber); | |
| 3601 { | |
| 3602 // The {lhs} is a Number, the {rhs} is some other HeapObject. | |
| 3603 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 3604 if_rhsisnotstring(assembler); | |
| 3605 assembler->Branch( | |
| 3606 assembler->IsStringInstanceType(rhs_instance_type), | |
| 3607 &if_rhsisstring, &if_rhsisnotstring); | |
| 3608 | |
| 3609 assembler->Bind(&if_rhsisstring); | |
| 3610 { | |
| 3611 // The {rhs} is a String and the {lhs} is a HeapNumber; we need | |
| 3612 // to convert the {rhs} to a Number and compare the output to | |
| 3613 // the Number on the {lhs}. | |
| 3614 assembler->Goto(&do_rhsstringtonumber); | |
| 3615 } | |
| 3616 | |
| 3617 assembler->Bind(&if_rhsisnotstring); | |
| 3618 { | |
| 3619 // Check if the {rhs} is a JSReceiver. | |
| 3620 Label if_rhsisreceiver(assembler), | |
| 3621 if_rhsisnotreceiver(assembler); | |
| 3622 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
| 3623 assembler->Branch( | |
| 3624 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3625 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3626 | |
| 3627 assembler->Bind(&if_rhsisreceiver); | |
| 3628 { | |
| 3629 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
| 3630 // Swapping {lhs} and {rhs} is not observable and doesn't | |
| 3631 // matter for the result, so we can just swap them and use | |
| 3632 // the JSReceiver handling below (for {lhs} being a | |
| 3633 // JSReceiver). | |
| 3634 var_lhs.Bind(rhs); | |
| 3635 var_rhs.Bind(lhs); | |
| 3636 assembler->Goto(&loop); | |
| 3637 } | |
| 3638 | |
| 3639 assembler->Bind(&if_rhsisnotreceiver); | |
| 3640 { | |
| 3641 // Check if {rhs} is a Boolean. | |
| 3642 Label if_rhsisboolean(assembler), | |
| 3643 if_rhsisnotboolean(assembler); | |
| 3644 assembler->Branch(assembler->IsBooleanMap(rhs_map), | |
| 3645 &if_rhsisboolean, &if_rhsisnotboolean); | |
| 3646 | |
| 3647 assembler->Bind(&if_rhsisboolean); | |
| 3648 { | |
| 3649 // The {rhs} is a Boolean, convert it to a Smi first. | |
| 3650 var_rhs.Bind(assembler->LoadObjectField( | |
| 3651 rhs, Oddball::kToNumberOffset)); | |
| 3652 assembler->Goto(&loop); | |
| 3653 } | |
| 3654 | |
| 3655 assembler->Bind(&if_rhsisnotboolean); | |
| 3656 assembler->Goto(&if_notequal); | |
| 3657 } | |
| 3658 } | |
| 3659 } | |
| 3660 } | |
| 3661 | |
| 3662 assembler->Bind(&if_lhsisoddball); | |
| 3663 { | |
| 3664 // The {lhs} is an Oddball and {rhs} is some other HeapObject. | |
| 3665 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); | |
| 3666 Node* boolean_map = assembler->BooleanMapConstant(); | |
| 3667 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), | |
| 3668 &if_lhsisboolean, &if_lhsisnotboolean); | |
| 3669 | |
| 3670 assembler->Bind(&if_lhsisboolean); | |
| 3671 { | |
| 3672 // The {lhs} is a Boolean, check if {rhs} is also a Boolean. | |
| 3673 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); | |
| 3674 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), | |
| 3675 &if_rhsisboolean, &if_rhsisnotboolean); | |
| 3676 | |
| 3677 assembler->Bind(&if_rhsisboolean); | |
| 3678 { | |
| 3679 // Both {lhs} and {rhs} are distinct Boolean values. | |
| 3680 assembler->Goto(&if_notequal); | |
| 3681 } | |
| 3682 | |
| 3683 assembler->Bind(&if_rhsisnotboolean); | |
| 3684 { | |
| 3685 // Convert the {lhs} to a Number first. | |
| 3686 var_lhs.Bind( | |
| 3687 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); | |
| 3688 assembler->Goto(&loop); | |
| 3689 } | |
| 3690 } | |
| 3691 | |
| 3692 assembler->Bind(&if_lhsisnotboolean); | |
| 3693 { | |
| 3694 // The {lhs} is either Null or Undefined; check if the {rhs} is | |
| 3695 // undetectable (i.e. either also Null or Undefined or some | |
| 3696 // undetectable JSReceiver). | |
| 3697 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); | |
| 3698 assembler->BranchIfWord32Equal( | |
| 3699 assembler->Word32And( | |
| 3700 rhs_bitfield, | |
| 3701 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
| 3702 assembler->Int32Constant(0), &if_notequal, &if_equal); | |
| 3703 } | |
| 3704 } | |
| 3705 | |
| 3706 assembler->Bind(&if_lhsissymbol); | |
| 3707 { | |
| 3708 // Check if the {rhs} is a JSReceiver. | |
| 3709 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
| 3710 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
| 3711 assembler->Branch( | |
| 3712 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3713 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3714 | |
| 3715 assembler->Bind(&if_rhsisreceiver); | |
| 3716 { | |
| 3717 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
| 3718 // Swapping {lhs} and {rhs} is not observable and doesn't | |
| 3719 // matter for the result, so we can just swap them and use | |
| 3720 // the JSReceiver handling below (for {lhs} being a JSReceiver). | |
| 3721 var_lhs.Bind(rhs); | |
| 3722 var_rhs.Bind(lhs); | |
| 3723 assembler->Goto(&loop); | |
| 3724 } | |
| 3725 | |
| 3726 assembler->Bind(&if_rhsisnotreceiver); | |
| 3727 { | |
| 3728 // The {rhs} is not a JSReceiver and also not the same Symbol | |
| 3729 // as the {lhs}, so this is equality check is considered false. | |
| 3730 assembler->Goto(&if_notequal); | |
| 3731 } | |
| 3732 } | |
| 3733 | |
| 3734 assembler->Bind(&if_lhsissimd128value); | |
| 3735 { | |
| 3736 // Check if the {rhs} is also a Simd128Value. | |
| 3737 Label if_rhsissimd128value(assembler), | |
| 3738 if_rhsisnotsimd128value(assembler); | |
| 3739 assembler->Branch( | |
| 3740 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), | |
| 3741 &if_rhsissimd128value, &if_rhsisnotsimd128value); | |
| 3742 | |
| 3743 assembler->Bind(&if_rhsissimd128value); | |
| 3744 { | |
| 3745 // Both {lhs} and {rhs} is a Simd128Value. | |
| 3746 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, | |
| 3747 rhs, rhs_map, &if_equal, | |
| 3748 &if_notequal); | |
| 3749 } | |
| 3750 | |
| 3751 assembler->Bind(&if_rhsisnotsimd128value); | |
| 3752 { | |
| 3753 // Check if the {rhs} is a JSReceiver. | |
| 3754 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
| 3755 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
| 3756 assembler->Branch( | |
| 3757 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3758 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3759 | |
| 3760 assembler->Bind(&if_rhsisreceiver); | |
| 3761 { | |
| 3762 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
| 3763 // Swapping {lhs} and {rhs} is not observable and doesn't | |
| 3764 // matter for the result, so we can just swap them and use | |
| 3765 // the JSReceiver handling below (for {lhs} being a JSReceiver). | |
| 3766 var_lhs.Bind(rhs); | |
| 3767 var_rhs.Bind(lhs); | |
| 3768 assembler->Goto(&loop); | |
| 3769 } | |
| 3770 | |
| 3771 assembler->Bind(&if_rhsisnotreceiver); | |
| 3772 { | |
| 3773 // The {rhs} is some other Primitive. | |
| 3774 assembler->Goto(&if_notequal); | |
| 3775 } | |
| 3776 } | |
| 3777 } | |
| 3778 | |
| 3779 assembler->Bind(&if_lhsisreceiver); | |
| 3780 { | |
| 3781 // Check if the {rhs} is also a JSReceiver. | |
| 3782 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
| 3783 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
| 3784 assembler->Branch( | |
| 3785 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
| 3786 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
| 3787 | |
| 3788 assembler->Bind(&if_rhsisreceiver); | |
| 3789 { | |
| 3790 // Both {lhs} and {rhs} are different JSReceiver references, so | |
| 3791 // this cannot be considered equal. | |
| 3792 assembler->Goto(&if_notequal); | |
| 3793 } | |
| 3794 | |
| 3795 assembler->Bind(&if_rhsisnotreceiver); | |
| 3796 { | |
| 3797 // Check if {rhs} is Null or Undefined (an undetectable check | |
| 3798 // is sufficient here, since we already know that {rhs} is not | |
| 3799 // a JSReceiver). | |
| 3800 Label if_rhsisundetectable(assembler), | |
| 3801 if_rhsisnotundetectable(assembler, Label::kDeferred); | |
| 3802 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); | |
| 3803 assembler->BranchIfWord32Equal( | |
| 3804 assembler->Word32And( | |
| 3805 rhs_bitfield, | |
| 3806 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
| 3807 assembler->Int32Constant(0), &if_rhsisnotundetectable, | |
| 3808 &if_rhsisundetectable); | |
| 3809 | |
| 3810 assembler->Bind(&if_rhsisundetectable); | |
| 3811 { | |
| 3812 // Check if {lhs} is an undetectable JSReceiver. | |
| 3813 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map); | |
| 3814 assembler->BranchIfWord32Equal( | |
| 3815 assembler->Word32And( | |
| 3816 lhs_bitfield, | |
| 3817 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
| 3818 assembler->Int32Constant(0), &if_notequal, &if_equal); | |
| 3819 } | |
| 3820 | |
| 3821 assembler->Bind(&if_rhsisnotundetectable); | |
| 3822 { | |
| 3823 // The {rhs} is some Primitive different from Null and | |
| 3824 // Undefined, need to convert {lhs} to Primitive first. | |
| 3825 Callable callable = | |
| 3826 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
| 3827 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
| 3828 assembler->Goto(&loop); | |
| 3829 } | |
| 3830 } | |
| 3831 } | |
| 3832 } | |
| 3833 } | |
| 3834 } | |
| 3835 | |
| 3836 assembler->Bind(&do_rhsstringtonumber); | |
| 3837 { | |
| 3838 Callable callable = CodeFactory::StringToNumber(assembler->isolate()); | |
| 3839 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
| 3840 assembler->Goto(&loop); | |
| 3841 } | |
| 3842 } | |
| 3843 | |
| 3844 assembler->Bind(&do_fcmp); | |
| 3845 { | |
| 3846 // Load the {lhs} and {rhs} floating point values. | |
| 3847 Node* lhs = var_fcmp_lhs.value(); | |
| 3848 Node* rhs = var_fcmp_rhs.value(); | |
| 3849 | |
| 3850 // Perform a fast floating point comparison. | |
| 3851 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); | |
| 3852 } | |
| 3853 | |
| 3854 assembler->Bind(&if_equal); | |
| 3855 { | |
| 3856 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); | |
| 3857 assembler->Goto(&end); | |
| 3858 } | |
| 3859 | |
| 3860 assembler->Bind(&if_notequal); | |
| 3861 { | |
| 3862 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); | |
| 3863 assembler->Goto(&end); | |
| 3864 } | |
| 3865 | |
| 3866 assembler->Bind(&end); | |
| 3867 return result.value(); | |
| 3868 } | |
| 3869 | |
| 3870 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, | |
| 3871 ResultMode mode, compiler::Node* lhs, | |
| 3872 compiler::Node* rhs, | |
| 3873 compiler::Node* context) { | |
| 3874 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | |
| 3875 // mode; for kNegateResult mode we properly negate the result. | |
| 3876 // | |
| 3877 // if (lhs == rhs) { | |
| 3878 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | |
| 3879 // return true; | |
| 3880 // } | |
| 3881 // if (!lhs->IsSmi()) { | |
| 3882 // if (lhs->IsHeapNumber()) { | |
| 3883 // if (rhs->IsSmi()) { | |
| 3884 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); | |
| 3885 // } else if (rhs->IsHeapNumber()) { | |
| 3886 // return HeapNumber::cast(rhs)->value() == | |
| 3887 // HeapNumber::cast(lhs)->value(); | |
| 3888 // } else { | |
| 3889 // return false; | |
| 3890 // } | |
| 3891 // } else { | |
| 3892 // if (rhs->IsSmi()) { | |
| 3893 // return false; | |
| 3894 // } else { | |
| 3895 // if (lhs->IsString()) { | |
| 3896 // if (rhs->IsString()) { | |
| 3897 // return %StringEqual(lhs, rhs); | |
| 3898 // } else { | |
| 3899 // return false; | |
| 3900 // } | |
| 3901 // } else if (lhs->IsSimd128()) { | |
| 3902 // if (rhs->IsSimd128()) { | |
| 3903 // return %StrictEqual(lhs, rhs); | |
| 3904 // } | |
| 3905 // } else { | |
| 3906 // return false; | |
| 3907 // } | |
| 3908 // } | |
| 3909 // } | |
| 3910 // } else { | |
| 3911 // if (rhs->IsSmi()) { | |
| 3912 // return false; | |
| 3913 // } else { | |
| 3914 // if (rhs->IsHeapNumber()) { | |
| 3915 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); | |
| 3916 // } else { | |
| 3917 // return false; | |
| 3918 // } | |
| 3919 // } | |
| 3920 // } | |
| 3921 | |
| 3922 typedef CodeStubAssembler::Label Label; | |
| 3923 typedef CodeStubAssembler::Variable Variable; | |
| 3924 typedef compiler::Node Node; | |
| 3925 | |
| 3926 Label if_equal(assembler), if_notequal(assembler), end(assembler); | |
| 3927 Variable result(assembler, MachineRepresentation::kTagged); | |
| 3928 | |
| 3929 // Check if {lhs} and {rhs} refer to the same object. | |
| 3930 Label if_same(assembler), if_notsame(assembler); | |
| 3931 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
| 3932 | |
| 3933 assembler->Bind(&if_same); | |
| 3934 { | |
| 3935 // The {lhs} and {rhs} reference the exact same value, yet we need special | |
| 3936 // treatment for HeapNumber, as NaN is not equal to NaN. | |
| 3937 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | |
| 3938 } | |
| 3939 | |
| 3940 assembler->Bind(&if_notsame); | |
| 3941 { | |
| 3942 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, | |
| 3943 // String and Simd128Value they can still be considered equal. | |
| 3944 Node* number_map = assembler->HeapNumberMapConstant(); | |
| 3945 | |
| 3946 // Check if {lhs} is a Smi or a HeapObject. | |
| 3947 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
| 3948 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
| 3949 | |
| 3950 assembler->Bind(&if_lhsisnotsmi); | |
| 3951 { | |
| 3952 // Load the map of {lhs}. | |
| 3953 Node* lhs_map = assembler->LoadMap(lhs); | |
| 3954 | |
| 3955 // Check if {lhs} is a HeapNumber. | |
| 3956 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
| 3957 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
| 3958 &if_lhsisnumber, &if_lhsisnotnumber); | |
| 3959 | |
| 3960 assembler->Bind(&if_lhsisnumber); | |
| 3961 { | |
| 3962 // Check if {rhs} is a Smi or a HeapObject. | |
| 3963 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 3964 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 3965 &if_rhsisnotsmi); | |
| 3966 | |
| 3967 assembler->Bind(&if_rhsissmi); | |
| 3968 { | |
| 3969 // Convert {lhs} and {rhs} to floating point values. | |
| 3970 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | |
| 3971 Node* rhs_value = assembler->SmiToFloat64(rhs); | |
| 3972 | |
| 3973 // Perform a floating point comparison of {lhs} and {rhs}. | |
| 3974 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
| 3975 &if_notequal); | |
| 3976 } | |
| 3977 | |
| 3978 assembler->Bind(&if_rhsisnotsmi); | |
| 3979 { | |
| 3980 // Load the map of {rhs}. | |
| 3981 Node* rhs_map = assembler->LoadMap(rhs); | |
| 3982 | |
| 3983 // Check if {rhs} is also a HeapNumber. | |
| 3984 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
| 3985 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 3986 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 3987 | |
| 3988 assembler->Bind(&if_rhsisnumber); | |
| 3989 { | |
| 3990 // Convert {lhs} and {rhs} to floating point values. | |
| 3991 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | |
| 3992 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | |
| 3993 | |
| 3994 // Perform a floating point comparison of {lhs} and {rhs}. | |
| 3995 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
| 3996 &if_notequal); | |
| 3997 } | |
| 3998 | |
| 3999 assembler->Bind(&if_rhsisnotnumber); | |
| 4000 assembler->Goto(&if_notequal); | |
| 4001 } | |
| 4002 } | |
| 4003 | |
| 4004 assembler->Bind(&if_lhsisnotnumber); | |
| 4005 { | |
| 4006 // Check if {rhs} is a Smi or a HeapObject. | |
| 4007 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 4008 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 4009 &if_rhsisnotsmi); | |
| 4010 | |
| 4011 assembler->Bind(&if_rhsissmi); | |
| 4012 assembler->Goto(&if_notequal); | |
| 4013 | |
| 4014 assembler->Bind(&if_rhsisnotsmi); | |
| 4015 { | |
| 4016 // Load the instance type of {lhs}. | |
| 4017 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
| 4018 | |
| 4019 // Check if {lhs} is a String. | |
| 4020 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); | |
| 4021 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
| 4022 &if_lhsisstring, &if_lhsisnotstring); | |
| 4023 | |
| 4024 assembler->Bind(&if_lhsisstring); | |
| 4025 { | |
| 4026 // Load the instance type of {rhs}. | |
| 4027 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
| 4028 | |
| 4029 // Check if {rhs} is also a String. | |
| 4030 Label if_rhsisstring(assembler, Label::kDeferred), | |
| 4031 if_rhsisnotstring(assembler); | |
| 4032 assembler->Branch( | |
| 4033 assembler->IsStringInstanceType(rhs_instance_type), | |
| 4034 &if_rhsisstring, &if_rhsisnotstring); | |
| 4035 | |
| 4036 assembler->Bind(&if_rhsisstring); | |
| 4037 { | |
| 4038 Callable callable = | |
| 4039 (mode == kDontNegateResult) | |
| 4040 ? CodeFactory::StringEqual(assembler->isolate()) | |
| 4041 : CodeFactory::StringNotEqual(assembler->isolate()); | |
| 4042 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | |
| 4043 assembler->Goto(&end); | |
| 4044 } | |
| 4045 | |
| 4046 assembler->Bind(&if_rhsisnotstring); | |
| 4047 assembler->Goto(&if_notequal); | |
| 4048 } | |
| 4049 | |
| 4050 assembler->Bind(&if_lhsisnotstring); | |
| 4051 { | |
| 4052 // Check if {lhs} is a Simd128Value. | |
| 4053 Label if_lhsissimd128value(assembler), | |
| 4054 if_lhsisnotsimd128value(assembler); | |
| 4055 assembler->Branch(assembler->Word32Equal( | |
| 4056 lhs_instance_type, | |
| 4057 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | |
| 4058 &if_lhsissimd128value, &if_lhsisnotsimd128value); | |
| 4059 | |
| 4060 assembler->Bind(&if_lhsissimd128value); | |
| 4061 { | |
| 4062 // Load the map of {rhs}. | |
| 4063 Node* rhs_map = assembler->LoadMap(rhs); | |
| 4064 | |
| 4065 // Check if {rhs} is also a Simd128Value that is equal to {lhs}. | |
| 4066 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, | |
| 4067 rhs, rhs_map, &if_equal, | |
| 4068 &if_notequal); | |
| 4069 } | |
| 4070 | |
| 4071 assembler->Bind(&if_lhsisnotsimd128value); | |
| 4072 assembler->Goto(&if_notequal); | |
| 4073 } | |
| 4074 } | |
| 4075 } | |
| 4076 } | |
| 4077 | |
| 4078 assembler->Bind(&if_lhsissmi); | |
| 4079 { | |
| 4080 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} | |
| 4081 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a | |
| 4082 // HeapNumber with an equal floating point value. | |
| 4083 | |
| 4084 // Check if {rhs} is a Smi or a HeapObject. | |
| 4085 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
| 4086 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
| 4087 &if_rhsisnotsmi); | |
| 4088 | |
| 4089 assembler->Bind(&if_rhsissmi); | |
| 4090 assembler->Goto(&if_notequal); | |
| 4091 | |
| 4092 assembler->Bind(&if_rhsisnotsmi); | |
| 4093 { | |
| 4094 // Load the map of the {rhs}. | |
| 4095 Node* rhs_map = assembler->LoadMap(rhs); | |
| 4096 | |
| 4097 // The {rhs} could be a HeapNumber with the same value as {lhs}. | |
| 4098 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
| 4099 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
| 4100 &if_rhsisnumber, &if_rhsisnotnumber); | |
| 4101 | |
| 4102 assembler->Bind(&if_rhsisnumber); | |
| 4103 { | |
| 4104 // Convert {lhs} and {rhs} to floating point values. | |
| 4105 Node* lhs_value = assembler->SmiToFloat64(lhs); | |
| 4106 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | |
| 4107 | |
| 4108 // Perform a floating point comparison of {lhs} and {rhs}. | |
| 4109 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
| 4110 &if_notequal); | |
| 4111 } | |
| 4112 | |
| 4113 assembler->Bind(&if_rhsisnotnumber); | |
| 4114 assembler->Goto(&if_notequal); | |
| 4115 } | |
| 4116 } | |
| 4117 } | |
| 4118 | |
| 4119 assembler->Bind(&if_equal); | |
| 4120 { | |
| 4121 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); | |
| 4122 assembler->Goto(&end); | |
| 4123 } | |
| 4124 | |
| 4125 assembler->Bind(&if_notequal); | |
| 4126 { | |
| 4127 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); | |
| 4128 assembler->Goto(&end); | |
| 4129 } | |
| 4130 | |
| 4131 assembler->Bind(&end); | |
| 4132 return result.value(); | |
| 4133 } | |
| 4134 | |
| 4135 } // namespace | |
| 4136 | |
| 4137 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 1551 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
| 4138 typedef compiler::Node Node; | 1552 typedef compiler::Node Node; |
| 4139 Node* context = assembler->Parameter(Descriptor::kContext); | 1553 Node* context = assembler->Parameter(Descriptor::kContext); |
| 4140 Node* receiver = assembler->Parameter(Descriptor::kReceiver); | 1554 Node* receiver = assembler->Parameter(Descriptor::kReceiver); |
| 4141 // For now we only support receiver_is_holder. | 1555 // For now we only support receiver_is_holder. |
| 4142 DCHECK(receiver_is_holder()); | 1556 DCHECK(receiver_is_holder()); |
| 4143 Node* holder = receiver; | 1557 Node* holder = receiver; |
| 4144 Node* map = assembler->LoadMap(receiver); | 1558 Node* map = assembler->LoadMap(receiver); |
| 4145 Node* descriptors = assembler->LoadMapDescriptors(map); | 1559 Node* descriptors = assembler->LoadMapDescriptors(map); |
| 4146 Node* value_index = | 1560 Node* value_index = |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4356 Node* value = assembler->Parameter(Descriptor::kValue); | 1770 Node* value = assembler->Parameter(Descriptor::kValue); |
| 4357 Node* context = assembler->Parameter(Descriptor::kContext); | 1771 Node* context = assembler->Parameter(Descriptor::kContext); |
| 4358 | 1772 |
| 4359 Node* script_context = assembler->LoadScriptContext(context, context_index()); | 1773 Node* script_context = assembler->LoadScriptContext(context, context_index()); |
| 4360 assembler->StoreFixedArrayElement( | 1774 assembler->StoreFixedArrayElement( |
| 4361 script_context, assembler->IntPtrConstant(slot_index()), value, | 1775 script_context, assembler->IntPtrConstant(slot_index()), value, |
| 4362 UPDATE_WRITE_BARRIER, CodeStubAssembler::INTPTR_PARAMETERS); | 1776 UPDATE_WRITE_BARRIER, CodeStubAssembler::INTPTR_PARAMETERS); |
| 4363 assembler->Return(value); | 1777 assembler->Return(value); |
| 4364 } | 1778 } |
| 4365 | 1779 |
| 4366 // static | |
| 4367 compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler, | |
| 4368 compiler::Node* lhs, compiler::Node* rhs, | |
| 4369 compiler::Node* context) { | |
| 4370 return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs, | |
| 4371 context); | |
| 4372 } | |
| 4373 | |
| 4374 // static | |
| 4375 compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler, | |
| 4376 compiler::Node* lhs, | |
| 4377 compiler::Node* rhs, | |
| 4378 compiler::Node* context) { | |
| 4379 return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs, | |
| 4380 rhs, context); | |
| 4381 } | |
| 4382 | |
| 4383 // static | |
| 4384 compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler, | |
| 4385 compiler::Node* lhs, | |
| 4386 compiler::Node* rhs, | |
| 4387 compiler::Node* context) { | |
| 4388 return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs, | |
| 4389 context); | |
| 4390 } | |
| 4391 | |
| 4392 // static | |
| 4393 compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler, | |
| 4394 compiler::Node* lhs, | |
| 4395 compiler::Node* rhs, | |
| 4396 compiler::Node* context) { | |
| 4397 return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual, | |
| 4398 lhs, rhs, context); | |
| 4399 } | |
| 4400 | |
| 4401 // static | |
| 4402 compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler, | |
| 4403 compiler::Node* lhs, compiler::Node* rhs, | |
| 4404 compiler::Node* context) { | |
| 4405 return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context); | |
| 4406 } | |
| 4407 | |
| 4408 // static | |
| 4409 compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler, | |
| 4410 compiler::Node* lhs, compiler::Node* rhs, | |
| 4411 compiler::Node* context) { | |
| 4412 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); | |
| 4413 } | |
| 4414 | |
| 4415 // static | |
| 4416 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, | |
| 4417 compiler::Node* lhs, | |
| 4418 compiler::Node* rhs, | |
| 4419 compiler::Node* context) { | |
| 4420 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context); | |
| 4421 } | |
| 4422 | |
| 4423 // static | |
| 4424 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, | |
| 4425 compiler::Node* lhs, | |
| 4426 compiler::Node* rhs, | |
| 4427 compiler::Node* context) { | |
| 4428 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); | |
| 4429 } | |
| 4430 | |
| 4431 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
| 4432 typedef CodeStubAssembler::Label Label; | |
| 4433 typedef compiler::Node Node; | |
| 4434 typedef CodeStubAssembler::Variable Variable; | |
| 4435 | |
| 4436 Node* context = assembler->Parameter(1); | |
| 4437 | |
| 4438 // We might need to loop once for ToNumber conversion. | |
| 4439 Variable var_len(assembler, MachineRepresentation::kTagged); | |
| 4440 Label loop(assembler, &var_len); | |
| 4441 var_len.Bind(assembler->Parameter(0)); | |
| 4442 assembler->Goto(&loop); | |
| 4443 assembler->Bind(&loop); | |
| 4444 { | |
| 4445 // Shared entry points. | |
| 4446 Label return_len(assembler), | |
| 4447 return_two53minus1(assembler, Label::kDeferred), | |
| 4448 return_zero(assembler, Label::kDeferred); | |
| 4449 | |
| 4450 // Load the current {len} value. | |
| 4451 Node* len = var_len.value(); | |
| 4452 | |
| 4453 // Check if {len} is a positive Smi. | |
| 4454 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len); | |
| 4455 | |
| 4456 // Check if {len} is a (negative) Smi. | |
| 4457 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero); | |
| 4458 | |
| 4459 // Check if {len} is a HeapNumber. | |
| 4460 Label if_lenisheapnumber(assembler), | |
| 4461 if_lenisnotheapnumber(assembler, Label::kDeferred); | |
| 4462 assembler->Branch(assembler->IsHeapNumberMap(assembler->LoadMap(len)), | |
| 4463 &if_lenisheapnumber, &if_lenisnotheapnumber); | |
| 4464 | |
| 4465 assembler->Bind(&if_lenisheapnumber); | |
| 4466 { | |
| 4467 // Load the floating-point value of {len}. | |
| 4468 Node* len_value = assembler->LoadHeapNumberValue(len); | |
| 4469 | |
| 4470 // Check if {len} is not greater than zero. | |
| 4471 assembler->GotoUnless(assembler->Float64GreaterThan( | |
| 4472 len_value, assembler->Float64Constant(0.0)), | |
| 4473 &return_zero); | |
| 4474 | |
| 4475 // Check if {len} is greater than or equal to 2^53-1. | |
| 4476 assembler->GotoIf( | |
| 4477 assembler->Float64GreaterThanOrEqual( | |
| 4478 len_value, assembler->Float64Constant(kMaxSafeInteger)), | |
| 4479 &return_two53minus1); | |
| 4480 | |
| 4481 // Round the {len} towards -Infinity. | |
| 4482 Node* value = assembler->Float64Floor(len_value); | |
| 4483 Node* result = assembler->ChangeFloat64ToTagged(value); | |
| 4484 assembler->Return(result); | |
| 4485 } | |
| 4486 | |
| 4487 assembler->Bind(&if_lenisnotheapnumber); | |
| 4488 { | |
| 4489 // Need to convert {len} to a Number first. | |
| 4490 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate()); | |
| 4491 var_len.Bind(assembler->CallStub(callable, context, len)); | |
| 4492 assembler->Goto(&loop); | |
| 4493 } | |
| 4494 | |
| 4495 assembler->Bind(&return_len); | |
| 4496 assembler->Return(var_len.value()); | |
| 4497 | |
| 4498 assembler->Bind(&return_two53minus1); | |
| 4499 assembler->Return(assembler->NumberConstant(kMaxSafeInteger)); | |
| 4500 | |
| 4501 assembler->Bind(&return_zero); | |
| 4502 assembler->Return(assembler->SmiConstant(Smi::FromInt(0))); | |
| 4503 } | |
| 4504 } | |
| 4505 | |
| 4506 void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
| 4507 typedef compiler::Node Node; | |
| 4508 | |
| 4509 Node* input = assembler->Parameter(Descriptor::kArgument); | |
| 4510 Node* context = assembler->Parameter(Descriptor::kContext); | |
| 4511 | |
| 4512 assembler->Return(assembler->ToInteger(context, input)); | |
| 4513 } | |
| 4514 | |
| 4515 void StoreInterceptorStub::GenerateAssembly( | 1780 void StoreInterceptorStub::GenerateAssembly( |
| 4516 CodeStubAssembler* assembler) const { | 1781 CodeStubAssembler* assembler) const { |
| 4517 typedef compiler::Node Node; | 1782 typedef compiler::Node Node; |
| 4518 | 1783 |
| 4519 Node* receiver = assembler->Parameter(Descriptor::kReceiver); | 1784 Node* receiver = assembler->Parameter(Descriptor::kReceiver); |
| 4520 Node* name = assembler->Parameter(Descriptor::kName); | 1785 Node* name = assembler->Parameter(Descriptor::kName); |
| 4521 Node* value = assembler->Parameter(Descriptor::kValue); | 1786 Node* value = assembler->Parameter(Descriptor::kValue); |
| 4522 Node* context = assembler->Parameter(Descriptor::kContext); | 1787 Node* context = assembler->Parameter(Descriptor::kContext); |
| 4523 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, | 1788 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, |
| 4524 receiver, name, value); | 1789 receiver, name, value); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4805 descriptor->Initialize( | 2070 descriptor->Initialize( |
| 4806 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); | 2071 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); |
| 4807 } | 2072 } |
| 4808 | 2073 |
| 4809 | 2074 |
| 4810 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { | 2075 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { |
| 4811 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); | 2076 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); |
| 4812 descriptor->SetMissHandler(Runtime::kStringAdd); | 2077 descriptor->SetMissHandler(Runtime::kStringAdd); |
| 4813 } | 2078 } |
| 4814 | 2079 |
| 4815 namespace { | |
| 4816 | |
| 4817 compiler::Node* GenerateHasProperty( | |
| 4818 CodeStubAssembler* assembler, compiler::Node* object, compiler::Node* key, | |
| 4819 compiler::Node* context, Runtime::FunctionId fallback_runtime_function_id) { | |
| 4820 typedef compiler::Node Node; | |
| 4821 typedef CodeStubAssembler::Label Label; | |
| 4822 typedef CodeStubAssembler::Variable Variable; | |
| 4823 | |
| 4824 Label call_runtime(assembler, Label::kDeferred), return_true(assembler), | |
| 4825 return_false(assembler), end(assembler); | |
| 4826 | |
| 4827 CodeStubAssembler::LookupInHolder lookup_property_in_holder = | |
| 4828 [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, | |
| 4829 Node* holder_instance_type, Node* unique_name, | |
| 4830 Label* next_holder, Label* if_bailout) { | |
| 4831 assembler->TryHasOwnProperty(holder, holder_map, holder_instance_type, | |
| 4832 unique_name, &return_true, next_holder, | |
| 4833 if_bailout); | |
| 4834 }; | |
| 4835 | |
| 4836 CodeStubAssembler::LookupInHolder lookup_element_in_holder = | |
| 4837 [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, | |
| 4838 Node* holder_instance_type, Node* index, | |
| 4839 Label* next_holder, Label* if_bailout) { | |
| 4840 assembler->TryLookupElement(holder, holder_map, holder_instance_type, | |
| 4841 index, &return_true, next_holder, | |
| 4842 if_bailout); | |
| 4843 }; | |
| 4844 | |
| 4845 assembler->TryPrototypeChainLookup(object, key, lookup_property_in_holder, | |
| 4846 lookup_element_in_holder, &return_false, | |
| 4847 &call_runtime); | |
| 4848 | |
| 4849 Variable result(assembler, MachineRepresentation::kTagged); | |
| 4850 assembler->Bind(&return_true); | |
| 4851 { | |
| 4852 result.Bind(assembler->BooleanConstant(true)); | |
| 4853 assembler->Goto(&end); | |
| 4854 } | |
| 4855 | |
| 4856 assembler->Bind(&return_false); | |
| 4857 { | |
| 4858 result.Bind(assembler->BooleanConstant(false)); | |
| 4859 assembler->Goto(&end); | |
| 4860 } | |
| 4861 | |
| 4862 assembler->Bind(&call_runtime); | |
| 4863 { | |
| 4864 result.Bind(assembler->CallRuntime(fallback_runtime_function_id, context, | |
| 4865 object, key)); | |
| 4866 assembler->Goto(&end); | |
| 4867 } | |
| 4868 | |
| 4869 assembler->Bind(&end); | |
| 4870 return result.value(); | |
| 4871 } | |
| 4872 | |
| 4873 } // namespace | |
| 4874 | |
| 4875 // static | |
| 4876 compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler, | |
| 4877 compiler::Node* key, | |
| 4878 compiler::Node* object, | |
| 4879 compiler::Node* context) { | |
| 4880 return GenerateHasProperty(assembler, object, key, context, | |
| 4881 Runtime::kHasProperty); | |
| 4882 } | |
| 4883 | |
| 4884 // static | |
| 4885 compiler::Node* ForInFilterStub::Generate(CodeStubAssembler* assembler, | |
| 4886 compiler::Node* key, | |
| 4887 compiler::Node* object, | |
| 4888 compiler::Node* context) { | |
| 4889 typedef compiler::Node Node; | |
| 4890 typedef CodeStubAssembler::Label Label; | |
| 4891 typedef CodeStubAssembler::Variable Variable; | |
| 4892 | |
| 4893 Label return_undefined(assembler, Label::kDeferred), | |
| 4894 return_to_name(assembler), end(assembler); | |
| 4895 | |
| 4896 Variable var_result(assembler, MachineRepresentation::kTagged); | |
| 4897 | |
| 4898 Node* has_property = GenerateHasProperty(assembler, object, key, context, | |
| 4899 Runtime::kForInHasProperty); | |
| 4900 | |
| 4901 assembler->Branch( | |
| 4902 assembler->WordEqual(has_property, assembler->BooleanConstant(true)), | |
| 4903 &return_to_name, &return_undefined); | |
| 4904 | |
| 4905 assembler->Bind(&return_to_name); | |
| 4906 { | |
| 4907 var_result.Bind(assembler->ToName(context, key)); | |
| 4908 assembler->Goto(&end); | |
| 4909 } | |
| 4910 | |
| 4911 assembler->Bind(&return_undefined); | |
| 4912 { | |
| 4913 var_result.Bind(assembler->UndefinedConstant()); | |
| 4914 assembler->Goto(&end); | |
| 4915 } | |
| 4916 | |
| 4917 assembler->Bind(&end); | |
| 4918 return var_result.value(); | |
| 4919 } | |
| 4920 | 2080 |
| 4921 void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 2081 void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
| 4922 typedef compiler::Node Node; | 2082 typedef compiler::Node Node; |
| 4923 typedef CodeStubAssembler::Label Label; | 2083 typedef CodeStubAssembler::Label Label; |
| 4924 typedef CodeStubAssembler::Variable Variable; | 2084 typedef CodeStubAssembler::Variable Variable; |
| 4925 | 2085 |
| 4926 Label call_runtime(assembler, Label::kDeferred), return_undefined(assembler), | 2086 Label call_runtime(assembler, Label::kDeferred), return_undefined(assembler), |
| 4927 end(assembler); | 2087 end(assembler); |
| 4928 | 2088 |
| 4929 Node* object = assembler->Parameter(0); | 2089 Node* object = assembler->Parameter(0); |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5826 | 2986 |
| 5827 if (type == MachineType::Pointer()) { | 2987 if (type == MachineType::Pointer()) { |
| 5828 return Representation::External(); | 2988 return Representation::External(); |
| 5829 } | 2989 } |
| 5830 | 2990 |
| 5831 return Representation::Tagged(); | 2991 return Representation::Tagged(); |
| 5832 } | 2992 } |
| 5833 | 2993 |
| 5834 } // namespace internal | 2994 } // namespace internal |
| 5835 } // namespace v8 | 2995 } // namespace v8 |
| OLD | NEW |