| 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 |