clang 22.0.0git
Value.cpp
Go to the documentation of this file.
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
15#include "InterpreterUtils.h"
17#include "clang/AST/Type.h"
19#include "llvm/ADT/StringExtras.h"
20#include <cassert>
21#include <utility>
22
23using namespace clang;
24
25namespace {
26
27// This is internal buffer maintained by Value, used to hold temporaries.
28class ValueStorage {
29public:
30 using DtorFunc = void (*)(void *);
31
32 static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,
33 size_t ElementsSize) {
34 if (AllocSize < sizeof(Canary))
35 AllocSize = sizeof(Canary);
36 unsigned char *Buf =
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();
41 }
42
43 unsigned char *getPayload() { return Storage; }
44 const unsigned char *getPayload() const { return Storage; }
45
46 static unsigned getPayloadOffset() {
47 static ValueStorage Dummy(nullptr, 0, 0);
48 return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);
49 }
50
51 static ValueStorage *getFromPayload(void *Payload) {
52 ValueStorage *R = reinterpret_cast<ValueStorage *>(
53 (unsigned char *)Payload - getPayloadOffset());
54 return R;
55 }
56
57 void Retain() { ++RefCnt; }
58
59 void Release() {
60 assert(RefCnt > 0 && "Can't release if reference count is already zero");
61 if (--RefCnt == 0) {
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);
68 }
69 delete[] reinterpret_cast<unsigned char *>(this);
70 }
71 }
72
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;
78 }
79
80private:
81 ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)
82 : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),
83 AllocSize(AllocSize), Elements(ElementsNum) {}
84
85 mutable unsigned RefCnt;
86 DtorFunc Dtor = nullptr;
87 size_t AllocSize = 0;
88 size_t Elements = 0;
89 unsigned char Storage[1];
90
91 // These are some canary bits that are used for protecting the storage been
92 // damaged.
93 static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
94 0x2d, 0x23, 0x95, 0x91};
95};
96} // namespace
97
98namespace clang {
99
101 if (Ctx.hasSameType(QT, Ctx.VoidTy))
102 return Value::K_Void;
103
104 if (const auto *ED = QT->getAsEnumDecl())
105 QT = ED->getIntegerType();
106
107 const auto *BT = QT->getAs<BuiltinType>();
108 if (!BT || BT->isNullPtrType())
109 return Value::K_PtrOrObj;
110
111 switch (QT->castAs<BuiltinType>()->getKind()) {
112 default:
113 assert(false && "Type not supported");
115#define X(type, name) \
116 case BuiltinType::name: \
117 return Value::K_##name;
119#undef X
120 }
121}
122
123Value::Value(const Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {
124 const ASTContext &C = getASTContext();
126 if (ValueKind == K_PtrOrObj) {
128 if ((Canon->isPointerType() || Canon->isObjectType() ||
129 Canon->isReferenceType()) &&
130 (Canon->isRecordType() || Canon->isConstantArrayType() ||
131 Canon->isMemberPointerType())) {
132 IsManuallyAlloc = true;
133 // Compile dtor function.
135 void *DtorF = nullptr;
136 size_t ElementsSize = 1;
137 QualType DtorTy = getType();
138
139 if (const auto *ArrTy =
140 llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) {
141 DtorTy = ArrTy->getElementType();
142 llvm::APInt ArrSize(sizeof(size_t) * 8, 1);
143 do {
144 ArrSize *= ArrTy->getSize();
145 ArrTy = llvm::dyn_cast<ConstantArrayType>(
146 ArrTy->getElementType().getTypePtr());
147 } while (ArrTy);
148 ElementsSize = static_cast<size_t>(ArrSize.getZExtValue());
149 }
150 if (auto *CXXRD = DtorTy->getAsCXXRecordDecl()) {
152 Interp.CompileDtorCall(CXXRD))
153 DtorF = reinterpret_cast<void *>(Addr->getValue());
154 else
155 llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());
156 }
157
158 size_t AllocSize =
160 unsigned char *Payload =
161 ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);
162 setPtr((void *)Payload);
163 }
164 }
165}
166
168 : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data),
169 ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) {
170 if (IsManuallyAlloc)
171 ValueStorage::getFromPayload(getPtr())->Retain();
172}
173
174Value::Value(Value &&RHS) noexcept {
175 Interp = std::exchange(RHS.Interp, nullptr);
176 OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
177 Data = RHS.Data;
178 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
179 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
180
181 if (IsManuallyAlloc)
182 ValueStorage::getFromPayload(getPtr())->Release();
183}
184
186 if (IsManuallyAlloc)
187 ValueStorage::getFromPayload(getPtr())->Release();
188
189 Interp = RHS.Interp;
191 Data = RHS.Data;
192 ValueKind = RHS.ValueKind;
194
195 if (IsManuallyAlloc)
196 ValueStorage::getFromPayload(getPtr())->Retain();
197
198 return *this;
199}
200
201Value &Value::operator=(Value &&RHS) noexcept {
202 if (this != &RHS) {
203 if (IsManuallyAlloc)
204 ValueStorage::getFromPayload(getPtr())->Release();
205
206 Interp = std::exchange(RHS.Interp, nullptr);
207 OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
208 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
209 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
210
211 Data = RHS.Data;
212 }
213 return *this;
214}
215
217 if (IsManuallyAlloc)
218 ValueStorage::getFromPayload(getPtr())->Release();
220 OpaqueType = nullptr;
221 Interp = nullptr;
222 IsManuallyAlloc = false;
223}
224
226
227void *Value::getPtr() const {
228 assert(ValueKind == K_PtrOrObj);
229 return Data.m_Ptr;
230}
231
232void Value::setRawBits(void *Ptr, unsigned NBits /*= sizeof(Storage)*/) {
233 assert(NBits <= sizeof(Storage) && "Greater than the total size");
234 memcpy(/*dest=*/Data.m_RawBits, /*src=*/Ptr, /*nbytes=*/NBits / 8);
235}
236
239}
240
242 assert(Interp != nullptr &&
243 "Can't get interpreter from a default constructed value");
244 return *Interp;
245}
246
248 return getInterpreter().getASTContext();
249}
250
251void Value::dump() const { print(llvm::outs()); }
252
253void Value::printType(llvm::raw_ostream &Out) const {
254 Out << Interp->ValueTypeToString(*this);
255}
256
257void Value::printData(llvm::raw_ostream &Out) const {
258 Out << Interp->ValueDataToString(*this);
259}
260// FIXME: We do not support the multiple inheritance case where one of the base
261// classes has a pretty-printer and the other does not.
262void Value::print(llvm::raw_ostream &Out) const {
263 assert(OpaqueType != nullptr && "Can't print default Value");
264
265 // Don't even try to print a void or an invalid type, it doesn't make sense.
266 if (getType()->isVoidType() || !isValid())
267 return;
268
269 // We need to get all the results together then print it, since `printType` is
270 // much faster than `printData`.
271 std::string Str;
272 llvm::raw_string_ostream SS(Str);
273
274 SS << "(";
275 printType(SS);
276 SS << ") ";
277 printData(SS);
278 SS << "\n";
279 Out << Str;
280}
281
282} // namespace clang
Defines the clang::ASTContext interface.
#define REPL_BUILTIN_TYPES
Definition: Value.h:77
C Language Family Type Representation.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2867
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType VoidTy
Definition: ASTContext.h:1222
This class is used for builtin types like 'int'.
Definition: TypeBase.h:3182
Kind getKind() const
Definition: TypeBase.h:3230
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition: CharUnits.h:185
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:86
const ASTContext & getASTContext() const
A (possibly-)qualified type.
Definition: TypeBase.h:937
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: TypeBase.h:8343
static QualType getFromOpaquePtr(const void *Ptr)
Definition: TypeBase.h:986
QualType getCanonicalType() const
Definition: TypeBase.h:8395
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.h:26
bool isConstantArrayType() const
Definition: TypeBase.h:8683
bool isPointerType() const
Definition: TypeBase.h:8580
const T * castAs() const
Member-template castAs<specific type>.
Definition: TypeBase.h:9226
bool isReferenceType() const
Definition: TypeBase.h:8604
bool isMemberPointerType() const
Definition: TypeBase.h:8661
bool isObjectType() const
Determine whether this type is an object type.
Definition: TypeBase.h:2528
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition: Type.h:53
const T * getAs() const
Member-template getAs<specific type>'.
Definition: TypeBase.h:9159
bool isRecordType() const
Definition: TypeBase.h:8707
const Interpreter & getInterpreter() const
Definition: Value.cpp:241
QualType getType() const
Definition: Value.cpp:237
void setKind(Kind K)
Definition: Value.h:138
void print(llvm::raw_ostream &Out) const
Definition: Value.cpp:262
void printType(llvm::raw_ostream &Out) const
Definition: Value.cpp:253
void * OpaqueType
Definition: Value.h:198
Kind ValueKind
Definition: Value.h:200
void dump() const
Definition: Value.cpp:251
Value & operator=(const Value &RHS)
Definition: Value.cpp:185
void clear()
Definition: Value.cpp:216
void printData(llvm::raw_ostream &Out) const
Definition: Value.cpp:257
Value()=default
void * getPtr() const
Definition: Value.cpp:227
bool IsManuallyAlloc
Definition: Value.h:201
bool isValid() const
Definition: Value.h:133
void setRawBits(void *Ptr, unsigned NBits=sizeof(Storage))
Definition: Value.cpp:232
void setPtr(void *Ptr)
Definition: Value.h:142
const ASTContext & getASTContext() const
Definition: Value.cpp:247
@ K_PtrOrObj
Definition: Value.h:111
@ K_Unspecified
Definition: Value.h:112
Storage Data
Definition: Value.h:199
const Interpreter * Interp
Definition: Value.h:197
The JSON file list parser is used to communicate input to InstallAPI.
static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT)
Definition: Value.cpp:100