1 //===------------ Value.cpp - Definition of interpreter value -------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the class that used to represent a value in incremental
10 // C++.
11 //
12 //===----------------------------------------------------------------------===//
13
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 <cassert>
20 #include <utility>
21
22 namespace {
23
24 // This is internal buffer maintained by Value, used to hold temporaries.
25 class ValueStorage {
26 public:
27 using DtorFunc = void (*)(void *);
28
CreatePayload(void * DtorF,size_t AllocSize,size_t ElementsSize)29 static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,
30 size_t ElementsSize) {
31 if (AllocSize < sizeof(Canary))
32 AllocSize = sizeof(Canary);
33 unsigned char *Buf =
34 new unsigned char[ValueStorage::getPayloadOffset() + AllocSize];
35 ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize);
36 std::memcpy(VS->getPayload(), Canary, sizeof(Canary));
37 return VS->getPayload();
38 }
39
getPayload()40 unsigned char *getPayload() { return Storage; }
getPayload() const41 const unsigned char *getPayload() const { return Storage; }
42
getPayloadOffset()43 static unsigned getPayloadOffset() {
44 static ValueStorage Dummy(nullptr, 0, 0);
45 return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);
46 }
47
getFromPayload(void * Payload)48 static ValueStorage *getFromPayload(void *Payload) {
49 ValueStorage *R = reinterpret_cast<ValueStorage *>(
50 (unsigned char *)Payload - getPayloadOffset());
51 return R;
52 }
53
Retain()54 void Retain() { ++RefCnt; }
55
Release()56 void Release() {
57 assert(RefCnt > 0 && "Can't release if reference count is already zero");
58 if (--RefCnt == 0) {
59 // We have a non-trivial dtor.
60 if (Dtor && IsAlive()) {
61 assert(Elements && "We at least should have 1 element in Value");
62 size_t Stride = AllocSize / Elements;
63 for (size_t Idx = 0; Idx < Elements; ++Idx)
64 (*Dtor)(getPayload() + Idx * Stride);
65 }
66 delete[] reinterpret_cast<unsigned char *>(this);
67 }
68 }
69
70 // Check whether the storage is valid by validating the canary bits.
71 // If someone accidentally write some invalid bits in the storage, the canary
72 // will be changed first, and `IsAlive` will return false then.
IsAlive() const73 bool IsAlive() const {
74 return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0;
75 }
76
77 private:
ValueStorage(void * DtorF,size_t AllocSize,size_t ElementsNum)78 ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)
79 : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),
80 AllocSize(AllocSize), Elements(ElementsNum) {}
81
82 mutable unsigned RefCnt;
83 DtorFunc Dtor = nullptr;
84 size_t AllocSize = 0;
85 size_t Elements = 0;
86 unsigned char Storage[1];
87
88 // These are some canary bits that are used for protecting the storage been
89 // damaged.
90 static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
91 0x2d, 0x23, 0x95, 0x91};
92 };
93 } // namespace
94
95 namespace clang {
96
ConvertQualTypeToKind(const ASTContext & Ctx,QualType QT)97 static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) {
98 if (Ctx.hasSameType(QT, Ctx.VoidTy))
99 return Value::K_Void;
100
101 if (const auto *ET = QT->getAs<EnumType>())
102 QT = ET->getDecl()->getIntegerType();
103
104 const auto *BT = QT->getAs<BuiltinType>();
105 if (!BT || BT->isNullPtrType())
106 return Value::K_PtrOrObj;
107
108 switch (QT->castAs<BuiltinType>()->getKind()) {
109 default:
110 assert(false && "Type not supported");
111 return Value::K_Unspecified;
112 #define X(type, name) \
113 case BuiltinType::name: \
114 return Value::K_##name;
115 REPL_BUILTIN_TYPES
116 #undef X
117 }
118 }
119
Value(Interpreter * In,void * Ty)120 Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {
121 setKind(ConvertQualTypeToKind(getASTContext(), getType()));
122 if (ValueKind == K_PtrOrObj) {
123 QualType Canon = getType().getCanonicalType();
124 if ((Canon->isPointerType() || Canon->isObjectType() ||
125 Canon->isReferenceType()) &&
126 (Canon->isRecordType() || Canon->isConstantArrayType() ||
127 Canon->isMemberPointerType())) {
128 IsManuallyAlloc = true;
129 // Compile dtor function.
130 Interpreter &Interp = getInterpreter();
131 void *DtorF = nullptr;
132 size_t ElementsSize = 1;
133 QualType DtorTy = getType();
134
135 if (const auto *ArrTy =
136 llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) {
137 DtorTy = ArrTy->getElementType();
138 llvm::APInt ArrSize(sizeof(size_t) * 8, 1);
139 do {
140 ArrSize *= ArrTy->getSize();
141 ArrTy = llvm::dyn_cast<ConstantArrayType>(
142 ArrTy->getElementType().getTypePtr());
143 } while (ArrTy);
144 ElementsSize = static_cast<size_t>(ArrSize.getZExtValue());
145 }
146 if (const auto *RT = DtorTy->getAs<RecordType>()) {
147 if (CXXRecordDecl *CXXRD =
148 llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
149 if (llvm::Expected<llvm::orc::ExecutorAddr> Addr =
150 Interp.CompileDtorCall(CXXRD))
151 DtorF = reinterpret_cast<void *>(Addr->getValue());
152 else
153 llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());
154 }
155 }
156
157 size_t AllocSize =
158 getASTContext().getTypeSizeInChars(getType()).getQuantity();
159 unsigned char *Payload =
160 ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);
161 setPtr((void *)Payload);
162 }
163 }
164 }
165
Value(const Value & RHS)166 Value::Value(const Value &RHS)
167 : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data),
168 ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) {
169 if (IsManuallyAlloc)
170 ValueStorage::getFromPayload(getPtr())->Retain();
171 }
172
Value(Value && RHS)173 Value::Value(Value &&RHS) noexcept {
174 Interp = std::exchange(RHS.Interp, nullptr);
175 OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
176 Data = RHS.Data;
177 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
178 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
179
180 if (IsManuallyAlloc)
181 ValueStorage::getFromPayload(getPtr())->Release();
182 }
183
operator =(const Value & RHS)184 Value &Value::operator=(const Value &RHS) {
185 if (IsManuallyAlloc)
186 ValueStorage::getFromPayload(getPtr())->Release();
187
188 Interp = RHS.Interp;
189 OpaqueType = RHS.OpaqueType;
190 Data = RHS.Data;
191 ValueKind = RHS.ValueKind;
192 IsManuallyAlloc = RHS.IsManuallyAlloc;
193
194 if (IsManuallyAlloc)
195 ValueStorage::getFromPayload(getPtr())->Retain();
196
197 return *this;
198 }
199
operator =(Value && RHS)200 Value &Value::operator=(Value &&RHS) noexcept {
201 if (this != &RHS) {
202 if (IsManuallyAlloc)
203 ValueStorage::getFromPayload(getPtr())->Release();
204
205 Interp = std::exchange(RHS.Interp, nullptr);
206 OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
207 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
208 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
209
210 Data = RHS.Data;
211 }
212 return *this;
213 }
214
clear()215 void Value::clear() {
216 if (IsManuallyAlloc)
217 ValueStorage::getFromPayload(getPtr())->Release();
218 ValueKind = K_Unspecified;
219 OpaqueType = nullptr;
220 Interp = nullptr;
221 IsManuallyAlloc = false;
222 }
223
~Value()224 Value::~Value() { clear(); }
225
getPtr() const226 void *Value::getPtr() const {
227 assert(ValueKind == K_PtrOrObj);
228 return Data.m_Ptr;
229 }
230
getType() const231 QualType Value::getType() const {
232 return QualType::getFromOpaquePtr(OpaqueType);
233 }
234
getInterpreter()235 Interpreter &Value::getInterpreter() {
236 assert(Interp != nullptr &&
237 "Can't get interpreter from a default constructed value");
238 return *Interp;
239 }
240
getInterpreter() const241 const Interpreter &Value::getInterpreter() const {
242 assert(Interp != nullptr &&
243 "Can't get interpreter from a default constructed value");
244 return *Interp;
245 }
246
getASTContext()247 ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }
248
getASTContext() const249 const ASTContext &Value::getASTContext() const {
250 return getInterpreter().getASTContext();
251 }
252
dump() const253 void Value::dump() const { print(llvm::outs()); }
254
printType(llvm::raw_ostream & Out) const255 void Value::printType(llvm::raw_ostream &Out) const {
256 Out << "Not implement yet.\n";
257 }
printData(llvm::raw_ostream & Out) const258 void Value::printData(llvm::raw_ostream &Out) const {
259 Out << "Not implement yet.\n";
260 }
print(llvm::raw_ostream & Out) const261 void Value::print(llvm::raw_ostream &Out) const {
262 assert(OpaqueType != nullptr && "Can't print default Value");
263 Out << "Not implement yet.\n";
264 }
265
266 } // namespace clang
267