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 15using namespace clang; 16using namespace clang::interp; 17 18template <typename T> 19static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) { 20 new (Ptr) T(); 21} 22 23template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) { 24 reinterpret_cast<T *>(Ptr)->~T(); 25} 26 27template <typename T> 28static 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 34template <typename T> 35static 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 41template <typename T> 42static 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 53template <typename T> 54static 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 62static 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 88static 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 103static 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 124static 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 148static 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 161static 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 172static BlockCtorFn getCtorPrim(PrimType Type) { 173 COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr); 174} 175 176static BlockDtorFn getDtorPrim(PrimType Type) { 177 COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr); 178} 179 180static BlockMoveFn getMovePrim(PrimType Type) { 181 COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr); 182} 183 184static BlockCtorFn getCtorArrayPrim(PrimType Type) { 185 COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr); 186} 187 188static BlockDtorFn getDtorArrayPrim(PrimType Type) { 189 TYPE_SWITCH(Type, return dtorArrayTy<T>); 190 llvm_unreachable("unknown Expr"); 191} 192 193static BlockMoveFn getMoveArrayPrim(PrimType Type) { 194 COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr); 195} 196 197Descriptor::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 207Descriptor::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 219Descriptor::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 228Descriptor::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 240Descriptor::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 250Descriptor::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 260QualType 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 268SourceLocation 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 276InitMap::InitMap(unsigned N) : UninitFields(N) { 277 std::fill_n(data(), (N + PER_FIELD - 1) / PER_FIELD, 0); 278} 279 280InitMap::T *InitMap::data() { 281 auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap)); 282 return reinterpret_cast<T *>(Start); 283} 284 285const 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 290bool 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 300bool InitMap::isInitialized(unsigned I) const { 301 unsigned Bucket = I / PER_FIELD; 302 return data()[Bucket] & (T(1) << (I % PER_FIELD)); 303} 304 305InitMap *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