1 //===------------ Value.cpp - Definition of interpreter value -------------===// 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 // This file defines the class that used to represent a value in incremental 10 // C++. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Interpreter/Value.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/Type.h" 17 #include "clang/Interpreter/Interpreter.h" 18 #include "llvm/ADT/StringExtras.h" 19 #include <cassert> 20 #include <utility> 21 22 namespace { 23 24 // This is internal buffer maintained by Value, used to hold temporaries. 25 class ValueStorage { 26 public: 27 using DtorFunc = void (*)(void *); 28 29 static unsigned char *CreatePayload(void *DtorF, size_t AllocSize, 30 size_t ElementsSize) { 31 if (AllocSize < sizeof(Canary)) 32 AllocSize = sizeof(Canary); 33 unsigned char *Buf = 34 new unsigned char[ValueStorage::getPayloadOffset() + AllocSize]; 35 ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize); 36 std::memcpy(VS->getPayload(), Canary, sizeof(Canary)); 37 return VS->getPayload(); 38 } 39 40 unsigned char *getPayload() { return Storage; } 41 const unsigned char *getPayload() const { return Storage; } 42 43 static unsigned getPayloadOffset() { 44 static ValueStorage Dummy(nullptr, 0, 0); 45 return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy); 46 } 47 48 static ValueStorage *getFromPayload(void *Payload) { 49 ValueStorage *R = reinterpret_cast<ValueStorage *>( 50 (unsigned char *)Payload - getPayloadOffset()); 51 return R; 52 } 53 54 void Retain() { ++RefCnt; } 55 56 void Release() { 57 assert(RefCnt > 0 && "Can't release if reference count is already zero"); 58 if (--RefCnt == 0) { 59 // We have a non-trivial dtor. 60 if (Dtor && IsAlive()) { 61 assert(Elements && "We at least should have 1 element in Value"); 62 size_t Stride = AllocSize / Elements; 63 for (size_t Idx = 0; Idx < Elements; ++Idx) 64 (*Dtor)(getPayload() + Idx * Stride); 65 } 66 delete[] reinterpret_cast<unsigned char *>(this); 67 } 68 } 69 70 // Check whether the storage is valid by validating the canary bits. 71 // If someone accidentally write some invalid bits in the storage, the canary 72 // will be changed first, and `IsAlive` will return false then. 73 bool IsAlive() const { 74 return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0; 75 } 76 77 private: 78 ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum) 79 : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)), 80 AllocSize(AllocSize), Elements(ElementsNum) {} 81 82 mutable unsigned RefCnt; 83 DtorFunc Dtor = nullptr; 84 size_t AllocSize = 0; 85 size_t Elements = 0; 86 unsigned char Storage[1]; 87 88 // These are some canary bits that are used for protecting the storage been 89 // damaged. 90 static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f, 91 0x2d, 0x23, 0x95, 0x91}; 92 }; 93 } // namespace 94 95 namespace clang { 96 97 static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { 98 if (Ctx.hasSameType(QT, Ctx.VoidTy)) 99 return Value::K_Void; 100 101 if (const auto *ET = QT->getAs<EnumType>()) 102 QT = ET->getDecl()->getIntegerType(); 103 104 const auto *BT = QT->getAs<BuiltinType>(); 105 if (!BT || BT->isNullPtrType()) 106 return Value::K_PtrOrObj; 107 108 switch (QT->castAs<BuiltinType>()->getKind()) { 109 default: 110 assert(false && "Type not supported"); 111 return Value::K_Unspecified; 112 #define X(type, name) \ 113 case BuiltinType::name: \ 114 return Value::K_##name; 115 REPL_BUILTIN_TYPES 116 #undef X 117 } 118 } 119 120 Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) { 121 setKind(ConvertQualTypeToKind(getASTContext(), getType())); 122 if (ValueKind == K_PtrOrObj) { 123 QualType Canon = getType().getCanonicalType(); 124 if ((Canon->isPointerType() || Canon->isObjectType() || 125 Canon->isReferenceType()) && 126 (Canon->isRecordType() || Canon->isConstantArrayType() || 127 Canon->isMemberPointerType())) { 128 IsManuallyAlloc = true; 129 // Compile dtor function. 130 Interpreter &Interp = getInterpreter(); 131 void *DtorF = nullptr; 132 size_t ElementsSize = 1; 133 QualType DtorTy = getType(); 134 135 if (const auto *ArrTy = 136 llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) { 137 DtorTy = ArrTy->getElementType(); 138 llvm::APInt ArrSize(sizeof(size_t) * 8, 1); 139 do { 140 ArrSize *= ArrTy->getSize(); 141 ArrTy = llvm::dyn_cast<ConstantArrayType>( 142 ArrTy->getElementType().getTypePtr()); 143 } while (ArrTy); 144 ElementsSize = static_cast<size_t>(ArrSize.getZExtValue()); 145 } 146 if (const auto *RT = DtorTy->getAs<RecordType>()) { 147 if (CXXRecordDecl *CXXRD = 148 llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) { 149 if (llvm::Expected<llvm::orc::ExecutorAddr> Addr = 150 Interp.CompileDtorCall(CXXRD)) 151 DtorF = reinterpret_cast<void *>(Addr->getValue()); 152 else 153 llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs()); 154 } 155 } 156 157 size_t AllocSize = 158 getASTContext().getTypeSizeInChars(getType()).getQuantity(); 159 unsigned char *Payload = 160 ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize); 161 setPtr((void *)Payload); 162 } 163 } 164 } 165 166 Value::Value(const Value &RHS) 167 : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data), 168 ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) { 169 if (IsManuallyAlloc) 170 ValueStorage::getFromPayload(getPtr())->Retain(); 171 } 172 173 Value::Value(Value &&RHS) noexcept { 174 Interp = std::exchange(RHS.Interp, nullptr); 175 OpaqueType = std::exchange(RHS.OpaqueType, nullptr); 176 Data = RHS.Data; 177 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); 178 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); 179 180 if (IsManuallyAlloc) 181 ValueStorage::getFromPayload(getPtr())->Release(); 182 } 183 184 Value &Value::operator=(const Value &RHS) { 185 if (IsManuallyAlloc) 186 ValueStorage::getFromPayload(getPtr())->Release(); 187 188 Interp = RHS.Interp; 189 OpaqueType = RHS.OpaqueType; 190 Data = RHS.Data; 191 ValueKind = RHS.ValueKind; 192 IsManuallyAlloc = RHS.IsManuallyAlloc; 193 194 if (IsManuallyAlloc) 195 ValueStorage::getFromPayload(getPtr())->Retain(); 196 197 return *this; 198 } 199 200 Value &Value::operator=(Value &&RHS) noexcept { 201 if (this != &RHS) { 202 if (IsManuallyAlloc) 203 ValueStorage::getFromPayload(getPtr())->Release(); 204 205 Interp = std::exchange(RHS.Interp, nullptr); 206 OpaqueType = std::exchange(RHS.OpaqueType, nullptr); 207 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); 208 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); 209 210 Data = RHS.Data; 211 } 212 return *this; 213 } 214 215 void Value::clear() { 216 if (IsManuallyAlloc) 217 ValueStorage::getFromPayload(getPtr())->Release(); 218 ValueKind = K_Unspecified; 219 OpaqueType = nullptr; 220 Interp = nullptr; 221 IsManuallyAlloc = false; 222 } 223 224 Value::~Value() { clear(); } 225 226 void *Value::getPtr() const { 227 assert(ValueKind == K_PtrOrObj); 228 return Data.m_Ptr; 229 } 230 231 QualType Value::getType() const { 232 return QualType::getFromOpaquePtr(OpaqueType); 233 } 234 235 Interpreter &Value::getInterpreter() { 236 assert(Interp != nullptr && 237 "Can't get interpreter from a default constructed value"); 238 return *Interp; 239 } 240 241 const Interpreter &Value::getInterpreter() const { 242 assert(Interp != nullptr && 243 "Can't get interpreter from a default constructed value"); 244 return *Interp; 245 } 246 247 ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); } 248 249 const ASTContext &Value::getASTContext() const { 250 return getInterpreter().getASTContext(); 251 } 252 253 void Value::dump() const { print(llvm::outs()); } 254 255 void Value::printType(llvm::raw_ostream &Out) const { 256 Out << "Not implement yet.\n"; 257 } 258 void Value::printData(llvm::raw_ostream &Out) const { 259 Out << "Not implement yet.\n"; 260 } 261 void Value::print(llvm::raw_ostream &Out) const { 262 assert(OpaqueType != nullptr && "Can't print default Value"); 263 Out << "Not implement yet.\n"; 264 } 265 266 } // namespace clang 267