1 //===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the class that used to represent a value in incremental
12 //===----------------------------------------------------------------------===//
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"
25 using namespace clang
;
29 // This is internal buffer maintained by Value, used to hold temporaries.
32 using DtorFunc
= void (*)(void *);
34 static unsigned char *CreatePayload(void *DtorF
, size_t AllocSize
,
35 size_t ElementsSize
) {
36 if (AllocSize
< sizeof(Canary
))
37 AllocSize
= sizeof(Canary
);
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();
45 unsigned char *getPayload() { return Storage
; }
46 const unsigned char *getPayload() const { return Storage
; }
48 static unsigned getPayloadOffset() {
49 static ValueStorage
Dummy(nullptr, 0, 0);
50 return Dummy
.getPayload() - reinterpret_cast<unsigned char *>(&Dummy
);
53 static ValueStorage
*getFromPayload(void *Payload
) {
54 ValueStorage
*R
= reinterpret_cast<ValueStorage
*>(
55 (unsigned char *)Payload
- getPayloadOffset());
59 void Retain() { ++RefCnt
; }
62 assert(RefCnt
> 0 && "Can't release if reference count is already zero");
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
);
71 delete[] reinterpret_cast<unsigned char *>(this);
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;
83 ValueStorage(void *DtorF
, size_t AllocSize
, size_t ElementsNum
)
84 : RefCnt(1), Dtor(reinterpret_cast<DtorFunc
>(DtorF
)),
85 AllocSize(AllocSize
), Elements(ElementsNum
) {}
87 mutable unsigned RefCnt
;
88 DtorFunc Dtor
= nullptr;
91 unsigned char Storage
[1];
93 // These are some canary bits that are used for protecting the storage been
95 static constexpr unsigned char Canary
[8] = {0x4c, 0x37, 0xad, 0x8f,
96 0x2d, 0x23, 0x95, 0x91};
100 static Value::Kind
ConvertQualTypeToKind(const ASTContext
&Ctx
, QualType QT
) {
101 if (Ctx
.hasSameType(QT
, Ctx
.VoidTy
))
102 return Value::K_Void
;
104 if (const auto *ET
= QT
->getAs
<EnumType
>())
105 QT
= ET
->getDecl()->getIntegerType();
107 const auto *BT
= QT
->getAs
<BuiltinType
>();
108 if (!BT
|| BT
->isNullPtrType())
109 return Value::K_PtrOrObj
;
111 switch (QT
->castAs
<BuiltinType
>()->getKind()) {
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;
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();
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);
143 ArrSize
*= ArrTy
->getSize();
144 ArrTy
= llvm::dyn_cast
<ConstantArrayType
>(
145 ArrTy
->getElementType().getTypePtr());
147 ElementsSize
= static_cast<size_t>(ArrSize
.getZExtValue());
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());
156 llvm::logAllUnhandledErrors(Addr
.takeError(), llvm::errs());
161 getASTContext().getTypeSizeInChars(getType()).getQuantity();
162 unsigned char *Payload
=
163 ValueStorage::CreatePayload(DtorF
, AllocSize
, ElementsSize
);
164 setPtr((void *)Payload
);
169 Value::Value(const Value
&RHS
)
170 : Interp(RHS
.Interp
), OpaqueType(RHS
.OpaqueType
), Data(RHS
.Data
),
171 ValueKind(RHS
.ValueKind
), IsManuallyAlloc(RHS
.IsManuallyAlloc
) {
173 ValueStorage::getFromPayload(getPtr())->Retain();
176 Value::Value(Value
&&RHS
) noexcept
{
177 Interp
= std::exchange(RHS
.Interp
, nullptr);
178 OpaqueType
= std::exchange(RHS
.OpaqueType
, nullptr);
180 ValueKind
= std::exchange(RHS
.ValueKind
, K_Unspecified
);
181 IsManuallyAlloc
= std::exchange(RHS
.IsManuallyAlloc
, false);
184 ValueStorage::getFromPayload(getPtr())->Release();
187 Value
&Value::operator=(const Value
&RHS
) {
189 ValueStorage::getFromPayload(getPtr())->Release();
192 OpaqueType
= RHS
.OpaqueType
;
194 ValueKind
= RHS
.ValueKind
;
195 IsManuallyAlloc
= RHS
.IsManuallyAlloc
;
198 ValueStorage::getFromPayload(getPtr())->Retain();
203 Value
&Value::operator=(Value
&&RHS
) noexcept
{
206 ValueStorage::getFromPayload(getPtr())->Release();
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);
218 void Value::clear() {
220 ValueStorage::getFromPayload(getPtr())->Release();
221 ValueKind
= K_Unspecified
;
222 OpaqueType
= nullptr;
224 IsManuallyAlloc
= false;
227 Value::~Value() { clear(); }
229 void *Value::getPtr() const {
230 assert(ValueKind
== K_PtrOrObj
);
234 QualType
Value::getType() const {
235 return QualType::getFromOpaquePtr(OpaqueType
);
238 Interpreter
&Value::getInterpreter() {
239 assert(Interp
!= nullptr &&
240 "Can't get interpreter from a default constructed value");
244 const Interpreter
&Value::getInterpreter() const {
245 assert(Interp
!= nullptr &&
246 "Can't get interpreter from a default constructed value");
250 ASTContext
&Value::getASTContext() { return getInterpreter().getASTContext(); }
252 const ASTContext
&Value::getASTContext() const {
253 return getInterpreter().getASTContext();
256 void Value::dump() const { print(llvm::outs()); }
258 void Value::printType(llvm::raw_ostream
&Out
) const {
259 Out
<< "Not implement yet.\n";
261 void Value::printData(llvm::raw_ostream
&Out
) const {
262 Out
<< "Not implement yet.\n";
264 void Value::print(llvm::raw_ostream
&Out
) const {
265 assert(OpaqueType
!= nullptr && "Can't print default Value");
266 Out
<< "Not implement yet.\n";