1*0fca6ea1SDimitry Andric //===------------ Value.cpp - Definition of interpreter value -------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // This file defines the class that used to represent a value in incremental 1006c3fb27SDimitry Andric // C++. 1106c3fb27SDimitry Andric // 1206c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1306c3fb27SDimitry Andric 1406c3fb27SDimitry Andric #include "clang/Interpreter/Value.h" 1506c3fb27SDimitry Andric #include "clang/AST/ASTContext.h" 1606c3fb27SDimitry Andric #include "clang/AST/Type.h" 1706c3fb27SDimitry Andric #include "clang/Interpreter/Interpreter.h" 1806c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 1906c3fb27SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2006c3fb27SDimitry Andric #include "llvm/Support/raw_os_ostream.h" 2106c3fb27SDimitry Andric #include <cassert> 2206c3fb27SDimitry Andric #include <cstdint> 2306c3fb27SDimitry Andric #include <utility> 2406c3fb27SDimitry Andric 2506c3fb27SDimitry Andric namespace { 2606c3fb27SDimitry Andric 2706c3fb27SDimitry Andric // This is internal buffer maintained by Value, used to hold temporaries. 2806c3fb27SDimitry Andric class ValueStorage { 2906c3fb27SDimitry Andric public: 3006c3fb27SDimitry Andric using DtorFunc = void (*)(void *); 3106c3fb27SDimitry Andric 3206c3fb27SDimitry Andric static unsigned char *CreatePayload(void *DtorF, size_t AllocSize, 3306c3fb27SDimitry Andric size_t ElementsSize) { 3406c3fb27SDimitry Andric if (AllocSize < sizeof(Canary)) 3506c3fb27SDimitry Andric AllocSize = sizeof(Canary); 3606c3fb27SDimitry Andric unsigned char *Buf = 3706c3fb27SDimitry Andric new unsigned char[ValueStorage::getPayloadOffset() + AllocSize]; 3806c3fb27SDimitry Andric ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize); 3906c3fb27SDimitry Andric std::memcpy(VS->getPayload(), Canary, sizeof(Canary)); 4006c3fb27SDimitry Andric return VS->getPayload(); 4106c3fb27SDimitry Andric } 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric unsigned char *getPayload() { return Storage; } 4406c3fb27SDimitry Andric const unsigned char *getPayload() const { return Storage; } 4506c3fb27SDimitry Andric 4606c3fb27SDimitry Andric static unsigned getPayloadOffset() { 4706c3fb27SDimitry Andric static ValueStorage Dummy(nullptr, 0, 0); 4806c3fb27SDimitry Andric return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy); 4906c3fb27SDimitry Andric } 5006c3fb27SDimitry Andric 5106c3fb27SDimitry Andric static ValueStorage *getFromPayload(void *Payload) { 5206c3fb27SDimitry Andric ValueStorage *R = reinterpret_cast<ValueStorage *>( 5306c3fb27SDimitry Andric (unsigned char *)Payload - getPayloadOffset()); 5406c3fb27SDimitry Andric return R; 5506c3fb27SDimitry Andric } 5606c3fb27SDimitry Andric 5706c3fb27SDimitry Andric void Retain() { ++RefCnt; } 5806c3fb27SDimitry Andric 5906c3fb27SDimitry Andric void Release() { 6006c3fb27SDimitry Andric assert(RefCnt > 0 && "Can't release if reference count is already zero"); 6106c3fb27SDimitry Andric if (--RefCnt == 0) { 62*0fca6ea1SDimitry Andric // We have a non-trivial dtor. 6306c3fb27SDimitry Andric if (Dtor && IsAlive()) { 6406c3fb27SDimitry Andric assert(Elements && "We at least should have 1 element in Value"); 6506c3fb27SDimitry Andric size_t Stride = AllocSize / Elements; 6606c3fb27SDimitry Andric for (size_t Idx = 0; Idx < Elements; ++Idx) 6706c3fb27SDimitry Andric (*Dtor)(getPayload() + Idx * Stride); 6806c3fb27SDimitry Andric } 6906c3fb27SDimitry Andric delete[] reinterpret_cast<unsigned char *>(this); 7006c3fb27SDimitry Andric } 7106c3fb27SDimitry Andric } 7206c3fb27SDimitry Andric 7306c3fb27SDimitry Andric // Check whether the storage is valid by validating the canary bits. 7406c3fb27SDimitry Andric // If someone accidentally write some invalid bits in the storage, the canary 7506c3fb27SDimitry Andric // will be changed first, and `IsAlive` will return false then. 7606c3fb27SDimitry Andric bool IsAlive() const { 7706c3fb27SDimitry Andric return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0; 7806c3fb27SDimitry Andric } 7906c3fb27SDimitry Andric 8006c3fb27SDimitry Andric private: 8106c3fb27SDimitry Andric ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum) 8206c3fb27SDimitry Andric : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)), 8306c3fb27SDimitry Andric AllocSize(AllocSize), Elements(ElementsNum) {} 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric mutable unsigned RefCnt; 8606c3fb27SDimitry Andric DtorFunc Dtor = nullptr; 8706c3fb27SDimitry Andric size_t AllocSize = 0; 8806c3fb27SDimitry Andric size_t Elements = 0; 8906c3fb27SDimitry Andric unsigned char Storage[1]; 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric // These are some canary bits that are used for protecting the storage been 9206c3fb27SDimitry Andric // damaged. 9306c3fb27SDimitry Andric static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f, 9406c3fb27SDimitry Andric 0x2d, 0x23, 0x95, 0x91}; 9506c3fb27SDimitry Andric }; 9606c3fb27SDimitry Andric } // namespace 9706c3fb27SDimitry Andric 98*0fca6ea1SDimitry Andric namespace clang { 99*0fca6ea1SDimitry Andric 10006c3fb27SDimitry Andric static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { 10106c3fb27SDimitry Andric if (Ctx.hasSameType(QT, Ctx.VoidTy)) 10206c3fb27SDimitry Andric return Value::K_Void; 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric if (const auto *ET = QT->getAs<EnumType>()) 10506c3fb27SDimitry Andric QT = ET->getDecl()->getIntegerType(); 10606c3fb27SDimitry Andric 10706c3fb27SDimitry Andric const auto *BT = QT->getAs<BuiltinType>(); 10806c3fb27SDimitry Andric if (!BT || BT->isNullPtrType()) 10906c3fb27SDimitry Andric return Value::K_PtrOrObj; 11006c3fb27SDimitry Andric 11106c3fb27SDimitry Andric switch (QT->castAs<BuiltinType>()->getKind()) { 11206c3fb27SDimitry Andric default: 11306c3fb27SDimitry Andric assert(false && "Type not supported"); 11406c3fb27SDimitry Andric return Value::K_Unspecified; 11506c3fb27SDimitry Andric #define X(type, name) \ 11606c3fb27SDimitry Andric case BuiltinType::name: \ 11706c3fb27SDimitry Andric return Value::K_##name; 11806c3fb27SDimitry Andric REPL_BUILTIN_TYPES 11906c3fb27SDimitry Andric #undef X 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric } 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) { 12406c3fb27SDimitry Andric setKind(ConvertQualTypeToKind(getASTContext(), getType())); 12506c3fb27SDimitry Andric if (ValueKind == K_PtrOrObj) { 12606c3fb27SDimitry Andric QualType Canon = getType().getCanonicalType(); 12706c3fb27SDimitry Andric if ((Canon->isPointerType() || Canon->isObjectType() || 12806c3fb27SDimitry Andric Canon->isReferenceType()) && 12906c3fb27SDimitry Andric (Canon->isRecordType() || Canon->isConstantArrayType() || 13006c3fb27SDimitry Andric Canon->isMemberPointerType())) { 13106c3fb27SDimitry Andric IsManuallyAlloc = true; 13206c3fb27SDimitry Andric // Compile dtor function. 13306c3fb27SDimitry Andric Interpreter &Interp = getInterpreter(); 13406c3fb27SDimitry Andric void *DtorF = nullptr; 13506c3fb27SDimitry Andric size_t ElementsSize = 1; 13606c3fb27SDimitry Andric QualType DtorTy = getType(); 13706c3fb27SDimitry Andric 13806c3fb27SDimitry Andric if (const auto *ArrTy = 13906c3fb27SDimitry Andric llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) { 14006c3fb27SDimitry Andric DtorTy = ArrTy->getElementType(); 14106c3fb27SDimitry Andric llvm::APInt ArrSize(sizeof(size_t) * 8, 1); 14206c3fb27SDimitry Andric do { 14306c3fb27SDimitry Andric ArrSize *= ArrTy->getSize(); 14406c3fb27SDimitry Andric ArrTy = llvm::dyn_cast<ConstantArrayType>( 14506c3fb27SDimitry Andric ArrTy->getElementType().getTypePtr()); 14606c3fb27SDimitry Andric } while (ArrTy); 14706c3fb27SDimitry Andric ElementsSize = static_cast<size_t>(ArrSize.getZExtValue()); 14806c3fb27SDimitry Andric } 14906c3fb27SDimitry Andric if (const auto *RT = DtorTy->getAs<RecordType>()) { 15006c3fb27SDimitry Andric if (CXXRecordDecl *CXXRD = 15106c3fb27SDimitry Andric llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) { 15206c3fb27SDimitry Andric if (llvm::Expected<llvm::orc::ExecutorAddr> Addr = 15306c3fb27SDimitry Andric Interp.CompileDtorCall(CXXRD)) 15406c3fb27SDimitry Andric DtorF = reinterpret_cast<void *>(Addr->getValue()); 15506c3fb27SDimitry Andric else 15606c3fb27SDimitry Andric llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs()); 15706c3fb27SDimitry Andric } 15806c3fb27SDimitry Andric } 15906c3fb27SDimitry Andric 16006c3fb27SDimitry Andric size_t AllocSize = 16106c3fb27SDimitry Andric getASTContext().getTypeSizeInChars(getType()).getQuantity(); 16206c3fb27SDimitry Andric unsigned char *Payload = 16306c3fb27SDimitry Andric ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize); 16406c3fb27SDimitry Andric setPtr((void *)Payload); 16506c3fb27SDimitry Andric } 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric } 16806c3fb27SDimitry Andric 16906c3fb27SDimitry Andric Value::Value(const Value &RHS) 17006c3fb27SDimitry Andric : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data), 17106c3fb27SDimitry Andric ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) { 17206c3fb27SDimitry Andric if (IsManuallyAlloc) 17306c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Retain(); 17406c3fb27SDimitry Andric } 17506c3fb27SDimitry Andric 17606c3fb27SDimitry Andric Value::Value(Value &&RHS) noexcept { 17706c3fb27SDimitry Andric Interp = std::exchange(RHS.Interp, nullptr); 17806c3fb27SDimitry Andric OpaqueType = std::exchange(RHS.OpaqueType, nullptr); 17906c3fb27SDimitry Andric Data = RHS.Data; 18006c3fb27SDimitry Andric ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); 18106c3fb27SDimitry Andric IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); 18206c3fb27SDimitry Andric 18306c3fb27SDimitry Andric if (IsManuallyAlloc) 18406c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Release(); 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric 18706c3fb27SDimitry Andric Value &Value::operator=(const Value &RHS) { 18806c3fb27SDimitry Andric if (IsManuallyAlloc) 18906c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Release(); 19006c3fb27SDimitry Andric 19106c3fb27SDimitry Andric Interp = RHS.Interp; 19206c3fb27SDimitry Andric OpaqueType = RHS.OpaqueType; 19306c3fb27SDimitry Andric Data = RHS.Data; 19406c3fb27SDimitry Andric ValueKind = RHS.ValueKind; 19506c3fb27SDimitry Andric IsManuallyAlloc = RHS.IsManuallyAlloc; 19606c3fb27SDimitry Andric 19706c3fb27SDimitry Andric if (IsManuallyAlloc) 19806c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Retain(); 19906c3fb27SDimitry Andric 20006c3fb27SDimitry Andric return *this; 20106c3fb27SDimitry Andric } 20206c3fb27SDimitry Andric 20306c3fb27SDimitry Andric Value &Value::operator=(Value &&RHS) noexcept { 2045f757f3fSDimitry Andric if (this != &RHS) { 20506c3fb27SDimitry Andric if (IsManuallyAlloc) 20606c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Release(); 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric Interp = std::exchange(RHS.Interp, nullptr); 20906c3fb27SDimitry Andric OpaqueType = std::exchange(RHS.OpaqueType, nullptr); 21006c3fb27SDimitry Andric ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); 21106c3fb27SDimitry Andric IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric Data = RHS.Data; 2145f757f3fSDimitry Andric } 21506c3fb27SDimitry Andric return *this; 21606c3fb27SDimitry Andric } 21706c3fb27SDimitry Andric 21806c3fb27SDimitry Andric void Value::clear() { 21906c3fb27SDimitry Andric if (IsManuallyAlloc) 22006c3fb27SDimitry Andric ValueStorage::getFromPayload(getPtr())->Release(); 22106c3fb27SDimitry Andric ValueKind = K_Unspecified; 22206c3fb27SDimitry Andric OpaqueType = nullptr; 22306c3fb27SDimitry Andric Interp = nullptr; 22406c3fb27SDimitry Andric IsManuallyAlloc = false; 22506c3fb27SDimitry Andric } 22606c3fb27SDimitry Andric 22706c3fb27SDimitry Andric Value::~Value() { clear(); } 22806c3fb27SDimitry Andric 22906c3fb27SDimitry Andric void *Value::getPtr() const { 23006c3fb27SDimitry Andric assert(ValueKind == K_PtrOrObj); 23106c3fb27SDimitry Andric return Data.m_Ptr; 23206c3fb27SDimitry Andric } 23306c3fb27SDimitry Andric 23406c3fb27SDimitry Andric QualType Value::getType() const { 23506c3fb27SDimitry Andric return QualType::getFromOpaquePtr(OpaqueType); 23606c3fb27SDimitry Andric } 23706c3fb27SDimitry Andric 23806c3fb27SDimitry Andric Interpreter &Value::getInterpreter() { 23906c3fb27SDimitry Andric assert(Interp != nullptr && 24006c3fb27SDimitry Andric "Can't get interpreter from a default constructed value"); 24106c3fb27SDimitry Andric return *Interp; 24206c3fb27SDimitry Andric } 24306c3fb27SDimitry Andric 24406c3fb27SDimitry Andric const Interpreter &Value::getInterpreter() const { 24506c3fb27SDimitry Andric assert(Interp != nullptr && 24606c3fb27SDimitry Andric "Can't get interpreter from a default constructed value"); 24706c3fb27SDimitry Andric return *Interp; 24806c3fb27SDimitry Andric } 24906c3fb27SDimitry Andric 25006c3fb27SDimitry Andric ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); } 25106c3fb27SDimitry Andric 25206c3fb27SDimitry Andric const ASTContext &Value::getASTContext() const { 25306c3fb27SDimitry Andric return getInterpreter().getASTContext(); 25406c3fb27SDimitry Andric } 25506c3fb27SDimitry Andric 25606c3fb27SDimitry Andric void Value::dump() const { print(llvm::outs()); } 25706c3fb27SDimitry Andric 25806c3fb27SDimitry Andric void Value::printType(llvm::raw_ostream &Out) const { 25906c3fb27SDimitry Andric Out << "Not implement yet.\n"; 26006c3fb27SDimitry Andric } 26106c3fb27SDimitry Andric void Value::printData(llvm::raw_ostream &Out) const { 26206c3fb27SDimitry Andric Out << "Not implement yet.\n"; 26306c3fb27SDimitry Andric } 26406c3fb27SDimitry Andric void Value::print(llvm::raw_ostream &Out) const { 26506c3fb27SDimitry Andric assert(OpaqueType != nullptr && "Can't print default Value"); 26606c3fb27SDimitry Andric Out << "Not implement yet.\n"; 26706c3fb27SDimitry Andric } 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric } // namespace clang 270