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