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

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

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