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 std::optional<APValue> Pointer::toRValue(const Context &Ctx) const { 235 // Method to recursively traverse composites. 236 std::function<bool(QualType, const Pointer &, APValue &)> Composite; 237 Composite = [&Composite, &Ctx](QualType Ty, const Pointer &Ptr, APValue &R) { 238 if (const auto *AT = Ty->getAs<AtomicType>()) 239 Ty = AT->getValueType(); 240 241 // Invalid pointers. 242 if (Ptr.isDummy() || !Ptr.isLive() || 243 (!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd())) 244 return false; 245 246 // Primitive values. 247 if (std::optional<PrimType> T = Ctx.classify(Ty)) { 248 if (T == PT_Ptr || T == PT_FnPtr) { 249 R = Ptr.toAPValue(); 250 } else { 251 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue()); 252 } 253 return true; 254 } 255 256 if (const auto *RT = Ty->getAs<RecordType>()) { 257 const auto *Record = Ptr.getRecord(); 258 assert(Record && "Missing record descriptor"); 259 260 bool Ok = true; 261 if (RT->getDecl()->isUnion()) { 262 const FieldDecl *ActiveField = nullptr; 263 APValue Value; 264 for (const auto &F : Record->fields()) { 265 const Pointer &FP = Ptr.atField(F.Offset); 266 QualType FieldTy = F.Decl->getType(); 267 if (FP.isActive()) { 268 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 269 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue()); 270 } else { 271 Ok &= Composite(FieldTy, FP, Value); 272 } 273 break; 274 } 275 } 276 R = APValue(ActiveField, Value); 277 } else { 278 unsigned NF = Record->getNumFields(); 279 unsigned NB = Record->getNumBases(); 280 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases(); 281 282 R = APValue(APValue::UninitStruct(), NB, NF); 283 284 for (unsigned I = 0; I < NF; ++I) { 285 const Record::Field *FD = Record->getField(I); 286 QualType FieldTy = FD->Decl->getType(); 287 const Pointer &FP = Ptr.atField(FD->Offset); 288 APValue &Value = R.getStructField(I); 289 290 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 291 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue()); 292 } else { 293 Ok &= Composite(FieldTy, FP, Value); 294 } 295 } 296 297 for (unsigned I = 0; I < NB; ++I) { 298 const Record::Base *BD = Record->getBase(I); 299 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl); 300 const Pointer &BP = Ptr.atField(BD->Offset); 301 Ok &= Composite(BaseTy, BP, R.getStructBase(I)); 302 } 303 304 for (unsigned I = 0; I < NV; ++I) { 305 const Record::Base *VD = Record->getVirtualBase(I); 306 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl); 307 const Pointer &VP = Ptr.atField(VD->Offset); 308 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); 309 } 310 } 311 return Ok; 312 } 313 314 if (Ty->isIncompleteArrayType()) { 315 R = APValue(APValue::UninitArray(), 0, 0); 316 return true; 317 } 318 319 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) { 320 const size_t NumElems = Ptr.getNumElems(); 321 QualType ElemTy = AT->getElementType(); 322 R = APValue(APValue::UninitArray{}, NumElems, NumElems); 323 324 bool Ok = true; 325 for (unsigned I = 0; I < NumElems; ++I) { 326 APValue &Slot = R.getArrayInitializedElt(I); 327 const Pointer &EP = Ptr.atIndex(I); 328 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 329 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue()); 330 } else { 331 Ok &= Composite(ElemTy, EP.narrow(), Slot); 332 } 333 } 334 return Ok; 335 } 336 337 // Complex types. 338 if (const auto *CT = Ty->getAs<ComplexType>()) { 339 QualType ElemTy = CT->getElementType(); 340 std::optional<PrimType> ElemT = Ctx.classify(ElemTy); 341 assert(ElemT); 342 343 if (ElemTy->isIntegerType()) { 344 INT_TYPE_SWITCH(*ElemT, { 345 auto V1 = Ptr.atIndex(0).deref<T>(); 346 auto V2 = Ptr.atIndex(1).deref<T>(); 347 R = APValue(V1.toAPSInt(), V2.toAPSInt()); 348 return true; 349 }); 350 } else if (ElemTy->isFloatingType()) { 351 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(), 352 Ptr.atIndex(1).deref<Floating>().getAPFloat()); 353 return true; 354 } 355 return false; 356 } 357 358 llvm_unreachable("invalid value to return"); 359 }; 360 361 if (isZero()) 362 return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {}, false, 363 true); 364 365 if (isDummy() || !isLive()) 366 return std::nullopt; 367 368 // Return the composite type. 369 APValue Result; 370 if (!Composite(getType(), *this, Result)) 371 return std::nullopt; 372 return Result; 373 } 374