OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/frames.h" | 8 #include "src/frames.h" |
9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 5723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5734 StoreObjectField(cell, WeakCell::kValueOffset, value); | 5734 StoreObjectField(cell, WeakCell::kValueOffset, value); |
5735 StoreObjectFieldRoot(cell, WeakCell::kNextOffset, | 5735 StoreObjectFieldRoot(cell, WeakCell::kNextOffset, |
5736 Heap::kTheHoleValueRootIndex); | 5736 Heap::kTheHoleValueRootIndex); |
5737 | 5737 |
5738 // Store the WeakCell in the feedback vector. | 5738 // Store the WeakCell in the feedback vector. |
5739 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 5739 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
5740 CodeStubAssembler::SMI_PARAMETERS); | 5740 CodeStubAssembler::SMI_PARAMETERS); |
5741 return cell; | 5741 return cell; |
5742 } | 5742 } |
5743 | 5743 |
| 5744 compiler::Node* CodeStubAssembler::RelationalComparison( |
| 5745 RelationalComparisonMode mode, compiler::Node* lhs, compiler::Node* rhs, |
| 5746 compiler::Node* context) { |
| 5747 typedef compiler::Node Node; |
| 5748 |
| 5749 Label return_true(this), return_false(this), end(this); |
| 5750 Variable result(this, MachineRepresentation::kTagged); |
| 5751 |
| 5752 // Shared entry for floating point comparison. |
| 5753 Label do_fcmp(this); |
| 5754 Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64), |
| 5755 var_fcmp_rhs(this, MachineRepresentation::kFloat64); |
| 5756 |
| 5757 // We might need to loop several times due to ToPrimitive and/or ToNumber |
| 5758 // conversions. |
| 5759 Variable var_lhs(this, MachineRepresentation::kTagged), |
| 5760 var_rhs(this, MachineRepresentation::kTagged); |
| 5761 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
| 5762 Label loop(this, 2, loop_vars); |
| 5763 var_lhs.Bind(lhs); |
| 5764 var_rhs.Bind(rhs); |
| 5765 Goto(&loop); |
| 5766 Bind(&loop); |
| 5767 { |
| 5768 // Load the current {lhs} and {rhs} values. |
| 5769 lhs = var_lhs.value(); |
| 5770 rhs = var_rhs.value(); |
| 5771 |
| 5772 // Check if the {lhs} is a Smi or a HeapObject. |
| 5773 Label if_lhsissmi(this), if_lhsisnotsmi(this); |
| 5774 Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
| 5775 |
| 5776 Bind(&if_lhsissmi); |
| 5777 { |
| 5778 // Check if {rhs} is a Smi or a HeapObject. |
| 5779 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 5780 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 5781 |
| 5782 Bind(&if_rhsissmi); |
| 5783 { |
| 5784 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. |
| 5785 switch (mode) { |
| 5786 case kLessThan: |
| 5787 BranchIfSmiLessThan(lhs, rhs, &return_true, &return_false); |
| 5788 break; |
| 5789 case kLessThanOrEqual: |
| 5790 BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, &return_false); |
| 5791 break; |
| 5792 case kGreaterThan: |
| 5793 BranchIfSmiLessThan(rhs, lhs, &return_true, &return_false); |
| 5794 break; |
| 5795 case kGreaterThanOrEqual: |
| 5796 BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, &return_false); |
| 5797 break; |
| 5798 } |
| 5799 } |
| 5800 |
| 5801 Bind(&if_rhsisnotsmi); |
| 5802 { |
| 5803 // Load the map of {rhs}. |
| 5804 Node* rhs_map = LoadMap(rhs); |
| 5805 |
| 5806 // Check if the {rhs} is a HeapNumber. |
| 5807 Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
| 5808 Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber); |
| 5809 |
| 5810 Bind(&if_rhsisnumber); |
| 5811 { |
| 5812 // Convert the {lhs} and {rhs} to floating point values, and |
| 5813 // perform a floating point comparison. |
| 5814 var_fcmp_lhs.Bind(SmiToFloat64(lhs)); |
| 5815 var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
| 5816 Goto(&do_fcmp); |
| 5817 } |
| 5818 |
| 5819 Bind(&if_rhsisnotnumber); |
| 5820 { |
| 5821 // Convert the {rhs} to a Number; we don't need to perform the |
| 5822 // dedicated ToPrimitive(rhs, hint Number) operation, as the |
| 5823 // ToNumber(rhs) will by itself already invoke ToPrimitive with |
| 5824 // a Number hint. |
| 5825 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| 5826 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 5827 Goto(&loop); |
| 5828 } |
| 5829 } |
| 5830 } |
| 5831 |
| 5832 Bind(&if_lhsisnotsmi); |
| 5833 { |
| 5834 // Load the HeapNumber map for later comparisons. |
| 5835 Node* number_map = HeapNumberMapConstant(); |
| 5836 |
| 5837 // Load the map of {lhs}. |
| 5838 Node* lhs_map = LoadMap(lhs); |
| 5839 |
| 5840 // Check if {rhs} is a Smi or a HeapObject. |
| 5841 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 5842 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 5843 |
| 5844 Bind(&if_rhsissmi); |
| 5845 { |
| 5846 // Check if the {lhs} is a HeapNumber. |
| 5847 Label if_lhsisnumber(this), if_lhsisnotnumber(this, Label::kDeferred); |
| 5848 Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
| 5849 &if_lhsisnotnumber); |
| 5850 |
| 5851 Bind(&if_lhsisnumber); |
| 5852 { |
| 5853 // Convert the {lhs} and {rhs} to floating point values, and |
| 5854 // perform a floating point comparison. |
| 5855 var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
| 5856 var_fcmp_rhs.Bind(SmiToFloat64(rhs)); |
| 5857 Goto(&do_fcmp); |
| 5858 } |
| 5859 |
| 5860 Bind(&if_lhsisnotnumber); |
| 5861 { |
| 5862 // Convert the {lhs} to a Number; we don't need to perform the |
| 5863 // dedicated ToPrimitive(lhs, hint Number) operation, as the |
| 5864 // ToNumber(lhs) will by itself already invoke ToPrimitive with |
| 5865 // a Number hint. |
| 5866 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| 5867 var_lhs.Bind(CallStub(callable, context, lhs)); |
| 5868 Goto(&loop); |
| 5869 } |
| 5870 } |
| 5871 |
| 5872 Bind(&if_rhsisnotsmi); |
| 5873 { |
| 5874 // Load the map of {rhs}. |
| 5875 Node* rhs_map = LoadMap(rhs); |
| 5876 |
| 5877 // Check if {lhs} is a HeapNumber. |
| 5878 Label if_lhsisnumber(this), if_lhsisnotnumber(this); |
| 5879 Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
| 5880 &if_lhsisnotnumber); |
| 5881 |
| 5882 Bind(&if_lhsisnumber); |
| 5883 { |
| 5884 // Check if {rhs} is also a HeapNumber. |
| 5885 Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
| 5886 Branch(WordEqual(lhs_map, rhs_map), &if_rhsisnumber, |
| 5887 &if_rhsisnotnumber); |
| 5888 |
| 5889 Bind(&if_rhsisnumber); |
| 5890 { |
| 5891 // Convert the {lhs} and {rhs} to floating point values, and |
| 5892 // perform a floating point comparison. |
| 5893 var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
| 5894 var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
| 5895 Goto(&do_fcmp); |
| 5896 } |
| 5897 |
| 5898 Bind(&if_rhsisnotnumber); |
| 5899 { |
| 5900 // Convert the {rhs} to a Number; we don't need to perform |
| 5901 // dedicated ToPrimitive(rhs, hint Number) operation, as the |
| 5902 // ToNumber(rhs) will by itself already invoke ToPrimitive with |
| 5903 // a Number hint. |
| 5904 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| 5905 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 5906 Goto(&loop); |
| 5907 } |
| 5908 } |
| 5909 |
| 5910 Bind(&if_lhsisnotnumber); |
| 5911 { |
| 5912 // Load the instance type of {lhs}. |
| 5913 Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
| 5914 |
| 5915 // Check if {lhs} is a String. |
| 5916 Label if_lhsisstring(this), if_lhsisnotstring(this, Label::kDeferred); |
| 5917 Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring, |
| 5918 &if_lhsisnotstring); |
| 5919 |
| 5920 Bind(&if_lhsisstring); |
| 5921 { |
| 5922 // Load the instance type of {rhs}. |
| 5923 Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
| 5924 |
| 5925 // Check if {rhs} is also a String. |
| 5926 Label if_rhsisstring(this, Label::kDeferred), |
| 5927 if_rhsisnotstring(this, Label::kDeferred); |
| 5928 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
| 5929 &if_rhsisnotstring); |
| 5930 |
| 5931 Bind(&if_rhsisstring); |
| 5932 { |
| 5933 // Both {lhs} and {rhs} are strings. |
| 5934 switch (mode) { |
| 5935 case kLessThan: |
| 5936 result.Bind(CallStub(CodeFactory::StringLessThan(isolate()), |
| 5937 context, lhs, rhs)); |
| 5938 Goto(&end); |
| 5939 break; |
| 5940 case kLessThanOrEqual: |
| 5941 result.Bind( |
| 5942 CallStub(CodeFactory::StringLessThanOrEqual(isolate()), |
| 5943 context, lhs, rhs)); |
| 5944 Goto(&end); |
| 5945 break; |
| 5946 case kGreaterThan: |
| 5947 result.Bind( |
| 5948 CallStub(CodeFactory::StringGreaterThan(isolate()), |
| 5949 context, lhs, rhs)); |
| 5950 Goto(&end); |
| 5951 break; |
| 5952 case kGreaterThanOrEqual: |
| 5953 result.Bind( |
| 5954 CallStub(CodeFactory::StringGreaterThanOrEqual(isolate()), |
| 5955 context, lhs, rhs)); |
| 5956 Goto(&end); |
| 5957 break; |
| 5958 } |
| 5959 } |
| 5960 |
| 5961 Bind(&if_rhsisnotstring); |
| 5962 { |
| 5963 // The {lhs} is a String, while {rhs} is neither a Number nor a |
| 5964 // String, so we need to call ToPrimitive(rhs, hint Number) if |
| 5965 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the |
| 5966 // other cases. |
| 5967 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 5968 Label if_rhsisreceiver(this, Label::kDeferred), |
| 5969 if_rhsisnotreceiver(this, Label::kDeferred); |
| 5970 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 5971 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 5972 |
| 5973 Bind(&if_rhsisreceiver); |
| 5974 { |
| 5975 // Convert {rhs} to a primitive first passing Number hint. |
| 5976 Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
| 5977 isolate(), ToPrimitiveHint::kNumber); |
| 5978 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 5979 Goto(&loop); |
| 5980 } |
| 5981 |
| 5982 Bind(&if_rhsisnotreceiver); |
| 5983 { |
| 5984 // Convert both {lhs} and {rhs} to Number. |
| 5985 Callable callable = CodeFactory::ToNumber(isolate()); |
| 5986 var_lhs.Bind(CallStub(callable, context, lhs)); |
| 5987 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 5988 Goto(&loop); |
| 5989 } |
| 5990 } |
| 5991 } |
| 5992 |
| 5993 Bind(&if_lhsisnotstring); |
| 5994 { |
| 5995 // The {lhs} is neither a Number nor a String, so we need to call |
| 5996 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or |
| 5997 // ToNumber(lhs) and ToNumber(rhs) in the other cases. |
| 5998 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 5999 Label if_lhsisreceiver(this, Label::kDeferred), |
| 6000 if_lhsisnotreceiver(this, Label::kDeferred); |
| 6001 Branch(IsJSReceiverInstanceType(lhs_instance_type), |
| 6002 &if_lhsisreceiver, &if_lhsisnotreceiver); |
| 6003 |
| 6004 Bind(&if_lhsisreceiver); |
| 6005 { |
| 6006 // Convert {lhs} to a primitive first passing Number hint. |
| 6007 Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
| 6008 isolate(), ToPrimitiveHint::kNumber); |
| 6009 var_lhs.Bind(CallStub(callable, context, lhs)); |
| 6010 Goto(&loop); |
| 6011 } |
| 6012 |
| 6013 Bind(&if_lhsisnotreceiver); |
| 6014 { |
| 6015 // Convert both {lhs} and {rhs} to Number. |
| 6016 Callable callable = CodeFactory::ToNumber(isolate()); |
| 6017 var_lhs.Bind(CallStub(callable, context, lhs)); |
| 6018 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 6019 Goto(&loop); |
| 6020 } |
| 6021 } |
| 6022 } |
| 6023 } |
| 6024 } |
| 6025 } |
| 6026 |
| 6027 Bind(&do_fcmp); |
| 6028 { |
| 6029 // Load the {lhs} and {rhs} floating point values. |
| 6030 Node* lhs = var_fcmp_lhs.value(); |
| 6031 Node* rhs = var_fcmp_rhs.value(); |
| 6032 |
| 6033 // Perform a fast floating point comparison. |
| 6034 switch (mode) { |
| 6035 case kLessThan: |
| 6036 BranchIfFloat64LessThan(lhs, rhs, &return_true, &return_false); |
| 6037 break; |
| 6038 case kLessThanOrEqual: |
| 6039 BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, &return_false); |
| 6040 break; |
| 6041 case kGreaterThan: |
| 6042 BranchIfFloat64GreaterThan(lhs, rhs, &return_true, &return_false); |
| 6043 break; |
| 6044 case kGreaterThanOrEqual: |
| 6045 BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, |
| 6046 &return_false); |
| 6047 break; |
| 6048 } |
| 6049 } |
| 6050 |
| 6051 Bind(&return_true); |
| 6052 { |
| 6053 result.Bind(BooleanConstant(true)); |
| 6054 Goto(&end); |
| 6055 } |
| 6056 |
| 6057 Bind(&return_false); |
| 6058 { |
| 6059 result.Bind(BooleanConstant(false)); |
| 6060 Goto(&end); |
| 6061 } |
| 6062 |
| 6063 Bind(&end); |
| 6064 return result.value(); |
| 6065 } |
| 6066 |
| 6067 namespace { |
| 6068 |
| 6069 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, |
| 6070 CodeStubAssembler::Label* if_equal, |
| 6071 CodeStubAssembler::Label* if_notequal) { |
| 6072 // In case of abstract or strict equality checks, we need additional checks |
| 6073 // for NaN values because they are not considered equal, even if both the |
| 6074 // left and the right hand side reference exactly the same value. |
| 6075 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
| 6076 // seems to be what is tested in the current SIMD.js testsuite. |
| 6077 |
| 6078 typedef CodeStubAssembler::Label Label; |
| 6079 typedef compiler::Node Node; |
| 6080 |
| 6081 // Check if {value} is a Smi or a HeapObject. |
| 6082 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
| 6083 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, |
| 6084 &if_valueisnotsmi); |
| 6085 |
| 6086 assembler->Bind(&if_valueisnotsmi); |
| 6087 { |
| 6088 // Load the map of {value}. |
| 6089 Node* value_map = assembler->LoadMap(value); |
| 6090 |
| 6091 // Check if {value} (and therefore {rhs}) is a HeapNumber. |
| 6092 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); |
| 6093 assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber, |
| 6094 &if_valueisnotnumber); |
| 6095 |
| 6096 assembler->Bind(&if_valueisnumber); |
| 6097 { |
| 6098 // Convert {value} (and therefore {rhs}) to floating point value. |
| 6099 Node* value_value = assembler->LoadHeapNumberValue(value); |
| 6100 |
| 6101 // Check if the HeapNumber value is a NaN. |
| 6102 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); |
| 6103 } |
| 6104 |
| 6105 assembler->Bind(&if_valueisnotnumber); |
| 6106 assembler->Goto(if_equal); |
| 6107 } |
| 6108 |
| 6109 assembler->Bind(&if_valueissmi); |
| 6110 assembler->Goto(if_equal); |
| 6111 } |
| 6112 |
| 6113 void GenerateEqual_Simd128Value_HeapObject( |
| 6114 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, |
| 6115 compiler::Node* rhs, compiler::Node* rhs_map, |
| 6116 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { |
| 6117 assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal, |
| 6118 if_notequal); |
| 6119 } |
| 6120 |
| 6121 } // namespace |
| 6122 |
| 6123 // ES6 section 7.2.12 Abstract Equality Comparison |
| 6124 compiler::Node* CodeStubAssembler::Equal(ResultMode mode, compiler::Node* lhs, |
| 6125 compiler::Node* rhs, |
| 6126 compiler::Node* context) { |
| 6127 // This is a slightly optimized version of Object::Equals represented as |
| 6128 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you |
| 6129 // change something functionality wise in here, remember to update the |
| 6130 // Object::Equals method as well. |
| 6131 typedef compiler::Node Node; |
| 6132 |
| 6133 Label if_equal(this), if_notequal(this), |
| 6134 do_rhsstringtonumber(this, Label::kDeferred), end(this); |
| 6135 Variable result(this, MachineRepresentation::kTagged); |
| 6136 |
| 6137 // Shared entry for floating point comparison. |
| 6138 Label do_fcmp(this); |
| 6139 Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64), |
| 6140 var_fcmp_rhs(this, MachineRepresentation::kFloat64); |
| 6141 |
| 6142 // We might need to loop several times due to ToPrimitive and/or ToNumber |
| 6143 // conversions. |
| 6144 Variable var_lhs(this, MachineRepresentation::kTagged), |
| 6145 var_rhs(this, MachineRepresentation::kTagged); |
| 6146 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
| 6147 Label loop(this, 2, loop_vars); |
| 6148 var_lhs.Bind(lhs); |
| 6149 var_rhs.Bind(rhs); |
| 6150 Goto(&loop); |
| 6151 Bind(&loop); |
| 6152 { |
| 6153 // Load the current {lhs} and {rhs} values. |
| 6154 lhs = var_lhs.value(); |
| 6155 rhs = var_rhs.value(); |
| 6156 |
| 6157 // Check if {lhs} and {rhs} refer to the same object. |
| 6158 Label if_same(this), if_notsame(this); |
| 6159 Branch(WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 6160 |
| 6161 Bind(&if_same); |
| 6162 { |
| 6163 // The {lhs} and {rhs} reference the exact same value, yet we need special |
| 6164 // treatment for HeapNumber, as NaN is not equal to NaN. |
| 6165 GenerateEqual_Same(this, lhs, &if_equal, &if_notequal); |
| 6166 } |
| 6167 |
| 6168 Bind(&if_notsame); |
| 6169 { |
| 6170 // Check if {lhs} is a Smi or a HeapObject. |
| 6171 Label if_lhsissmi(this), if_lhsisnotsmi(this); |
| 6172 Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
| 6173 |
| 6174 Bind(&if_lhsissmi); |
| 6175 { |
| 6176 // Check if {rhs} is a Smi or a HeapObject. |
| 6177 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 6178 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 6179 |
| 6180 Bind(&if_rhsissmi); |
| 6181 // We have already checked for {lhs} and {rhs} being the same value, so |
| 6182 // if both are Smis when we get here they must not be equal. |
| 6183 Goto(&if_notequal); |
| 6184 |
| 6185 Bind(&if_rhsisnotsmi); |
| 6186 { |
| 6187 // Load the map of {rhs}. |
| 6188 Node* rhs_map = LoadMap(rhs); |
| 6189 |
| 6190 // Check if {rhs} is a HeapNumber. |
| 6191 Node* number_map = HeapNumberMapConstant(); |
| 6192 Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
| 6193 Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
| 6194 &if_rhsisnotnumber); |
| 6195 |
| 6196 Bind(&if_rhsisnumber); |
| 6197 { |
| 6198 // Convert {lhs} and {rhs} to floating point values, and |
| 6199 // perform a floating point comparison. |
| 6200 var_fcmp_lhs.Bind(SmiToFloat64(lhs)); |
| 6201 var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
| 6202 Goto(&do_fcmp); |
| 6203 } |
| 6204 |
| 6205 Bind(&if_rhsisnotnumber); |
| 6206 { |
| 6207 // Load the instance type of the {rhs}. |
| 6208 Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
| 6209 |
| 6210 // Check if the {rhs} is a String. |
| 6211 Label if_rhsisstring(this, Label::kDeferred), |
| 6212 if_rhsisnotstring(this); |
| 6213 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
| 6214 &if_rhsisnotstring); |
| 6215 |
| 6216 Bind(&if_rhsisstring); |
| 6217 { |
| 6218 // The {rhs} is a String and the {lhs} is a Smi; we need |
| 6219 // to convert the {rhs} to a Number and compare the output to |
| 6220 // the Number on the {lhs}. |
| 6221 Goto(&do_rhsstringtonumber); |
| 6222 } |
| 6223 |
| 6224 Bind(&if_rhsisnotstring); |
| 6225 { |
| 6226 // Check if the {rhs} is a Boolean. |
| 6227 Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
| 6228 Branch(IsBooleanMap(rhs_map), &if_rhsisboolean, |
| 6229 &if_rhsisnotboolean); |
| 6230 |
| 6231 Bind(&if_rhsisboolean); |
| 6232 { |
| 6233 // The {rhs} is a Boolean, load its number value. |
| 6234 var_rhs.Bind(LoadObjectField(rhs, Oddball::kToNumberOffset)); |
| 6235 Goto(&loop); |
| 6236 } |
| 6237 |
| 6238 Bind(&if_rhsisnotboolean); |
| 6239 { |
| 6240 // Check if the {rhs} is a Receiver. |
| 6241 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 6242 Label if_rhsisreceiver(this, Label::kDeferred), |
| 6243 if_rhsisnotreceiver(this); |
| 6244 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 6245 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 6246 |
| 6247 Bind(&if_rhsisreceiver); |
| 6248 { |
| 6249 // Convert {rhs} to a primitive first (passing no hint). |
| 6250 Callable callable = |
| 6251 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
| 6252 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 6253 Goto(&loop); |
| 6254 } |
| 6255 |
| 6256 Bind(&if_rhsisnotreceiver); |
| 6257 Goto(&if_notequal); |
| 6258 } |
| 6259 } |
| 6260 } |
| 6261 } |
| 6262 } |
| 6263 |
| 6264 Bind(&if_lhsisnotsmi); |
| 6265 { |
| 6266 // Check if {rhs} is a Smi or a HeapObject. |
| 6267 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 6268 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 6269 |
| 6270 Bind(&if_rhsissmi); |
| 6271 { |
| 6272 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} |
| 6273 // and {rhs} is not observable and doesn't matter for the result, so |
| 6274 // we can just swap them and use the Smi handling above (for {lhs} |
| 6275 // being a Smi). |
| 6276 var_lhs.Bind(rhs); |
| 6277 var_rhs.Bind(lhs); |
| 6278 Goto(&loop); |
| 6279 } |
| 6280 |
| 6281 Bind(&if_rhsisnotsmi); |
| 6282 { |
| 6283 Label if_lhsisstring(this), if_lhsisnumber(this), |
| 6284 if_lhsissymbol(this), if_lhsissimd128value(this), |
| 6285 if_lhsisoddball(this), if_lhsisreceiver(this); |
| 6286 |
| 6287 // Both {lhs} and {rhs} are HeapObjects, load their maps |
| 6288 // and their instance types. |
| 6289 Node* lhs_map = LoadMap(lhs); |
| 6290 Node* rhs_map = LoadMap(rhs); |
| 6291 |
| 6292 // Load the instance types of {lhs} and {rhs}. |
| 6293 Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
| 6294 Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
| 6295 |
| 6296 // Dispatch based on the instance type of {lhs}. |
| 6297 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; |
| 6298 Label* case_labels[kNumCases]; |
| 6299 int32_t case_values[kNumCases]; |
| 6300 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
| 6301 case_labels[i] = new Label(this); |
| 6302 case_values[i] = i; |
| 6303 } |
| 6304 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; |
| 6305 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; |
| 6306 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; |
| 6307 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; |
| 6308 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; |
| 6309 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; |
| 6310 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; |
| 6311 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; |
| 6312 Switch(lhs_instance_type, &if_lhsisreceiver, case_values, case_labels, |
| 6313 arraysize(case_values)); |
| 6314 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
| 6315 Bind(case_labels[i]); |
| 6316 Goto(&if_lhsisstring); |
| 6317 delete case_labels[i]; |
| 6318 } |
| 6319 |
| 6320 Bind(&if_lhsisstring); |
| 6321 { |
| 6322 // Check if {rhs} is also a String. |
| 6323 Label if_rhsisstring(this, Label::kDeferred), |
| 6324 if_rhsisnotstring(this); |
| 6325 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
| 6326 &if_rhsisnotstring); |
| 6327 |
| 6328 Bind(&if_rhsisstring); |
| 6329 { |
| 6330 // Both {lhs} and {rhs} are of type String, just do the |
| 6331 // string comparison then. |
| 6332 Callable callable = (mode == kDontNegateResult) |
| 6333 ? CodeFactory::StringEqual(isolate()) |
| 6334 : CodeFactory::StringNotEqual(isolate()); |
| 6335 result.Bind(CallStub(callable, context, lhs, rhs)); |
| 6336 Goto(&end); |
| 6337 } |
| 6338 |
| 6339 Bind(&if_rhsisnotstring); |
| 6340 { |
| 6341 // The {lhs} is a String and the {rhs} is some other HeapObject. |
| 6342 // Swapping {lhs} and {rhs} is not observable and doesn't matter |
| 6343 // for the result, so we can just swap them and use the String |
| 6344 // handling below (for {rhs} being a String). |
| 6345 var_lhs.Bind(rhs); |
| 6346 var_rhs.Bind(lhs); |
| 6347 Goto(&loop); |
| 6348 } |
| 6349 } |
| 6350 |
| 6351 Bind(&if_lhsisnumber); |
| 6352 { |
| 6353 // Check if {rhs} is also a HeapNumber. |
| 6354 Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
| 6355 Branch(Word32Equal(lhs_instance_type, rhs_instance_type), |
| 6356 &if_rhsisnumber, &if_rhsisnotnumber); |
| 6357 |
| 6358 Bind(&if_rhsisnumber); |
| 6359 { |
| 6360 // Convert {lhs} and {rhs} to floating point values, and |
| 6361 // perform a floating point comparison. |
| 6362 var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs)); |
| 6363 var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs)); |
| 6364 Goto(&do_fcmp); |
| 6365 } |
| 6366 |
| 6367 Bind(&if_rhsisnotnumber); |
| 6368 { |
| 6369 // The {lhs} is a Number, the {rhs} is some other HeapObject. |
| 6370 Label if_rhsisstring(this, Label::kDeferred), |
| 6371 if_rhsisnotstring(this); |
| 6372 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
| 6373 &if_rhsisnotstring); |
| 6374 |
| 6375 Bind(&if_rhsisstring); |
| 6376 { |
| 6377 // The {rhs} is a String and the {lhs} is a HeapNumber; we need |
| 6378 // to convert the {rhs} to a Number and compare the output to |
| 6379 // the Number on the {lhs}. |
| 6380 Goto(&do_rhsstringtonumber); |
| 6381 } |
| 6382 |
| 6383 Bind(&if_rhsisnotstring); |
| 6384 { |
| 6385 // Check if the {rhs} is a JSReceiver. |
| 6386 Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
| 6387 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 6388 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 6389 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 6390 |
| 6391 Bind(&if_rhsisreceiver); |
| 6392 { |
| 6393 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
| 6394 // Swapping {lhs} and {rhs} is not observable and doesn't |
| 6395 // matter for the result, so we can just swap them and use |
| 6396 // the JSReceiver handling below (for {lhs} being a |
| 6397 // JSReceiver). |
| 6398 var_lhs.Bind(rhs); |
| 6399 var_rhs.Bind(lhs); |
| 6400 Goto(&loop); |
| 6401 } |
| 6402 |
| 6403 Bind(&if_rhsisnotreceiver); |
| 6404 { |
| 6405 // Check if {rhs} is a Boolean. |
| 6406 Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
| 6407 Branch(IsBooleanMap(rhs_map), &if_rhsisboolean, |
| 6408 &if_rhsisnotboolean); |
| 6409 |
| 6410 Bind(&if_rhsisboolean); |
| 6411 { |
| 6412 // The {rhs} is a Boolean, convert it to a Smi first. |
| 6413 var_rhs.Bind( |
| 6414 LoadObjectField(rhs, Oddball::kToNumberOffset)); |
| 6415 Goto(&loop); |
| 6416 } |
| 6417 |
| 6418 Bind(&if_rhsisnotboolean); |
| 6419 Goto(&if_notequal); |
| 6420 } |
| 6421 } |
| 6422 } |
| 6423 } |
| 6424 |
| 6425 Bind(&if_lhsisoddball); |
| 6426 { |
| 6427 // The {lhs} is an Oddball and {rhs} is some other HeapObject. |
| 6428 Label if_lhsisboolean(this), if_lhsisnotboolean(this); |
| 6429 Node* boolean_map = BooleanMapConstant(); |
| 6430 Branch(WordEqual(lhs_map, boolean_map), &if_lhsisboolean, |
| 6431 &if_lhsisnotboolean); |
| 6432 |
| 6433 Bind(&if_lhsisboolean); |
| 6434 { |
| 6435 // The {lhs} is a Boolean, check if {rhs} is also a Boolean. |
| 6436 Label if_rhsisboolean(this), if_rhsisnotboolean(this); |
| 6437 Branch(WordEqual(rhs_map, boolean_map), &if_rhsisboolean, |
| 6438 &if_rhsisnotboolean); |
| 6439 |
| 6440 Bind(&if_rhsisboolean); |
| 6441 { |
| 6442 // Both {lhs} and {rhs} are distinct Boolean values. |
| 6443 Goto(&if_notequal); |
| 6444 } |
| 6445 |
| 6446 Bind(&if_rhsisnotboolean); |
| 6447 { |
| 6448 // Convert the {lhs} to a Number first. |
| 6449 var_lhs.Bind(LoadObjectField(lhs, Oddball::kToNumberOffset)); |
| 6450 Goto(&loop); |
| 6451 } |
| 6452 } |
| 6453 |
| 6454 Bind(&if_lhsisnotboolean); |
| 6455 { |
| 6456 // The {lhs} is either Null or Undefined; check if the {rhs} is |
| 6457 // undetectable (i.e. either also Null or Undefined or some |
| 6458 // undetectable JSReceiver). |
| 6459 Node* rhs_bitfield = LoadMapBitField(rhs_map); |
| 6460 BranchIfWord32Equal( |
| 6461 Word32And(rhs_bitfield, |
| 6462 Int32Constant(1 << Map::kIsUndetectable)), |
| 6463 Int32Constant(0), &if_notequal, &if_equal); |
| 6464 } |
| 6465 } |
| 6466 |
| 6467 Bind(&if_lhsissymbol); |
| 6468 { |
| 6469 // Check if the {rhs} is a JSReceiver. |
| 6470 Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
| 6471 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 6472 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 6473 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 6474 |
| 6475 Bind(&if_rhsisreceiver); |
| 6476 { |
| 6477 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
| 6478 // Swapping {lhs} and {rhs} is not observable and doesn't |
| 6479 // matter for the result, so we can just swap them and use |
| 6480 // the JSReceiver handling below (for {lhs} being a JSReceiver). |
| 6481 var_lhs.Bind(rhs); |
| 6482 var_rhs.Bind(lhs); |
| 6483 Goto(&loop); |
| 6484 } |
| 6485 |
| 6486 Bind(&if_rhsisnotreceiver); |
| 6487 { |
| 6488 // The {rhs} is not a JSReceiver and also not the same Symbol |
| 6489 // as the {lhs}, so this is equality check is considered false. |
| 6490 Goto(&if_notequal); |
| 6491 } |
| 6492 } |
| 6493 |
| 6494 Bind(&if_lhsissimd128value); |
| 6495 { |
| 6496 // Check if the {rhs} is also a Simd128Value. |
| 6497 Label if_rhsissimd128value(this), if_rhsisnotsimd128value(this); |
| 6498 Branch(Word32Equal(lhs_instance_type, rhs_instance_type), |
| 6499 &if_rhsissimd128value, &if_rhsisnotsimd128value); |
| 6500 |
| 6501 Bind(&if_rhsissimd128value); |
| 6502 { |
| 6503 // Both {lhs} and {rhs} is a Simd128Value. |
| 6504 GenerateEqual_Simd128Value_HeapObject( |
| 6505 this, lhs, lhs_map, rhs, rhs_map, &if_equal, &if_notequal); |
| 6506 } |
| 6507 |
| 6508 Bind(&if_rhsisnotsimd128value); |
| 6509 { |
| 6510 // Check if the {rhs} is a JSReceiver. |
| 6511 Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
| 6512 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 6513 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 6514 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 6515 |
| 6516 Bind(&if_rhsisreceiver); |
| 6517 { |
| 6518 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. |
| 6519 // Swapping {lhs} and {rhs} is not observable and doesn't |
| 6520 // matter for the result, so we can just swap them and use |
| 6521 // the JSReceiver handling below (for {lhs} being a JSReceiver). |
| 6522 var_lhs.Bind(rhs); |
| 6523 var_rhs.Bind(lhs); |
| 6524 Goto(&loop); |
| 6525 } |
| 6526 |
| 6527 Bind(&if_rhsisnotreceiver); |
| 6528 { |
| 6529 // The {rhs} is some other Primitive. |
| 6530 Goto(&if_notequal); |
| 6531 } |
| 6532 } |
| 6533 } |
| 6534 |
| 6535 Bind(&if_lhsisreceiver); |
| 6536 { |
| 6537 // Check if the {rhs} is also a JSReceiver. |
| 6538 Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); |
| 6539 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 6540 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
| 6541 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 6542 |
| 6543 Bind(&if_rhsisreceiver); |
| 6544 { |
| 6545 // Both {lhs} and {rhs} are different JSReceiver references, so |
| 6546 // this cannot be considered equal. |
| 6547 Goto(&if_notequal); |
| 6548 } |
| 6549 |
| 6550 Bind(&if_rhsisnotreceiver); |
| 6551 { |
| 6552 // Check if {rhs} is Null or Undefined (an undetectable check |
| 6553 // is sufficient here, since we already know that {rhs} is not |
| 6554 // a JSReceiver). |
| 6555 Label if_rhsisundetectable(this), |
| 6556 if_rhsisnotundetectable(this, Label::kDeferred); |
| 6557 Node* rhs_bitfield = LoadMapBitField(rhs_map); |
| 6558 BranchIfWord32Equal( |
| 6559 Word32And(rhs_bitfield, |
| 6560 Int32Constant(1 << Map::kIsUndetectable)), |
| 6561 Int32Constant(0), &if_rhsisnotundetectable, |
| 6562 &if_rhsisundetectable); |
| 6563 |
| 6564 Bind(&if_rhsisundetectable); |
| 6565 { |
| 6566 // Check if {lhs} is an undetectable JSReceiver. |
| 6567 Node* lhs_bitfield = LoadMapBitField(lhs_map); |
| 6568 BranchIfWord32Equal( |
| 6569 Word32And(lhs_bitfield, |
| 6570 Int32Constant(1 << Map::kIsUndetectable)), |
| 6571 Int32Constant(0), &if_notequal, &if_equal); |
| 6572 } |
| 6573 |
| 6574 Bind(&if_rhsisnotundetectable); |
| 6575 { |
| 6576 // The {rhs} is some Primitive different from Null and |
| 6577 // Undefined, need to convert {lhs} to Primitive first. |
| 6578 Callable callable = |
| 6579 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
| 6580 var_lhs.Bind(CallStub(callable, context, lhs)); |
| 6581 Goto(&loop); |
| 6582 } |
| 6583 } |
| 6584 } |
| 6585 } |
| 6586 } |
| 6587 } |
| 6588 |
| 6589 Bind(&do_rhsstringtonumber); |
| 6590 { |
| 6591 Callable callable = CodeFactory::StringToNumber(isolate()); |
| 6592 var_rhs.Bind(CallStub(callable, context, rhs)); |
| 6593 Goto(&loop); |
| 6594 } |
| 6595 } |
| 6596 |
| 6597 Bind(&do_fcmp); |
| 6598 { |
| 6599 // Load the {lhs} and {rhs} floating point values. |
| 6600 Node* lhs = var_fcmp_lhs.value(); |
| 6601 Node* rhs = var_fcmp_rhs.value(); |
| 6602 |
| 6603 // Perform a fast floating point comparison. |
| 6604 BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); |
| 6605 } |
| 6606 |
| 6607 Bind(&if_equal); |
| 6608 { |
| 6609 result.Bind(BooleanConstant(mode == kDontNegateResult)); |
| 6610 Goto(&end); |
| 6611 } |
| 6612 |
| 6613 Bind(&if_notequal); |
| 6614 { |
| 6615 result.Bind(BooleanConstant(mode == kNegateResult)); |
| 6616 Goto(&end); |
| 6617 } |
| 6618 |
| 6619 Bind(&end); |
| 6620 return result.value(); |
| 6621 } |
| 6622 |
| 6623 compiler::Node* CodeStubAssembler::StrictEqual(ResultMode mode, |
| 6624 compiler::Node* lhs, |
| 6625 compiler::Node* rhs, |
| 6626 compiler::Node* context) { |
| 6627 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
| 6628 // mode; for kNegateResult mode we properly negate the result. |
| 6629 // |
| 6630 // if (lhs == rhs) { |
| 6631 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
| 6632 // return true; |
| 6633 // } |
| 6634 // if (!lhs->IsSmi()) { |
| 6635 // if (lhs->IsHeapNumber()) { |
| 6636 // if (rhs->IsSmi()) { |
| 6637 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); |
| 6638 // } else if (rhs->IsHeapNumber()) { |
| 6639 // return HeapNumber::cast(rhs)->value() == |
| 6640 // HeapNumber::cast(lhs)->value(); |
| 6641 // } else { |
| 6642 // return false; |
| 6643 // } |
| 6644 // } else { |
| 6645 // if (rhs->IsSmi()) { |
| 6646 // return false; |
| 6647 // } else { |
| 6648 // if (lhs->IsString()) { |
| 6649 // if (rhs->IsString()) { |
| 6650 // return %StringEqual(lhs, rhs); |
| 6651 // } else { |
| 6652 // return false; |
| 6653 // } |
| 6654 // } else if (lhs->IsSimd128()) { |
| 6655 // if (rhs->IsSimd128()) { |
| 6656 // return %StrictEqual(lhs, rhs); |
| 6657 // } |
| 6658 // } else { |
| 6659 // return false; |
| 6660 // } |
| 6661 // } |
| 6662 // } |
| 6663 // } else { |
| 6664 // if (rhs->IsSmi()) { |
| 6665 // return false; |
| 6666 // } else { |
| 6667 // if (rhs->IsHeapNumber()) { |
| 6668 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); |
| 6669 // } else { |
| 6670 // return false; |
| 6671 // } |
| 6672 // } |
| 6673 // } |
| 6674 |
| 6675 typedef compiler::Node Node; |
| 6676 |
| 6677 Label if_equal(this), if_notequal(this), end(this); |
| 6678 Variable result(this, MachineRepresentation::kTagged); |
| 6679 |
| 6680 // Check if {lhs} and {rhs} refer to the same object. |
| 6681 Label if_same(this), if_notsame(this); |
| 6682 Branch(WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 6683 |
| 6684 Bind(&if_same); |
| 6685 { |
| 6686 // The {lhs} and {rhs} reference the exact same value, yet we need special |
| 6687 // treatment for HeapNumber, as NaN is not equal to NaN. |
| 6688 GenerateEqual_Same(this, lhs, &if_equal, &if_notequal); |
| 6689 } |
| 6690 |
| 6691 Bind(&if_notsame); |
| 6692 { |
| 6693 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, |
| 6694 // String and Simd128Value they can still be considered equal. |
| 6695 Node* number_map = HeapNumberMapConstant(); |
| 6696 |
| 6697 // Check if {lhs} is a Smi or a HeapObject. |
| 6698 Label if_lhsissmi(this), if_lhsisnotsmi(this); |
| 6699 Branch(WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
| 6700 |
| 6701 Bind(&if_lhsisnotsmi); |
| 6702 { |
| 6703 // Load the map of {lhs}. |
| 6704 Node* lhs_map = LoadMap(lhs); |
| 6705 |
| 6706 // Check if {lhs} is a HeapNumber. |
| 6707 Label if_lhsisnumber(this), if_lhsisnotnumber(this); |
| 6708 Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
| 6709 &if_lhsisnotnumber); |
| 6710 |
| 6711 Bind(&if_lhsisnumber); |
| 6712 { |
| 6713 // Check if {rhs} is a Smi or a HeapObject. |
| 6714 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 6715 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 6716 |
| 6717 Bind(&if_rhsissmi); |
| 6718 { |
| 6719 // Convert {lhs} and {rhs} to floating point values. |
| 6720 Node* lhs_value = LoadHeapNumberValue(lhs); |
| 6721 Node* rhs_value = SmiToFloat64(rhs); |
| 6722 |
| 6723 // Perform a floating point comparison of {lhs} and {rhs}. |
| 6724 BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
| 6725 } |
| 6726 |
| 6727 Bind(&if_rhsisnotsmi); |
| 6728 { |
| 6729 // Load the map of {rhs}. |
| 6730 Node* rhs_map = LoadMap(rhs); |
| 6731 |
| 6732 // Check if {rhs} is also a HeapNumber. |
| 6733 Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
| 6734 Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
| 6735 &if_rhsisnotnumber); |
| 6736 |
| 6737 Bind(&if_rhsisnumber); |
| 6738 { |
| 6739 // Convert {lhs} and {rhs} to floating point values. |
| 6740 Node* lhs_value = LoadHeapNumberValue(lhs); |
| 6741 Node* rhs_value = LoadHeapNumberValue(rhs); |
| 6742 |
| 6743 // Perform a floating point comparison of {lhs} and {rhs}. |
| 6744 BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
| 6745 } |
| 6746 |
| 6747 Bind(&if_rhsisnotnumber); |
| 6748 Goto(&if_notequal); |
| 6749 } |
| 6750 } |
| 6751 |
| 6752 Bind(&if_lhsisnotnumber); |
| 6753 { |
| 6754 // Check if {rhs} is a Smi or a HeapObject. |
| 6755 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 6756 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 6757 |
| 6758 Bind(&if_rhsissmi); |
| 6759 Goto(&if_notequal); |
| 6760 |
| 6761 Bind(&if_rhsisnotsmi); |
| 6762 { |
| 6763 // Load the instance type of {lhs}. |
| 6764 Node* lhs_instance_type = LoadMapInstanceType(lhs_map); |
| 6765 |
| 6766 // Check if {lhs} is a String. |
| 6767 Label if_lhsisstring(this), if_lhsisnotstring(this); |
| 6768 Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring, |
| 6769 &if_lhsisnotstring); |
| 6770 |
| 6771 Bind(&if_lhsisstring); |
| 6772 { |
| 6773 // Load the instance type of {rhs}. |
| 6774 Node* rhs_instance_type = LoadInstanceType(rhs); |
| 6775 |
| 6776 // Check if {rhs} is also a String. |
| 6777 Label if_rhsisstring(this, Label::kDeferred), |
| 6778 if_rhsisnotstring(this); |
| 6779 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
| 6780 &if_rhsisnotstring); |
| 6781 |
| 6782 Bind(&if_rhsisstring); |
| 6783 { |
| 6784 Callable callable = (mode == kDontNegateResult) |
| 6785 ? CodeFactory::StringEqual(isolate()) |
| 6786 : CodeFactory::StringNotEqual(isolate()); |
| 6787 result.Bind(CallStub(callable, context, lhs, rhs)); |
| 6788 Goto(&end); |
| 6789 } |
| 6790 |
| 6791 Bind(&if_rhsisnotstring); |
| 6792 Goto(&if_notequal); |
| 6793 } |
| 6794 |
| 6795 Bind(&if_lhsisnotstring); |
| 6796 { |
| 6797 // Check if {lhs} is a Simd128Value. |
| 6798 Label if_lhsissimd128value(this), if_lhsisnotsimd128value(this); |
| 6799 Branch(Word32Equal(lhs_instance_type, |
| 6800 Int32Constant(SIMD128_VALUE_TYPE)), |
| 6801 &if_lhsissimd128value, &if_lhsisnotsimd128value); |
| 6802 |
| 6803 Bind(&if_lhsissimd128value); |
| 6804 { |
| 6805 // Load the map of {rhs}. |
| 6806 Node* rhs_map = LoadMap(rhs); |
| 6807 |
| 6808 // Check if {rhs} is also a Simd128Value that is equal to {lhs}. |
| 6809 GenerateEqual_Simd128Value_HeapObject( |
| 6810 this, lhs, lhs_map, rhs, rhs_map, &if_equal, &if_notequal); |
| 6811 } |
| 6812 |
| 6813 Bind(&if_lhsisnotsimd128value); |
| 6814 Goto(&if_notequal); |
| 6815 } |
| 6816 } |
| 6817 } |
| 6818 } |
| 6819 |
| 6820 Bind(&if_lhsissmi); |
| 6821 { |
| 6822 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} |
| 6823 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a |
| 6824 // HeapNumber with an equal floating point value. |
| 6825 |
| 6826 // Check if {rhs} is a Smi or a HeapObject. |
| 6827 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
| 6828 Branch(WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
| 6829 |
| 6830 Bind(&if_rhsissmi); |
| 6831 Goto(&if_notequal); |
| 6832 |
| 6833 Bind(&if_rhsisnotsmi); |
| 6834 { |
| 6835 // Load the map of the {rhs}. |
| 6836 Node* rhs_map = LoadMap(rhs); |
| 6837 |
| 6838 // The {rhs} could be a HeapNumber with the same value as {lhs}. |
| 6839 Label if_rhsisnumber(this), if_rhsisnotnumber(this); |
| 6840 Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
| 6841 &if_rhsisnotnumber); |
| 6842 |
| 6843 Bind(&if_rhsisnumber); |
| 6844 { |
| 6845 // Convert {lhs} and {rhs} to floating point values. |
| 6846 Node* lhs_value = SmiToFloat64(lhs); |
| 6847 Node* rhs_value = LoadHeapNumberValue(rhs); |
| 6848 |
| 6849 // Perform a floating point comparison of {lhs} and {rhs}. |
| 6850 BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, &if_notequal); |
| 6851 } |
| 6852 |
| 6853 Bind(&if_rhsisnotnumber); |
| 6854 Goto(&if_notequal); |
| 6855 } |
| 6856 } |
| 6857 } |
| 6858 |
| 6859 Bind(&if_equal); |
| 6860 { |
| 6861 result.Bind(BooleanConstant(mode == kDontNegateResult)); |
| 6862 Goto(&end); |
| 6863 } |
| 6864 |
| 6865 Bind(&if_notequal); |
| 6866 { |
| 6867 result.Bind(BooleanConstant(mode == kNegateResult)); |
| 6868 Goto(&end); |
| 6869 } |
| 6870 |
| 6871 Bind(&end); |
| 6872 return result.value(); |
| 6873 } |
| 6874 |
| 6875 compiler::Node* CodeStubAssembler::ForInFilter(compiler::Node* key, |
| 6876 compiler::Node* object, |
| 6877 compiler::Node* context) { |
| 6878 Label return_undefined(this, Label::kDeferred), return_to_name(this), |
| 6879 end(this); |
| 6880 |
| 6881 Variable var_result(this, MachineRepresentation::kTagged); |
| 6882 |
| 6883 Node* has_property = |
| 6884 HasProperty(object, key, context, Runtime::kForInHasProperty); |
| 6885 |
| 6886 Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name, |
| 6887 &return_undefined); |
| 6888 |
| 6889 Bind(&return_to_name); |
| 6890 { |
| 6891 var_result.Bind(ToName(context, key)); |
| 6892 Goto(&end); |
| 6893 } |
| 6894 |
| 6895 Bind(&return_undefined); |
| 6896 { |
| 6897 var_result.Bind(UndefinedConstant()); |
| 6898 Goto(&end); |
| 6899 } |
| 6900 |
| 6901 Bind(&end); |
| 6902 return var_result.value(); |
| 6903 } |
| 6904 |
| 6905 compiler::Node* CodeStubAssembler::HasProperty( |
| 6906 compiler::Node* object, compiler::Node* key, compiler::Node* context, |
| 6907 Runtime::FunctionId fallback_runtime_function_id) { |
| 6908 typedef compiler::Node Node; |
| 6909 typedef CodeStubAssembler::Label Label; |
| 6910 typedef CodeStubAssembler::Variable Variable; |
| 6911 |
| 6912 Label call_runtime(this, Label::kDeferred), return_true(this), |
| 6913 return_false(this), end(this); |
| 6914 |
| 6915 CodeStubAssembler::LookupInHolder lookup_property_in_holder = |
| 6916 [this, &return_true](Node* receiver, Node* holder, Node* holder_map, |
| 6917 Node* holder_instance_type, Node* unique_name, |
| 6918 Label* next_holder, Label* if_bailout) { |
| 6919 TryHasOwnProperty(holder, holder_map, holder_instance_type, unique_name, |
| 6920 &return_true, next_holder, if_bailout); |
| 6921 }; |
| 6922 |
| 6923 CodeStubAssembler::LookupInHolder lookup_element_in_holder = |
| 6924 [this, &return_true](Node* receiver, Node* holder, Node* holder_map, |
| 6925 Node* holder_instance_type, Node* index, |
| 6926 Label* next_holder, Label* if_bailout) { |
| 6927 TryLookupElement(holder, holder_map, holder_instance_type, index, |
| 6928 &return_true, next_holder, if_bailout); |
| 6929 }; |
| 6930 |
| 6931 TryPrototypeChainLookup(object, key, lookup_property_in_holder, |
| 6932 lookup_element_in_holder, &return_false, |
| 6933 &call_runtime); |
| 6934 |
| 6935 Variable result(this, MachineRepresentation::kTagged); |
| 6936 Bind(&return_true); |
| 6937 { |
| 6938 result.Bind(BooleanConstant(true)); |
| 6939 Goto(&end); |
| 6940 } |
| 6941 |
| 6942 Bind(&return_false); |
| 6943 { |
| 6944 result.Bind(BooleanConstant(false)); |
| 6945 Goto(&end); |
| 6946 } |
| 6947 |
| 6948 Bind(&call_runtime); |
| 6949 { |
| 6950 result.Bind( |
| 6951 CallRuntime(fallback_runtime_function_id, context, object, key)); |
| 6952 Goto(&end); |
| 6953 } |
| 6954 |
| 6955 Bind(&end); |
| 6956 return result.value(); |
| 6957 } |
| 6958 |
| 6959 compiler::Node* CodeStubAssembler::Typeof(compiler::Node* value, |
| 6960 compiler::Node* context) { |
| 6961 Variable result_var(this, MachineRepresentation::kTagged); |
| 6962 |
| 6963 Label return_number(this, Label::kDeferred), if_oddball(this), |
| 6964 return_function(this), return_undefined(this), return_object(this), |
| 6965 return_string(this), return_result(this); |
| 6966 |
| 6967 GotoIf(WordIsSmi(value), &return_number); |
| 6968 |
| 6969 Node* map = LoadMap(value); |
| 6970 |
| 6971 GotoIf(IsHeapNumberMap(map), &return_number); |
| 6972 |
| 6973 Node* instance_type = LoadMapInstanceType(map); |
| 6974 |
| 6975 GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), &if_oddball); |
| 6976 |
| 6977 Node* callable_or_undetectable_mask = Word32And( |
| 6978 LoadMapBitField(map), |
| 6979 Int32Constant(1 << Map::kIsCallable | 1 << Map::kIsUndetectable)); |
| 6980 |
| 6981 GotoIf(Word32Equal(callable_or_undetectable_mask, |
| 6982 Int32Constant(1 << Map::kIsCallable)), |
| 6983 &return_function); |
| 6984 |
| 6985 GotoUnless(Word32Equal(callable_or_undetectable_mask, Int32Constant(0)), |
| 6986 &return_undefined); |
| 6987 |
| 6988 GotoIf(IsJSReceiverInstanceType(instance_type), &return_object); |
| 6989 |
| 6990 GotoIf(IsStringInstanceType(instance_type), &return_string); |
| 6991 |
| 6992 #define SIMD128_BRANCH(TYPE, Type, type, lane_count, lane_type) \ |
| 6993 Label return_##type(this); \ |
| 6994 Node* type##_map = HeapConstant(factory()->type##_map()); \ |
| 6995 GotoIf(WordEqual(map, type##_map), &return_##type); |
| 6996 SIMD128_TYPES(SIMD128_BRANCH) |
| 6997 #undef SIMD128_BRANCH |
| 6998 |
| 6999 Assert(Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE))); |
| 7000 result_var.Bind(HeapConstant(isolate()->factory()->symbol_string())); |
| 7001 Goto(&return_result); |
| 7002 |
| 7003 Bind(&return_number); |
| 7004 { |
| 7005 result_var.Bind(HeapConstant(isolate()->factory()->number_string())); |
| 7006 Goto(&return_result); |
| 7007 } |
| 7008 |
| 7009 Bind(&if_oddball); |
| 7010 { |
| 7011 Node* type = LoadObjectField(value, Oddball::kTypeOfOffset); |
| 7012 result_var.Bind(type); |
| 7013 Goto(&return_result); |
| 7014 } |
| 7015 |
| 7016 Bind(&return_function); |
| 7017 { |
| 7018 result_var.Bind(HeapConstant(isolate()->factory()->function_string())); |
| 7019 Goto(&return_result); |
| 7020 } |
| 7021 |
| 7022 Bind(&return_undefined); |
| 7023 { |
| 7024 result_var.Bind(HeapConstant(isolate()->factory()->undefined_string())); |
| 7025 Goto(&return_result); |
| 7026 } |
| 7027 |
| 7028 Bind(&return_object); |
| 7029 { |
| 7030 result_var.Bind(HeapConstant(isolate()->factory()->object_string())); |
| 7031 Goto(&return_result); |
| 7032 } |
| 7033 |
| 7034 Bind(&return_string); |
| 7035 { |
| 7036 result_var.Bind(HeapConstant(isolate()->factory()->string_string())); |
| 7037 Goto(&return_result); |
| 7038 } |
| 7039 |
| 7040 #define SIMD128_BIND_RETURN(TYPE, Type, type, lane_count, lane_type) \ |
| 7041 Bind(&return_##type); \ |
| 7042 { \ |
| 7043 result_var.Bind(HeapConstant(isolate()->factory()->type##_string())); \ |
| 7044 Goto(&return_result); \ |
| 7045 } |
| 7046 SIMD128_TYPES(SIMD128_BIND_RETURN) |
| 7047 #undef SIMD128_BIND_RETURN |
| 7048 |
| 7049 Bind(&return_result); |
| 7050 return result_var.value(); |
| 7051 } |
| 7052 |
| 7053 compiler::Node* CodeStubAssembler::InstanceOf(compiler::Node* object, |
| 7054 compiler::Node* callable, |
| 7055 compiler::Node* context) { |
| 7056 Label return_runtime(this, Label::kDeferred), end(this); |
| 7057 Variable result(this, MachineRepresentation::kTagged); |
| 7058 |
| 7059 // Check if no one installed @@hasInstance somewhere. |
| 7060 GotoUnless( |
| 7061 WordEqual(LoadObjectField(LoadRoot(Heap::kHasInstanceProtectorRootIndex), |
| 7062 PropertyCell::kValueOffset), |
| 7063 SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
| 7064 &return_runtime); |
| 7065 |
| 7066 // Check if {callable} is a valid receiver. |
| 7067 GotoIf(WordIsSmi(callable), &return_runtime); |
| 7068 GotoIf(Word32Equal(Word32And(LoadMapBitField(LoadMap(callable)), |
| 7069 Int32Constant(1 << Map::kIsCallable)), |
| 7070 Int32Constant(0)), |
| 7071 &return_runtime); |
| 7072 |
| 7073 // Use the inline OrdinaryHasInstance directly. |
| 7074 result.Bind(OrdinaryHasInstance(context, callable, object)); |
| 7075 Goto(&end); |
| 7076 |
| 7077 // TODO(bmeurer): Use GetPropertyStub here once available. |
| 7078 Bind(&return_runtime); |
| 7079 { |
| 7080 result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); |
| 7081 Goto(&end); |
| 7082 } |
| 7083 |
| 7084 Bind(&end); |
| 7085 return result.value(); |
| 7086 } |
| 7087 |
5744 } // namespace internal | 7088 } // namespace internal |
5745 } // namespace v8 | 7089 } // namespace v8 |
OLD | NEW |