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