1 //===--- Pointer.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 "Pointer.h" 10 #include "Boolean.h" 11 #include "Context.h" 12 #include "Floating.h" 13 #include "Function.h" 14 #include "Integral.h" 15 #include "InterpBlock.h" 16 #include "PrimType.h" 17 #include "Record.h" 18 19 using namespace clang; 20 using namespace clang::interp; 21 22 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} 23 24 Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) 25 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} 26 27 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} 28 29 Pointer::Pointer(Pointer &&P) 30 : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { 31 if (Pointee) 32 Pointee->replacePointer(&P, this); 33 } 34 35 Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) 36 : Pointee(Pointee), Base(Base), Offset(Offset) { 37 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); 38 if (Pointee) 39 Pointee->addPointer(this); 40 } 41 42 Pointer::~Pointer() { 43 if (Pointee) { 44 Pointee->removePointer(this); 45 Pointee->cleanup(); 46 } 47 } 48 49 void Pointer::operator=(const Pointer &P) { 50 Block *Old = Pointee; 51 52 if (Pointee) 53 Pointee->removePointer(this); 54 55 Offset = P.Offset; 56 Base = P.Base; 57 58 Pointee = P.Pointee; 59 if (Pointee) 60 Pointee->addPointer(this); 61 62 if (Old) 63 Old->cleanup(); 64 } 65 66 void Pointer::operator=(Pointer &&P) { 67 Block *Old = Pointee; 68 69 if (Pointee) 70 Pointee->removePointer(this); 71 72 Offset = P.Offset; 73 Base = P.Base; 74 75 Pointee = P.Pointee; 76 if (Pointee) 77 Pointee->replacePointer(&P, this); 78 79 if (Old) 80 Old->cleanup(); 81 } 82 83 APValue Pointer::toAPValue() const { 84 APValue::LValueBase Base; 85 llvm::SmallVector<APValue::LValuePathEntry, 5> Path; 86 CharUnits Offset; 87 bool IsNullPtr; 88 bool IsOnePastEnd; 89 90 if (isZero()) { 91 Base = static_cast<const Expr *>(nullptr); 92 IsNullPtr = true; 93 IsOnePastEnd = false; 94 Offset = CharUnits::Zero(); 95 } else { 96 // Build the lvalue base from the block. 97 const Descriptor *Desc = getDeclDesc(); 98 if (auto *VD = Desc->asValueDecl()) 99 Base = VD; 100 else if (auto *E = Desc->asExpr()) 101 Base = E; 102 else 103 llvm_unreachable("Invalid allocation type"); 104 105 // Not a null pointer. 106 IsNullPtr = false; 107 108 if (isUnknownSizeArray()) { 109 IsOnePastEnd = false; 110 Offset = CharUnits::Zero(); 111 } else if (Desc->asExpr()) { 112 // Pointer pointing to a an expression. 113 IsOnePastEnd = false; 114 Offset = CharUnits::Zero(); 115 } else { 116 // TODO: compute the offset into the object. 117 Offset = CharUnits::Zero(); 118 119 // Build the path into the object. 120 Pointer Ptr = *this; 121 while (Ptr.isField() || Ptr.isArrayElement()) { 122 if (Ptr.isArrayElement()) { 123 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); 124 Ptr = Ptr.getArray(); 125 } else { 126 // TODO: figure out if base is virtual 127 bool IsVirtual = false; 128 129 // Create a path entry for the field. 130 const Descriptor *Desc = Ptr.getFieldDesc(); 131 if (const auto *BaseOrMember = Desc->asDecl()) { 132 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 133 Ptr = Ptr.getBase(); 134 continue; 135 } 136 llvm_unreachable("Invalid field type"); 137 } 138 } 139 140 IsOnePastEnd = isOnePastEnd(); 141 } 142 } 143 144 // We assemble the LValuePath starting from the innermost pointer to the 145 // outermost one. SO in a.b.c, the first element in Path will refer to 146 // the field 'c', while later code expects it to refer to 'a'. 147 // Just invert the order of the elements. 148 std::reverse(Path.begin(), Path.end()); 149 150 return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); 151 } 152 153 std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { 154 if (!Pointee) 155 return "nullptr"; 156 157 return toAPValue().getAsString(Ctx, getType()); 158 } 159 160 bool Pointer::isInitialized() const { 161 assert(Pointee && "Cannot check if null pointer was initialized"); 162 const Descriptor *Desc = getFieldDesc(); 163 assert(Desc); 164 if (Desc->isPrimitiveArray()) { 165 if (isStatic() && Base == 0) 166 return true; 167 168 InitMapPtr &IM = getInitMap(); 169 170 if (!IM) 171 return false; 172 173 if (IM->first) 174 return true; 175 176 return IM->second->isElementInitialized(getIndex()); 177 } 178 179 // Field has its bit in an inline descriptor. 180 return Base == 0 || getInlineDesc()->IsInitialized; 181 } 182 183 void Pointer::initialize() const { 184 assert(Pointee && "Cannot initialize null pointer"); 185 const Descriptor *Desc = getFieldDesc(); 186 187 assert(Desc); 188 if (Desc->isPrimitiveArray()) { 189 // Primitive global arrays don't have an initmap. 190 if (isStatic() && Base == 0) 191 return; 192 193 InitMapPtr &IM = getInitMap(); 194 if (!IM) 195 IM = 196 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems())); 197 198 assert(IM); 199 200 // All initialized. 201 if (IM->first) 202 return; 203 204 if (IM->second->initializeElement(getIndex())) { 205 IM->first = true; 206 IM->second.reset(); 207 } 208 return; 209 } 210 211 // Field has its bit in an inline descriptor. 212 assert(Base != 0 && "Only composite fields can be initialised"); 213 getInlineDesc()->IsInitialized = true; 214 } 215 216 void Pointer::activate() const { 217 // Field has its bit in an inline descriptor. 218 assert(Base != 0 && "Only composite fields can be initialised"); 219 getInlineDesc()->IsActive = true; 220 } 221 222 void Pointer::deactivate() const { 223 // TODO: this only appears in constructors, so nothing to deactivate. 224 } 225 226 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 227 return A.Pointee == B.Pointee; 228 } 229 230 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 231 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; 232 } 233 234 APValue Pointer::toRValue(const Context &Ctx) const { 235 // Primitives. 236 if (getFieldDesc()->isPrimitive()) { 237 PrimType PT = *Ctx.classify(getType()); 238 TYPE_SWITCH(PT, return deref<T>().toAPValue()); 239 llvm_unreachable("Unhandled PrimType?"); 240 } 241 242 APValue Result; 243 // Records. 244 if (getFieldDesc()->isRecord()) { 245 const Record *R = getRecord(); 246 Result = 247 APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields()); 248 249 for (unsigned I = 0; I != R->getNumFields(); ++I) { 250 const Pointer &FieldPtr = this->atField(R->getField(I)->Offset); 251 Result.getStructField(I) = FieldPtr.toRValue(Ctx); 252 } 253 254 for (unsigned I = 0; I != R->getNumBases(); ++I) { 255 const Pointer &BasePtr = this->atField(R->getBase(I)->Offset); 256 Result.getStructBase(I) = BasePtr.toRValue(Ctx); 257 } 258 } 259 260 // TODO: Arrays 261 262 return Result; 263 } 264