Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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-stubs.h" | 5 #include "src/code-stubs.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-factory.h" | |
| 10 #include "src/compiler/code-stub-assembler.h" | 11 #include "src/compiler/code-stub-assembler.h" |
| 11 #include "src/factory.h" | 12 #include "src/factory.h" |
| 12 #include "src/gdb-jit.h" | 13 #include "src/gdb-jit.h" |
| 13 #include "src/ic/handler-compiler.h" | 14 #include "src/ic/handler-compiler.h" |
| 14 #include "src/ic/ic.h" | 15 #include "src/ic/ic.h" |
| 15 #include "src/macro-assembler.h" | 16 #include "src/macro-assembler.h" |
| 16 #include "src/parsing/parser.h" | 17 #include "src/parsing/parser.h" |
| 17 #include "src/profiler/cpu-profiler.h" | 18 #include "src/profiler/cpu-profiler.h" |
| 18 | 19 |
| 19 namespace v8 { | 20 namespace v8 { |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 compiler::Node* value = assembler->Parameter(0); | 494 compiler::Node* value = assembler->Parameter(0); |
| 494 compiler::Node* string = | 495 compiler::Node* string = |
| 495 assembler->LoadObjectField(value, JSValue::kValueOffset); | 496 assembler->LoadObjectField(value, JSValue::kValueOffset); |
| 496 compiler::Node* result = | 497 compiler::Node* result = |
| 497 assembler->LoadObjectField(string, String::kLengthOffset); | 498 assembler->LoadObjectField(string, String::kLengthOffset); |
| 498 assembler->Return(result); | 499 assembler->Return(result); |
| 499 } | 500 } |
| 500 | 501 |
| 501 namespace { | 502 namespace { |
| 502 | 503 |
| 503 enum StrictEqualMode { kStrictEqual, kStrictNotEqual }; | 504 enum ResultMode { kDontNegateResult, kNegateResult }; |
| 504 | 505 |
| 505 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, | 506 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, |
| 506 StrictEqualMode mode) { | 507 Isolate* isolate, ResultMode mode) { |
| 507 // Here's pseudo-code for the algorithm below in case of kStrictEqual mode; | 508 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
| 508 // for kStrictNotEqual mode we properly negate the result. | 509 // mode; for kNegateResult mode we properly negate the result. |
| 509 // | 510 // |
| 510 // if (lhs == rhs) { | 511 // if (lhs == rhs) { |
| 511 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | 512 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
| 512 // return true; | 513 // return true; |
| 513 // } | 514 // } |
| 514 // if (!lhs->IsSmi()) { | 515 // if (!lhs->IsSmi()) { |
| 515 // if (lhs->IsHeapNumber()) { | 516 // if (lhs->IsHeapNumber()) { |
| 516 // if (rhs->IsSmi()) { | 517 // if (rhs->IsSmi()) { |
| 517 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); | 518 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); |
| 518 // } else if (rhs->IsHeapNumber()) { | 519 // } else if (rhs->IsHeapNumber()) { |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); | 701 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); |
| 701 assembler->Branch(assembler->Int32LessThan( | 702 assembler->Branch(assembler->Int32LessThan( |
| 702 rhs_instance_type, assembler->Int32Constant( | 703 rhs_instance_type, assembler->Int32Constant( |
| 703 FIRST_NONSTRING_TYPE)), | 704 FIRST_NONSTRING_TYPE)), |
| 704 &if_rhsisstring, &if_rhsisnotstring); | 705 &if_rhsisstring, &if_rhsisnotstring); |
| 705 | 706 |
| 706 assembler->Bind(&if_rhsisstring); | 707 assembler->Bind(&if_rhsisstring); |
| 707 { | 708 { |
| 708 // TODO(bmeurer): Optimize this further once the StringEqual | 709 // TODO(bmeurer): Optimize this further once the StringEqual |
| 709 // functionality is available in TurboFan land. | 710 // functionality is available in TurboFan land. |
| 710 Runtime::FunctionId function_id = (mode == kStrictEqual) | 711 Callable callable = (mode == kDontNegateResult) |
|
epertoso
2016/03/03 09:41:45
Does the TODO above still apply?
Benedikt Meurer
2016/03/03 09:45:07
Done.
| |
| 711 ? Runtime::kStringEqual | 712 ? CodeFactory::StringEqual(isolate) |
| 712 : Runtime::kStringNotEqual; | 713 : CodeFactory::StringNotEqual(isolate); |
| 713 assembler->TailCallRuntime(function_id, context, lhs, rhs); | 714 assembler->TailCallStub(callable, context, lhs, rhs); |
| 714 } | 715 } |
| 715 | 716 |
| 716 assembler->Bind(&if_rhsisnotstring); | 717 assembler->Bind(&if_rhsisnotstring); |
| 717 assembler->Goto(&if_notequal); | 718 assembler->Goto(&if_notequal); |
| 718 } | 719 } |
| 719 | 720 |
| 720 assembler->Bind(&if_lhsisnotstring); | 721 assembler->Bind(&if_lhsisnotstring); |
| 721 { | 722 { |
| 722 // Check if {lhs} is a Simd128Value. | 723 // Check if {lhs} is a Simd128Value. |
| 723 Label if_lhsissimd128value(assembler), | 724 Label if_lhsissimd128value(assembler), |
| 724 if_lhsisnotsimd128value(assembler); | 725 if_lhsisnotsimd128value(assembler); |
| 725 assembler->Branch(assembler->Word32Equal( | 726 assembler->Branch(assembler->Word32Equal( |
| 726 lhs_instance_type, | 727 lhs_instance_type, |
| 727 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | 728 assembler->Int32Constant(SIMD128_VALUE_TYPE)), |
| 728 &if_lhsissimd128value, &if_lhsisnotsimd128value); | 729 &if_lhsissimd128value, &if_lhsisnotsimd128value); |
| 729 | 730 |
| 730 assembler->Bind(&if_lhsissimd128value); | 731 assembler->Bind(&if_lhsissimd128value); |
| 731 { | 732 { |
| 732 // TODO(bmeurer): Inline the Simd128Value equality check. | 733 // TODO(bmeurer): Inline the Simd128Value equality check. |
| 733 Runtime::FunctionId function_id = (mode == kStrictEqual) | 734 Runtime::FunctionId function_id = (mode == kDontNegateResult) |
| 734 ? Runtime::kStrictEqual | 735 ? Runtime::kStrictEqual |
| 735 : Runtime::kStrictNotEqual; | 736 : Runtime::kStrictNotEqual; |
| 736 assembler->TailCallRuntime(function_id, context, lhs, rhs); | 737 assembler->TailCallRuntime(function_id, context, lhs, rhs); |
| 737 } | 738 } |
| 738 | 739 |
| 739 assembler->Bind(&if_lhsisnotsimd128value); | 740 assembler->Bind(&if_lhsisnotsimd128value); |
| 740 assembler->Goto(&if_notequal); | 741 assembler->Goto(&if_notequal); |
| 741 } | 742 } |
| 742 } | 743 } |
| 743 } | 744 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 778 &if_notequal); | 779 &if_notequal); |
| 779 } | 780 } |
| 780 | 781 |
| 781 assembler->Bind(&if_rhsisnotnumber); | 782 assembler->Bind(&if_rhsisnotnumber); |
| 782 assembler->Goto(&if_notequal); | 783 assembler->Goto(&if_notequal); |
| 783 } | 784 } |
| 784 } | 785 } |
| 785 } | 786 } |
| 786 | 787 |
| 787 assembler->Bind(&if_equal); | 788 assembler->Bind(&if_equal); |
| 788 assembler->Return(assembler->BooleanConstant(mode == kStrictEqual)); | 789 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
| 789 | 790 |
| 790 assembler->Bind(&if_notequal); | 791 assembler->Bind(&if_notequal); |
| 791 assembler->Return(assembler->BooleanConstant(mode == kStrictNotEqual)); | 792 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
| 793 } | |
| 794 | |
| 795 void GenerateStringEqual(compiler::CodeStubAssembler* assembler, | |
| 796 ResultMode mode) { | |
| 797 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | |
| 798 // mode; for kNegateResult mode we properly negate the result. | |
| 799 // | |
| 800 // if (lhs == rhs) return true; | |
| 801 // if (lhs->length() != rhs->length()) return false; | |
| 802 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { | |
| 803 // return false; | |
| 804 // } | |
| 805 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { | |
| 806 // for (i = 0; i != lhs->length(); ++i) { | |
| 807 // if (lhs[i] != rhs[i]) return false; | |
| 808 // } | |
| 809 // return true; | |
| 810 // } | |
| 811 // return %StringEqual(lhs, rhs); | |
| 812 | |
| 813 typedef compiler::CodeStubAssembler::Label Label; | |
| 814 typedef compiler::Node Node; | |
| 815 typedef compiler::CodeStubAssembler::Variable Variable; | |
| 816 | |
| 817 Node* lhs = assembler->Parameter(0); | |
| 818 Node* rhs = assembler->Parameter(1); | |
| 819 Node* context = assembler->Parameter(2); | |
| 820 | |
| 821 Label if_equal(assembler), if_notequal(assembler); | |
| 822 | |
| 823 // Fast check to see if {lhs} and {rhs} refer to the same String object. | |
| 824 Label if_same(assembler), if_notsame(assembler); | |
| 825 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
| 826 | |
| 827 assembler->Bind(&if_same); | |
| 828 assembler->Goto(&if_equal); | |
| 829 | |
| 830 assembler->Bind(&if_notsame); | |
| 831 { | |
| 832 // The {lhs} and {rhs} don't refer to the exact same String object. | |
| 833 | |
| 834 // Load the length of {lhs} and {rhs}. | |
| 835 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); | |
| 836 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); | |
| 837 | |
| 838 // Check if the lengths of {lhs} and {rhs} are equal. | |
| 839 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); | |
| 840 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), | |
| 841 &if_lengthisequal, &if_lengthisnotequal); | |
| 842 | |
| 843 assembler->Bind(&if_lengthisequal); | |
| 844 { | |
| 845 // Load instance types of {lhs} and {rhs}. | |
| 846 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | |
| 847 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
| 848 | |
| 849 // Combine the instance types into a single 16-bit value, so we can check | |
| 850 // both of them at once. | |
| 851 Node* both_instance_types = assembler->Word32Or( | |
| 852 lhs_instance_type, | |
| 853 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); | |
| 854 | |
| 855 // Check if both {lhs} and {rhs} are internalized. | |
| 856 int const kBothInternalizedMask = | |
| 857 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); | |
| 858 int const kBothInternalizedTag = | |
| 859 kInternalizedTag | (kInternalizedTag << 8); | |
| 860 Label if_bothinternalized(assembler), if_notbothinternalized(assembler); | |
| 861 assembler->Branch(assembler->Word32Equal( | |
| 862 assembler->Word32And(both_instance_types, | |
| 863 assembler->Int32Constant( | |
| 864 kBothInternalizedMask)), | |
| 865 assembler->Int32Constant(kBothInternalizedTag)), | |
| 866 &if_bothinternalized, &if_notbothinternalized); | |
| 867 | |
| 868 assembler->Bind(&if_bothinternalized); | |
| 869 { | |
| 870 // Fast negative check for internalized-to-internalized equality. | |
| 871 assembler->Goto(&if_notequal); | |
| 872 } | |
| 873 | |
| 874 assembler->Bind(&if_notbothinternalized); | |
| 875 { | |
| 876 // Check that both {lhs} and {rhs} are flat one-byte strings. | |
| 877 int const kBothSeqOneByteStringMask = | |
| 878 kStringEncodingMask | kStringRepresentationMask | | |
| 879 ((kStringEncodingMask | kStringRepresentationMask) << 8); | |
| 880 int const kBothSeqOneByteStringTag = | |
| 881 kOneByteStringTag | kSeqStringTag | | |
| 882 ((kOneByteStringTag | kSeqStringTag) << 8); | |
| 883 Label if_bothonebyteseqstrings(assembler), | |
| 884 if_notbothonebyteseqstrings(assembler); | |
| 885 assembler->Branch( | |
| 886 assembler->Word32Equal( | |
| 887 assembler->Word32And( | |
| 888 both_instance_types, | |
| 889 assembler->Int32Constant(kBothSeqOneByteStringMask)), | |
| 890 assembler->Int32Constant(kBothSeqOneByteStringTag)), | |
| 891 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); | |
| 892 | |
| 893 assembler->Bind(&if_bothonebyteseqstrings); | |
| 894 { | |
| 895 // Compute the effective offset of the first character. | |
| 896 Node* begin = assembler->IntPtrConstant( | |
| 897 SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
| 898 | |
| 899 // Compute the first offset after the string from the length. | |
| 900 Node* end = | |
| 901 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); | |
| 902 | |
| 903 // Loop over the {lhs} and {rhs} strings to see if they are equal. | |
| 904 Variable var_offset(assembler, kPointerSize == 8 | |
| 905 ? MachineRepresentation::kWord64 | |
|
epertoso
2016/03/03 09:41:45
nit: MachineType::PointerRepresentation() does thi
Benedikt Meurer
2016/03/03 09:45:07
Done.
| |
| 906 : MachineRepresentation::kWord32); | |
| 907 Label loop(assembler, &var_offset); | |
| 908 var_offset.Bind(begin); | |
| 909 assembler->Goto(&loop); | |
| 910 assembler->Bind(&loop); | |
| 911 { | |
| 912 // Check if {offset} equals {end}. | |
| 913 Node* offset = var_offset.value(); | |
| 914 Label if_done(assembler), if_notdone(assembler); | |
| 915 assembler->Branch(assembler->WordEqual(offset, end), &if_done, | |
| 916 &if_notdone); | |
| 917 | |
| 918 assembler->Bind(&if_notdone); | |
| 919 { | |
| 920 // Load the next characters from {lhs} and {rhs}. | |
| 921 Node* lhs_value = | |
| 922 assembler->Load(MachineType::Uint8(), lhs, offset); | |
| 923 Node* rhs_value = | |
| 924 assembler->Load(MachineType::Uint8(), rhs, offset); | |
| 925 | |
| 926 // Check if the characters match. | |
| 927 Label if_valueissame(assembler), if_valueisnotsame(assembler); | |
| 928 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), | |
| 929 &if_valueissame, &if_valueisnotsame); | |
| 930 | |
| 931 assembler->Bind(&if_valueissame); | |
| 932 { | |
| 933 // Advance to next character. | |
| 934 var_offset.Bind( | |
| 935 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | |
| 936 } | |
| 937 assembler->Goto(&loop); | |
| 938 | |
| 939 assembler->Bind(&if_valueisnotsame); | |
| 940 assembler->Goto(&if_notequal); | |
| 941 } | |
| 942 | |
| 943 assembler->Bind(&if_done); | |
| 944 assembler->Goto(&if_equal); | |
| 945 } | |
| 946 } | |
| 947 | |
| 948 assembler->Bind(&if_notbothonebyteseqstrings); | |
| 949 { | |
| 950 // TODO(bmeurer): Add fast case support for flattened cons strings; | |
| 951 // also add support for two byte string equality checks. | |
| 952 Runtime::FunctionId function_id = (mode == kDontNegateResult) | |
| 953 ? Runtime::kStringEqual | |
| 954 : Runtime::kStringNotEqual; | |
| 955 assembler->TailCallRuntime(function_id, context, lhs, rhs); | |
| 956 } | |
| 957 } | |
| 958 } | |
| 959 | |
| 960 assembler->Bind(&if_lengthisnotequal); | |
| 961 { | |
| 962 // Mismatch in length of {lhs} and {rhs}, cannot be equal. | |
| 963 assembler->Goto(&if_notequal); | |
| 964 } | |
| 965 } | |
| 966 | |
| 967 assembler->Bind(&if_equal); | |
| 968 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); | |
| 969 | |
| 970 assembler->Bind(&if_notequal); | |
| 971 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); | |
| 792 } | 972 } |
| 793 | 973 |
| 794 } // namespace | 974 } // namespace |
| 795 | 975 |
| 796 void StrictEqualStub::GenerateAssembly( | 976 void StrictEqualStub::GenerateAssembly( |
| 797 compiler::CodeStubAssembler* assembler) const { | 977 compiler::CodeStubAssembler* assembler) const { |
| 798 GenerateStrictEqual(assembler, kStrictEqual); | 978 GenerateStrictEqual(assembler, isolate(), kDontNegateResult); |
| 799 } | 979 } |
| 800 | 980 |
| 801 void StrictNotEqualStub::GenerateAssembly( | 981 void StrictNotEqualStub::GenerateAssembly( |
| 802 compiler::CodeStubAssembler* assembler) const { | 982 compiler::CodeStubAssembler* assembler) const { |
| 803 GenerateStrictEqual(assembler, kStrictNotEqual); | 983 GenerateStrictEqual(assembler, isolate(), kNegateResult); |
| 984 } | |
| 985 | |
| 986 void StringEqualStub::GenerateAssembly( | |
| 987 compiler::CodeStubAssembler* assembler) const { | |
| 988 GenerateStringEqual(assembler, kDontNegateResult); | |
| 989 } | |
| 990 | |
| 991 void StringNotEqualStub::GenerateAssembly( | |
| 992 compiler::CodeStubAssembler* assembler) const { | |
| 993 GenerateStringEqual(assembler, kNegateResult); | |
| 804 } | 994 } |
| 805 | 995 |
| 806 void ToBooleanStub::GenerateAssembly( | 996 void ToBooleanStub::GenerateAssembly( |
| 807 compiler::CodeStubAssembler* assembler) const { | 997 compiler::CodeStubAssembler* assembler) const { |
| 808 typedef compiler::Node Node; | 998 typedef compiler::Node Node; |
| 809 typedef compiler::CodeStubAssembler::Label Label; | 999 typedef compiler::CodeStubAssembler::Label Label; |
| 810 | 1000 |
| 811 Node* value = assembler->Parameter(0); | 1001 Node* value = assembler->Parameter(0); |
| 812 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | 1002 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
| 813 | 1003 |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1371 if (type->Is(Type::UntaggedPointer())) { | 1561 if (type->Is(Type::UntaggedPointer())) { |
| 1372 return Representation::External(); | 1562 return Representation::External(); |
| 1373 } | 1563 } |
| 1374 | 1564 |
| 1375 DCHECK(!type->Is(Type::Untagged())); | 1565 DCHECK(!type->Is(Type::Untagged())); |
| 1376 return Representation::Tagged(); | 1566 return Representation::Tagged(); |
| 1377 } | 1567 } |
| 1378 | 1568 |
| 1379 } // namespace internal | 1569 } // namespace internal |
| 1380 } // namespace v8 | 1570 } // namespace v8 |
| OLD | NEW |