OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/frames.h" | 8 #include "src/frames.h" |
9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 5629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 |
OLD | NEW |