xref: /llvm-project/clang/lib/Interpreter/Value.cpp (revision 546dc2245ffc4cccd0b05b58b7a5955e355a3b27)
1*546dc224SStefan Gränitz //===------------ Value.cpp - Definition of interpreter value -------------===//
25111286fSJun Zhang //
35111286fSJun Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45111286fSJun Zhang // See https://llvm.org/LICENSE.txt for license information.
55111286fSJun Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65111286fSJun Zhang //
75111286fSJun Zhang //===----------------------------------------------------------------------===//
85111286fSJun Zhang //
95111286fSJun Zhang // This file defines the class that used to represent a value in incremental
105111286fSJun Zhang // C++.
115111286fSJun Zhang //
125111286fSJun Zhang //===----------------------------------------------------------------------===//
135111286fSJun Zhang 
145111286fSJun Zhang #include "clang/Interpreter/Value.h"
155111286fSJun Zhang #include "clang/AST/ASTContext.h"
165111286fSJun Zhang #include "clang/AST/Type.h"
175111286fSJun Zhang #include "clang/Interpreter/Interpreter.h"
185111286fSJun Zhang #include "llvm/ADT/StringExtras.h"
195111286fSJun Zhang #include "llvm/Support/ErrorHandling.h"
205111286fSJun Zhang #include "llvm/Support/raw_os_ostream.h"
215111286fSJun Zhang #include <cassert>
225111286fSJun Zhang #include <cstdint>
235111286fSJun Zhang #include <utility>
245111286fSJun Zhang 
255111286fSJun Zhang namespace {
265111286fSJun Zhang 
275111286fSJun Zhang // This is internal buffer maintained by Value, used to hold temporaries.
285111286fSJun Zhang class ValueStorage {
295111286fSJun Zhang public:
305111286fSJun Zhang   using DtorFunc = void (*)(void *);
315111286fSJun Zhang 
CreatePayload(void * DtorF,size_t AllocSize,size_t ElementsSize)325111286fSJun Zhang   static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,
335111286fSJun Zhang                                       size_t ElementsSize) {
345111286fSJun Zhang     if (AllocSize < sizeof(Canary))
355111286fSJun Zhang       AllocSize = sizeof(Canary);
365111286fSJun Zhang     unsigned char *Buf =
375111286fSJun Zhang         new unsigned char[ValueStorage::getPayloadOffset() + AllocSize];
385111286fSJun Zhang     ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize);
395111286fSJun Zhang     std::memcpy(VS->getPayload(), Canary, sizeof(Canary));
405111286fSJun Zhang     return VS->getPayload();
415111286fSJun Zhang   }
425111286fSJun Zhang 
getPayload()435111286fSJun Zhang   unsigned char *getPayload() { return Storage; }
getPayload() const445111286fSJun Zhang   const unsigned char *getPayload() const { return Storage; }
455111286fSJun Zhang 
getPayloadOffset()465111286fSJun Zhang   static unsigned getPayloadOffset() {
475111286fSJun Zhang     static ValueStorage Dummy(nullptr, 0, 0);
485111286fSJun Zhang     return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);
495111286fSJun Zhang   }
505111286fSJun Zhang 
getFromPayload(void * Payload)515111286fSJun Zhang   static ValueStorage *getFromPayload(void *Payload) {
525111286fSJun Zhang     ValueStorage *R = reinterpret_cast<ValueStorage *>(
535111286fSJun Zhang         (unsigned char *)Payload - getPayloadOffset());
545111286fSJun Zhang     return R;
555111286fSJun Zhang   }
565111286fSJun Zhang 
Retain()575111286fSJun Zhang   void Retain() { ++RefCnt; }
585111286fSJun Zhang 
Release()595111286fSJun Zhang   void Release() {
605111286fSJun Zhang     assert(RefCnt > 0 && "Can't release if reference count is already zero");
615111286fSJun Zhang     if (--RefCnt == 0) {
62*546dc224SStefan Gränitz       // We have a non-trivial dtor.
635111286fSJun Zhang       if (Dtor && IsAlive()) {
645111286fSJun Zhang         assert(Elements && "We at least should have 1 element in Value");
655111286fSJun Zhang         size_t Stride = AllocSize / Elements;
665111286fSJun Zhang         for (size_t Idx = 0; Idx < Elements; ++Idx)
675111286fSJun Zhang           (*Dtor)(getPayload() + Idx * Stride);
685111286fSJun Zhang       }
695111286fSJun Zhang       delete[] reinterpret_cast<unsigned char *>(this);
705111286fSJun Zhang     }
715111286fSJun Zhang   }
725111286fSJun Zhang 
735111286fSJun Zhang   // Check whether the storage is valid by validating the canary bits.
745111286fSJun Zhang   // If someone accidentally write some invalid bits in the storage, the canary
755111286fSJun Zhang   // will be changed first, and `IsAlive` will return false then.
IsAlive() const765111286fSJun Zhang   bool IsAlive() const {
775111286fSJun Zhang     return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0;
785111286fSJun Zhang   }
795111286fSJun Zhang 
805111286fSJun Zhang private:
ValueStorage(void * DtorF,size_t AllocSize,size_t ElementsNum)815111286fSJun Zhang   ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)
825111286fSJun Zhang       : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),
835111286fSJun Zhang         AllocSize(AllocSize), Elements(ElementsNum) {}
845111286fSJun Zhang 
855111286fSJun Zhang   mutable unsigned RefCnt;
865111286fSJun Zhang   DtorFunc Dtor = nullptr;
875111286fSJun Zhang   size_t AllocSize = 0;
885111286fSJun Zhang   size_t Elements = 0;
895111286fSJun Zhang   unsigned char Storage[1];
905111286fSJun Zhang 
915111286fSJun Zhang   // These are some canary bits that are used for protecting the storage been
925111286fSJun Zhang   // damaged.
935111286fSJun Zhang   static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
945111286fSJun Zhang                                               0x2d, 0x23, 0x95, 0x91};
955111286fSJun Zhang };
965111286fSJun Zhang } // namespace
975111286fSJun Zhang 
98*546dc224SStefan Gränitz namespace clang {
99*546dc224SStefan Gränitz 
ConvertQualTypeToKind(const ASTContext & Ctx,QualType QT)1005111286fSJun Zhang static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) {
1015111286fSJun Zhang   if (Ctx.hasSameType(QT, Ctx.VoidTy))
1025111286fSJun Zhang     return Value::K_Void;
1035111286fSJun Zhang 
1045111286fSJun Zhang   if (const auto *ET = QT->getAs<EnumType>())
1055111286fSJun Zhang     QT = ET->getDecl()->getIntegerType();
1065111286fSJun Zhang 
1075111286fSJun Zhang   const auto *BT = QT->getAs<BuiltinType>();
1085111286fSJun Zhang   if (!BT || BT->isNullPtrType())
1095111286fSJun Zhang     return Value::K_PtrOrObj;
1105111286fSJun Zhang 
111b0525f66SManna, Soumi   switch (QT->castAs<BuiltinType>()->getKind()) {
1125111286fSJun Zhang   default:
1135111286fSJun Zhang     assert(false && "Type not supported");
1145111286fSJun Zhang     return Value::K_Unspecified;
1155111286fSJun Zhang #define X(type, name)                                                          \
1165111286fSJun Zhang   case BuiltinType::name:                                                      \
1175111286fSJun Zhang     return Value::K_##name;
1185111286fSJun Zhang     REPL_BUILTIN_TYPES
1195111286fSJun Zhang #undef X
1205111286fSJun Zhang   }
1215111286fSJun Zhang }
1225111286fSJun Zhang 
Value(Interpreter * In,void * Ty)1235111286fSJun Zhang Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {
1245111286fSJun Zhang   setKind(ConvertQualTypeToKind(getASTContext(), getType()));
1255111286fSJun Zhang   if (ValueKind == K_PtrOrObj) {
1265111286fSJun Zhang     QualType Canon = getType().getCanonicalType();
1275111286fSJun Zhang     if ((Canon->isPointerType() || Canon->isObjectType() ||
1285111286fSJun Zhang          Canon->isReferenceType()) &&
1295111286fSJun Zhang         (Canon->isRecordType() || Canon->isConstantArrayType() ||
1305111286fSJun Zhang          Canon->isMemberPointerType())) {
1315111286fSJun Zhang       IsManuallyAlloc = true;
1325111286fSJun Zhang       // Compile dtor function.
1335111286fSJun Zhang       Interpreter &Interp = getInterpreter();
1345111286fSJun Zhang       void *DtorF = nullptr;
1355111286fSJun Zhang       size_t ElementsSize = 1;
1365111286fSJun Zhang       QualType DtorTy = getType();
1375111286fSJun Zhang 
1385111286fSJun Zhang       if (const auto *ArrTy =
1395111286fSJun Zhang               llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) {
1405111286fSJun Zhang         DtorTy = ArrTy->getElementType();
1415111286fSJun Zhang         llvm::APInt ArrSize(sizeof(size_t) * 8, 1);
1425111286fSJun Zhang         do {
1435111286fSJun Zhang           ArrSize *= ArrTy->getSize();
1445111286fSJun Zhang           ArrTy = llvm::dyn_cast<ConstantArrayType>(
1455111286fSJun Zhang               ArrTy->getElementType().getTypePtr());
1465111286fSJun Zhang         } while (ArrTy);
1475111286fSJun Zhang         ElementsSize = static_cast<size_t>(ArrSize.getZExtValue());
1485111286fSJun Zhang       }
1495111286fSJun Zhang       if (const auto *RT = DtorTy->getAs<RecordType>()) {
1505111286fSJun Zhang         if (CXXRecordDecl *CXXRD =
1515111286fSJun Zhang                 llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
1525111286fSJun Zhang           if (llvm::Expected<llvm::orc::ExecutorAddr> Addr =
1535111286fSJun Zhang                   Interp.CompileDtorCall(CXXRD))
1545111286fSJun Zhang             DtorF = reinterpret_cast<void *>(Addr->getValue());
1555111286fSJun Zhang           else
1565111286fSJun Zhang             llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());
1575111286fSJun Zhang         }
1585111286fSJun Zhang       }
1595111286fSJun Zhang 
1605111286fSJun Zhang       size_t AllocSize =
1615111286fSJun Zhang           getASTContext().getTypeSizeInChars(getType()).getQuantity();
1625111286fSJun Zhang       unsigned char *Payload =
1635111286fSJun Zhang           ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);
1645111286fSJun Zhang       setPtr((void *)Payload);
1655111286fSJun Zhang     }
1665111286fSJun Zhang   }
1675111286fSJun Zhang }
1685111286fSJun Zhang 
Value(const Value & RHS)1695111286fSJun Zhang Value::Value(const Value &RHS)
1705111286fSJun Zhang     : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data),
1715111286fSJun Zhang       ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) {
1725111286fSJun Zhang   if (IsManuallyAlloc)
1735111286fSJun Zhang     ValueStorage::getFromPayload(getPtr())->Retain();
1745111286fSJun Zhang }
1755111286fSJun Zhang 
Value(Value && RHS)1765111286fSJun Zhang Value::Value(Value &&RHS) noexcept {
1775111286fSJun Zhang   Interp = std::exchange(RHS.Interp, nullptr);
1785111286fSJun Zhang   OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
1795111286fSJun Zhang   Data = RHS.Data;
1805111286fSJun Zhang   ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
1815111286fSJun Zhang   IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
1825111286fSJun Zhang 
1835111286fSJun Zhang   if (IsManuallyAlloc)
1845111286fSJun Zhang     ValueStorage::getFromPayload(getPtr())->Release();
1855111286fSJun Zhang }
1865111286fSJun Zhang 
operator =(const Value & RHS)1875111286fSJun Zhang Value &Value::operator=(const Value &RHS) {
1885111286fSJun Zhang   if (IsManuallyAlloc)
1895111286fSJun Zhang     ValueStorage::getFromPayload(getPtr())->Release();
1905111286fSJun Zhang 
1915111286fSJun Zhang   Interp = RHS.Interp;
1925111286fSJun Zhang   OpaqueType = RHS.OpaqueType;
1935111286fSJun Zhang   Data = RHS.Data;
1945111286fSJun Zhang   ValueKind = RHS.ValueKind;
1955111286fSJun Zhang   IsManuallyAlloc = RHS.IsManuallyAlloc;
1965111286fSJun Zhang 
1975111286fSJun Zhang   if (IsManuallyAlloc)
1985111286fSJun Zhang     ValueStorage::getFromPayload(getPtr())->Retain();
1995111286fSJun Zhang 
2005111286fSJun Zhang   return *this;
2015111286fSJun Zhang }
2025111286fSJun Zhang 
operator =(Value && RHS)2035111286fSJun Zhang Value &Value::operator=(Value &&RHS) noexcept {
2044ad89131SSindhu Chittireddy   if (this != &RHS) {
2055111286fSJun Zhang     if (IsManuallyAlloc)
2065111286fSJun Zhang       ValueStorage::getFromPayload(getPtr())->Release();
2075111286fSJun Zhang 
2085111286fSJun Zhang     Interp = std::exchange(RHS.Interp, nullptr);
2095111286fSJun Zhang     OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
2105111286fSJun Zhang     ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
2115111286fSJun Zhang     IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
2125111286fSJun Zhang 
2135111286fSJun Zhang     Data = RHS.Data;
2144ad89131SSindhu Chittireddy   }
2155111286fSJun Zhang   return *this;
2165111286fSJun Zhang }
2175111286fSJun Zhang 
clear()2185111286fSJun Zhang void Value::clear() {
2195111286fSJun Zhang   if (IsManuallyAlloc)
2205111286fSJun Zhang     ValueStorage::getFromPayload(getPtr())->Release();
2215111286fSJun Zhang   ValueKind = K_Unspecified;
2225111286fSJun Zhang   OpaqueType = nullptr;
2235111286fSJun Zhang   Interp = nullptr;
2245111286fSJun Zhang   IsManuallyAlloc = false;
2255111286fSJun Zhang }
2265111286fSJun Zhang 
~Value()2275111286fSJun Zhang Value::~Value() { clear(); }
2285111286fSJun Zhang 
getPtr() const2295111286fSJun Zhang void *Value::getPtr() const {
2305111286fSJun Zhang   assert(ValueKind == K_PtrOrObj);
2315111286fSJun Zhang   return Data.m_Ptr;
2325111286fSJun Zhang }
2335111286fSJun Zhang 
getType() const2345111286fSJun Zhang QualType Value::getType() const {
2355111286fSJun Zhang   return QualType::getFromOpaquePtr(OpaqueType);
2365111286fSJun Zhang }
2375111286fSJun Zhang 
getInterpreter()2385111286fSJun Zhang Interpreter &Value::getInterpreter() {
2395111286fSJun Zhang   assert(Interp != nullptr &&
2405111286fSJun Zhang          "Can't get interpreter from a default constructed value");
2415111286fSJun Zhang   return *Interp;
2425111286fSJun Zhang }
2435111286fSJun Zhang 
getInterpreter() const2445111286fSJun Zhang const Interpreter &Value::getInterpreter() const {
2455111286fSJun Zhang   assert(Interp != nullptr &&
2465111286fSJun Zhang          "Can't get interpreter from a default constructed value");
2475111286fSJun Zhang   return *Interp;
2485111286fSJun Zhang }
2495111286fSJun Zhang 
getASTContext()2505111286fSJun Zhang ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }
2515111286fSJun Zhang 
getASTContext() const2525111286fSJun Zhang const ASTContext &Value::getASTContext() const {
2535111286fSJun Zhang   return getInterpreter().getASTContext();
2545111286fSJun Zhang }
2555111286fSJun Zhang 
dump() const2565111286fSJun Zhang void Value::dump() const { print(llvm::outs()); }
2575111286fSJun Zhang 
printType(llvm::raw_ostream & Out) const2585111286fSJun Zhang void Value::printType(llvm::raw_ostream &Out) const {
2595111286fSJun Zhang   Out << "Not implement yet.\n";
2605111286fSJun Zhang }
printData(llvm::raw_ostream & Out) const2615111286fSJun Zhang void Value::printData(llvm::raw_ostream &Out) const {
2625111286fSJun Zhang   Out << "Not implement yet.\n";
2635111286fSJun Zhang }
print(llvm::raw_ostream & Out) const2645111286fSJun Zhang void Value::print(llvm::raw_ostream &Out) const {
2655111286fSJun Zhang   assert(OpaqueType != nullptr && "Can't print default Value");
2665111286fSJun Zhang   Out << "Not implement yet.\n";
2675111286fSJun Zhang }
268*546dc224SStefan Gränitz 
269*546dc224SStefan Gränitz } // namespace clang
270