/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CodeGen/CGBlocks.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This is the internal state used for llvm translation for block literals. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H |
14 | | #define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H |
15 | | |
16 | | #include "CGBuilder.h" |
17 | | #include "CGCall.h" |
18 | | #include "CGValue.h" |
19 | | #include "CodeGenFunction.h" |
20 | | #include "CodeGenTypes.h" |
21 | | #include "clang/AST/CharUnits.h" |
22 | | #include "clang/AST/Expr.h" |
23 | | #include "clang/AST/ExprCXX.h" |
24 | | #include "clang/AST/ExprObjC.h" |
25 | | #include "clang/AST/Type.h" |
26 | | #include "clang/Basic/TargetInfo.h" |
27 | | |
28 | | namespace llvm { |
29 | | class Value; |
30 | | } |
31 | | |
32 | | namespace clang { |
33 | | namespace CodeGen { |
34 | | |
35 | | class CGBlockInfo; |
36 | | |
37 | | // Flags stored in __block variables. |
38 | | enum BlockByrefFlags { |
39 | | BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler |
40 | | BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler |
41 | | BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28), |
42 | | BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28), |
43 | | BLOCK_BYREF_LAYOUT_STRONG = (3 << 28), |
44 | | BLOCK_BYREF_LAYOUT_WEAK = (4 << 28), |
45 | | BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28) |
46 | | }; |
47 | | |
48 | | enum BlockLiteralFlags { |
49 | | BLOCK_IS_NOESCAPE = (1 << 23), |
50 | | BLOCK_HAS_COPY_DISPOSE = (1 << 25), |
51 | | BLOCK_HAS_CXX_OBJ = (1 << 26), |
52 | | BLOCK_IS_GLOBAL = (1 << 28), |
53 | | BLOCK_USE_STRET = (1 << 29), |
54 | | BLOCK_HAS_SIGNATURE = (1 << 30), |
55 | | BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31) |
56 | | }; |
57 | | class BlockFlags { |
58 | | uint32_t flags; |
59 | | |
60 | | public: |
61 | 344 | BlockFlags(uint32_t flags) : flags(flags) {} |
62 | 980 | BlockFlags() : flags(0) {} |
63 | 2.34k | BlockFlags(BlockLiteralFlags flag) : flags(flag) {} |
64 | 313 | BlockFlags(BlockByrefFlags flag) : flags(flag) {} |
65 | | |
66 | 1.30k | uint32_t getBitMask() const { return flags; } |
67 | 0 | bool empty() const { return flags == 0; } |
68 | | |
69 | 324 | friend BlockFlags operator|(BlockFlags l, BlockFlags r) { |
70 | 324 | return BlockFlags(l.flags | r.flags); |
71 | 324 | } |
72 | 1.14k | friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) { |
73 | 1.14k | l.flags |= r.flags; |
74 | 1.14k | return l; |
75 | 1.14k | } |
76 | 40 | friend bool operator&(BlockFlags l, BlockFlags r) { |
77 | 40 | return (l.flags & r.flags); |
78 | 40 | } |
79 | 100 | bool operator==(BlockFlags r) { |
80 | 100 | return (flags == r.flags); |
81 | 100 | } |
82 | | }; |
83 | 324 | inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) { |
84 | 324 | return BlockFlags(l) | BlockFlags(r); |
85 | 324 | } |
86 | | |
87 | | enum BlockFieldFlag_t { |
88 | | BLOCK_FIELD_IS_OBJECT = 0x03, /* id, NSObject, __attribute__((NSObject)), |
89 | | block, ... */ |
90 | | BLOCK_FIELD_IS_BLOCK = 0x07, /* a block variable */ |
91 | | |
92 | | BLOCK_FIELD_IS_BYREF = 0x08, /* the on stack structure holding the __block |
93 | | variable */ |
94 | | BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy |
95 | | helpers */ |
96 | | BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */ |
97 | | BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose |
98 | | support routines */ |
99 | | BLOCK_BYREF_CURRENT_MAX = 256 |
100 | | }; |
101 | | |
102 | | class BlockFieldFlags { |
103 | | uint32_t flags; |
104 | | |
105 | 36 | BlockFieldFlags(uint32_t flags) : flags(flags) {} |
106 | | public: |
107 | 16.8k | BlockFieldFlags() : flags(0) {} |
108 | 3.28k | BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {} |
109 | | |
110 | 1.92k | uint32_t getBitMask() const { return flags; } |
111 | 0 | bool empty() const { return flags == 0; } |
112 | | |
113 | | /// Answers whether the flags indicate that this field is an object |
114 | | /// or block pointer that requires _Block_object_assign/dispose. |
115 | 0 | bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; } |
116 | | |
117 | 36 | friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) { |
118 | 36 | return BlockFieldFlags(l.flags | r.flags); |
119 | 36 | } |
120 | 52 | friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) { |
121 | 52 | l.flags |= r.flags; |
122 | 52 | return l; |
123 | 52 | } |
124 | 0 | friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) { |
125 | 0 | return (l.flags & r.flags); |
126 | 0 | } |
127 | 502 | bool operator==(BlockFieldFlags Other) const { |
128 | 502 | return flags == Other.flags; |
129 | 502 | } |
130 | | }; |
131 | 0 | inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) { |
132 | 0 | return BlockFieldFlags(l) | BlockFieldFlags(r); |
133 | 0 | } |
134 | | |
135 | | /// Information about the layout of a __block variable. |
136 | | class BlockByrefInfo { |
137 | | public: |
138 | | llvm::StructType *Type; |
139 | | unsigned FieldIndex; |
140 | | CharUnits ByrefAlignment; |
141 | | CharUnits FieldOffset; |
142 | | }; |
143 | | |
144 | | /// Represents a type of copy/destroy operation that should be performed for an |
145 | | /// entity that's captured by a block. |
146 | | enum class BlockCaptureEntityKind { |
147 | | None, |
148 | | CXXRecord, // Copy or destroy |
149 | | ARCWeak, |
150 | | ARCStrong, |
151 | | NonTrivialCStruct, |
152 | | BlockObject, // Assign or release |
153 | | }; |
154 | | |
155 | | /// CGBlockInfo - Information to generate a block literal. |
156 | | class CGBlockInfo { |
157 | | public: |
158 | | /// Name - The name of the block, kindof. |
159 | | StringRef Name; |
160 | | |
161 | | /// The field index of 'this' within the block, if there is one. |
162 | | unsigned CXXThisIndex; |
163 | | |
164 | | class Capture { |
165 | | uintptr_t Data; |
166 | | EHScopeStack::stable_iterator Cleanup; |
167 | | CharUnits::QuantityType Offset; |
168 | | |
169 | | /// Type of the capture field. Normally, this is identical to the type of |
170 | | /// the capture's VarDecl, but can be different if there is an enclosing |
171 | | /// lambda. |
172 | | QualType FieldType; |
173 | | |
174 | | public: |
175 | 27.7k | bool isIndex() const { return (Data & 1) != 0; } |
176 | 13.4k | bool isConstant() const { return !isIndex(); } |
177 | | |
178 | 12.2k | unsigned getIndex() const { |
179 | 12.2k | assert(isIndex()); |
180 | 0 | return Data >> 1; |
181 | 12.2k | } |
182 | 1.95k | CharUnits getOffset() const { |
183 | 1.95k | assert(isIndex()); |
184 | 0 | return CharUnits::fromQuantity(Offset); |
185 | 1.95k | } |
186 | 0 | EHScopeStack::stable_iterator getCleanup() const { |
187 | 0 | assert(isIndex()); |
188 | 0 | return Cleanup; |
189 | 0 | } |
190 | 0 | void setCleanup(EHScopeStack::stable_iterator cleanup) { |
191 | 0 | assert(isIndex()); |
192 | 0 | Cleanup = cleanup; |
193 | 0 | } |
194 | | |
195 | 5 | llvm::Value *getConstant() const { |
196 | 5 | assert(isConstant()); |
197 | 0 | return reinterpret_cast<llvm::Value*>(Data); |
198 | 5 | } |
199 | | |
200 | 8.63k | QualType fieldType() const { |
201 | 8.63k | return FieldType; |
202 | 8.63k | } |
203 | | |
204 | | static Capture |
205 | | makeIndex(unsigned index, CharUnits offset, QualType FieldType, |
206 | | BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags, |
207 | | BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags, |
208 | 2.31k | const BlockDecl::Capture *Cap) { |
209 | 2.31k | Capture v; |
210 | 2.31k | v.Data = (index << 1) | 1; |
211 | 2.31k | v.Offset = offset.getQuantity(); |
212 | 2.31k | v.FieldType = FieldType; |
213 | 2.31k | v.CopyKind = CopyKind; |
214 | 2.31k | v.CopyFlags = CopyFlags; |
215 | 2.31k | v.DisposeKind = DisposeKind; |
216 | 2.31k | v.DisposeFlags = DisposeFlags; |
217 | 2.31k | v.Cap = Cap; |
218 | 2.31k | return v; |
219 | 2.31k | } |
220 | | |
221 | | static Capture makeConstant(llvm::Value *value, |
222 | 5 | const BlockDecl::Capture *Cap) { |
223 | 5 | Capture v; |
224 | 5 | v.Data = reinterpret_cast<uintptr_t>(value); |
225 | 5 | v.Cap = Cap; |
226 | 5 | return v; |
227 | 5 | } |
228 | | |
229 | 7.55k | bool isConstantOrTrivial() const { |
230 | 7.55k | return CopyKind == BlockCaptureEntityKind::None && |
231 | 7.55k | DisposeKind == BlockCaptureEntityKind::None4.77k ; |
232 | 7.55k | } |
233 | | |
234 | | BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None, |
235 | | DisposeKind = BlockCaptureEntityKind::None; |
236 | | BlockFieldFlags CopyFlags, DisposeFlags; |
237 | | const BlockDecl::Capture *Cap; |
238 | | }; |
239 | | |
240 | | /// CanBeGlobal - True if the block can be global, i.e. it has |
241 | | /// no non-constant captures. |
242 | | bool CanBeGlobal : 1; |
243 | | |
244 | | /// True if the block has captures that would necessitate custom copy or |
245 | | /// dispose helper functions if the block were escaping. |
246 | | bool NeedsCopyDispose : 1; |
247 | | |
248 | | /// Indicates whether the block is non-escaping. |
249 | | bool NoEscape : 1; |
250 | | |
251 | | /// HasCXXObject - True if the block's custom copy/dispose functions |
252 | | /// need to be run even in GC mode. |
253 | | bool HasCXXObject : 1; |
254 | | |
255 | | /// UsesStret : True if the block uses an stret return. Mutable |
256 | | /// because it gets set later in the block-creation process. |
257 | | mutable bool UsesStret : 1; |
258 | | |
259 | | /// HasCapturedVariableLayout : True if block has captured variables |
260 | | /// and their layout meta-data has been generated. |
261 | | bool HasCapturedVariableLayout : 1; |
262 | | |
263 | | /// Indicates whether an object of a non-external C++ class is captured. This |
264 | | /// bit is used to determine the linkage of the block copy/destroy helper |
265 | | /// functions. |
266 | | bool CapturesNonExternalType : 1; |
267 | | |
268 | | /// Mapping from variables to pointers to captures in SortedCaptures. |
269 | | llvm::DenseMap<const VarDecl *, Capture *> Captures; |
270 | | |
271 | | /// The block's captures. Non-constant captures are sorted by their offsets. |
272 | | llvm::SmallVector<Capture, 4> SortedCaptures; |
273 | | |
274 | | Address LocalAddress; |
275 | | llvm::StructType *StructureType; |
276 | | const BlockDecl *Block; |
277 | | const BlockExpr *BlockExpression; |
278 | | CharUnits BlockSize; |
279 | | CharUnits BlockAlign; |
280 | | CharUnits CXXThisOffset; |
281 | | |
282 | | // Offset of the gap caused by block header having a smaller |
283 | | // alignment than the alignment of the block descriptor. This |
284 | | // is the gap offset before the first capturued field. |
285 | | CharUnits BlockHeaderForcedGapOffset; |
286 | | // Gap size caused by aligning first field after block header. |
287 | | // This could be zero if no forced alignment is required. |
288 | | CharUnits BlockHeaderForcedGapSize; |
289 | | |
290 | | /// The next block in the block-info chain. Invalid if this block |
291 | | /// info is not part of the CGF's block-info chain, which is true |
292 | | /// if it corresponds to a global block or a block whose expression |
293 | | /// has been encountered. |
294 | | CGBlockInfo *NextBlockInfo; |
295 | | |
296 | 769 | void buildCaptureMap() { |
297 | 769 | for (auto &C : SortedCaptures) |
298 | 2.32k | Captures[C.Cap->getVariable()] = &C; |
299 | 769 | } |
300 | | |
301 | 14.6k | const Capture &getCapture(const VarDecl *var) const { |
302 | 14.6k | return const_cast<CGBlockInfo*>(this)->getCapture(var); |
303 | 14.6k | } |
304 | 14.6k | Capture &getCapture(const VarDecl *var) { |
305 | 14.6k | auto it = Captures.find(var); |
306 | 14.6k | assert(it != Captures.end() && "no entry for variable!"); |
307 | 0 | return *it->second; |
308 | 14.6k | } |
309 | | |
310 | 5.15k | const BlockDecl *getBlockDecl() const { return Block; } |
311 | 7.37k | const BlockExpr *getBlockExpr() const { |
312 | 7.37k | assert(BlockExpression); |
313 | 0 | assert(BlockExpression->getBlockDecl() == Block); |
314 | 0 | return BlockExpression; |
315 | 7.37k | } |
316 | | |
317 | | CGBlockInfo(const BlockDecl *blockDecl, StringRef Name); |
318 | | }; |
319 | | |
320 | | } // end namespace CodeGen |
321 | | } // end namespace clang |
322 | | |
323 | | #endif |