Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: src/code-stub-assembler.cc

Issue 2372113004: [turbofan] JSGenericLowering mostly uses builtins instead of code stubs now (Closed)
Patch Set: Ross' comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698