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

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

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

Powered by Google App Engine
This is Rietveld 408576698