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