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