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->replacePointer(&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->replacePointer(&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 if (Desc->asExpr()) { 107 // Pointer pointing to a an expression. 108 IsOnePastEnd = false; 109 Offset = CharUnits::Zero(); 110 } else { 111 // TODO: compute the offset into the object. 112 Offset = CharUnits::Zero(); 113 114 // Build the path into the object. 115 Pointer Ptr = *this; 116 while (Ptr.isField() || Ptr.isArrayElement()) { 117 if (Ptr.isArrayElement()) { 118 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); 119 Ptr = Ptr.getArray(); 120 } else { 121 // TODO: figure out if base is virtual 122 bool IsVirtual = false; 123 124 // Create a path entry for the field. 125 Descriptor *Desc = Ptr.getFieldDesc(); 126 if (auto *BaseOrMember = Desc->asDecl()) { 127 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 128 Ptr = Ptr.getBase(); 129 continue; 130 } 131 llvm_unreachable("Invalid field type"); 132 } 133 } 134 135 IsOnePastEnd = isOnePastEnd(); 136 } 137 } 138 139 // We assemble the LValuePath starting from the innermost pointer to the 140 // outermost one. SO in a.b.c, the first element in Path will refer to 141 // the field 'c', while later code expects it to refer to 'a'. 142 // Just invert the order of the elements. 143 std::reverse(Path.begin(), Path.end()); 144 145 return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); 146 } 147 148 bool Pointer::isInitialized() const { 149 assert(Pointee && "Cannot check if null pointer was initialized"); 150 const Descriptor *Desc = getFieldDesc(); 151 assert(Desc); 152 if (Desc->isPrimitiveArray()) { 153 if (isStatic() && Base == 0) 154 return true; 155 // Primitive array field are stored in a bitset. 156 InitMap *Map = getInitMap(); 157 if (!Map) 158 return false; 159 if (Map == (InitMap *)-1) 160 return true; 161 return Map->isInitialized(getIndex()); 162 } 163 164 // Field has its bit in an inline descriptor. 165 return Base == 0 || getInlineDesc()->IsInitialized; 166 } 167 168 void Pointer::initialize() const { 169 assert(Pointee && "Cannot initialize null pointer"); 170 const Descriptor *Desc = getFieldDesc(); 171 172 assert(Desc); 173 if (Desc->isPrimitiveArray()) { 174 // Primitive global arrays don't have an initmap. 175 if (isStatic() && Base == 0) 176 return; 177 178 // Primitive array initializer. 179 InitMap *&Map = getInitMap(); 180 if (Map == (InitMap *)-1) 181 return; 182 if (Map == nullptr) 183 Map = InitMap::allocate(Desc->getNumElems()); 184 if (Map->initialize(getIndex())) { 185 free(Map); 186 Map = (InitMap *)-1; 187 } 188 return; 189 } 190 191 // Field has its bit in an inline descriptor. 192 assert(Base != 0 && "Only composite fields can be initialised"); 193 getInlineDesc()->IsInitialized = true; 194 } 195 196 void Pointer::activate() const { 197 // Field has its bit in an inline descriptor. 198 assert(Base != 0 && "Only composite fields can be initialised"); 199 getInlineDesc()->IsActive = true; 200 } 201 202 void Pointer::deactivate() const { 203 // TODO: this only appears in constructors, so nothing to deactivate. 204 } 205 206 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 207 return A.Pointee == B.Pointee; 208 } 209 210 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 211 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; 212 } 213