llvm-project

Форк
0
269 строк · 8.4 Кб
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 "llvm/Support/ErrorHandling.h"
20
#include "llvm/Support/raw_os_ostream.h"
21
#include <cassert>
22
#include <cstdint>
23
#include <utility>
24

25
namespace {
26

27
// This is internal buffer maintained by Value, used to hold temporaries.
28
class ValueStorage {
29
public:
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

80
private:
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

98
namespace clang {
99

100
static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) {
101
  if (Ctx.hasSameType(QT, Ctx.VoidTy))
102
    return Value::K_Void;
103

104
  if (const auto *ET = QT->getAs<EnumType>())
105
    QT = ET->getDecl()->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");
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
120
  }
121
}
122

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();
137

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());
148
      }
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());
157
        }
158
      }
159

160
      size_t AllocSize =
161
          getASTContext().getTypeSizeInChars(getType()).getQuantity();
162
      unsigned char *Payload =
163
          ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);
164
      setPtr((void *)Payload);
165
    }
166
  }
167
}
168

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();
174
}
175

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);
182

183
  if (IsManuallyAlloc)
184
    ValueStorage::getFromPayload(getPtr())->Release();
185
}
186

187
Value &Value::operator=(const Value &RHS) {
188
  if (IsManuallyAlloc)
189
    ValueStorage::getFromPayload(getPtr())->Release();
190

191
  Interp = RHS.Interp;
192
  OpaqueType = RHS.OpaqueType;
193
  Data = RHS.Data;
194
  ValueKind = RHS.ValueKind;
195
  IsManuallyAlloc = RHS.IsManuallyAlloc;
196

197
  if (IsManuallyAlloc)
198
    ValueStorage::getFromPayload(getPtr())->Retain();
199

200
  return *this;
201
}
202

203
Value &Value::operator=(Value &&RHS) noexcept {
204
  if (this != &RHS) {
205
    if (IsManuallyAlloc)
206
      ValueStorage::getFromPayload(getPtr())->Release();
207

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);
212

213
    Data = RHS.Data;
214
  }
215
  return *this;
216
}
217

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;
225
}
226

227
Value::~Value() { clear(); }
228

229
void *Value::getPtr() const {
230
  assert(ValueKind == K_PtrOrObj);
231
  return Data.m_Ptr;
232
}
233

234
QualType Value::getType() const {
235
  return QualType::getFromOpaquePtr(OpaqueType);
236
}
237

238
Interpreter &Value::getInterpreter() {
239
  assert(Interp != nullptr &&
240
         "Can't get interpreter from a default constructed value");
241
  return *Interp;
242
}
243

244
const Interpreter &Value::getInterpreter() const {
245
  assert(Interp != nullptr &&
246
         "Can't get interpreter from a default constructed value");
247
  return *Interp;
248
}
249

250
ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }
251

252
const ASTContext &Value::getASTContext() const {
253
  return getInterpreter().getASTContext();
254
}
255

256
void Value::dump() const { print(llvm::outs()); }
257

258
void Value::printType(llvm::raw_ostream &Out) const {
259
  Out << "Not implement yet.\n";
260
}
261
void Value::printData(llvm::raw_ostream &Out) const {
262
  Out << "Not implement yet.\n";
263
}
264
void Value::print(llvm::raw_ostream &Out) const {
265
  assert(OpaqueType != nullptr && "Can't print default Value");
266
  Out << "Not implement yet.\n";
267
}
268

269
} // namespace clang
270

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.