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