OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #ifndef V8_ARM64_ASSEMBLER_ARM64_H_ | 5 #ifndef V8_ARM64_ASSEMBLER_ARM64_H_ |
6 #define V8_ARM64_ASSEMBLER_ARM64_H_ | 6 #define V8_ARM64_ASSEMBLER_ARM64_H_ |
7 | 7 |
8 #include <list> | 8 #include <list> |
| 9 #include <vector> |
9 #include <map> | 10 #include <map> |
10 | 11 |
11 #include "src/cpu.h" | 12 #include "src/cpu.h" |
12 #include "src/globals.h" | 13 #include "src/globals.h" |
13 #include "src/utils.h" | 14 #include "src/utils.h" |
14 #include "src/assembler.h" | 15 #include "src/assembler.h" |
15 #include "src/serialize.h" | 16 #include "src/serialize.h" |
16 #include "src/arm64/instructions-arm64.h" | 17 #include "src/arm64/instructions-arm64.h" |
17 | 18 |
18 | 19 |
(...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 Register base_; | 734 Register base_; |
734 Register regoffset_; | 735 Register regoffset_; |
735 ptrdiff_t offset_; | 736 ptrdiff_t offset_; |
736 AddrMode addrmode_; | 737 AddrMode addrmode_; |
737 Shift shift_; | 738 Shift shift_; |
738 Extend extend_; | 739 Extend extend_; |
739 unsigned shift_amount_; | 740 unsigned shift_amount_; |
740 }; | 741 }; |
741 | 742 |
742 | 743 |
| 744 class ConstPool { |
| 745 public: |
| 746 explicit ConstPool(Assembler* assm) |
| 747 : assm_(assm), |
| 748 first_use_(-1), |
| 749 shared_entries_count(0) {} |
| 750 void RecordEntry(intptr_t data, RelocInfo::Mode mode); |
| 751 int EntryCount() const { |
| 752 return shared_entries_count + unique_entries_.size(); |
| 753 } |
| 754 bool IsEmpty() const { |
| 755 return shared_entries_.empty() && unique_entries_.empty(); |
| 756 } |
| 757 // Distance in bytes between the current pc and the first instruction |
| 758 // using the pool. If there are no pending entries return kMaxInt. |
| 759 int DistanceToFirstUse(); |
| 760 // Offset after which instructions using the pool will be out of range. |
| 761 int MaxPcOffset(); |
| 762 // Maximum size the constant pool can be with current entries. It always |
| 763 // includes alignment padding and branch over. |
| 764 int WorstCaseSize(); |
| 765 // Size in bytes of the literal pool *if* it is emitted at the current |
| 766 // pc. The size will include the branch over the pool if it was requested. |
| 767 int SizeIfEmittedAtCurrentPc(bool require_jump); |
| 768 // Emit the literal pool at the current pc with a branch over the pool if |
| 769 // requested. |
| 770 void Emit(bool require_jump); |
| 771 // Discard any pending pool entries. |
| 772 void Clear(); |
| 773 |
| 774 private: |
| 775 bool CanBeShared(RelocInfo::Mode mode); |
| 776 void EmitMarker(); |
| 777 void EmitGuard(); |
| 778 void EmitEntries(); |
| 779 |
| 780 Assembler* assm_; |
| 781 // Keep track of the first instruction requiring a constant pool entry |
| 782 // since the previous constant pool was emitted. |
| 783 int first_use_; |
| 784 // values, pc offset(s) of entries which can be shared. |
| 785 std::multimap<uint64_t, int> shared_entries_; |
| 786 // Number of distinct literal in shared entries. |
| 787 int shared_entries_count; |
| 788 // values, pc offset of entries which cannot be shared. |
| 789 std::vector<std::pair<uint64_t, int> > unique_entries_; |
| 790 }; |
| 791 |
| 792 |
743 // ----------------------------------------------------------------------------- | 793 // ----------------------------------------------------------------------------- |
744 // Assembler. | 794 // Assembler. |
745 | 795 |
746 class Assembler : public AssemblerBase { | 796 class Assembler : public AssemblerBase { |
747 public: | 797 public: |
748 // Create an assembler. Instructions and relocation information are emitted | 798 // Create an assembler. Instructions and relocation information are emitted |
749 // into a buffer, with the instructions starting from the beginning and the | 799 // into a buffer, with the instructions starting from the beginning and the |
750 // relocation information starting from the end of the buffer. See CodeDesc | 800 // relocation information starting from the end of the buffer. See CodeDesc |
751 // for a detailed comment on the layout (globals.h). | 801 // for a detailed comment on the layout (globals.h). |
752 // | 802 // |
753 // If the provided buffer is NULL, the assembler allocates and grows its own | 803 // If the provided buffer is NULL, the assembler allocates and grows its own |
754 // buffer, and buffer_size determines the initial buffer size. The buffer is | 804 // buffer, and buffer_size determines the initial buffer size. The buffer is |
755 // owned by the assembler and deallocated upon destruction of the assembler. | 805 // owned by the assembler and deallocated upon destruction of the assembler. |
756 // | 806 // |
757 // If the provided buffer is not NULL, the assembler uses the provided buffer | 807 // If the provided buffer is not NULL, the assembler uses the provided buffer |
758 // for code generation and assumes its size to be buffer_size. If the buffer | 808 // for code generation and assumes its size to be buffer_size. If the buffer |
759 // is too small, a fatal error occurs. No deallocation of the buffer is done | 809 // is too small, a fatal error occurs. No deallocation of the buffer is done |
760 // upon destruction of the assembler. | 810 // upon destruction of the assembler. |
761 Assembler(Isolate* arg_isolate, void* buffer, int buffer_size); | 811 Assembler(Isolate* arg_isolate, void* buffer, int buffer_size); |
762 | 812 |
763 virtual ~Assembler(); | 813 virtual ~Assembler(); |
764 | 814 |
765 virtual void AbortedCodeGeneration() { | 815 virtual void AbortedCodeGeneration() { |
766 num_pending_reloc_info_ = 0; | 816 constpool_.Clear(); |
767 } | 817 } |
768 | 818 |
769 // System functions --------------------------------------------------------- | 819 // System functions --------------------------------------------------------- |
770 // Start generating code from the beginning of the buffer, discarding any code | 820 // Start generating code from the beginning of the buffer, discarding any code |
771 // and data that has already been emitted into the buffer. | 821 // and data that has already been emitted into the buffer. |
772 // | 822 // |
773 // In order to avoid any accidental transfer of state, Reset ASSERTs that the | 823 // In order to avoid any accidental transfer of state, Reset ASSERTs that the |
774 // constant pool is not blocked. | 824 // constant pool is not blocked. |
775 void Reset(); | 825 void Reset(); |
776 | 826 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 void StartBlockConstPool(); | 955 void StartBlockConstPool(); |
906 | 956 |
907 // Resume constant pool emission. Need to be called as many time as | 957 // Resume constant pool emission. Need to be called as many time as |
908 // StartBlockConstPool to have an effect. | 958 // StartBlockConstPool to have an effect. |
909 void EndBlockConstPool(); | 959 void EndBlockConstPool(); |
910 | 960 |
911 bool is_const_pool_blocked() const; | 961 bool is_const_pool_blocked() const; |
912 static bool IsConstantPoolAt(Instruction* instr); | 962 static bool IsConstantPoolAt(Instruction* instr); |
913 static int ConstantPoolSizeAt(Instruction* instr); | 963 static int ConstantPoolSizeAt(Instruction* instr); |
914 // See Assembler::CheckConstPool for more info. | 964 // See Assembler::CheckConstPool for more info. |
915 void ConstantPoolMarker(uint32_t size); | |
916 void EmitPoolGuard(); | 965 void EmitPoolGuard(); |
917 void ConstantPoolGuard(); | |
918 | 966 |
919 // Prevent veneer pool emission until EndBlockVeneerPool is called. | 967 // Prevent veneer pool emission until EndBlockVeneerPool is called. |
920 // Call to this function can be nested but must be followed by an equal | 968 // Call to this function can be nested but must be followed by an equal |
921 // number of call to EndBlockConstpool. | 969 // number of call to EndBlockConstpool. |
922 void StartBlockVeneerPool(); | 970 void StartBlockVeneerPool(); |
923 | 971 |
924 // Resume constant pool emission. Need to be called as many time as | 972 // Resume constant pool emission. Need to be called as many time as |
925 // StartBlockVeneerPool to have an effect. | 973 // StartBlockVeneerPool to have an effect. |
926 void EndBlockVeneerPool(); | 974 void EndBlockVeneerPool(); |
927 | 975 |
(...skipping 760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1688 | 1736 |
1689 // Parameters are described in arm64/instructions-arm64.h. | 1737 // Parameters are described in arm64/instructions-arm64.h. |
1690 void debug(const char* message, uint32_t code, Instr params = BREAK); | 1738 void debug(const char* message, uint32_t code, Instr params = BREAK); |
1691 | 1739 |
1692 // Required by V8. | 1740 // Required by V8. |
1693 void dd(uint32_t data) { dc32(data); } | 1741 void dd(uint32_t data) { dc32(data); } |
1694 void db(uint8_t data) { dc8(data); } | 1742 void db(uint8_t data) { dc8(data); } |
1695 | 1743 |
1696 // Code generation helpers -------------------------------------------------- | 1744 // Code generation helpers -------------------------------------------------- |
1697 | 1745 |
1698 unsigned num_pending_reloc_info() const { return num_pending_reloc_info_; } | 1746 bool IsConstPoolEmpty() const { return constpool_.IsEmpty(); } |
| 1747 |
| 1748 Instruction* pc() const { return Instruction::Cast(pc_); } |
1699 | 1749 |
1700 Instruction* InstructionAt(int offset) const { | 1750 Instruction* InstructionAt(int offset) const { |
1701 return reinterpret_cast<Instruction*>(buffer_ + offset); | 1751 return reinterpret_cast<Instruction*>(buffer_ + offset); |
1702 } | 1752 } |
1703 | 1753 |
1704 ptrdiff_t InstructionOffset(Instruction* instr) const { | 1754 ptrdiff_t InstructionOffset(Instruction* instr) const { |
1705 return reinterpret_cast<byte*>(instr) - buffer_; | 1755 return reinterpret_cast<byte*>(instr) - buffer_; |
1706 } | 1756 } |
1707 | 1757 |
1708 // Register encoding. | 1758 // Register encoding. |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2012 | 2062 |
2013 // Verify that a label's link chain is intact. | 2063 // Verify that a label's link chain is intact. |
2014 void CheckLabelLinkChain(Label const * label); | 2064 void CheckLabelLinkChain(Label const * label); |
2015 | 2065 |
2016 void RecordLiteral(int64_t imm, unsigned size); | 2066 void RecordLiteral(int64_t imm, unsigned size); |
2017 | 2067 |
2018 // Postpone the generation of the constant pool for the specified number of | 2068 // Postpone the generation of the constant pool for the specified number of |
2019 // instructions. | 2069 // instructions. |
2020 void BlockConstPoolFor(int instructions); | 2070 void BlockConstPoolFor(int instructions); |
2021 | 2071 |
| 2072 // Set how far from current pc the next constant pool check will be. |
| 2073 void SetNextConstPoolCheckIn(int instructions) { |
| 2074 next_constant_pool_check_ = pc_offset() + instructions * kInstructionSize; |
| 2075 } |
| 2076 |
2022 // Emit the instruction at pc_. | 2077 // Emit the instruction at pc_. |
2023 void Emit(Instr instruction) { | 2078 void Emit(Instr instruction) { |
2024 STATIC_ASSERT(sizeof(*pc_) == 1); | 2079 STATIC_ASSERT(sizeof(*pc_) == 1); |
2025 STATIC_ASSERT(sizeof(instruction) == kInstructionSize); | 2080 STATIC_ASSERT(sizeof(instruction) == kInstructionSize); |
2026 ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_)); | 2081 ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_)); |
2027 | 2082 |
2028 memcpy(pc_, &instruction, sizeof(instruction)); | 2083 memcpy(pc_, &instruction, sizeof(instruction)); |
2029 pc_ += sizeof(instruction); | 2084 pc_ += sizeof(instruction); |
2030 CheckBuffer(); | 2085 CheckBuffer(); |
2031 } | 2086 } |
(...skipping 11 matching lines...) Expand all Loading... |
2043 } | 2098 } |
2044 | 2099 |
2045 void GrowBuffer(); | 2100 void GrowBuffer(); |
2046 void CheckBufferSpace(); | 2101 void CheckBufferSpace(); |
2047 void CheckBuffer(); | 2102 void CheckBuffer(); |
2048 | 2103 |
2049 // Pc offset of the next constant pool check. | 2104 // Pc offset of the next constant pool check. |
2050 int next_constant_pool_check_; | 2105 int next_constant_pool_check_; |
2051 | 2106 |
2052 // Constant pool generation | 2107 // Constant pool generation |
2053 // Pools are emitted in the instruction stream, preferably after unconditional | 2108 // Pools are emitted in the instruction stream. They are emitted when: |
2054 // jumps or after returns from functions (in dead code locations). | 2109 // * the distance to the first use is above a pre-defined distance or |
2055 // If a long code sequence does not contain unconditional jumps, it is | 2110 // * the numbers of entries in the pool is above a pre-defined size or |
2056 // necessary to emit the constant pool before the pool gets too far from the | 2111 // * code generation is finished |
2057 // location it is accessed from. In this case, we emit a jump over the emitted | 2112 // If a pool needs to be emitted before code generation is finished a branch |
2058 // constant pool. | 2113 // over the emitted pool will be inserted. |
| 2114 |
2059 // Constants in the pool may be addresses of functions that gets relocated; | 2115 // Constants in the pool may be addresses of functions that gets relocated; |
2060 // if so, a relocation info entry is associated to the constant pool entry. | 2116 // if so, a relocation info entry is associated to the constant pool entry. |
2061 | 2117 |
2062 // Repeated checking whether the constant pool should be emitted is rather | 2118 // Repeated checking whether the constant pool should be emitted is rather |
2063 // expensive. By default we only check again once a number of instructions | 2119 // expensive. By default we only check again once a number of instructions |
2064 // has been generated. That also means that the sizing of the buffers is not | 2120 // has been generated. That also means that the sizing of the buffers is not |
2065 // an exact science, and that we rely on some slop to not overrun buffers. | 2121 // an exact science, and that we rely on some slop to not overrun buffers. |
2066 static const int kCheckConstPoolIntervalInst = 128; | 2122 static const int kCheckConstPoolInterval = 128; |
2067 static const int kCheckConstPoolInterval = | |
2068 kCheckConstPoolIntervalInst * kInstructionSize; | |
2069 | 2123 |
2070 // Constants in pools are accessed via pc relative addressing, which can | 2124 // Distance to first use after a which a pool will be emitted. Pool entries |
2071 // reach +/-4KB thereby defining a maximum distance between the instruction | 2125 // are accessed with pc relative load therefore this cannot be more than |
2072 // and the accessed constant. | 2126 // 1 * MB. Since constant pool emission checks are interval based this value |
2073 static const int kMaxDistToConstPool = 4 * KB; | 2127 // is an approximation. |
2074 static const int kMaxNumPendingRelocInfo = | 2128 static const int kApproxMaxDistToConstPool = 64 * KB; |
2075 kMaxDistToConstPool / kInstructionSize; | |
2076 | 2129 |
2077 | 2130 // Number of pool entries after which a pool will be emitted. Since constant |
2078 // Average distance beetween a constant pool and the first instruction | 2131 // pool emission checks are interval based this value is an approximation. |
2079 // accessing the constant pool. Longer distance should result in less I-cache | 2132 static const int kApproxMaxPoolEntryCount = 512; |
2080 // pollution. | |
2081 // In practice the distance will be smaller since constant pool emission is | |
2082 // forced after function return and sometimes after unconditional branches. | |
2083 static const int kAvgDistToConstPool = | |
2084 kMaxDistToConstPool - kCheckConstPoolInterval; | |
2085 | 2133 |
2086 // Emission of the constant pool may be blocked in some code sequences. | 2134 // Emission of the constant pool may be blocked in some code sequences. |
2087 int const_pool_blocked_nesting_; // Block emission if this is not zero. | 2135 int const_pool_blocked_nesting_; // Block emission if this is not zero. |
2088 int no_const_pool_before_; // Block emission before this pc offset. | 2136 int no_const_pool_before_; // Block emission before this pc offset. |
2089 | 2137 |
2090 // Keep track of the first instruction requiring a constant pool entry | |
2091 // since the previous constant pool was emitted. | |
2092 int first_const_pool_use_; | |
2093 | |
2094 // Emission of the veneer pools may be blocked in some code sequences. | 2138 // Emission of the veneer pools may be blocked in some code sequences. |
2095 int veneer_pool_blocked_nesting_; // Block emission if this is not zero. | 2139 int veneer_pool_blocked_nesting_; // Block emission if this is not zero. |
2096 | 2140 |
2097 // Relocation info generation | 2141 // Relocation info generation |
2098 // Each relocation is encoded as a variable size value | 2142 // Each relocation is encoded as a variable size value |
2099 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 2143 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
2100 RelocInfoWriter reloc_info_writer; | 2144 RelocInfoWriter reloc_info_writer; |
2101 | 2145 |
2102 // Relocation info records are also used during code generation as temporary | 2146 // Relocation info records are also used during code generation as temporary |
2103 // containers for constants and code target addresses until they are emitted | 2147 // containers for constants and code target addresses until they are emitted |
2104 // to the constant pool. These pending relocation info records are temporarily | 2148 // to the constant pool. These pending relocation info records are temporarily |
2105 // stored in a separate buffer until a constant pool is emitted. | 2149 // stored in a separate buffer until a constant pool is emitted. |
2106 // If every instruction in a long sequence is accessing the pool, we need one | 2150 // If every instruction in a long sequence is accessing the pool, we need one |
2107 // pending relocation entry per instruction. | 2151 // pending relocation entry per instruction. |
2108 | 2152 |
2109 // the buffer of pending relocation info | 2153 // The pending constant pool. |
2110 RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo]; | 2154 ConstPool constpool_; |
2111 // number of pending reloc info entries in the buffer | |
2112 int num_pending_reloc_info_; | |
2113 | 2155 |
2114 // Relocation for a type-recording IC has the AST id added to it. This | 2156 // Relocation for a type-recording IC has the AST id added to it. This |
2115 // member variable is a way to pass the information from the call site to | 2157 // member variable is a way to pass the information from the call site to |
2116 // the relocation info. | 2158 // the relocation info. |
2117 TypeFeedbackId recorded_ast_id_; | 2159 TypeFeedbackId recorded_ast_id_; |
2118 | 2160 |
2119 inline TypeFeedbackId RecordedAstId(); | 2161 inline TypeFeedbackId RecordedAstId(); |
2120 inline void ClearRecordedAstId(); | 2162 inline void ClearRecordedAstId(); |
2121 | 2163 |
2122 protected: | 2164 protected: |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2189 // This function deletes the information related to the label by traversing | 2231 // This function deletes the information related to the label by traversing |
2190 // the label chain, and for each PC-relative instruction in the chain checking | 2232 // the label chain, and for each PC-relative instruction in the chain checking |
2191 // if pending unresolved information exists. Its complexity is proportional to | 2233 // if pending unresolved information exists. Its complexity is proportional to |
2192 // the length of the label chain. | 2234 // the length of the label chain. |
2193 void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label); | 2235 void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label); |
2194 | 2236 |
2195 private: | 2237 private: |
2196 PositionsRecorder positions_recorder_; | 2238 PositionsRecorder positions_recorder_; |
2197 friend class PositionsRecorder; | 2239 friend class PositionsRecorder; |
2198 friend class EnsureSpace; | 2240 friend class EnsureSpace; |
| 2241 friend class ConstPool; |
2199 }; | 2242 }; |
2200 | 2243 |
2201 class PatchingAssembler : public Assembler { | 2244 class PatchingAssembler : public Assembler { |
2202 public: | 2245 public: |
2203 // Create an Assembler with a buffer starting at 'start'. | 2246 // Create an Assembler with a buffer starting at 'start'. |
2204 // The buffer size is | 2247 // The buffer size is |
2205 // size of instructions to patch + kGap | 2248 // size of instructions to patch + kGap |
2206 // Where kGap is the distance from which the Assembler tries to grow the | 2249 // Where kGap is the distance from which the Assembler tries to grow the |
2207 // buffer. | 2250 // buffer. |
2208 // If more or fewer instructions than expected are generated or if some | 2251 // If more or fewer instructions than expected are generated or if some |
(...skipping 12 matching lines...) Expand all Loading... |
2221 StartBlockPools(); | 2264 StartBlockPools(); |
2222 } | 2265 } |
2223 | 2266 |
2224 ~PatchingAssembler() { | 2267 ~PatchingAssembler() { |
2225 // Const pool should still be blocked. | 2268 // Const pool should still be blocked. |
2226 ASSERT(is_const_pool_blocked()); | 2269 ASSERT(is_const_pool_blocked()); |
2227 EndBlockPools(); | 2270 EndBlockPools(); |
2228 // Verify we have generated the number of instruction we expected. | 2271 // Verify we have generated the number of instruction we expected. |
2229 ASSERT((pc_offset() + kGap) == buffer_size_); | 2272 ASSERT((pc_offset() + kGap) == buffer_size_); |
2230 // Verify no relocation information has been emitted. | 2273 // Verify no relocation information has been emitted. |
2231 ASSERT(num_pending_reloc_info() == 0); | 2274 ASSERT(IsConstPoolEmpty()); |
2232 // Flush the Instruction cache. | 2275 // Flush the Instruction cache. |
2233 size_t length = buffer_size_ - kGap; | 2276 size_t length = buffer_size_ - kGap; |
2234 CPU::FlushICache(buffer_, length); | 2277 CPU::FlushICache(buffer_, length); |
2235 } | 2278 } |
2236 | 2279 |
2237 static const int kMovInt64NInstrs = 4; | 2280 static const int kMovInt64NInstrs = 4; |
2238 void MovInt64(const Register& rd, int64_t imm); | 2281 void MovInt64(const Register& rd, int64_t imm); |
2239 | 2282 |
2240 // See definition of PatchAdrFar() for details. | 2283 // See definition of PatchAdrFar() for details. |
2241 static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1; | 2284 static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1; |
2242 static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3; | 2285 static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3; |
2243 void PatchAdrFar(Instruction* target); | 2286 void PatchAdrFar(Instruction* target); |
2244 }; | 2287 }; |
2245 | 2288 |
2246 | 2289 |
2247 class EnsureSpace BASE_EMBEDDED { | 2290 class EnsureSpace BASE_EMBEDDED { |
2248 public: | 2291 public: |
2249 explicit EnsureSpace(Assembler* assembler) { | 2292 explicit EnsureSpace(Assembler* assembler) { |
2250 assembler->CheckBufferSpace(); | 2293 assembler->CheckBufferSpace(); |
2251 } | 2294 } |
2252 }; | 2295 }; |
2253 | 2296 |
2254 } } // namespace v8::internal | 2297 } } // namespace v8::internal |
2255 | 2298 |
2256 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ | 2299 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ |
OLD | NEW |