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 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 | 699 |
699 // Check if {rhs} is also a String. | 700 // Check if {rhs} is also a String. |
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 Callable callable = (mode == kDontNegateResult) |
709 // functionality is available in TurboFan land. | 710 ? CodeFactory::StringEqual(isolate) |
710 Runtime::FunctionId function_id = (mode == kStrictEqual) | 711 : CodeFactory::StringNotEqual(isolate); |
711 ? Runtime::kStringEqual | 712 assembler->TailCallStub(callable, context, lhs, rhs); |
712 : Runtime::kStringNotEqual; | |
713 assembler->TailCallRuntime(function_id, context, lhs, rhs); | |
714 } | 713 } |
715 | 714 |
716 assembler->Bind(&if_rhsisnotstring); | 715 assembler->Bind(&if_rhsisnotstring); |
717 assembler->Goto(&if_notequal); | 716 assembler->Goto(&if_notequal); |
718 } | 717 } |
719 | 718 |
720 assembler->Bind(&if_lhsisnotstring); | 719 assembler->Bind(&if_lhsisnotstring); |
721 { | 720 { |
722 // Check if {lhs} is a Simd128Value. | 721 // Check if {lhs} is a Simd128Value. |
723 Label if_lhsissimd128value(assembler), | 722 Label if_lhsissimd128value(assembler), |
724 if_lhsisnotsimd128value(assembler); | 723 if_lhsisnotsimd128value(assembler); |
725 assembler->Branch(assembler->Word32Equal( | 724 assembler->Branch(assembler->Word32Equal( |
726 lhs_instance_type, | 725 lhs_instance_type, |
727 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | 726 assembler->Int32Constant(SIMD128_VALUE_TYPE)), |
728 &if_lhsissimd128value, &if_lhsisnotsimd128value); | 727 &if_lhsissimd128value, &if_lhsisnotsimd128value); |
729 | 728 |
730 assembler->Bind(&if_lhsissimd128value); | 729 assembler->Bind(&if_lhsissimd128value); |
731 { | 730 { |
732 // TODO(bmeurer): Inline the Simd128Value equality check. | 731 // TODO(bmeurer): Inline the Simd128Value equality check. |
733 Runtime::FunctionId function_id = (mode == kStrictEqual) | 732 Runtime::FunctionId function_id = (mode == kDontNegateResult) |
734 ? Runtime::kStrictEqual | 733 ? Runtime::kStrictEqual |
735 : Runtime::kStrictNotEqual; | 734 : Runtime::kStrictNotEqual; |
736 assembler->TailCallRuntime(function_id, context, lhs, rhs); | 735 assembler->TailCallRuntime(function_id, context, lhs, rhs); |
737 } | 736 } |
738 | 737 |
739 assembler->Bind(&if_lhsisnotsimd128value); | 738 assembler->Bind(&if_lhsisnotsimd128value); |
740 assembler->Goto(&if_notequal); | 739 assembler->Goto(&if_notequal); |
741 } | 740 } |
742 } | 741 } |
743 } | 742 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 &if_notequal); | 777 &if_notequal); |
779 } | 778 } |
780 | 779 |
781 assembler->Bind(&if_rhsisnotnumber); | 780 assembler->Bind(&if_rhsisnotnumber); |
782 assembler->Goto(&if_notequal); | 781 assembler->Goto(&if_notequal); |
783 } | 782 } |
784 } | 783 } |
785 } | 784 } |
786 | 785 |
787 assembler->Bind(&if_equal); | 786 assembler->Bind(&if_equal); |
788 assembler->Return(assembler->BooleanConstant(mode == kStrictEqual)); | 787 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
789 | 788 |
790 assembler->Bind(&if_notequal); | 789 assembler->Bind(&if_notequal); |
791 assembler->Return(assembler->BooleanConstant(mode == kStrictNotEqual)); | 790 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
| 791 } |
| 792 |
| 793 void GenerateStringEqual(compiler::CodeStubAssembler* assembler, |
| 794 ResultMode mode) { |
| 795 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
| 796 // mode; for kNegateResult mode we properly negate the result. |
| 797 // |
| 798 // if (lhs == rhs) return true; |
| 799 // if (lhs->length() != rhs->length()) return false; |
| 800 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { |
| 801 // return false; |
| 802 // } |
| 803 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { |
| 804 // for (i = 0; i != lhs->length(); ++i) { |
| 805 // if (lhs[i] != rhs[i]) return false; |
| 806 // } |
| 807 // return true; |
| 808 // } |
| 809 // return %StringEqual(lhs, rhs); |
| 810 |
| 811 typedef compiler::CodeStubAssembler::Label Label; |
| 812 typedef compiler::Node Node; |
| 813 typedef compiler::CodeStubAssembler::Variable Variable; |
| 814 |
| 815 Node* lhs = assembler->Parameter(0); |
| 816 Node* rhs = assembler->Parameter(1); |
| 817 Node* context = assembler->Parameter(2); |
| 818 |
| 819 Label if_equal(assembler), if_notequal(assembler); |
| 820 |
| 821 // Fast check to see if {lhs} and {rhs} refer to the same String object. |
| 822 Label if_same(assembler), if_notsame(assembler); |
| 823 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 824 |
| 825 assembler->Bind(&if_same); |
| 826 assembler->Goto(&if_equal); |
| 827 |
| 828 assembler->Bind(&if_notsame); |
| 829 { |
| 830 // The {lhs} and {rhs} don't refer to the exact same String object. |
| 831 |
| 832 // Load the length of {lhs} and {rhs}. |
| 833 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); |
| 834 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); |
| 835 |
| 836 // Check if the lengths of {lhs} and {rhs} are equal. |
| 837 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); |
| 838 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), |
| 839 &if_lengthisequal, &if_lengthisnotequal); |
| 840 |
| 841 assembler->Bind(&if_lengthisequal); |
| 842 { |
| 843 // Load instance types of {lhs} and {rhs}. |
| 844 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); |
| 845 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); |
| 846 |
| 847 // Combine the instance types into a single 16-bit value, so we can check |
| 848 // both of them at once. |
| 849 Node* both_instance_types = assembler->Word32Or( |
| 850 lhs_instance_type, |
| 851 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); |
| 852 |
| 853 // Check if both {lhs} and {rhs} are internalized. |
| 854 int const kBothInternalizedMask = |
| 855 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); |
| 856 int const kBothInternalizedTag = |
| 857 kInternalizedTag | (kInternalizedTag << 8); |
| 858 Label if_bothinternalized(assembler), if_notbothinternalized(assembler); |
| 859 assembler->Branch(assembler->Word32Equal( |
| 860 assembler->Word32And(both_instance_types, |
| 861 assembler->Int32Constant( |
| 862 kBothInternalizedMask)), |
| 863 assembler->Int32Constant(kBothInternalizedTag)), |
| 864 &if_bothinternalized, &if_notbothinternalized); |
| 865 |
| 866 assembler->Bind(&if_bothinternalized); |
| 867 { |
| 868 // Fast negative check for internalized-to-internalized equality. |
| 869 assembler->Goto(&if_notequal); |
| 870 } |
| 871 |
| 872 assembler->Bind(&if_notbothinternalized); |
| 873 { |
| 874 // Check that both {lhs} and {rhs} are flat one-byte strings. |
| 875 int const kBothSeqOneByteStringMask = |
| 876 kStringEncodingMask | kStringRepresentationMask | |
| 877 ((kStringEncodingMask | kStringRepresentationMask) << 8); |
| 878 int const kBothSeqOneByteStringTag = |
| 879 kOneByteStringTag | kSeqStringTag | |
| 880 ((kOneByteStringTag | kSeqStringTag) << 8); |
| 881 Label if_bothonebyteseqstrings(assembler), |
| 882 if_notbothonebyteseqstrings(assembler); |
| 883 assembler->Branch( |
| 884 assembler->Word32Equal( |
| 885 assembler->Word32And( |
| 886 both_instance_types, |
| 887 assembler->Int32Constant(kBothSeqOneByteStringMask)), |
| 888 assembler->Int32Constant(kBothSeqOneByteStringTag)), |
| 889 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); |
| 890 |
| 891 assembler->Bind(&if_bothonebyteseqstrings); |
| 892 { |
| 893 // Compute the effective offset of the first character. |
| 894 Node* begin = assembler->IntPtrConstant( |
| 895 SeqOneByteString::kHeaderSize - kHeapObjectTag); |
| 896 |
| 897 // Compute the first offset after the string from the length. |
| 898 Node* end = |
| 899 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); |
| 900 |
| 901 // Loop over the {lhs} and {rhs} strings to see if they are equal. |
| 902 Variable var_offset(assembler, MachineType::PointerRepresentation()); |
| 903 Label loop(assembler, &var_offset); |
| 904 var_offset.Bind(begin); |
| 905 assembler->Goto(&loop); |
| 906 assembler->Bind(&loop); |
| 907 { |
| 908 // Check if {offset} equals {end}. |
| 909 Node* offset = var_offset.value(); |
| 910 Label if_done(assembler), if_notdone(assembler); |
| 911 assembler->Branch(assembler->WordEqual(offset, end), &if_done, |
| 912 &if_notdone); |
| 913 |
| 914 assembler->Bind(&if_notdone); |
| 915 { |
| 916 // Load the next characters from {lhs} and {rhs}. |
| 917 Node* lhs_value = |
| 918 assembler->Load(MachineType::Uint8(), lhs, offset); |
| 919 Node* rhs_value = |
| 920 assembler->Load(MachineType::Uint8(), rhs, offset); |
| 921 |
| 922 // Check if the characters match. |
| 923 Label if_valueissame(assembler), if_valueisnotsame(assembler); |
| 924 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), |
| 925 &if_valueissame, &if_valueisnotsame); |
| 926 |
| 927 assembler->Bind(&if_valueissame); |
| 928 { |
| 929 // Advance to next character. |
| 930 var_offset.Bind( |
| 931 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); |
| 932 } |
| 933 assembler->Goto(&loop); |
| 934 |
| 935 assembler->Bind(&if_valueisnotsame); |
| 936 assembler->Goto(&if_notequal); |
| 937 } |
| 938 |
| 939 assembler->Bind(&if_done); |
| 940 assembler->Goto(&if_equal); |
| 941 } |
| 942 } |
| 943 |
| 944 assembler->Bind(&if_notbothonebyteseqstrings); |
| 945 { |
| 946 // TODO(bmeurer): Add fast case support for flattened cons strings; |
| 947 // also add support for two byte string equality checks. |
| 948 Runtime::FunctionId function_id = (mode == kDontNegateResult) |
| 949 ? Runtime::kStringEqual |
| 950 : Runtime::kStringNotEqual; |
| 951 assembler->TailCallRuntime(function_id, context, lhs, rhs); |
| 952 } |
| 953 } |
| 954 } |
| 955 |
| 956 assembler->Bind(&if_lengthisnotequal); |
| 957 { |
| 958 // Mismatch in length of {lhs} and {rhs}, cannot be equal. |
| 959 assembler->Goto(&if_notequal); |
| 960 } |
| 961 } |
| 962 |
| 963 assembler->Bind(&if_equal); |
| 964 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
| 965 |
| 966 assembler->Bind(&if_notequal); |
| 967 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
792 } | 968 } |
793 | 969 |
794 } // namespace | 970 } // namespace |
795 | 971 |
796 void StrictEqualStub::GenerateAssembly( | 972 void StrictEqualStub::GenerateAssembly( |
797 compiler::CodeStubAssembler* assembler) const { | 973 compiler::CodeStubAssembler* assembler) const { |
798 GenerateStrictEqual(assembler, kStrictEqual); | 974 GenerateStrictEqual(assembler, isolate(), kDontNegateResult); |
799 } | 975 } |
800 | 976 |
801 void StrictNotEqualStub::GenerateAssembly( | 977 void StrictNotEqualStub::GenerateAssembly( |
802 compiler::CodeStubAssembler* assembler) const { | 978 compiler::CodeStubAssembler* assembler) const { |
803 GenerateStrictEqual(assembler, kStrictNotEqual); | 979 GenerateStrictEqual(assembler, isolate(), kNegateResult); |
| 980 } |
| 981 |
| 982 void StringEqualStub::GenerateAssembly( |
| 983 compiler::CodeStubAssembler* assembler) const { |
| 984 GenerateStringEqual(assembler, kDontNegateResult); |
| 985 } |
| 986 |
| 987 void StringNotEqualStub::GenerateAssembly( |
| 988 compiler::CodeStubAssembler* assembler) const { |
| 989 GenerateStringEqual(assembler, kNegateResult); |
804 } | 990 } |
805 | 991 |
806 void ToBooleanStub::GenerateAssembly( | 992 void ToBooleanStub::GenerateAssembly( |
807 compiler::CodeStubAssembler* assembler) const { | 993 compiler::CodeStubAssembler* assembler) const { |
808 typedef compiler::Node Node; | 994 typedef compiler::Node Node; |
809 typedef compiler::CodeStubAssembler::Label Label; | 995 typedef compiler::CodeStubAssembler::Label Label; |
810 | 996 |
811 Node* value = assembler->Parameter(0); | 997 Node* value = assembler->Parameter(0); |
812 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | 998 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
813 | 999 |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1371 if (type->Is(Type::UntaggedPointer())) { | 1557 if (type->Is(Type::UntaggedPointer())) { |
1372 return Representation::External(); | 1558 return Representation::External(); |
1373 } | 1559 } |
1374 | 1560 |
1375 DCHECK(!type->Is(Type::Untagged())); | 1561 DCHECK(!type->Is(Type::Untagged())); |
1376 return Representation::Tagged(); | 1562 return Representation::Tagged(); |
1377 } | 1563 } |
1378 | 1564 |
1379 } // namespace internal | 1565 } // namespace internal |
1380 } // namespace v8 | 1566 } // namespace v8 |
OLD | NEW |