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