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