1*a7dea167SDimitry Andric //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===// 2*a7dea167SDimitry Andric // 3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a7dea167SDimitry Andric // 7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8*a7dea167SDimitry Andric // 9*a7dea167SDimitry Andric // Defines the classes responsible for pointer tracking. 10*a7dea167SDimitry Andric // 11*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12*a7dea167SDimitry Andric 13*a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_POINTER_H 14*a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_POINTER_H 15*a7dea167SDimitry Andric 16*a7dea167SDimitry Andric #include "Block.h" 17*a7dea167SDimitry Andric #include "Descriptor.h" 18*a7dea167SDimitry Andric #include "clang/AST/Decl.h" 19*a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 20*a7dea167SDimitry Andric #include "clang/AST/Expr.h" 21*a7dea167SDimitry Andric #include "clang/AST/ComparisonCategories.h" 22*a7dea167SDimitry Andric #include "llvm/ADT/PointerUnion.h" 23*a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h" 24*a7dea167SDimitry Andric 25*a7dea167SDimitry Andric namespace clang { 26*a7dea167SDimitry Andric namespace interp { 27*a7dea167SDimitry Andric class Block; 28*a7dea167SDimitry Andric class DeadBlock; 29*a7dea167SDimitry Andric class Context; 30*a7dea167SDimitry Andric class InterpState; 31*a7dea167SDimitry Andric class Pointer; 32*a7dea167SDimitry Andric class Function; 33*a7dea167SDimitry Andric enum PrimType : unsigned; 34*a7dea167SDimitry Andric 35*a7dea167SDimitry Andric /// A pointer to a memory block, live or dead. 36*a7dea167SDimitry Andric /// 37*a7dea167SDimitry Andric /// This object can be allocated into interpreter stack frames. If pointing to 38*a7dea167SDimitry Andric /// a live block, it is a link in the chain of pointers pointing to the block. 39*a7dea167SDimitry Andric class Pointer { 40*a7dea167SDimitry Andric private: 41*a7dea167SDimitry Andric static constexpr unsigned PastEndMark = (unsigned)-1; 42*a7dea167SDimitry Andric static constexpr unsigned RootPtrMark = (unsigned)-1; 43*a7dea167SDimitry Andric 44*a7dea167SDimitry Andric public: 45*a7dea167SDimitry Andric Pointer() {} 46*a7dea167SDimitry Andric Pointer(Block *B); 47*a7dea167SDimitry Andric Pointer(const Pointer &P); 48*a7dea167SDimitry Andric Pointer(Pointer &&P); 49*a7dea167SDimitry Andric ~Pointer(); 50*a7dea167SDimitry Andric 51*a7dea167SDimitry Andric void operator=(const Pointer &P); 52*a7dea167SDimitry Andric void operator=(Pointer &&P); 53*a7dea167SDimitry Andric 54*a7dea167SDimitry Andric /// Converts the pointer to an APValue. 55*a7dea167SDimitry Andric APValue toAPValue() const; 56*a7dea167SDimitry Andric 57*a7dea167SDimitry Andric /// Offsets a pointer inside an array. 58*a7dea167SDimitry Andric Pointer atIndex(unsigned Idx) const { 59*a7dea167SDimitry Andric if (Base == RootPtrMark) 60*a7dea167SDimitry Andric return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); 61*a7dea167SDimitry Andric unsigned Off = Idx * elemSize(); 62*a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 63*a7dea167SDimitry Andric Off += sizeof(InlineDescriptor); 64*a7dea167SDimitry Andric else 65*a7dea167SDimitry Andric Off += sizeof(InitMap *); 66*a7dea167SDimitry Andric return Pointer(Pointee, Base, Base + Off); 67*a7dea167SDimitry Andric } 68*a7dea167SDimitry Andric 69*a7dea167SDimitry Andric /// Creates a pointer to a field. 70*a7dea167SDimitry Andric Pointer atField(unsigned Off) const { 71*a7dea167SDimitry Andric unsigned Field = Offset + Off; 72*a7dea167SDimitry Andric return Pointer(Pointee, Field, Field); 73*a7dea167SDimitry Andric } 74*a7dea167SDimitry Andric 75*a7dea167SDimitry Andric /// Restricts the scope of an array element pointer. 76*a7dea167SDimitry Andric Pointer narrow() const { 77*a7dea167SDimitry Andric // Null pointers cannot be narrowed. 78*a7dea167SDimitry Andric if (isZero() || isUnknownSizeArray()) 79*a7dea167SDimitry Andric return *this; 80*a7dea167SDimitry Andric 81*a7dea167SDimitry Andric // Pointer to an array of base types - enter block. 82*a7dea167SDimitry Andric if (Base == RootPtrMark) 83*a7dea167SDimitry Andric return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark); 84*a7dea167SDimitry Andric 85*a7dea167SDimitry Andric // Pointer is one past end - magic offset marks that. 86*a7dea167SDimitry Andric if (isOnePastEnd()) 87*a7dea167SDimitry Andric return Pointer(Pointee, Base, PastEndMark); 88*a7dea167SDimitry Andric 89*a7dea167SDimitry Andric // Primitive arrays are a bit special since they do not have inline 90*a7dea167SDimitry Andric // descriptors. If Offset != Base, then the pointer already points to 91*a7dea167SDimitry Andric // an element and there is nothing to do. Otherwise, the pointer is 92*a7dea167SDimitry Andric // adjusted to the first element of the array. 93*a7dea167SDimitry Andric if (inPrimitiveArray()) { 94*a7dea167SDimitry Andric if (Offset != Base) 95*a7dea167SDimitry Andric return *this; 96*a7dea167SDimitry Andric return Pointer(Pointee, Base, Offset + sizeof(InitMap *)); 97*a7dea167SDimitry Andric } 98*a7dea167SDimitry Andric 99*a7dea167SDimitry Andric // Pointer is to a field or array element - enter it. 100*a7dea167SDimitry Andric if (Offset != Base) 101*a7dea167SDimitry Andric return Pointer(Pointee, Offset, Offset); 102*a7dea167SDimitry Andric 103*a7dea167SDimitry Andric // Enter the first element of an array. 104*a7dea167SDimitry Andric if (!getFieldDesc()->isArray()) 105*a7dea167SDimitry Andric return *this; 106*a7dea167SDimitry Andric 107*a7dea167SDimitry Andric const unsigned NewBase = Base + sizeof(InlineDescriptor); 108*a7dea167SDimitry Andric return Pointer(Pointee, NewBase, NewBase); 109*a7dea167SDimitry Andric } 110*a7dea167SDimitry Andric 111*a7dea167SDimitry Andric /// Expands a pointer to the containing array, undoing narrowing. 112*a7dea167SDimitry Andric Pointer expand() const { 113*a7dea167SDimitry Andric if (isElementPastEnd()) { 114*a7dea167SDimitry Andric // Revert to an outer one-past-end pointer. 115*a7dea167SDimitry Andric unsigned Adjust; 116*a7dea167SDimitry Andric if (inPrimitiveArray()) 117*a7dea167SDimitry Andric Adjust = sizeof(InitMap *); 118*a7dea167SDimitry Andric else 119*a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 120*a7dea167SDimitry Andric return Pointer(Pointee, Base, Base + getSize() + Adjust); 121*a7dea167SDimitry Andric } 122*a7dea167SDimitry Andric 123*a7dea167SDimitry Andric // Do not step out of array elements. 124*a7dea167SDimitry Andric if (Base != Offset) 125*a7dea167SDimitry Andric return *this; 126*a7dea167SDimitry Andric 127*a7dea167SDimitry Andric // If at base, point to an array of base types. 128*a7dea167SDimitry Andric if (Base == 0) 129*a7dea167SDimitry Andric return Pointer(Pointee, RootPtrMark, 0); 130*a7dea167SDimitry Andric 131*a7dea167SDimitry Andric // Step into the containing array, if inside one. 132*a7dea167SDimitry Andric unsigned Next = Base - getInlineDesc()->Offset; 133*a7dea167SDimitry Andric Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; 134*a7dea167SDimitry Andric if (!Desc->IsArray) 135*a7dea167SDimitry Andric return *this; 136*a7dea167SDimitry Andric return Pointer(Pointee, Next, Offset); 137*a7dea167SDimitry Andric } 138*a7dea167SDimitry Andric 139*a7dea167SDimitry Andric /// Checks if the pointer is null. 140*a7dea167SDimitry Andric bool isZero() const { return Pointee == nullptr; } 141*a7dea167SDimitry Andric /// Checks if the pointer is live. 142*a7dea167SDimitry Andric bool isLive() const { return Pointee && !Pointee->IsDead; } 143*a7dea167SDimitry Andric /// Checks if the item is a field in an object. 144*a7dea167SDimitry Andric bool isField() const { return Base != 0 && Base != RootPtrMark; } 145*a7dea167SDimitry Andric 146*a7dea167SDimitry Andric /// Accessor for information about the declaration site. 147*a7dea167SDimitry Andric Descriptor *getDeclDesc() const { return Pointee->Desc; } 148*a7dea167SDimitry Andric SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } 149*a7dea167SDimitry Andric 150*a7dea167SDimitry Andric /// Returns a pointer to the object of which this pointer is a field. 151*a7dea167SDimitry Andric Pointer getBase() const { 152*a7dea167SDimitry Andric if (Base == RootPtrMark) { 153*a7dea167SDimitry Andric assert(Offset == PastEndMark && "cannot get base of a block"); 154*a7dea167SDimitry Andric return Pointer(Pointee, Base, 0); 155*a7dea167SDimitry Andric } 156*a7dea167SDimitry Andric assert(Offset == Base && "not an inner field"); 157*a7dea167SDimitry Andric unsigned NewBase = Base - getInlineDesc()->Offset; 158*a7dea167SDimitry Andric return Pointer(Pointee, NewBase, NewBase); 159*a7dea167SDimitry Andric } 160*a7dea167SDimitry Andric /// Returns the parent array. 161*a7dea167SDimitry Andric Pointer getArray() const { 162*a7dea167SDimitry Andric if (Base == RootPtrMark) { 163*a7dea167SDimitry Andric assert(Offset != 0 && Offset != PastEndMark && "not an array element"); 164*a7dea167SDimitry Andric return Pointer(Pointee, Base, 0); 165*a7dea167SDimitry Andric } 166*a7dea167SDimitry Andric assert(Offset != Base && "not an array element"); 167*a7dea167SDimitry Andric return Pointer(Pointee, Base, Base); 168*a7dea167SDimitry Andric } 169*a7dea167SDimitry Andric 170*a7dea167SDimitry Andric /// Accessors for information about the innermost field. 171*a7dea167SDimitry Andric Descriptor *getFieldDesc() const { 172*a7dea167SDimitry Andric if (Base == 0 || Base == RootPtrMark) 173*a7dea167SDimitry Andric return getDeclDesc(); 174*a7dea167SDimitry Andric return getInlineDesc()->Desc; 175*a7dea167SDimitry Andric } 176*a7dea167SDimitry Andric 177*a7dea167SDimitry Andric /// Returns the type of the innermost field. 178*a7dea167SDimitry Andric QualType getType() const { return getFieldDesc()->getType(); } 179*a7dea167SDimitry Andric 180*a7dea167SDimitry Andric /// Returns the element size of the innermost field. 181*a7dea167SDimitry Andric size_t elemSize() const { 182*a7dea167SDimitry Andric if (Base == RootPtrMark) 183*a7dea167SDimitry Andric return getDeclDesc()->getSize(); 184*a7dea167SDimitry Andric return getFieldDesc()->getElemSize(); 185*a7dea167SDimitry Andric } 186*a7dea167SDimitry Andric /// Returns the total size of the innermost field. 187*a7dea167SDimitry Andric size_t getSize() const { return getFieldDesc()->getSize(); } 188*a7dea167SDimitry Andric 189*a7dea167SDimitry Andric /// Returns the offset into an array. 190*a7dea167SDimitry Andric unsigned getOffset() const { 191*a7dea167SDimitry Andric assert(Offset != PastEndMark && "invalid offset"); 192*a7dea167SDimitry Andric if (Base == RootPtrMark) 193*a7dea167SDimitry Andric return Offset; 194*a7dea167SDimitry Andric 195*a7dea167SDimitry Andric unsigned Adjust = 0; 196*a7dea167SDimitry Andric if (Offset != Base) { 197*a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 198*a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 199*a7dea167SDimitry Andric else 200*a7dea167SDimitry Andric Adjust = sizeof(InitMap *); 201*a7dea167SDimitry Andric } 202*a7dea167SDimitry Andric return Offset - Base - Adjust; 203*a7dea167SDimitry Andric } 204*a7dea167SDimitry Andric 205*a7dea167SDimitry Andric /// Checks if the innermost field is an array. 206*a7dea167SDimitry Andric bool inArray() const { return getFieldDesc()->IsArray; } 207*a7dea167SDimitry Andric /// Checks if the structure is a primitive array. 208*a7dea167SDimitry Andric bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } 209*a7dea167SDimitry Andric /// Checks if the structure is an array of unknown size. 210*a7dea167SDimitry Andric bool isUnknownSizeArray() const { 211*a7dea167SDimitry Andric return getFieldDesc()->isUnknownSizeArray(); 212*a7dea167SDimitry Andric } 213*a7dea167SDimitry Andric /// Checks if the pointer points to an array. 214*a7dea167SDimitry Andric bool isArrayElement() const { return Base != Offset; } 215*a7dea167SDimitry Andric /// Pointer points directly to a block. 216*a7dea167SDimitry Andric bool isRoot() const { 217*a7dea167SDimitry Andric return (Base == 0 || Base == RootPtrMark) && Offset == 0; 218*a7dea167SDimitry Andric } 219*a7dea167SDimitry Andric 220*a7dea167SDimitry Andric /// Returns the record descriptor of a class. 221*a7dea167SDimitry Andric Record *getRecord() const { return getFieldDesc()->ElemRecord; } 222*a7dea167SDimitry Andric /// Returns the field information. 223*a7dea167SDimitry Andric const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } 224*a7dea167SDimitry Andric 225*a7dea167SDimitry Andric /// Checks if the object is a union. 226*a7dea167SDimitry Andric bool isUnion() const; 227*a7dea167SDimitry Andric 228*a7dea167SDimitry Andric /// Checks if the storage is extern. 229*a7dea167SDimitry Andric bool isExtern() const { return Pointee->isExtern(); } 230*a7dea167SDimitry Andric /// Checks if the storage is static. 231*a7dea167SDimitry Andric bool isStatic() const { return Pointee->isStatic(); } 232*a7dea167SDimitry Andric /// Checks if the storage is temporary. 233*a7dea167SDimitry Andric bool isTemporary() const { return Pointee->isTemporary(); } 234*a7dea167SDimitry Andric /// Checks if the storage is a static temporary. 235*a7dea167SDimitry Andric bool isStaticTemporary() const { return isStatic() && isTemporary(); } 236*a7dea167SDimitry Andric 237*a7dea167SDimitry Andric /// Checks if the field is mutable. 238*a7dea167SDimitry Andric bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; } 239*a7dea167SDimitry Andric /// Checks if an object was initialized. 240*a7dea167SDimitry Andric bool isInitialized() const; 241*a7dea167SDimitry Andric /// Checks if the object is active. 242*a7dea167SDimitry Andric bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; } 243*a7dea167SDimitry Andric /// Checks if a structure is a base class. 244*a7dea167SDimitry Andric bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } 245*a7dea167SDimitry Andric 246*a7dea167SDimitry Andric /// Checks if an object or a subfield is mutable. 247*a7dea167SDimitry Andric bool isConst() const { 248*a7dea167SDimitry Andric return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; 249*a7dea167SDimitry Andric } 250*a7dea167SDimitry Andric 251*a7dea167SDimitry Andric /// Returns the declaration ID. 252*a7dea167SDimitry Andric llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); } 253*a7dea167SDimitry Andric 254*a7dea167SDimitry Andric /// Returns the byte offset from the start. 255*a7dea167SDimitry Andric unsigned getByteOffset() const { 256*a7dea167SDimitry Andric return Offset; 257*a7dea167SDimitry Andric } 258*a7dea167SDimitry Andric 259*a7dea167SDimitry Andric /// Returns the number of elements. 260*a7dea167SDimitry Andric unsigned getNumElems() const { return getSize() / elemSize(); } 261*a7dea167SDimitry Andric 262*a7dea167SDimitry Andric /// Returns the index into an array. 263*a7dea167SDimitry Andric int64_t getIndex() const { 264*a7dea167SDimitry Andric if (isElementPastEnd()) 265*a7dea167SDimitry Andric return 1; 266*a7dea167SDimitry Andric if (auto ElemSize = elemSize()) 267*a7dea167SDimitry Andric return getOffset() / ElemSize; 268*a7dea167SDimitry Andric return 0; 269*a7dea167SDimitry Andric } 270*a7dea167SDimitry Andric 271*a7dea167SDimitry Andric /// Checks if the index is one past end. 272*a7dea167SDimitry Andric bool isOnePastEnd() const { 273*a7dea167SDimitry Andric return isElementPastEnd() || getSize() == getOffset(); 274*a7dea167SDimitry Andric } 275*a7dea167SDimitry Andric 276*a7dea167SDimitry Andric /// Checks if the pointer is an out-of-bounds element pointer. 277*a7dea167SDimitry Andric bool isElementPastEnd() const { return Offset == PastEndMark; } 278*a7dea167SDimitry Andric 279*a7dea167SDimitry Andric /// Dereferences the pointer, if it's live. 280*a7dea167SDimitry Andric template <typename T> T &deref() const { 281*a7dea167SDimitry Andric assert(isLive() && "Invalid pointer"); 282*a7dea167SDimitry Andric return *reinterpret_cast<T *>(Pointee->data() + Offset); 283*a7dea167SDimitry Andric } 284*a7dea167SDimitry Andric 285*a7dea167SDimitry Andric /// Dereferences a primitive element. 286*a7dea167SDimitry Andric template <typename T> T &elem(unsigned I) const { 287*a7dea167SDimitry Andric return reinterpret_cast<T *>(Pointee->data())[I]; 288*a7dea167SDimitry Andric } 289*a7dea167SDimitry Andric 290*a7dea167SDimitry Andric /// Initializes a field. 291*a7dea167SDimitry Andric void initialize() const; 292*a7dea167SDimitry Andric /// Activats a field. 293*a7dea167SDimitry Andric void activate() const; 294*a7dea167SDimitry Andric /// Deactivates an entire strurcutre. 295*a7dea167SDimitry Andric void deactivate() const; 296*a7dea167SDimitry Andric 297*a7dea167SDimitry Andric /// Checks if two pointers are comparable. 298*a7dea167SDimitry Andric static bool hasSameBase(const Pointer &A, const Pointer &B); 299*a7dea167SDimitry Andric /// Checks if two pointers can be subtracted. 300*a7dea167SDimitry Andric static bool hasSameArray(const Pointer &A, const Pointer &B); 301*a7dea167SDimitry Andric 302*a7dea167SDimitry Andric /// Prints the pointer. 303*a7dea167SDimitry Andric void print(llvm::raw_ostream &OS) const { 304*a7dea167SDimitry Andric OS << "{" << Base << ", " << Offset << ", "; 305*a7dea167SDimitry Andric if (Pointee) 306*a7dea167SDimitry Andric OS << Pointee->getSize(); 307*a7dea167SDimitry Andric else 308*a7dea167SDimitry Andric OS << "nullptr"; 309*a7dea167SDimitry Andric OS << "}"; 310*a7dea167SDimitry Andric } 311*a7dea167SDimitry Andric 312*a7dea167SDimitry Andric private: 313*a7dea167SDimitry Andric friend class Block; 314*a7dea167SDimitry Andric friend class DeadBlock; 315*a7dea167SDimitry Andric 316*a7dea167SDimitry Andric Pointer(Block *Pointee, unsigned Base, unsigned Offset); 317*a7dea167SDimitry Andric 318*a7dea167SDimitry Andric /// Returns the embedded descriptor preceding a field. 319*a7dea167SDimitry Andric InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); } 320*a7dea167SDimitry Andric 321*a7dea167SDimitry Andric /// Returns a descriptor at a given offset. 322*a7dea167SDimitry Andric InlineDescriptor *getDescriptor(unsigned Offset) const { 323*a7dea167SDimitry Andric assert(Offset != 0 && "Not a nested pointer"); 324*a7dea167SDimitry Andric return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1; 325*a7dea167SDimitry Andric } 326*a7dea167SDimitry Andric 327*a7dea167SDimitry Andric /// Returns a reference to the pointer which stores the initialization map. 328*a7dea167SDimitry Andric InitMap *&getInitMap() const { 329*a7dea167SDimitry Andric return *reinterpret_cast<InitMap **>(Pointee->data() + Base); 330*a7dea167SDimitry Andric } 331*a7dea167SDimitry Andric 332*a7dea167SDimitry Andric /// The block the pointer is pointing to. 333*a7dea167SDimitry Andric Block *Pointee = nullptr; 334*a7dea167SDimitry Andric /// Start of the current subfield. 335*a7dea167SDimitry Andric unsigned Base = 0; 336*a7dea167SDimitry Andric /// Offset into the block. 337*a7dea167SDimitry Andric unsigned Offset = 0; 338*a7dea167SDimitry Andric 339*a7dea167SDimitry Andric /// Previous link in the pointer chain. 340*a7dea167SDimitry Andric Pointer *Prev = nullptr; 341*a7dea167SDimitry Andric /// Next link in the pointer chain. 342*a7dea167SDimitry Andric Pointer *Next = nullptr; 343*a7dea167SDimitry Andric }; 344*a7dea167SDimitry Andric 345*a7dea167SDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { 346*a7dea167SDimitry Andric P.print(OS); 347*a7dea167SDimitry Andric return OS; 348*a7dea167SDimitry Andric } 349*a7dea167SDimitry Andric 350*a7dea167SDimitry Andric } // namespace interp 351*a7dea167SDimitry Andric } // namespace clang 352*a7dea167SDimitry Andric 353*a7dea167SDimitry Andric #endif 354