1a7dea167SDimitry Andric //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "Pointer.h" 10a7dea167SDimitry Andric #include "Function.h" 115ffd83dbSDimitry Andric #include "InterpBlock.h" 12a7dea167SDimitry Andric #include "PrimType.h" 13a7dea167SDimitry Andric 14a7dea167SDimitry Andric using namespace clang; 15a7dea167SDimitry Andric using namespace clang::interp; 16a7dea167SDimitry Andric 17a7dea167SDimitry Andric Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {} 18a7dea167SDimitry Andric 19bdd1243dSDimitry Andric Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) 20bdd1243dSDimitry Andric : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} 21bdd1243dSDimitry Andric 22a7dea167SDimitry Andric Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} 23a7dea167SDimitry Andric 24a7dea167SDimitry Andric Pointer::Pointer(Pointer &&P) 25a7dea167SDimitry Andric : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { 26a7dea167SDimitry Andric if (Pointee) 27*06c3fb27SDimitry Andric Pointee->replacePointer(&P, this); 28a7dea167SDimitry Andric } 29a7dea167SDimitry Andric 30a7dea167SDimitry Andric Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) 31a7dea167SDimitry Andric : Pointee(Pointee), Base(Base), Offset(Offset) { 32a7dea167SDimitry Andric assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); 33a7dea167SDimitry Andric if (Pointee) 34a7dea167SDimitry Andric Pointee->addPointer(this); 35a7dea167SDimitry Andric } 36a7dea167SDimitry Andric 37a7dea167SDimitry Andric Pointer::~Pointer() { 38a7dea167SDimitry Andric if (Pointee) { 39a7dea167SDimitry Andric Pointee->removePointer(this); 40a7dea167SDimitry Andric Pointee->cleanup(); 41a7dea167SDimitry Andric } 42a7dea167SDimitry Andric } 43a7dea167SDimitry Andric 44a7dea167SDimitry Andric void Pointer::operator=(const Pointer &P) { 45a7dea167SDimitry Andric Block *Old = Pointee; 46a7dea167SDimitry Andric 47a7dea167SDimitry Andric if (Pointee) 48a7dea167SDimitry Andric Pointee->removePointer(this); 49a7dea167SDimitry Andric 50a7dea167SDimitry Andric Offset = P.Offset; 51a7dea167SDimitry Andric Base = P.Base; 52a7dea167SDimitry Andric 53a7dea167SDimitry Andric Pointee = P.Pointee; 54a7dea167SDimitry Andric if (Pointee) 55a7dea167SDimitry Andric Pointee->addPointer(this); 56a7dea167SDimitry Andric 57a7dea167SDimitry Andric if (Old) 58a7dea167SDimitry Andric Old->cleanup(); 59a7dea167SDimitry Andric } 60a7dea167SDimitry Andric 61a7dea167SDimitry Andric void Pointer::operator=(Pointer &&P) { 62a7dea167SDimitry Andric Block *Old = Pointee; 63a7dea167SDimitry Andric 64a7dea167SDimitry Andric if (Pointee) 65a7dea167SDimitry Andric Pointee->removePointer(this); 66a7dea167SDimitry Andric 67a7dea167SDimitry Andric Offset = P.Offset; 68a7dea167SDimitry Andric Base = P.Base; 69a7dea167SDimitry Andric 70a7dea167SDimitry Andric Pointee = P.Pointee; 71a7dea167SDimitry Andric if (Pointee) 72*06c3fb27SDimitry Andric Pointee->replacePointer(&P, this); 73a7dea167SDimitry Andric 74a7dea167SDimitry Andric if (Old) 75a7dea167SDimitry Andric Old->cleanup(); 76a7dea167SDimitry Andric } 77a7dea167SDimitry Andric 78a7dea167SDimitry Andric APValue Pointer::toAPValue() const { 79a7dea167SDimitry Andric APValue::LValueBase Base; 80a7dea167SDimitry Andric llvm::SmallVector<APValue::LValuePathEntry, 5> Path; 81a7dea167SDimitry Andric CharUnits Offset; 82a7dea167SDimitry Andric bool IsNullPtr; 83a7dea167SDimitry Andric bool IsOnePastEnd; 84a7dea167SDimitry Andric 85a7dea167SDimitry Andric if (isZero()) { 86a7dea167SDimitry Andric Base = static_cast<const Expr *>(nullptr); 87a7dea167SDimitry Andric IsNullPtr = true; 88a7dea167SDimitry Andric IsOnePastEnd = false; 89a7dea167SDimitry Andric Offset = CharUnits::Zero(); 90a7dea167SDimitry Andric } else { 91a7dea167SDimitry Andric // Build the lvalue base from the block. 92a7dea167SDimitry Andric Descriptor *Desc = getDeclDesc(); 93a7dea167SDimitry Andric if (auto *VD = Desc->asValueDecl()) 94a7dea167SDimitry Andric Base = VD; 95a7dea167SDimitry Andric else if (auto *E = Desc->asExpr()) 96a7dea167SDimitry Andric Base = E; 97a7dea167SDimitry Andric else 98a7dea167SDimitry Andric llvm_unreachable("Invalid allocation type"); 99a7dea167SDimitry Andric 100a7dea167SDimitry Andric // Not a null pointer. 101a7dea167SDimitry Andric IsNullPtr = false; 102a7dea167SDimitry Andric 103a7dea167SDimitry Andric if (isUnknownSizeArray()) { 104a7dea167SDimitry Andric IsOnePastEnd = false; 105a7dea167SDimitry Andric Offset = CharUnits::Zero(); 106*06c3fb27SDimitry Andric } else if (Desc->asExpr()) { 107*06c3fb27SDimitry Andric // Pointer pointing to a an expression. 108*06c3fb27SDimitry Andric IsOnePastEnd = false; 109*06c3fb27SDimitry Andric Offset = CharUnits::Zero(); 110a7dea167SDimitry Andric } else { 111a7dea167SDimitry Andric // TODO: compute the offset into the object. 112a7dea167SDimitry Andric Offset = CharUnits::Zero(); 113a7dea167SDimitry Andric 114a7dea167SDimitry Andric // Build the path into the object. 115a7dea167SDimitry Andric Pointer Ptr = *this; 116bdd1243dSDimitry Andric while (Ptr.isField() || Ptr.isArrayElement()) { 117a7dea167SDimitry Andric if (Ptr.isArrayElement()) { 118a7dea167SDimitry Andric Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); 119a7dea167SDimitry Andric Ptr = Ptr.getArray(); 120a7dea167SDimitry Andric } else { 121a7dea167SDimitry Andric // TODO: figure out if base is virtual 122a7dea167SDimitry Andric bool IsVirtual = false; 123a7dea167SDimitry Andric 124a7dea167SDimitry Andric // Create a path entry for the field. 125a7dea167SDimitry Andric Descriptor *Desc = Ptr.getFieldDesc(); 126a7dea167SDimitry Andric if (auto *BaseOrMember = Desc->asDecl()) { 127a7dea167SDimitry Andric Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 128a7dea167SDimitry Andric Ptr = Ptr.getBase(); 129a7dea167SDimitry Andric continue; 130a7dea167SDimitry Andric } 131a7dea167SDimitry Andric llvm_unreachable("Invalid field type"); 132a7dea167SDimitry Andric } 133a7dea167SDimitry Andric } 134a7dea167SDimitry Andric 135a7dea167SDimitry Andric IsOnePastEnd = isOnePastEnd(); 136a7dea167SDimitry Andric } 137a7dea167SDimitry Andric } 138a7dea167SDimitry Andric 139bdd1243dSDimitry Andric // We assemble the LValuePath starting from the innermost pointer to the 140bdd1243dSDimitry Andric // outermost one. SO in a.b.c, the first element in Path will refer to 141bdd1243dSDimitry Andric // the field 'c', while later code expects it to refer to 'a'. 142bdd1243dSDimitry Andric // Just invert the order of the elements. 143bdd1243dSDimitry Andric std::reverse(Path.begin(), Path.end()); 144bdd1243dSDimitry Andric 145a7dea167SDimitry Andric return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); 146a7dea167SDimitry Andric } 147a7dea167SDimitry Andric 148a7dea167SDimitry Andric bool Pointer::isInitialized() const { 149a7dea167SDimitry Andric assert(Pointee && "Cannot check if null pointer was initialized"); 150*06c3fb27SDimitry Andric const Descriptor *Desc = getFieldDesc(); 151bdd1243dSDimitry Andric assert(Desc); 152a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 153bdd1243dSDimitry Andric if (isStatic() && Base == 0) 154a7dea167SDimitry Andric return true; 155a7dea167SDimitry Andric // Primitive array field are stored in a bitset. 156a7dea167SDimitry Andric InitMap *Map = getInitMap(); 157a7dea167SDimitry Andric if (!Map) 158a7dea167SDimitry Andric return false; 159a7dea167SDimitry Andric if (Map == (InitMap *)-1) 160a7dea167SDimitry Andric return true; 161a7dea167SDimitry Andric return Map->isInitialized(getIndex()); 162*06c3fb27SDimitry Andric } 163*06c3fb27SDimitry Andric 164a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 165a7dea167SDimitry Andric return Base == 0 || getInlineDesc()->IsInitialized; 166a7dea167SDimitry Andric } 167a7dea167SDimitry Andric 168a7dea167SDimitry Andric void Pointer::initialize() const { 169a7dea167SDimitry Andric assert(Pointee && "Cannot initialize null pointer"); 170*06c3fb27SDimitry Andric const Descriptor *Desc = getFieldDesc(); 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric assert(Desc); 173a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 174bdd1243dSDimitry Andric // Primitive global arrays don't have an initmap. 175bdd1243dSDimitry Andric if (isStatic() && Base == 0) 176bdd1243dSDimitry Andric return; 177bdd1243dSDimitry Andric 178a7dea167SDimitry Andric // Primitive array initializer. 179a7dea167SDimitry Andric InitMap *&Map = getInitMap(); 180a7dea167SDimitry Andric if (Map == (InitMap *)-1) 181a7dea167SDimitry Andric return; 182a7dea167SDimitry Andric if (Map == nullptr) 183a7dea167SDimitry Andric Map = InitMap::allocate(Desc->getNumElems()); 184a7dea167SDimitry Andric if (Map->initialize(getIndex())) { 185a7dea167SDimitry Andric free(Map); 186a7dea167SDimitry Andric Map = (InitMap *)-1; 187a7dea167SDimitry Andric } 188*06c3fb27SDimitry Andric return; 189a7dea167SDimitry Andric } 190*06c3fb27SDimitry Andric 191a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 192a7dea167SDimitry Andric assert(Base != 0 && "Only composite fields can be initialised"); 193a7dea167SDimitry Andric getInlineDesc()->IsInitialized = true; 194a7dea167SDimitry Andric } 195a7dea167SDimitry Andric 196a7dea167SDimitry Andric void Pointer::activate() const { 197a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 198a7dea167SDimitry Andric assert(Base != 0 && "Only composite fields can be initialised"); 199a7dea167SDimitry Andric getInlineDesc()->IsActive = true; 200a7dea167SDimitry Andric } 201a7dea167SDimitry Andric 202a7dea167SDimitry Andric void Pointer::deactivate() const { 203a7dea167SDimitry Andric // TODO: this only appears in constructors, so nothing to deactivate. 204a7dea167SDimitry Andric } 205a7dea167SDimitry Andric 206a7dea167SDimitry Andric bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 207a7dea167SDimitry Andric return A.Pointee == B.Pointee; 208a7dea167SDimitry Andric } 209a7dea167SDimitry Andric 210a7dea167SDimitry Andric bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 211bdd1243dSDimitry Andric return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; 212a7dea167SDimitry Andric } 213