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 void Emit(bool require_jump); | |
rmcilroy
2014/06/17 13:09:57
comments on Emit and Clear please
Rodolph Perfetta (ARM)
2014/06/18 16:53:23
Done.
| |
769 void Clear(); | |
770 | |
771 private: | |
772 bool CanBeShared(RelocInfo::Mode mode); | |
773 void EmitMarker(); | |
774 void EmitGuard(); | |
775 void EmitEntries(); | |
776 | |
777 Assembler* assm_; | |
778 // Keep track of the first instruction requiring a constant pool entry | |
779 // since the previous constant pool was emitted. | |
780 int first_use_; | |
781 // values, pc offset(s) of entries which can be shared. | |
782 std::multimap<uint64_t, int> shared_entries_; | |
783 // Number of distinct literal in shared entries. | |
784 int shared_entries_count; | |
785 // values, pc offset of entries which cannot be shared. | |
786 std::vector<std::pair<uint64_t, int> > unique_entries_; | |
787 }; | |
788 | |
789 | |
743 // ----------------------------------------------------------------------------- | 790 // ----------------------------------------------------------------------------- |
744 // Assembler. | 791 // Assembler. |
745 | 792 |
746 class Assembler : public AssemblerBase { | 793 class Assembler : public AssemblerBase { |
747 public: | 794 public: |
748 // Create an assembler. Instructions and relocation information are emitted | 795 // Create an assembler. Instructions and relocation information are emitted |
749 // into a buffer, with the instructions starting from the beginning and the | 796 // into a buffer, with the instructions starting from the beginning and the |
750 // relocation information starting from the end of the buffer. See CodeDesc | 797 // relocation information starting from the end of the buffer. See CodeDesc |
751 // for a detailed comment on the layout (globals.h). | 798 // for a detailed comment on the layout (globals.h). |
752 // | 799 // |
753 // If the provided buffer is NULL, the assembler allocates and grows its own | 800 // 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 | 801 // buffer, and buffer_size determines the initial buffer size. The buffer is |
755 // owned by the assembler and deallocated upon destruction of the assembler. | 802 // owned by the assembler and deallocated upon destruction of the assembler. |
756 // | 803 // |
757 // If the provided buffer is not NULL, the assembler uses the provided buffer | 804 // 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 | 805 // 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 | 806 // is too small, a fatal error occurs. No deallocation of the buffer is done |
760 // upon destruction of the assembler. | 807 // upon destruction of the assembler. |
761 Assembler(Isolate* arg_isolate, void* buffer, int buffer_size); | 808 Assembler(Isolate* arg_isolate, void* buffer, int buffer_size); |
762 | 809 |
763 virtual ~Assembler(); | 810 virtual ~Assembler(); |
764 | 811 |
765 virtual void AbortedCodeGeneration() { | 812 virtual void AbortedCodeGeneration() { |
766 num_pending_reloc_info_ = 0; | 813 constpool_.Clear(); |
767 } | 814 } |
768 | 815 |
769 // System functions --------------------------------------------------------- | 816 // System functions --------------------------------------------------------- |
770 // Start generating code from the beginning of the buffer, discarding any code | 817 // Start generating code from the beginning of the buffer, discarding any code |
771 // and data that has already been emitted into the buffer. | 818 // and data that has already been emitted into the buffer. |
772 // | 819 // |
773 // In order to avoid any accidental transfer of state, Reset ASSERTs that the | 820 // In order to avoid any accidental transfer of state, Reset ASSERTs that the |
774 // constant pool is not blocked. | 821 // constant pool is not blocked. |
775 void Reset(); | 822 void Reset(); |
776 | 823 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
905 void StartBlockConstPool(); | 952 void StartBlockConstPool(); |
906 | 953 |
907 // Resume constant pool emission. Need to be called as many time as | 954 // Resume constant pool emission. Need to be called as many time as |
908 // StartBlockConstPool to have an effect. | 955 // StartBlockConstPool to have an effect. |
909 void EndBlockConstPool(); | 956 void EndBlockConstPool(); |
910 | 957 |
911 bool is_const_pool_blocked() const; | 958 bool is_const_pool_blocked() const; |
912 static bool IsConstantPoolAt(Instruction* instr); | 959 static bool IsConstantPoolAt(Instruction* instr); |
913 static int ConstantPoolSizeAt(Instruction* instr); | 960 static int ConstantPoolSizeAt(Instruction* instr); |
914 // See Assembler::CheckConstPool for more info. | 961 // See Assembler::CheckConstPool for more info. |
915 void ConstantPoolMarker(uint32_t size); | |
916 void EmitPoolGuard(); | 962 void EmitPoolGuard(); |
917 void ConstantPoolGuard(); | |
918 | 963 |
919 // Prevent veneer pool emission until EndBlockVeneerPool is called. | 964 // Prevent veneer pool emission until EndBlockVeneerPool is called. |
920 // Call to this function can be nested but must be followed by an equal | 965 // Call to this function can be nested but must be followed by an equal |
921 // number of call to EndBlockConstpool. | 966 // number of call to EndBlockConstpool. |
922 void StartBlockVeneerPool(); | 967 void StartBlockVeneerPool(); |
923 | 968 |
924 // Resume constant pool emission. Need to be called as many time as | 969 // Resume constant pool emission. Need to be called as many time as |
925 // StartBlockVeneerPool to have an effect. | 970 // StartBlockVeneerPool to have an effect. |
926 void EndBlockVeneerPool(); | 971 void EndBlockVeneerPool(); |
927 | 972 |
(...skipping 760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1688 | 1733 |
1689 // Parameters are described in arm64/instructions-arm64.h. | 1734 // Parameters are described in arm64/instructions-arm64.h. |
1690 void debug(const char* message, uint32_t code, Instr params = BREAK); | 1735 void debug(const char* message, uint32_t code, Instr params = BREAK); |
1691 | 1736 |
1692 // Required by V8. | 1737 // Required by V8. |
1693 void dd(uint32_t data) { dc32(data); } | 1738 void dd(uint32_t data) { dc32(data); } |
1694 void db(uint8_t data) { dc8(data); } | 1739 void db(uint8_t data) { dc8(data); } |
1695 | 1740 |
1696 // Code generation helpers -------------------------------------------------- | 1741 // Code generation helpers -------------------------------------------------- |
1697 | 1742 |
1698 unsigned num_pending_reloc_info() const { return num_pending_reloc_info_; } | 1743 bool IsConstPoolEmpty() const { return constpool_.IsEmpty(); } |
1744 | |
1745 Instruction* pc() const { return Instruction::Cast(pc_); } | |
1699 | 1746 |
1700 Instruction* InstructionAt(int offset) const { | 1747 Instruction* InstructionAt(int offset) const { |
1701 return reinterpret_cast<Instruction*>(buffer_ + offset); | 1748 return reinterpret_cast<Instruction*>(buffer_ + offset); |
1702 } | 1749 } |
1703 | 1750 |
1704 ptrdiff_t InstructionOffset(Instruction* instr) const { | 1751 ptrdiff_t InstructionOffset(Instruction* instr) const { |
1705 return reinterpret_cast<byte*>(instr) - buffer_; | 1752 return reinterpret_cast<byte*>(instr) - buffer_; |
1706 } | 1753 } |
1707 | 1754 |
1708 // Register encoding. | 1755 // Register encoding. |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2043 } | 2090 } |
2044 | 2091 |
2045 void GrowBuffer(); | 2092 void GrowBuffer(); |
2046 void CheckBufferSpace(); | 2093 void CheckBufferSpace(); |
2047 void CheckBuffer(); | 2094 void CheckBuffer(); |
2048 | 2095 |
2049 // Pc offset of the next constant pool check. | 2096 // Pc offset of the next constant pool check. |
2050 int next_constant_pool_check_; | 2097 int next_constant_pool_check_; |
2051 | 2098 |
2052 // Constant pool generation | 2099 // Constant pool generation |
2053 // Pools are emitted in the instruction stream, preferably after unconditional | 2100 // Pools are emitted in the instruction stream. They are emitted when: |
2054 // jumps or after returns from functions (in dead code locations). | 2101 // * 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 | 2102 // * 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 | 2103 // * code generation is finished |
rmcilroy
2014/06/17 13:09:57
Is it no longer the case that they are emitted in
Rodolph Perfetta (ARM)
2014/06/18 16:53:23
No we no longer emit in dead code location. On ARM
rmcilroy
2014/06/19 09:58:16
Interesting. Sounds good in that case.
| |
2057 // location it is accessed from. In this case, we emit a jump over the emitted | 2104 // If a pool needs to be emitted before code generation is finished a branch |
2058 // constant pool. | 2105 // over the emitted pool will be inserted. |
2106 | |
2059 // Constants in the pool may be addresses of functions that gets relocated; | 2107 // 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. | 2108 // if so, a relocation info entry is associated to the constant pool entry. |
2061 | 2109 |
2062 // Repeated checking whether the constant pool should be emitted is rather | 2110 // Repeated checking whether the constant pool should be emitted is rather |
2063 // expensive. By default we only check again once a number of instructions | 2111 // 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 | 2112 // 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. | 2113 // an exact science, and that we rely on some slop to not overrun buffers. |
2066 static const int kCheckConstPoolIntervalInst = 128; | 2114 static const int kCheckConstPoolIntervalInst = 128; |
2067 static const int kCheckConstPoolInterval = | 2115 static const int kCheckConstPoolInterval = |
2068 kCheckConstPoolIntervalInst * kInstructionSize; | 2116 kCheckConstPoolIntervalInst * kInstructionSize; |
2069 | 2117 |
2070 // Constants in pools are accessed via pc relative addressing, which can | 2118 // 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 | 2119 // are accessed with pc relative load therefore this cannot be more than |
2072 // and the accessed constant. | 2120 // 1 * MB. Since constant pool emission checks are interval based this value |
2073 static const int kMaxDistToConstPool = 4 * KB; | 2121 // is an approximation. |
2074 static const int kMaxNumPendingRelocInfo = | 2122 static const int kApproximateDistToConstPool = 64 * KB; |
rmcilroy
2014/06/17 13:09:57
How about kApproxMaxDistToConstPool?
Rodolph Perfetta (ARM)
2014/06/18 16:53:23
Done.
| |
2075 kMaxDistToConstPool / kInstructionSize; | |
2076 | 2123 |
2077 | 2124 // Number of pool entries after which a pool will be emitted. Since constant |
2078 // Average distance beetween a constant pool and the first instruction | 2125 // pool emission checks are interval based this value is an approximation. |
2079 // accessing the constant pool. Longer distance should result in less I-cache | 2126 static const int kApproximatePoolEntryCount = 512; |
rmcilroy
2014/06/17 13:09:57
kApproxMaxPoolEntryCount?
Rodolph Perfetta (ARM)
2014/06/18 16:53:23
Done.
| |
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 | 2127 |
2086 // Emission of the constant pool may be blocked in some code sequences. | 2128 // 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. | 2129 int const_pool_blocked_nesting_; // Block emission if this is not zero. |
2088 int no_const_pool_before_; // Block emission before this pc offset. | 2130 int no_const_pool_before_; // Block emission before this pc offset. |
2089 | 2131 |
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. | 2132 // 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. | 2133 int veneer_pool_blocked_nesting_; // Block emission if this is not zero. |
2096 | 2134 |
2097 // Relocation info generation | 2135 // Relocation info generation |
2098 // Each relocation is encoded as a variable size value | 2136 // Each relocation is encoded as a variable size value |
2099 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 2137 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
2100 RelocInfoWriter reloc_info_writer; | 2138 RelocInfoWriter reloc_info_writer; |
2101 | 2139 |
2102 // Relocation info records are also used during code generation as temporary | 2140 // Relocation info records are also used during code generation as temporary |
2103 // containers for constants and code target addresses until they are emitted | 2141 // containers for constants and code target addresses until they are emitted |
2104 // to the constant pool. These pending relocation info records are temporarily | 2142 // to the constant pool. These pending relocation info records are temporarily |
2105 // stored in a separate buffer until a constant pool is emitted. | 2143 // 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 | 2144 // If every instruction in a long sequence is accessing the pool, we need one |
2107 // pending relocation entry per instruction. | 2145 // pending relocation entry per instruction. |
2108 | 2146 |
2109 // the buffer of pending relocation info | 2147 // The pending constant pool. |
2110 RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo]; | 2148 ConstPool constpool_; |
2111 // number of pending reloc info entries in the buffer | |
2112 int num_pending_reloc_info_; | |
2113 | 2149 |
2114 // Relocation for a type-recording IC has the AST id added to it. This | 2150 // 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 | 2151 // member variable is a way to pass the information from the call site to |
2116 // the relocation info. | 2152 // the relocation info. |
2117 TypeFeedbackId recorded_ast_id_; | 2153 TypeFeedbackId recorded_ast_id_; |
2118 | 2154 |
2119 inline TypeFeedbackId RecordedAstId(); | 2155 inline TypeFeedbackId RecordedAstId(); |
2120 inline void ClearRecordedAstId(); | 2156 inline void ClearRecordedAstId(); |
2121 | 2157 |
2122 protected: | 2158 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 | 2225 // 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 | 2226 // the label chain, and for each PC-relative instruction in the chain checking |
2191 // if pending unresolved information exists. Its complexity is proportional to | 2227 // if pending unresolved information exists. Its complexity is proportional to |
2192 // the length of the label chain. | 2228 // the length of the label chain. |
2193 void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label); | 2229 void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label); |
2194 | 2230 |
2195 private: | 2231 private: |
2196 PositionsRecorder positions_recorder_; | 2232 PositionsRecorder positions_recorder_; |
2197 friend class PositionsRecorder; | 2233 friend class PositionsRecorder; |
2198 friend class EnsureSpace; | 2234 friend class EnsureSpace; |
2235 friend class ConstPool; | |
2199 }; | 2236 }; |
2200 | 2237 |
2201 class PatchingAssembler : public Assembler { | 2238 class PatchingAssembler : public Assembler { |
2202 public: | 2239 public: |
2203 // Create an Assembler with a buffer starting at 'start'. | 2240 // Create an Assembler with a buffer starting at 'start'. |
2204 // The buffer size is | 2241 // The buffer size is |
2205 // size of instructions to patch + kGap | 2242 // size of instructions to patch + kGap |
2206 // Where kGap is the distance from which the Assembler tries to grow the | 2243 // Where kGap is the distance from which the Assembler tries to grow the |
2207 // buffer. | 2244 // buffer. |
2208 // If more or fewer instructions than expected are generated or if some | 2245 // If more or fewer instructions than expected are generated or if some |
(...skipping 12 matching lines...) Expand all Loading... | |
2221 StartBlockPools(); | 2258 StartBlockPools(); |
2222 } | 2259 } |
2223 | 2260 |
2224 ~PatchingAssembler() { | 2261 ~PatchingAssembler() { |
2225 // Const pool should still be blocked. | 2262 // Const pool should still be blocked. |
2226 ASSERT(is_const_pool_blocked()); | 2263 ASSERT(is_const_pool_blocked()); |
2227 EndBlockPools(); | 2264 EndBlockPools(); |
2228 // Verify we have generated the number of instruction we expected. | 2265 // Verify we have generated the number of instruction we expected. |
2229 ASSERT((pc_offset() + kGap) == buffer_size_); | 2266 ASSERT((pc_offset() + kGap) == buffer_size_); |
2230 // Verify no relocation information has been emitted. | 2267 // Verify no relocation information has been emitted. |
2231 ASSERT(num_pending_reloc_info() == 0); | 2268 ASSERT(IsConstPoolEmpty()); |
2232 // Flush the Instruction cache. | 2269 // Flush the Instruction cache. |
2233 size_t length = buffer_size_ - kGap; | 2270 size_t length = buffer_size_ - kGap; |
2234 CPU::FlushICache(buffer_, length); | 2271 CPU::FlushICache(buffer_, length); |
2235 } | 2272 } |
2236 | 2273 |
2237 static const int kMovInt64NInstrs = 4; | 2274 static const int kMovInt64NInstrs = 4; |
2238 void MovInt64(const Register& rd, int64_t imm); | 2275 void MovInt64(const Register& rd, int64_t imm); |
2239 | 2276 |
2240 // See definition of PatchAdrFar() for details. | 2277 // See definition of PatchAdrFar() for details. |
2241 static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1; | 2278 static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1; |
2242 static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3; | 2279 static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3; |
2243 void PatchAdrFar(Instruction* target); | 2280 void PatchAdrFar(Instruction* target); |
2244 }; | 2281 }; |
2245 | 2282 |
2246 | 2283 |
2247 class EnsureSpace BASE_EMBEDDED { | 2284 class EnsureSpace BASE_EMBEDDED { |
2248 public: | 2285 public: |
2249 explicit EnsureSpace(Assembler* assembler) { | 2286 explicit EnsureSpace(Assembler* assembler) { |
2250 assembler->CheckBufferSpace(); | 2287 assembler->CheckBufferSpace(); |
2251 } | 2288 } |
2252 }; | 2289 }; |
2253 | 2290 |
2254 } } // namespace v8::internal | 2291 } } // namespace v8::internal |
2255 | 2292 |
2256 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ | 2293 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ |
OLD | NEW |