/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/Program.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- Program.cpp - Bytecode for the constexpr VM ------------*- 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 | | #include "Program.h" |
10 | | #include "ByteCodeStmtGen.h" |
11 | | #include "Context.h" |
12 | | #include "Function.h" |
13 | | #include "Integral.h" |
14 | | #include "Opcode.h" |
15 | | #include "PrimType.h" |
16 | | #include "clang/AST/Decl.h" |
17 | | #include "clang/AST/DeclCXX.h" |
18 | | |
19 | | using namespace clang; |
20 | | using namespace clang::interp; |
21 | | |
22 | 977 | unsigned Program::getOrCreateNativePointer(const void *Ptr) { |
23 | 977 | auto It = NativePointerIndices.find(Ptr); |
24 | 977 | if (It != NativePointerIndices.end()) |
25 | 494 | return It->second; |
26 | | |
27 | 483 | unsigned Idx = NativePointers.size(); |
28 | 483 | NativePointers.push_back(Ptr); |
29 | 483 | NativePointerIndices[Ptr] = Idx; |
30 | 483 | return Idx; |
31 | 977 | } |
32 | | |
33 | 5.16k | const void *Program::getNativePointer(unsigned Idx) { |
34 | 5.16k | return NativePointers[Idx]; |
35 | 5.16k | } |
36 | | |
37 | 1.89k | unsigned Program::createGlobalString(const StringLiteral *S) { |
38 | 1.89k | const size_t CharWidth = S->getCharByteWidth(); |
39 | 1.89k | const size_t BitWidth = CharWidth * Ctx.getCharBit(); |
40 | | |
41 | 1.89k | PrimType CharType; |
42 | 1.89k | switch (CharWidth) { |
43 | 1.88k | case 1: |
44 | 1.88k | CharType = PT_Sint8; |
45 | 1.88k | break; |
46 | 0 | case 2: |
47 | 0 | CharType = PT_Uint16; |
48 | 0 | break; |
49 | 8 | case 4: |
50 | 8 | CharType = PT_Uint32; |
51 | 8 | break; |
52 | 0 | default: |
53 | 0 | llvm_unreachable("unsupported character width"); |
54 | 1.89k | } |
55 | | |
56 | | // Create a descriptor for the string. |
57 | 1.89k | Descriptor *Desc = |
58 | 1.89k | allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1, |
59 | 1.89k | /*isConst=*/true, |
60 | 1.89k | /*isTemporary=*/false, |
61 | 1.89k | /*isMutable=*/false); |
62 | | |
63 | | // Allocate storage for the string. |
64 | | // The byte length does not include the null terminator. |
65 | 1.89k | unsigned I = Globals.size(); |
66 | 1.89k | unsigned Sz = Desc->getAllocSize(); |
67 | 1.89k | auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true, |
68 | 1.89k | /*isExtern=*/false); |
69 | 1.89k | G->block()->invokeCtor(); |
70 | 1.89k | Globals.push_back(G); |
71 | | |
72 | | // Construct the string in storage. |
73 | 1.89k | const Pointer Ptr(G->block()); |
74 | 59.5k | for (unsigned I = 0, N = S->getLength(); I <= N; ++I57.6k ) { |
75 | 57.6k | Pointer Field = Ptr.atIndex(I).narrow(); |
76 | 57.6k | const uint32_t CodePoint = I == N ? 01.89k : S->getCodeUnit(I)55.8k ; |
77 | 57.6k | switch (CharType) { |
78 | 57.5k | case PT_Sint8: { |
79 | 57.5k | using T = PrimConv<PT_Sint8>::T; |
80 | 57.5k | Field.deref<T>() = T::from(CodePoint, BitWidth); |
81 | 57.5k | break; |
82 | 0 | } |
83 | 0 | case PT_Uint16: { |
84 | 0 | using T = PrimConv<PT_Uint16>::T; |
85 | 0 | Field.deref<T>() = T::from(CodePoint, BitWidth); |
86 | 0 | break; |
87 | 0 | } |
88 | 104 | case PT_Uint32: { |
89 | 104 | using T = PrimConv<PT_Uint32>::T; |
90 | 104 | Field.deref<T>() = T::from(CodePoint, BitWidth); |
91 | 104 | break; |
92 | 0 | } |
93 | 0 | default: |
94 | 0 | llvm_unreachable("unsupported character type"); |
95 | 57.6k | } |
96 | 57.6k | } |
97 | 1.89k | return I; |
98 | 1.89k | } |
99 | | |
100 | 5.61k | Pointer Program::getPtrGlobal(unsigned Idx) { |
101 | 5.61k | assert(Idx < Globals.size()); |
102 | 5.61k | return Pointer(Globals[Idx]->block()); |
103 | 5.61k | } |
104 | | |
105 | 8.50k | std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) { |
106 | 8.50k | auto It = GlobalIndices.find(VD); |
107 | 8.50k | if (It != GlobalIndices.end()) |
108 | 3.66k | return It->second; |
109 | | |
110 | | // Find any previous declarations which were already evaluated. |
111 | 4.84k | std::optional<unsigned> Index; |
112 | 9.71k | for (const Decl *P = VD; P; P = P->getPreviousDecl()4.87k ) { |
113 | 4.87k | auto It = GlobalIndices.find(P); |
114 | 4.87k | if (It != GlobalIndices.end()) { |
115 | 0 | Index = It->second; |
116 | 0 | break; |
117 | 0 | } |
118 | 4.87k | } |
119 | | |
120 | | // Map the decl to the existing index. |
121 | 4.84k | if (Index) { |
122 | 0 | GlobalIndices[VD] = *Index; |
123 | 0 | return std::nullopt; |
124 | 0 | } |
125 | | |
126 | 4.84k | return Index; |
127 | 4.84k | } |
128 | | |
129 | | std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD, |
130 | 438 | const Expr *Init) { |
131 | 438 | if (auto Idx = getGlobal(VD)) |
132 | 145 | return Idx; |
133 | | |
134 | 293 | if (auto Idx = createGlobal(VD, Init)) { |
135 | 293 | GlobalIndices[VD] = *Idx; |
136 | 293 | return Idx; |
137 | 293 | } |
138 | 0 | return std::nullopt; |
139 | 293 | } |
140 | | |
141 | 288 | std::optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) { |
142 | | |
143 | | // Dedup blocks since they are immutable and pointers cannot be compared. |
144 | 288 | if (auto It = DummyParams.find(PD); |
145 | 288 | It != DummyParams.end()) |
146 | 253 | return It->second; |
147 | | |
148 | 35 | auto &ASTCtx = Ctx.getASTContext(); |
149 | | // Create a pointer to an incomplete array of the specified elements. |
150 | 35 | QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType(); |
151 | 35 | QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0); |
152 | | |
153 | 35 | if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) { |
154 | 35 | DummyParams[PD] = *Idx; |
155 | 35 | return Idx; |
156 | 35 | } |
157 | 0 | return std::nullopt; |
158 | 35 | } |
159 | | |
160 | | std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, |
161 | 1.25k | const Expr *Init) { |
162 | 1.25k | assert(!getGlobal(VD)); |
163 | 1.25k | bool IsStatic, IsExtern; |
164 | 1.25k | if (const auto *Var = dyn_cast<VarDecl>(VD)) { |
165 | 959 | IsStatic = Context::shouldBeGloballyIndexed(VD); |
166 | 959 | IsExtern = !Var->getAnyInitializer(); |
167 | 959 | } else if (293 isa<UnnamedGlobalConstantDecl>(VD)293 ) { |
168 | 293 | IsStatic = true; |
169 | 293 | IsExtern = false; |
170 | 293 | } else { |
171 | 0 | IsStatic = false; |
172 | 0 | IsExtern = true; |
173 | 0 | } |
174 | 1.25k | if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) { |
175 | 2.50k | for (const Decl *P = VD; P; P = P->getPreviousDecl()1.25k ) |
176 | 1.25k | GlobalIndices[P] = *Idx; |
177 | 1.24k | return *Idx; |
178 | 1.24k | } |
179 | 8 | return std::nullopt; |
180 | 1.25k | } |
181 | | |
182 | 35 | std::optional<unsigned> Program::createGlobal(const Expr *E) { |
183 | 35 | return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false); |
184 | 35 | } |
185 | | |
186 | | std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, |
187 | | bool IsStatic, bool IsExtern, |
188 | 1.32k | const Expr *Init) { |
189 | | // Create a descriptor for the global. |
190 | 1.32k | Descriptor *Desc; |
191 | 1.32k | const bool IsConst = Ty.isConstQualified(); |
192 | 1.32k | const bool IsTemporary = D.dyn_cast<const Expr *>(); |
193 | 1.32k | if (auto T = Ctx.classify(Ty)) { |
194 | 580 | Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary); |
195 | 742 | } else { |
196 | 742 | Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst, |
197 | 742 | IsTemporary); |
198 | 742 | } |
199 | 1.32k | if (!Desc) |
200 | 8 | return std::nullopt; |
201 | | |
202 | | // Allocate a block for storage. |
203 | 1.31k | unsigned I = Globals.size(); |
204 | | |
205 | 1.31k | auto *G = new (Allocator, Desc->getAllocSize()) |
206 | 1.31k | Global(getCurrentDecl(), Desc, IsStatic, IsExtern); |
207 | 1.31k | G->block()->invokeCtor(); |
208 | | |
209 | 1.31k | Globals.push_back(G); |
210 | | |
211 | 1.31k | return I; |
212 | 1.32k | } |
213 | | |
214 | 8.84k | Function *Program::getFunction(const FunctionDecl *F) { |
215 | 8.84k | F = F->getCanonicalDecl(); |
216 | 8.84k | assert(F); |
217 | 8.84k | auto It = Funcs.find(F); |
218 | 8.84k | return It == Funcs.end() ? nullptr2.99k : It->second.get()5.85k ; |
219 | 8.84k | } |
220 | | |
221 | 5.31k | Record *Program::getOrCreateRecord(const RecordDecl *RD) { |
222 | | // Use the actual definition as a key. |
223 | 5.31k | RD = RD->getDefinition(); |
224 | 5.31k | if (!RD) |
225 | 2 | return nullptr; |
226 | | |
227 | | // Deduplicate records. |
228 | 5.30k | if (auto It = Records.find(RD); It != Records.end()) |
229 | 4.76k | return It->second; |
230 | | |
231 | | // We insert nullptr now and replace that later, so recursive calls |
232 | | // to this function with the same RecordDecl don't run into |
233 | | // infinite recursion. |
234 | 545 | Records.insert({RD, nullptr}); |
235 | | |
236 | | // Number of bytes required by fields and base classes. |
237 | 545 | unsigned BaseSize = 0; |
238 | | // Number of bytes required by virtual base. |
239 | 545 | unsigned VirtSize = 0; |
240 | | |
241 | | // Helper to get a base descriptor. |
242 | 545 | auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * { |
243 | 121 | if (!BR) |
244 | 0 | return nullptr; |
245 | 121 | return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false, |
246 | 121 | /*isTemporary=*/false, |
247 | 121 | /*isMutable=*/false); |
248 | 121 | }; |
249 | | |
250 | | // Reserve space for base classes. |
251 | 545 | Record::BaseList Bases; |
252 | 545 | Record::VirtualBaseList VirtBases; |
253 | 545 | if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) { |
254 | 545 | for (const CXXBaseSpecifier &Spec : CD->bases()) { |
255 | 121 | if (Spec.isVirtual()) |
256 | 0 | continue; |
257 | | |
258 | 121 | const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl(); |
259 | 121 | Record *BR = getOrCreateRecord(BD); |
260 | 121 | if (Descriptor *Desc = GetBaseDesc(BD, BR)) { |
261 | 121 | BaseSize += align(sizeof(InlineDescriptor)); |
262 | 121 | Bases.push_back({BD, BaseSize, Desc, BR}); |
263 | 121 | BaseSize += align(BR->getSize()); |
264 | 121 | continue; |
265 | 121 | } |
266 | 0 | return nullptr; |
267 | 121 | } |
268 | | |
269 | 545 | for (const CXXBaseSpecifier &Spec : CD->vbases()) { |
270 | 0 | const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl(); |
271 | 0 | Record *BR = getOrCreateRecord(BD); |
272 | |
|
273 | 0 | if (Descriptor *Desc = GetBaseDesc(BD, BR)) { |
274 | 0 | VirtSize += align(sizeof(InlineDescriptor)); |
275 | 0 | VirtBases.push_back({BD, VirtSize, Desc, BR}); |
276 | 0 | VirtSize += align(BR->getSize()); |
277 | 0 | continue; |
278 | 0 | } |
279 | 0 | return nullptr; |
280 | 0 | } |
281 | 545 | } |
282 | | |
283 | | // Reserve space for fields. |
284 | 545 | Record::FieldList Fields; |
285 | 666 | for (const FieldDecl *FD : RD->fields()) { |
286 | | // Reserve space for the field's descriptor and the offset. |
287 | 666 | BaseSize += align(sizeof(InlineDescriptor)); |
288 | | |
289 | | // Classify the field and add its metadata. |
290 | 666 | QualType FT = FD->getType(); |
291 | 666 | const bool IsConst = FT.isConstQualified(); |
292 | 666 | const bool IsMutable = FD->isMutable(); |
293 | 666 | Descriptor *Desc; |
294 | 666 | if (std::optional<PrimType> T = Ctx.classify(FT)) { |
295 | 524 | Desc = createDescriptor(FD, *T, std::nullopt, IsConst, |
296 | 524 | /*isTemporary=*/false, IsMutable); |
297 | 524 | } else { |
298 | 142 | Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst, |
299 | 142 | /*isTemporary=*/false, IsMutable); |
300 | 142 | } |
301 | 666 | if (!Desc) |
302 | 6 | return nullptr; |
303 | 660 | Fields.push_back({FD, BaseSize, Desc}); |
304 | 660 | BaseSize += align(Desc->getAllocSize()); |
305 | 660 | } |
306 | | |
307 | 539 | Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), |
308 | 539 | std::move(VirtBases), VirtSize, BaseSize); |
309 | 539 | Records[RD] = R; |
310 | 539 | return R; |
311 | 545 | } |
312 | | |
313 | | Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, |
314 | | Descriptor::MetadataSize MDSize, |
315 | | bool IsConst, bool IsTemporary, |
316 | 1.98k | bool IsMutable, const Expr *Init) { |
317 | | // Classes and structures. |
318 | 1.98k | if (auto *RT = Ty->getAs<RecordType>()) { |
319 | 1.79k | if (auto *Record = getOrCreateRecord(RT->getDecl())) |
320 | 1.77k | return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, |
321 | 1.77k | IsMutable); |
322 | 1.79k | } |
323 | | |
324 | | // Arrays. |
325 | 212 | if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) { |
326 | 196 | QualType ElemTy = ArrayType->getElementType(); |
327 | | // Array of well-known bounds. |
328 | 196 | if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) { |
329 | 161 | size_t NumElems = CAT->getSize().getZExtValue(); |
330 | 161 | if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { |
331 | | // Arrays of primitives. |
332 | 131 | unsigned ElemSize = primSize(*T); |
333 | 131 | if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { |
334 | 0 | return {}; |
335 | 0 | } |
336 | 131 | return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, |
337 | 131 | IsMutable); |
338 | 131 | } else { |
339 | | // Arrays of composites. In this case, the array is a list of pointers, |
340 | | // followed by the actual elements. |
341 | 30 | Descriptor *ElemDesc = createDescriptor( |
342 | 30 | D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); |
343 | 30 | if (!ElemDesc) |
344 | 0 | return nullptr; |
345 | 30 | unsigned ElemSize = |
346 | 30 | ElemDesc->getAllocSize() + sizeof(InlineDescriptor); |
347 | 30 | if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) |
348 | 0 | return {}; |
349 | 30 | return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, |
350 | 30 | IsTemporary, IsMutable); |
351 | 30 | } |
352 | 161 | } |
353 | | |
354 | | // Array of unknown bounds - cannot be accessed and pointer arithmetic |
355 | | // is forbidden on pointers to such objects. |
356 | 35 | if (isa<IncompleteArrayType>(ArrayType)) { |
357 | 35 | if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { |
358 | 35 | return allocateDescriptor(D, *T, IsTemporary, |
359 | 35 | Descriptor::UnknownSize{}); |
360 | 35 | } else { |
361 | 0 | Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize, |
362 | 0 | IsConst, IsTemporary); |
363 | 0 | if (!Desc) |
364 | 0 | return nullptr; |
365 | 0 | return allocateDescriptor(D, Desc, IsTemporary, |
366 | 0 | Descriptor::UnknownSize{}); |
367 | 0 | } |
368 | 35 | } |
369 | 35 | } |
370 | | |
371 | | // Atomic types. |
372 | 16 | if (auto *AT = Ty->getAs<AtomicType>()) { |
373 | 0 | const Type *InnerTy = AT->getValueType().getTypePtr(); |
374 | 0 | return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, |
375 | 0 | IsMutable); |
376 | 0 | } |
377 | | |
378 | | // Complex types - represented as arrays of elements. |
379 | 16 | if (auto *CT = Ty->getAs<ComplexType>()) { |
380 | 0 | PrimType ElemTy = *Ctx.classify(CT->getElementType()); |
381 | 0 | return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary, |
382 | 0 | IsMutable); |
383 | 0 | } |
384 | | |
385 | 16 | return nullptr; |
386 | 16 | } |