106c3fb27SDimitry Andric //===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===//
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 using namespace clang;
2606c3fb27SDimitry Andric 
2706c3fb27SDimitry Andric namespace {
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric // This is internal buffer maintained by Value, used to hold temporaries.
3006c3fb27SDimitry Andric class ValueStorage {
3106c3fb27SDimitry Andric public:
3206c3fb27SDimitry Andric   using DtorFunc = void (*)(void *);
3306c3fb27SDimitry Andric 
CreatePayload(void * DtorF,size_t AllocSize,size_t ElementsSize)3406c3fb27SDimitry Andric   static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,
3506c3fb27SDimitry Andric                                       size_t ElementsSize) {
3606c3fb27SDimitry Andric     if (AllocSize < sizeof(Canary))
3706c3fb27SDimitry Andric       AllocSize = sizeof(Canary);
3806c3fb27SDimitry Andric     unsigned char *Buf =
3906c3fb27SDimitry Andric         new unsigned char[ValueStorage::getPayloadOffset() + AllocSize];
4006c3fb27SDimitry Andric     ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize);
4106c3fb27SDimitry Andric     std::memcpy(VS->getPayload(), Canary, sizeof(Canary));
4206c3fb27SDimitry Andric     return VS->getPayload();
4306c3fb27SDimitry Andric   }
4406c3fb27SDimitry Andric 
getPayload()4506c3fb27SDimitry Andric   unsigned char *getPayload() { return Storage; }
getPayload() const4606c3fb27SDimitry Andric   const unsigned char *getPayload() const { return Storage; }
4706c3fb27SDimitry Andric 
getPayloadOffset()4806c3fb27SDimitry Andric   static unsigned getPayloadOffset() {
4906c3fb27SDimitry Andric     static ValueStorage Dummy(nullptr, 0, 0);
5006c3fb27SDimitry Andric     return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);
5106c3fb27SDimitry Andric   }
5206c3fb27SDimitry Andric 
getFromPayload(void * Payload)5306c3fb27SDimitry Andric   static ValueStorage *getFromPayload(void *Payload) {
5406c3fb27SDimitry Andric     ValueStorage *R = reinterpret_cast<ValueStorage *>(
5506c3fb27SDimitry Andric         (unsigned char *)Payload - getPayloadOffset());
5606c3fb27SDimitry Andric     return R;
5706c3fb27SDimitry Andric   }
5806c3fb27SDimitry Andric 
Retain()5906c3fb27SDimitry Andric   void Retain() { ++RefCnt; }
6006c3fb27SDimitry Andric 
Release()6106c3fb27SDimitry Andric   void Release() {
6206c3fb27SDimitry Andric     assert(RefCnt > 0 && "Can't release if reference count is already zero");
6306c3fb27SDimitry Andric     if (--RefCnt == 0) {
6406c3fb27SDimitry Andric       // We hace a non-trivial dtor.
6506c3fb27SDimitry Andric       if (Dtor && IsAlive()) {
6606c3fb27SDimitry Andric         assert(Elements && "We at least should have 1 element in Value");
6706c3fb27SDimitry Andric         size_t Stride = AllocSize / Elements;
6806c3fb27SDimitry Andric         for (size_t Idx = 0; Idx < Elements; ++Idx)
6906c3fb27SDimitry Andric           (*Dtor)(getPayload() + Idx * Stride);
7006c3fb27SDimitry Andric       }
7106c3fb27SDimitry Andric       delete[] reinterpret_cast<unsigned char *>(this);
7206c3fb27SDimitry Andric     }
7306c3fb27SDimitry Andric   }
7406c3fb27SDimitry Andric 
7506c3fb27SDimitry Andric   // Check whether the storage is valid by validating the canary bits.
7606c3fb27SDimitry Andric   // If someone accidentally write some invalid bits in the storage, the canary
7706c3fb27SDimitry Andric   // will be changed first, and `IsAlive` will return false then.
IsAlive() const7806c3fb27SDimitry Andric   bool IsAlive() const {
7906c3fb27SDimitry Andric     return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0;
8006c3fb27SDimitry Andric   }
8106c3fb27SDimitry Andric 
8206c3fb27SDimitry Andric private:
ValueStorage(void * DtorF,size_t AllocSize,size_t ElementsNum)8306c3fb27SDimitry Andric   ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)
8406c3fb27SDimitry Andric       : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),
8506c3fb27SDimitry Andric         AllocSize(AllocSize), Elements(ElementsNum) {}
8606c3fb27SDimitry Andric 
8706c3fb27SDimitry Andric   mutable unsigned RefCnt;
8806c3fb27SDimitry Andric   DtorFunc Dtor = nullptr;
8906c3fb27SDimitry Andric   size_t AllocSize = 0;
9006c3fb27SDimitry Andric   size_t Elements = 0;
9106c3fb27SDimitry Andric   unsigned char Storage[1];
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric   // These are some canary bits that are used for protecting the storage been
9406c3fb27SDimitry Andric   // damaged.
9506c3fb27SDimitry Andric   static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
9606c3fb27SDimitry Andric                                               0x2d, 0x23, 0x95, 0x91};
9706c3fb27SDimitry Andric };
9806c3fb27SDimitry Andric } // namespace
9906c3fb27SDimitry Andric 
ConvertQualTypeToKind(const ASTContext & Ctx,QualType QT)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 
Value(Interpreter * In,void * Ty)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 
Value(const Value & RHS)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 
Value(Value && RHS)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 
operator =(const Value & RHS)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 
operator =(Value && RHS)20306c3fb27SDimitry Andric Value &Value::operator=(Value &&RHS) noexcept {
204*5f757f3fSDimitry 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;
214*5f757f3fSDimitry Andric   }
21506c3fb27SDimitry Andric   return *this;
21606c3fb27SDimitry Andric }
21706c3fb27SDimitry Andric 
clear()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 
~Value()22706c3fb27SDimitry Andric Value::~Value() { clear(); }
22806c3fb27SDimitry Andric 
getPtr() const22906c3fb27SDimitry Andric void *Value::getPtr() const {
23006c3fb27SDimitry Andric   assert(ValueKind == K_PtrOrObj);
23106c3fb27SDimitry Andric   return Data.m_Ptr;
23206c3fb27SDimitry Andric }
23306c3fb27SDimitry Andric 
getType() const23406c3fb27SDimitry Andric QualType Value::getType() const {
23506c3fb27SDimitry Andric   return QualType::getFromOpaquePtr(OpaqueType);
23606c3fb27SDimitry Andric }
23706c3fb27SDimitry Andric 
getInterpreter()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 
getInterpreter() const24406c3fb27SDimitry 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 
getASTContext()25006c3fb27SDimitry Andric ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }
25106c3fb27SDimitry Andric 
getASTContext() const25206c3fb27SDimitry Andric const ASTContext &Value::getASTContext() const {
25306c3fb27SDimitry Andric   return getInterpreter().getASTContext();
25406c3fb27SDimitry Andric }
25506c3fb27SDimitry Andric 
dump() const25606c3fb27SDimitry Andric void Value::dump() const { print(llvm::outs()); }
25706c3fb27SDimitry Andric 
printType(llvm::raw_ostream & Out) const25806c3fb27SDimitry Andric void Value::printType(llvm::raw_ostream &Out) const {
25906c3fb27SDimitry Andric   Out << "Not implement yet.\n";
26006c3fb27SDimitry Andric }
printData(llvm::raw_ostream & Out) const26106c3fb27SDimitry Andric void Value::printData(llvm::raw_ostream &Out) const {
26206c3fb27SDimitry Andric   Out << "Not implement yet.\n";
26306c3fb27SDimitry Andric }
print(llvm::raw_ostream & Out) const26406c3fb27SDimitry 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