/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/Descriptor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- Descriptor.cpp - Types 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 "Descriptor.h" |
10 | | #include "Pointer.h" |
11 | | #include "PrimType.h" |
12 | | #include "Record.h" |
13 | | |
14 | | using namespace clang; |
15 | | using namespace clang::interp; |
16 | | |
17 | | template <typename T> |
18 | 0 | static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) { |
19 | 0 | new (Ptr) T(); |
20 | 0 | } |
21 | | |
22 | 0 | template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) { |
23 | 0 | reinterpret_cast<T *>(Ptr)->~T(); |
24 | 0 | } |
25 | | |
26 | | template <typename T> |
27 | 0 | static void moveTy(Block *, char *Src, char *Dst, Descriptor *) { |
28 | 0 | auto *SrcPtr = reinterpret_cast<T *>(Src); |
29 | 0 | auto *DstPtr = reinterpret_cast<T *>(Dst); |
30 | 0 | new (DstPtr) T(std::move(*SrcPtr)); |
31 | 0 | } |
32 | | |
33 | | template <typename T> |
34 | 0 | static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) { |
35 | 0 | for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { |
36 | 0 | new (&reinterpret_cast<T *>(Ptr)[I]) T(); |
37 | 0 | } |
38 | 0 | } |
39 | | |
40 | | template <typename T> |
41 | 0 | static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) { |
42 | 0 | for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { |
43 | 0 | reinterpret_cast<T *>(Ptr)[I].~T(); |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | | template <typename T> |
48 | 0 | static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) { |
49 | 0 | for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { |
50 | 0 | auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; |
51 | 0 | auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; |
52 | 0 | new (DstPtr) T(std::move(*SrcPtr)); |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | | static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable, |
57 | 0 | bool IsActive, Descriptor *D) { |
58 | 0 | const unsigned NumElems = D->getNumElems(); |
59 | 0 | const unsigned ElemSize = |
60 | 0 | D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); |
61 | |
|
62 | 0 | unsigned ElemOffset = 0; |
63 | 0 | for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { |
64 | 0 | auto *ElemPtr = Ptr + ElemOffset; |
65 | 0 | auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr); |
66 | 0 | auto *ElemLoc = reinterpret_cast<char *>(Desc + 1); |
67 | 0 | auto *SD = D->ElemDesc; |
68 | |
|
69 | 0 | Desc->Offset = ElemOffset + sizeof(InlineDescriptor); |
70 | 0 | Desc->Desc = SD; |
71 | 0 | Desc->IsInitialized = true; |
72 | 0 | Desc->IsBase = false; |
73 | 0 | Desc->IsActive = IsActive; |
74 | 0 | Desc->IsConst = IsConst || D->IsConst; |
75 | 0 | Desc->IsMutable = IsMutable || D->IsMutable; |
76 | 0 | if (auto Fn = D->ElemDesc->CtorFn) |
77 | 0 | Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | 0 | static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) { |
82 | 0 | const unsigned NumElems = D->getNumElems(); |
83 | 0 | const unsigned ElemSize = |
84 | 0 | D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); |
85 | |
|
86 | 0 | unsigned ElemOffset = 0; |
87 | 0 | for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { |
88 | 0 | auto *ElemPtr = Ptr + ElemOffset; |
89 | 0 | auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr); |
90 | 0 | auto *ElemLoc = reinterpret_cast<char *>(Desc + 1); |
91 | 0 | if (auto Fn = D->ElemDesc->DtorFn) |
92 | 0 | Fn(B, ElemLoc, D->ElemDesc); |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | 0 | static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) { |
97 | 0 | const unsigned NumElems = D->getNumElems(); |
98 | 0 | const unsigned ElemSize = |
99 | 0 | D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); |
100 | |
|
101 | 0 | unsigned ElemOffset = 0; |
102 | 0 | for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { |
103 | 0 | auto *SrcPtr = Src + ElemOffset; |
104 | 0 | auto *DstPtr = Dst + ElemOffset; |
105 | |
|
106 | 0 | auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr); |
107 | 0 | auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1); |
108 | 0 | auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr); |
109 | 0 | auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1); |
110 | |
|
111 | 0 | *DstDesc = *SrcDesc; |
112 | 0 | if (auto Fn = D->ElemDesc->MoveFn) |
113 | 0 | Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable, |
118 | 0 | bool IsActive, Descriptor *D) { |
119 | 0 | const bool IsUnion = D->ElemRecord->isUnion(); |
120 | 0 | auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) { |
121 | 0 | auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1; |
122 | 0 | Desc->Offset = SubOff; |
123 | 0 | Desc->Desc = F; |
124 | 0 | Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase; |
125 | 0 | Desc->IsBase = IsBase; |
126 | 0 | Desc->IsActive = IsActive && !IsUnion; |
127 | 0 | Desc->IsConst = IsConst || F->IsConst; |
128 | 0 | Desc->IsMutable = IsMutable || F->IsMutable; |
129 | 0 | if (auto Fn = F->CtorFn) |
130 | 0 | Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F); |
131 | 0 | }; |
132 | 0 | for (const auto &B : D->ElemRecord->bases()) |
133 | 0 | CtorSub(B.Offset, B.Desc, /*isBase=*/true); |
134 | 0 | for (const auto &F : D->ElemRecord->fields()) |
135 | 0 | CtorSub(F.Offset, F.Desc, /*isBase=*/false); |
136 | 0 | for (const auto &V : D->ElemRecord->virtual_bases()) |
137 | 0 | CtorSub(V.Offset, V.Desc, /*isBase=*/true); |
138 | 0 | } |
139 | | |
140 | 0 | static void dtorRecord(Block *B, char *Ptr, Descriptor *D) { |
141 | 0 | auto DtorSub = [=](unsigned SubOff, Descriptor *F) { |
142 | 0 | if (auto Fn = F->DtorFn) |
143 | 0 | Fn(B, Ptr + SubOff, F); |
144 | 0 | }; |
145 | 0 | for (const auto &F : D->ElemRecord->bases()) |
146 | 0 | DtorSub(F.Offset, F.Desc); |
147 | 0 | for (const auto &F : D->ElemRecord->fields()) |
148 | 0 | DtorSub(F.Offset, F.Desc); |
149 | 0 | for (const auto &F : D->ElemRecord->virtual_bases()) |
150 | 0 | DtorSub(F.Offset, F.Desc); |
151 | 0 | } |
152 | | |
153 | 0 | static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) { |
154 | 0 | for (const auto &F : D->ElemRecord->fields()) { |
155 | 0 | auto FieldOff = F.Offset; |
156 | 0 | auto FieldDesc = F.Desc; |
157 | |
|
158 | 0 | *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc; |
159 | 0 | if (auto Fn = FieldDesc->MoveFn) |
160 | 0 | Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc); |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | 3 | static BlockCtorFn getCtorPrim(PrimType Type) { |
165 | 3 | COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr); |
166 | 3 | } |
167 | | |
168 | 3 | static BlockDtorFn getDtorPrim(PrimType Type) { |
169 | 3 | COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr); |
170 | 3 | } |
171 | | |
172 | 3 | static BlockMoveFn getMovePrim(PrimType Type) { |
173 | 3 | COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr); |
174 | 3 | } |
175 | | |
176 | 0 | static BlockCtorFn getCtorArrayPrim(PrimType Type) { |
177 | 0 | COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr); |
178 | 0 | } |
179 | | |
180 | 0 | static BlockDtorFn getDtorArrayPrim(PrimType Type) { |
181 | 0 | COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr); |
182 | 0 | } |
183 | | |
184 | 0 | static BlockMoveFn getMoveArrayPrim(PrimType Type) { |
185 | 0 | COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr); |
186 | 0 | } |
187 | | |
188 | | Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst, |
189 | | bool IsTemporary, bool IsMutable) |
190 | | : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size), |
191 | | IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), |
192 | | CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)), |
193 | 3 | MoveFn(getMovePrim(Type)) { |
194 | 3 | assert(Source && "Missing source"); |
195 | 3 | } |
196 | | |
197 | | Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, |
198 | | bool IsConst, bool IsTemporary, bool IsMutable) |
199 | | : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems), |
200 | | AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst), |
201 | | IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true), |
202 | | CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)), |
203 | 0 | MoveFn(getMoveArrayPrim(Type)) { |
204 | 0 | assert(Source && "Missing source"); |
205 | 0 | } |
206 | | |
207 | | Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, |
208 | | UnknownSize) |
209 | | : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), |
210 | | AllocSize(alignof(void *)), IsConst(true), IsMutable(false), |
211 | | IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)), |
212 | 0 | DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { |
213 | 0 | assert(Source && "Missing source"); |
214 | 0 | } |
215 | | |
216 | | Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, |
217 | | bool IsConst, bool IsTemporary, bool IsMutable) |
218 | | : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), |
219 | | Size(ElemSize * NumElems), |
220 | | AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem), |
221 | | IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), |
222 | | IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), |
223 | 0 | MoveFn(moveArrayDesc) { |
224 | 0 | assert(Source && "Missing source"); |
225 | 0 | } |
226 | | |
227 | | Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, |
228 | | UnknownSize) |
229 | | : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), |
230 | | Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem), |
231 | | IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true), |
232 | 0 | CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) { |
233 | 0 | assert(Source && "Missing source"); |
234 | 0 | } |
235 | | |
236 | | Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst, |
237 | | bool IsTemporary, bool IsMutable) |
238 | | : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())), |
239 | | Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst), |
240 | | IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord), |
241 | 0 | DtorFn(dtorRecord), MoveFn(moveRecord) { |
242 | 0 | assert(Source && "Missing source"); |
243 | 0 | } |
244 | | |
245 | 0 | QualType Descriptor::getType() const { |
246 | 0 | if (auto *E = asExpr()) |
247 | 0 | return E->getType(); |
248 | 0 | if (auto *D = asValueDecl()) |
249 | 0 | return D->getType(); |
250 | 0 | llvm_unreachable("Invalid descriptor type"); |
251 | 0 | } |
252 | | |
253 | 0 | SourceLocation Descriptor::getLocation() const { |
254 | 0 | if (auto *D = Source.dyn_cast<const Decl *>()) |
255 | 0 | return D->getLocation(); |
256 | 0 | if (auto *E = Source.dyn_cast<const Expr *>()) |
257 | 0 | return E->getExprLoc(); |
258 | 0 | llvm_unreachable("Invalid descriptor type"); |
259 | 0 | } |
260 | | |
261 | 0 | InitMap::InitMap(unsigned N) : UninitFields(N) { |
262 | 0 | for (unsigned I = 0; I < N / PER_FIELD; ++I) { |
263 | 0 | data()[I] = 0; |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | 0 | InitMap::T *InitMap::data() { |
268 | 0 | auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap)); |
269 | 0 | return reinterpret_cast<T *>(Start); |
270 | 0 | } |
271 | | |
272 | 0 | bool InitMap::initialize(unsigned I) { |
273 | 0 | unsigned Bucket = I / PER_FIELD; |
274 | 0 | unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD); |
275 | 0 | if (!(data()[Bucket] & Mask)) { |
276 | 0 | data()[Bucket] |= Mask; |
277 | 0 | UninitFields -= 1; |
278 | 0 | } |
279 | 0 | return UninitFields == 0; |
280 | 0 | } |
281 | | |
282 | 0 | bool InitMap::isInitialized(unsigned I) { |
283 | 0 | unsigned Bucket = I / PER_FIELD; |
284 | 0 | unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD); |
285 | 0 | return data()[Bucket] & Mask; |
286 | 0 | } |
287 | | |
288 | 0 | InitMap *InitMap::allocate(unsigned N) { |
289 | 0 | const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD); |
290 | 0 | const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD; |
291 | 0 | return new (malloc(Size)) InitMap(N); |
292 | 0 | } |