[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / Interpreter / Value.cpp
blob1d6b2da087e9fbe40d85111bddc3159199ebd94d
1 //===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===//
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++.
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"
21 #include <cassert>
22 #include <cstdint>
23 #include <utility>
25 using namespace clang;
27 namespace {
29 // This is internal buffer maintained by Value, used to hold temporaries.
30 class ValueStorage {
31 public:
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);
38 unsigned char *Buf =
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());
56 return R;
59 void Retain() { ++RefCnt; }
61 void Release() {
62 assert(RefCnt > 0 && "Can't release if reference count is already zero");
63 if (--RefCnt == 0) {
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;
82 private:
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;
89 size_t AllocSize = 0;
90 size_t Elements = 0;
91 unsigned char Storage[1];
93 // These are some canary bits that are used for protecting the storage been
94 // damaged.
95 static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
96 0x2d, 0x23, 0x95, 0x91};
98 } // namespace
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()) {
112 default:
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;
118 REPL_BUILTIN_TYPES
119 #undef X
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);
142 do {
143 ArrSize *= ArrTy->getSize();
144 ArrTy = llvm::dyn_cast<ConstantArrayType>(
145 ArrTy->getElementType().getTypePtr());
146 } while (ArrTy);
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());
155 else
156 llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());
160 size_t AllocSize =
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) {
172 if (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);
179 Data = RHS.Data;
180 ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
181 IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
183 if (IsManuallyAlloc)
184 ValueStorage::getFromPayload(getPtr())->Release();
187 Value &Value::operator=(const Value &RHS) {
188 if (IsManuallyAlloc)
189 ValueStorage::getFromPayload(getPtr())->Release();
191 Interp = RHS.Interp;
192 OpaqueType = RHS.OpaqueType;
193 Data = RHS.Data;
194 ValueKind = RHS.ValueKind;
195 IsManuallyAlloc = RHS.IsManuallyAlloc;
197 if (IsManuallyAlloc)
198 ValueStorage::getFromPayload(getPtr())->Retain();
200 return *this;
203 Value &Value::operator=(Value &&RHS) noexcept {
204 if (this != &RHS) {
205 if (IsManuallyAlloc)
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);
213 Data = RHS.Data;
215 return *this;
218 void Value::clear() {
219 if (IsManuallyAlloc)
220 ValueStorage::getFromPayload(getPtr())->Release();
221 ValueKind = K_Unspecified;
222 OpaqueType = nullptr;
223 Interp = nullptr;
224 IsManuallyAlloc = false;
227 Value::~Value() { clear(); }
229 void *Value::getPtr() const {
230 assert(ValueKind == K_PtrOrObj);
231 return Data.m_Ptr;
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");
241 return *Interp;
244 const Interpreter &Value::getInterpreter() const {
245 assert(Interp != nullptr &&
246 "Can't get interpreter from a default constructed value");
247 return *Interp;
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";