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 |