OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 friend class JumpTarget; | 605 friend class JumpTarget; |
606 friend class Reference; | 606 friend class Reference; |
607 friend class FastCodeGenerator; | 607 friend class FastCodeGenerator; |
608 friend class FullCodeGenerator; | 608 friend class FullCodeGenerator; |
609 friend class FullCodeGenSyntaxChecker; | 609 friend class FullCodeGenSyntaxChecker; |
610 | 610 |
611 DISALLOW_COPY_AND_ASSIGN(CodeGenerator); | 611 DISALLOW_COPY_AND_ASSIGN(CodeGenerator); |
612 }; | 612 }; |
613 | 613 |
614 | 614 |
615 // Compute a transcendental math function natively, or call the | |
616 // TranscendentalCache runtime function. | |
617 class TranscendentalCacheStub: public CodeStub { | |
618 public: | |
619 explicit TranscendentalCacheStub(TranscendentalCache::Type type) | |
620 : type_(type) {} | |
621 void Generate(MacroAssembler* masm); | |
622 private: | |
623 TranscendentalCache::Type type_; | |
624 Major MajorKey() { return TranscendentalCache; } | |
625 int MinorKey() { return type_; } | |
626 Runtime::FunctionId RuntimeFunction(); | |
627 }; | |
628 | |
629 | |
630 class ToBooleanStub: public CodeStub { | |
631 public: | |
632 explicit ToBooleanStub(Register tos) : tos_(tos) { } | |
633 | |
634 void Generate(MacroAssembler* masm); | |
635 | |
636 private: | |
637 Register tos_; | |
638 Major MajorKey() { return ToBoolean; } | |
639 int MinorKey() { return tos_.code(); } | |
640 }; | |
641 | |
642 | |
643 class GenericBinaryOpStub : public CodeStub { | |
644 public: | |
645 GenericBinaryOpStub(Token::Value op, | |
646 OverwriteMode mode, | |
647 Register lhs, | |
648 Register rhs, | |
649 int constant_rhs = CodeGenerator::kUnknownIntValue) | |
650 : op_(op), | |
651 mode_(mode), | |
652 lhs_(lhs), | |
653 rhs_(rhs), | |
654 constant_rhs_(constant_rhs), | |
655 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), | |
656 runtime_operands_type_(BinaryOpIC::DEFAULT), | |
657 name_(NULL) { } | |
658 | |
659 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) | |
660 : op_(OpBits::decode(key)), | |
661 mode_(ModeBits::decode(key)), | |
662 lhs_(LhsRegister(RegisterBits::decode(key))), | |
663 rhs_(RhsRegister(RegisterBits::decode(key))), | |
664 constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), | |
665 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), | |
666 runtime_operands_type_(type_info), | |
667 name_(NULL) { } | |
668 | |
669 private: | |
670 Token::Value op_; | |
671 OverwriteMode mode_; | |
672 Register lhs_; | |
673 Register rhs_; | |
674 int constant_rhs_; | |
675 bool specialized_on_rhs_; | |
676 BinaryOpIC::TypeInfo runtime_operands_type_; | |
677 char* name_; | |
678 | |
679 static const int kMaxKnownRhs = 0x40000000; | |
680 static const int kKnownRhsKeyBits = 6; | |
681 | |
682 // Minor key encoding in 17 bits. | |
683 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; | |
684 class OpBits: public BitField<Token::Value, 2, 6> {}; | |
685 class TypeInfoBits: public BitField<int, 8, 2> {}; | |
686 class RegisterBits: public BitField<bool, 10, 1> {}; | |
687 class KnownIntBits: public BitField<int, 11, kKnownRhsKeyBits> {}; | |
688 | |
689 Major MajorKey() { return GenericBinaryOp; } | |
690 int MinorKey() { | |
691 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || | |
692 (lhs_.is(r1) && rhs_.is(r0))); | |
693 // Encode the parameters in a unique 18 bit value. | |
694 return OpBits::encode(op_) | |
695 | ModeBits::encode(mode_) | |
696 | KnownIntBits::encode(MinorKeyForKnownInt()) | |
697 | TypeInfoBits::encode(runtime_operands_type_) | |
698 | RegisterBits::encode(lhs_.is(r0)); | |
699 } | |
700 | |
701 void Generate(MacroAssembler* masm); | |
702 void HandleNonSmiBitwiseOp(MacroAssembler* masm, | |
703 Register lhs, | |
704 Register rhs); | |
705 void HandleBinaryOpSlowCases(MacroAssembler* masm, | |
706 Label* not_smi, | |
707 Register lhs, | |
708 Register rhs, | |
709 const Builtins::JavaScript& builtin); | |
710 void GenerateTypeTransition(MacroAssembler* masm); | |
711 | |
712 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { | |
713 if (constant_rhs == CodeGenerator::kUnknownIntValue) return false; | |
714 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; | |
715 if (op == Token::MOD) { | |
716 if (constant_rhs <= 1) return false; | |
717 if (constant_rhs <= 10) return true; | |
718 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; | |
719 return false; | |
720 } | |
721 return false; | |
722 } | |
723 | |
724 int MinorKeyForKnownInt() { | |
725 if (!specialized_on_rhs_) return 0; | |
726 if (constant_rhs_ <= 10) return constant_rhs_ + 1; | |
727 ASSERT(IsPowerOf2(constant_rhs_)); | |
728 int key = 12; | |
729 int d = constant_rhs_; | |
730 while ((d & 1) == 0) { | |
731 key++; | |
732 d >>= 1; | |
733 } | |
734 ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits)); | |
735 return key; | |
736 } | |
737 | |
738 int KnownBitsForMinorKey(int key) { | |
739 if (!key) return 0; | |
740 if (key <= 11) return key - 1; | |
741 int d = 1; | |
742 while (key != 12) { | |
743 key--; | |
744 d <<= 1; | |
745 } | |
746 return d; | |
747 } | |
748 | |
749 Register LhsRegister(bool lhs_is_r0) { | |
750 return lhs_is_r0 ? r0 : r1; | |
751 } | |
752 | |
753 Register RhsRegister(bool lhs_is_r0) { | |
754 return lhs_is_r0 ? r1 : r0; | |
755 } | |
756 | |
757 bool ShouldGenerateSmiCode() { | |
758 return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) && | |
759 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && | |
760 runtime_operands_type_ != BinaryOpIC::STRINGS; | |
761 } | |
762 | |
763 bool ShouldGenerateFPCode() { | |
764 return runtime_operands_type_ != BinaryOpIC::STRINGS; | |
765 } | |
766 | |
767 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } | |
768 | |
769 virtual InlineCacheState GetICState() { | |
770 return BinaryOpIC::ToState(runtime_operands_type_); | |
771 } | |
772 | |
773 const char* GetName(); | |
774 | |
775 #ifdef DEBUG | |
776 void Print() { | |
777 if (!specialized_on_rhs_) { | |
778 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); | |
779 } else { | |
780 PrintF("GenericBinaryOpStub (%s by %d)\n", | |
781 Token::String(op_), | |
782 constant_rhs_); | |
783 } | |
784 } | |
785 #endif | |
786 }; | |
787 | |
788 | |
789 class StringHelper : public AllStatic { | |
790 public: | |
791 // Generate code for copying characters using a simple loop. This should only | |
792 // be used in places where the number of characters is small and the | |
793 // additional setup and checking in GenerateCopyCharactersLong adds too much | |
794 // overhead. Copying of overlapping regions is not supported. | |
795 // Dest register ends at the position after the last character written. | |
796 static void GenerateCopyCharacters(MacroAssembler* masm, | |
797 Register dest, | |
798 Register src, | |
799 Register count, | |
800 Register scratch, | |
801 bool ascii); | |
802 | |
803 // Generate code for copying a large number of characters. This function | |
804 // is allowed to spend extra time setting up conditions to make copying | |
805 // faster. Copying of overlapping regions is not supported. | |
806 // Dest register ends at the position after the last character written. | |
807 static void GenerateCopyCharactersLong(MacroAssembler* masm, | |
808 Register dest, | |
809 Register src, | |
810 Register count, | |
811 Register scratch1, | |
812 Register scratch2, | |
813 Register scratch3, | |
814 Register scratch4, | |
815 Register scratch5, | |
816 int flags); | |
817 | |
818 | |
819 // Probe the symbol table for a two character string. If the string is | |
820 // not found by probing a jump to the label not_found is performed. This jump | |
821 // does not guarantee that the string is not in the symbol table. If the | |
822 // string is found the code falls through with the string in register r0. | |
823 // Contents of both c1 and c2 registers are modified. At the exit c1 is | |
824 // guaranteed to contain halfword with low and high bytes equal to | |
825 // initial contents of c1 and c2 respectively. | |
826 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | |
827 Register c1, | |
828 Register c2, | |
829 Register scratch1, | |
830 Register scratch2, | |
831 Register scratch3, | |
832 Register scratch4, | |
833 Register scratch5, | |
834 Label* not_found); | |
835 | |
836 // Generate string hash. | |
837 static void GenerateHashInit(MacroAssembler* masm, | |
838 Register hash, | |
839 Register character); | |
840 | |
841 static void GenerateHashAddCharacter(MacroAssembler* masm, | |
842 Register hash, | |
843 Register character); | |
844 | |
845 static void GenerateHashGetHash(MacroAssembler* masm, | |
846 Register hash); | |
847 | |
848 private: | |
849 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); | |
850 }; | |
851 | |
852 | |
853 // Flag that indicates how to generate code for the stub StringAddStub. | |
854 enum StringAddFlags { | |
855 NO_STRING_ADD_FLAGS = 0, | |
856 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. | |
857 }; | |
858 | |
859 | |
860 class StringAddStub: public CodeStub { | |
861 public: | |
862 explicit StringAddStub(StringAddFlags flags) { | |
863 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); | |
864 } | |
865 | |
866 private: | |
867 Major MajorKey() { return StringAdd; } | |
868 int MinorKey() { return string_check_ ? 0 : 1; } | |
869 | |
870 void Generate(MacroAssembler* masm); | |
871 | |
872 // Should the stub check whether arguments are strings? | |
873 bool string_check_; | |
874 }; | |
875 | |
876 | |
877 class SubStringStub: public CodeStub { | |
878 public: | |
879 SubStringStub() {} | |
880 | |
881 private: | |
882 Major MajorKey() { return SubString; } | |
883 int MinorKey() { return 0; } | |
884 | |
885 void Generate(MacroAssembler* masm); | |
886 }; | |
887 | |
888 | |
889 | |
890 class StringCompareStub: public CodeStub { | |
891 public: | |
892 StringCompareStub() { } | |
893 | |
894 // Compare two flat ASCII strings and returns result in r0. | |
895 // Does not use the stack. | |
896 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | |
897 Register left, | |
898 Register right, | |
899 Register scratch1, | |
900 Register scratch2, | |
901 Register scratch3, | |
902 Register scratch4); | |
903 | |
904 private: | |
905 Major MajorKey() { return StringCompare; } | |
906 int MinorKey() { return 0; } | |
907 | |
908 void Generate(MacroAssembler* masm); | |
909 }; | |
910 | |
911 | |
912 // This stub can do a fast mod operation without using fp. | |
913 // It is tail called from the GenericBinaryOpStub and it always | |
914 // returns an answer. It never causes GC so it doesn't need a real frame. | |
915 // | |
916 // The inputs are always positive Smis. This is never called | |
917 // where the denominator is a power of 2. We handle that separately. | |
918 // | |
919 // If we consider the denominator as an odd number multiplied by a power of 2, | |
920 // then: | |
921 // * The exponent (power of 2) is in the shift_distance register. | |
922 // * The odd number is in the odd_number register. It is always in the range | |
923 // of 3 to 25. | |
924 // * The bits from the numerator that are to be copied to the answer (there are | |
925 // shift_distance of them) are in the mask_bits register. | |
926 // * The other bits of the numerator have been shifted down and are in the lhs | |
927 // register. | |
928 class IntegerModStub : public CodeStub { | |
929 public: | |
930 IntegerModStub(Register result, | |
931 Register shift_distance, | |
932 Register odd_number, | |
933 Register mask_bits, | |
934 Register lhs, | |
935 Register scratch) | |
936 : result_(result), | |
937 shift_distance_(shift_distance), | |
938 odd_number_(odd_number), | |
939 mask_bits_(mask_bits), | |
940 lhs_(lhs), | |
941 scratch_(scratch) { | |
942 // We don't code these in the minor key, so they should always be the same. | |
943 // We don't really want to fix that since this stub is rather large and we | |
944 // don't want many copies of it. | |
945 ASSERT(shift_distance_.is(r9)); | |
946 ASSERT(odd_number_.is(r4)); | |
947 ASSERT(mask_bits_.is(r3)); | |
948 ASSERT(scratch_.is(r5)); | |
949 } | |
950 | |
951 private: | |
952 Register result_; | |
953 Register shift_distance_; | |
954 Register odd_number_; | |
955 Register mask_bits_; | |
956 Register lhs_; | |
957 Register scratch_; | |
958 | |
959 // Minor key encoding in 16 bits. | |
960 class ResultRegisterBits: public BitField<int, 0, 4> {}; | |
961 class LhsRegisterBits: public BitField<int, 4, 4> {}; | |
962 | |
963 Major MajorKey() { return IntegerMod; } | |
964 int MinorKey() { | |
965 // Encode the parameters in a unique 16 bit value. | |
966 return ResultRegisterBits::encode(result_.code()) | |
967 | LhsRegisterBits::encode(lhs_.code()); | |
968 } | |
969 | |
970 void Generate(MacroAssembler* masm); | |
971 | |
972 const char* GetName() { return "IntegerModStub"; } | |
973 | |
974 // Utility functions. | |
975 void DigitSum(MacroAssembler* masm, | |
976 Register lhs, | |
977 int mask, | |
978 int shift, | |
979 Label* entry); | |
980 void DigitSum(MacroAssembler* masm, | |
981 Register lhs, | |
982 Register scratch, | |
983 int mask, | |
984 int shift1, | |
985 int shift2, | |
986 Label* entry); | |
987 void ModGetInRangeBySubtraction(MacroAssembler* masm, | |
988 Register lhs, | |
989 int shift, | |
990 int rhs); | |
991 void ModReduce(MacroAssembler* masm, | |
992 Register lhs, | |
993 int max, | |
994 int denominator); | |
995 void ModAnswer(MacroAssembler* masm, | |
996 Register result, | |
997 Register shift_distance, | |
998 Register mask_bits, | |
999 Register sum_of_digits); | |
1000 | |
1001 | |
1002 #ifdef DEBUG | |
1003 void Print() { PrintF("IntegerModStub\n"); } | |
1004 #endif | |
1005 }; | |
1006 | |
1007 | |
1008 // This stub can convert a signed int32 to a heap number (double). It does | |
1009 // not work for int32s that are in Smi range! No GC occurs during this stub | |
1010 // so you don't have to set up the frame. | |
1011 class WriteInt32ToHeapNumberStub : public CodeStub { | |
1012 public: | |
1013 WriteInt32ToHeapNumberStub(Register the_int, | |
1014 Register the_heap_number, | |
1015 Register scratch) | |
1016 : the_int_(the_int), | |
1017 the_heap_number_(the_heap_number), | |
1018 scratch_(scratch) { } | |
1019 | |
1020 private: | |
1021 Register the_int_; | |
1022 Register the_heap_number_; | |
1023 Register scratch_; | |
1024 | |
1025 // Minor key encoding in 16 bits. | |
1026 class IntRegisterBits: public BitField<int, 0, 4> {}; | |
1027 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; | |
1028 class ScratchRegisterBits: public BitField<int, 8, 4> {}; | |
1029 | |
1030 Major MajorKey() { return WriteInt32ToHeapNumber; } | |
1031 int MinorKey() { | |
1032 // Encode the parameters in a unique 16 bit value. | |
1033 return IntRegisterBits::encode(the_int_.code()) | |
1034 | HeapNumberRegisterBits::encode(the_heap_number_.code()) | |
1035 | ScratchRegisterBits::encode(scratch_.code()); | |
1036 } | |
1037 | |
1038 void Generate(MacroAssembler* masm); | |
1039 | |
1040 const char* GetName() { return "WriteInt32ToHeapNumberStub"; } | |
1041 | |
1042 #ifdef DEBUG | |
1043 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); } | |
1044 #endif | |
1045 }; | |
1046 | |
1047 | |
1048 class NumberToStringStub: public CodeStub { | |
1049 public: | |
1050 NumberToStringStub() { } | |
1051 | |
1052 // Generate code to do a lookup in the number string cache. If the number in | |
1053 // the register object is found in the cache the generated code falls through | |
1054 // with the result in the result register. The object and the result register | |
1055 // can be the same. If the number is not found in the cache the code jumps to | |
1056 // the label not_found with only the content of register object unchanged. | |
1057 static void GenerateLookupNumberStringCache(MacroAssembler* masm, | |
1058 Register object, | |
1059 Register result, | |
1060 Register scratch1, | |
1061 Register scratch2, | |
1062 Register scratch3, | |
1063 bool object_is_smi, | |
1064 Label* not_found); | |
1065 | |
1066 private: | |
1067 Major MajorKey() { return NumberToString; } | |
1068 int MinorKey() { return 0; } | |
1069 | |
1070 void Generate(MacroAssembler* masm); | |
1071 | |
1072 const char* GetName() { return "NumberToStringStub"; } | |
1073 | |
1074 #ifdef DEBUG | |
1075 void Print() { | |
1076 PrintF("NumberToStringStub\n"); | |
1077 } | |
1078 #endif | |
1079 }; | |
1080 | |
1081 | |
1082 class RecordWriteStub : public CodeStub { | |
1083 public: | |
1084 RecordWriteStub(Register object, Register offset, Register scratch) | |
1085 : object_(object), offset_(offset), scratch_(scratch) { } | |
1086 | |
1087 void Generate(MacroAssembler* masm); | |
1088 | |
1089 private: | |
1090 Register object_; | |
1091 Register offset_; | |
1092 Register scratch_; | |
1093 | |
1094 #ifdef DEBUG | |
1095 void Print() { | |
1096 PrintF("RecordWriteStub (object reg %d), (offset reg %d)," | |
1097 " (scratch reg %d)\n", | |
1098 object_.code(), offset_.code(), scratch_.code()); | |
1099 } | |
1100 #endif | |
1101 | |
1102 // Minor key encoding in 12 bits. 4 bits for each of the three | |
1103 // registers (object, offset and scratch) OOOOAAAASSSS. | |
1104 class ScratchBits: public BitField<uint32_t, 0, 4> {}; | |
1105 class OffsetBits: public BitField<uint32_t, 4, 4> {}; | |
1106 class ObjectBits: public BitField<uint32_t, 8, 4> {}; | |
1107 | |
1108 Major MajorKey() { return RecordWrite; } | |
1109 | |
1110 int MinorKey() { | |
1111 // Encode the registers. | |
1112 return ObjectBits::encode(object_.code()) | | |
1113 OffsetBits::encode(offset_.code()) | | |
1114 ScratchBits::encode(scratch_.code()); | |
1115 } | |
1116 }; | |
1117 | |
1118 | |
1119 } } // namespace v8::internal | 615 } } // namespace v8::internal |
1120 | 616 |
1121 #endif // V8_ARM_CODEGEN_ARM_H_ | 617 #endif // V8_ARM_CODEGEN_ARM_H_ |
OLD | NEW |