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