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