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),
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
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.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType VoidTy
This class is used for builtin types like 'int'.
Definition TypeBase.h:3164
Kind getKind() const
Definition TypeBase.h:3212
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:91
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:8285
static QualType getFromOpaquePtr(const void *Ptr)
Definition TypeBase.h:986
QualType getCanonicalType() const
Definition TypeBase.h:8337
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:8625
bool isPointerType() const
Definition TypeBase.h:8522
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9168
bool isReferenceType() const
Definition TypeBase.h:8546
bool isMemberPointerType() const
Definition TypeBase.h:8603
bool isObjectType() const
Determine whether this type is an object type.
Definition TypeBase.h:2510
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:9101
bool isRecordType() const
Definition TypeBase.h:8649
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_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