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