1 //===------------ Value.cpp - Definition of interpreter value -------------===//
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"
27 // This is internal buffer maintained by Value, used to hold temporaries.
30 using DtorFunc
= void (*)(void *);
32 static unsigned char *CreatePayload(void *DtorF
, size_t AllocSize
,
33 size_t ElementsSize
) {
34 if (AllocSize
< sizeof(Canary
))
35 AllocSize
= sizeof(Canary
);
37 new unsigned char[ValueStorage::getPayloadOffset() + AllocSize
];
38 ValueStorage
*VS
= new (Buf
) ValueStorage(DtorF
, AllocSize
, ElementsSize
);
39 std::memcpy(VS
->getPayload(), Canary
, sizeof(Canary
));
40 return VS
->getPayload();
43 unsigned char *getPayload() { return Storage
; }
44 const unsigned char *getPayload() const { return Storage
; }
46 static unsigned getPayloadOffset() {
47 static ValueStorage
Dummy(nullptr, 0, 0);
48 return Dummy
.getPayload() - reinterpret_cast<unsigned char *>(&Dummy
);
51 static ValueStorage
*getFromPayload(void *Payload
) {
52 ValueStorage
*R
= reinterpret_cast<ValueStorage
*>(
53 (unsigned char *)Payload
- getPayloadOffset());
57 void Retain() { ++RefCnt
; }
60 assert(RefCnt
> 0 && "Can't release if reference count is already zero");
62 // We have a non-trivial dtor.
63 if (Dtor
&& IsAlive()) {
64 assert(Elements
&& "We at least should have 1 element in Value");
65 size_t Stride
= AllocSize
/ Elements
;
66 for (size_t Idx
= 0; Idx
< Elements
; ++Idx
)
67 (*Dtor
)(getPayload() + Idx
* Stride
);
69 delete[] reinterpret_cast<unsigned char *>(this);
73 // Check whether the storage is valid by validating the canary bits.
74 // If someone accidentally write some invalid bits in the storage, the canary
75 // will be changed first, and `IsAlive` will return false then.
76 bool IsAlive() const {
77 return std::memcmp(getPayload(), Canary
, sizeof(Canary
)) != 0;
81 ValueStorage(void *DtorF
, size_t AllocSize
, size_t ElementsNum
)
82 : RefCnt(1), Dtor(reinterpret_cast<DtorFunc
>(DtorF
)),
83 AllocSize(AllocSize
), Elements(ElementsNum
) {}
85 mutable unsigned RefCnt
;
86 DtorFunc Dtor
= nullptr;
89 unsigned char Storage
[1];
91 // These are some canary bits that are used for protecting the storage been
93 static constexpr unsigned char Canary
[8] = {0x4c, 0x37, 0xad, 0x8f,
94 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";