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