1*a7dea167SDimitry Andric //===--- Pointer.cpp - 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 #include "Pointer.h" 10*a7dea167SDimitry Andric #include "Block.h" 11*a7dea167SDimitry Andric #include "Function.h" 12*a7dea167SDimitry Andric #include "PrimType.h" 13*a7dea167SDimitry Andric 14*a7dea167SDimitry Andric using namespace clang; 15*a7dea167SDimitry Andric using namespace clang::interp; 16*a7dea167SDimitry Andric 17*a7dea167SDimitry Andric Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} 18*a7dea167SDimitry Andric 19*a7dea167SDimitry Andric Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} 20*a7dea167SDimitry Andric 21*a7dea167SDimitry Andric Pointer::Pointer(Pointer &&P) 22*a7dea167SDimitry Andric : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { 23*a7dea167SDimitry Andric if (Pointee) 24*a7dea167SDimitry Andric Pointee->movePointer(&P, this); 25*a7dea167SDimitry Andric } 26*a7dea167SDimitry Andric 27*a7dea167SDimitry Andric Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) 28*a7dea167SDimitry Andric : Pointee(Pointee), Base(Base), Offset(Offset) { 29*a7dea167SDimitry Andric assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); 30*a7dea167SDimitry Andric if (Pointee) 31*a7dea167SDimitry Andric Pointee->addPointer(this); 32*a7dea167SDimitry Andric } 33*a7dea167SDimitry Andric 34*a7dea167SDimitry Andric Pointer::~Pointer() { 35*a7dea167SDimitry Andric if (Pointee) { 36*a7dea167SDimitry Andric Pointee->removePointer(this); 37*a7dea167SDimitry Andric Pointee->cleanup(); 38*a7dea167SDimitry Andric } 39*a7dea167SDimitry Andric } 40*a7dea167SDimitry Andric 41*a7dea167SDimitry Andric void Pointer::operator=(const Pointer &P) { 42*a7dea167SDimitry Andric Block *Old = Pointee; 43*a7dea167SDimitry Andric 44*a7dea167SDimitry Andric if (Pointee) 45*a7dea167SDimitry Andric Pointee->removePointer(this); 46*a7dea167SDimitry Andric 47*a7dea167SDimitry Andric Offset = P.Offset; 48*a7dea167SDimitry Andric Base = P.Base; 49*a7dea167SDimitry Andric 50*a7dea167SDimitry Andric Pointee = P.Pointee; 51*a7dea167SDimitry Andric if (Pointee) 52*a7dea167SDimitry Andric Pointee->addPointer(this); 53*a7dea167SDimitry Andric 54*a7dea167SDimitry Andric if (Old) 55*a7dea167SDimitry Andric Old->cleanup(); 56*a7dea167SDimitry Andric } 57*a7dea167SDimitry Andric 58*a7dea167SDimitry Andric void Pointer::operator=(Pointer &&P) { 59*a7dea167SDimitry Andric Block *Old = Pointee; 60*a7dea167SDimitry Andric 61*a7dea167SDimitry Andric if (Pointee) 62*a7dea167SDimitry Andric Pointee->removePointer(this); 63*a7dea167SDimitry Andric 64*a7dea167SDimitry Andric Offset = P.Offset; 65*a7dea167SDimitry Andric Base = P.Base; 66*a7dea167SDimitry Andric 67*a7dea167SDimitry Andric Pointee = P.Pointee; 68*a7dea167SDimitry Andric if (Pointee) 69*a7dea167SDimitry Andric Pointee->movePointer(&P, this); 70*a7dea167SDimitry Andric 71*a7dea167SDimitry Andric if (Old) 72*a7dea167SDimitry Andric Old->cleanup(); 73*a7dea167SDimitry Andric } 74*a7dea167SDimitry Andric 75*a7dea167SDimitry Andric APValue Pointer::toAPValue() const { 76*a7dea167SDimitry Andric APValue::LValueBase Base; 77*a7dea167SDimitry Andric llvm::SmallVector<APValue::LValuePathEntry, 5> Path; 78*a7dea167SDimitry Andric CharUnits Offset; 79*a7dea167SDimitry Andric bool IsNullPtr; 80*a7dea167SDimitry Andric bool IsOnePastEnd; 81*a7dea167SDimitry Andric 82*a7dea167SDimitry Andric if (isZero()) { 83*a7dea167SDimitry Andric Base = static_cast<const Expr *>(nullptr); 84*a7dea167SDimitry Andric IsNullPtr = true; 85*a7dea167SDimitry Andric IsOnePastEnd = false; 86*a7dea167SDimitry Andric Offset = CharUnits::Zero(); 87*a7dea167SDimitry Andric } else { 88*a7dea167SDimitry Andric // Build the lvalue base from the block. 89*a7dea167SDimitry Andric Descriptor *Desc = getDeclDesc(); 90*a7dea167SDimitry Andric if (auto *VD = Desc->asValueDecl()) 91*a7dea167SDimitry Andric Base = VD; 92*a7dea167SDimitry Andric else if (auto *E = Desc->asExpr()) 93*a7dea167SDimitry Andric Base = E; 94*a7dea167SDimitry Andric else 95*a7dea167SDimitry Andric llvm_unreachable("Invalid allocation type"); 96*a7dea167SDimitry Andric 97*a7dea167SDimitry Andric // Not a null pointer. 98*a7dea167SDimitry Andric IsNullPtr = false; 99*a7dea167SDimitry Andric 100*a7dea167SDimitry Andric if (isUnknownSizeArray()) { 101*a7dea167SDimitry Andric IsOnePastEnd = false; 102*a7dea167SDimitry Andric Offset = CharUnits::Zero(); 103*a7dea167SDimitry Andric } else { 104*a7dea167SDimitry Andric // TODO: compute the offset into the object. 105*a7dea167SDimitry Andric Offset = CharUnits::Zero(); 106*a7dea167SDimitry Andric 107*a7dea167SDimitry Andric // Build the path into the object. 108*a7dea167SDimitry Andric Pointer Ptr = *this; 109*a7dea167SDimitry Andric while (Ptr.isField()) { 110*a7dea167SDimitry Andric if (Ptr.isArrayElement()) { 111*a7dea167SDimitry Andric Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); 112*a7dea167SDimitry Andric Ptr = Ptr.getArray(); 113*a7dea167SDimitry Andric } else { 114*a7dea167SDimitry Andric // TODO: figure out if base is virtual 115*a7dea167SDimitry Andric bool IsVirtual = false; 116*a7dea167SDimitry Andric 117*a7dea167SDimitry Andric // Create a path entry for the field. 118*a7dea167SDimitry Andric Descriptor *Desc = Ptr.getFieldDesc(); 119*a7dea167SDimitry Andric if (auto *BaseOrMember = Desc->asDecl()) { 120*a7dea167SDimitry Andric Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 121*a7dea167SDimitry Andric Ptr = Ptr.getBase(); 122*a7dea167SDimitry Andric continue; 123*a7dea167SDimitry Andric } 124*a7dea167SDimitry Andric llvm_unreachable("Invalid field type"); 125*a7dea167SDimitry Andric } 126*a7dea167SDimitry Andric } 127*a7dea167SDimitry Andric 128*a7dea167SDimitry Andric IsOnePastEnd = isOnePastEnd(); 129*a7dea167SDimitry Andric } 130*a7dea167SDimitry Andric } 131*a7dea167SDimitry Andric 132*a7dea167SDimitry Andric return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); 133*a7dea167SDimitry Andric } 134*a7dea167SDimitry Andric 135*a7dea167SDimitry Andric bool Pointer::isInitialized() const { 136*a7dea167SDimitry Andric assert(Pointee && "Cannot check if null pointer was initialized"); 137*a7dea167SDimitry Andric Descriptor *Desc = getFieldDesc(); 138*a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 139*a7dea167SDimitry Andric if (Pointee->IsStatic) 140*a7dea167SDimitry Andric return true; 141*a7dea167SDimitry Andric // Primitive array field are stored in a bitset. 142*a7dea167SDimitry Andric InitMap *Map = getInitMap(); 143*a7dea167SDimitry Andric if (!Map) 144*a7dea167SDimitry Andric return false; 145*a7dea167SDimitry Andric if (Map == (InitMap *)-1) 146*a7dea167SDimitry Andric return true; 147*a7dea167SDimitry Andric return Map->isInitialized(getIndex()); 148*a7dea167SDimitry Andric } else { 149*a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 150*a7dea167SDimitry Andric return Base == 0 || getInlineDesc()->IsInitialized; 151*a7dea167SDimitry Andric } 152*a7dea167SDimitry Andric } 153*a7dea167SDimitry Andric 154*a7dea167SDimitry Andric void Pointer::initialize() const { 155*a7dea167SDimitry Andric assert(Pointee && "Cannot initialize null pointer"); 156*a7dea167SDimitry Andric Descriptor *Desc = getFieldDesc(); 157*a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 158*a7dea167SDimitry Andric if (!Pointee->IsStatic) { 159*a7dea167SDimitry Andric // Primitive array initializer. 160*a7dea167SDimitry Andric InitMap *&Map = getInitMap(); 161*a7dea167SDimitry Andric if (Map == (InitMap *)-1) 162*a7dea167SDimitry Andric return; 163*a7dea167SDimitry Andric if (Map == nullptr) 164*a7dea167SDimitry Andric Map = InitMap::allocate(Desc->getNumElems()); 165*a7dea167SDimitry Andric if (Map->initialize(getIndex())) { 166*a7dea167SDimitry Andric free(Map); 167*a7dea167SDimitry Andric Map = (InitMap *)-1; 168*a7dea167SDimitry Andric } 169*a7dea167SDimitry Andric } 170*a7dea167SDimitry Andric } else { 171*a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 172*a7dea167SDimitry Andric assert(Base != 0 && "Only composite fields can be initialised"); 173*a7dea167SDimitry Andric getInlineDesc()->IsInitialized = true; 174*a7dea167SDimitry Andric } 175*a7dea167SDimitry Andric } 176*a7dea167SDimitry Andric 177*a7dea167SDimitry Andric void Pointer::activate() const { 178*a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 179*a7dea167SDimitry Andric assert(Base != 0 && "Only composite fields can be initialised"); 180*a7dea167SDimitry Andric getInlineDesc()->IsActive = true; 181*a7dea167SDimitry Andric } 182*a7dea167SDimitry Andric 183*a7dea167SDimitry Andric void Pointer::deactivate() const { 184*a7dea167SDimitry Andric // TODO: this only appears in constructors, so nothing to deactivate. 185*a7dea167SDimitry Andric } 186*a7dea167SDimitry Andric 187*a7dea167SDimitry Andric bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 188*a7dea167SDimitry Andric return A.Pointee == B.Pointee; 189*a7dea167SDimitry Andric } 190*a7dea167SDimitry Andric 191*a7dea167SDimitry Andric bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 192*a7dea167SDimitry Andric return A.Base == B.Base && A.getFieldDesc()->IsArray; 193*a7dea167SDimitry Andric } 194