brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · d4c9d51 Raw
283 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the class that used to represent a value in incremental10// C++.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Interpreter/Value.h"15#include "InterpreterUtils.h"16#include "clang/AST/ASTContext.h"17#include "clang/AST/Type.h"18#include "clang/Interpreter/Interpreter.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 canary75  // 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 been92  // damaged.93  static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,94                                              0x2d, 0x23, 0x95, 0x91};95};96} // namespace97 98namespace clang {99 100static 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 *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");114    return Value::K_Unspecified;115#define X(type, name)                                                          \116  case BuiltinType::name:                                                      \117    return Value::K_##name;118    REPL_BUILTIN_TYPES119#undef X120  }121}122 123Value::Value(const Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {124  const ASTContext &C = getASTContext();125  setKind(ConvertQualTypeToKind(C, getType()));126  if (ValueKind == K_PtrOrObj) {127    QualType Canon = getType().getCanonicalType();128    if ((Canon->isPointerType() || Canon->isObjectType() ||129         Canon->isReferenceType()) &&130        (Canon->isRecordType() || Canon->isConstantArrayType() ||131         Canon->isMemberPointerType())) {132      IsManuallyAlloc = true;133      // Compile dtor function.134      const Interpreter &Interp = getInterpreter();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()) {151        if (llvm::Expected<llvm::orc::ExecutorAddr> Addr =152                Interp.CompileDtorCall(CXXRD))153          DtorF = reinterpret_cast<void *>(Addr->getValue());154        else155          llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());156      }157 158      size_t AllocSize =159          getASTContext().getTypeSizeInChars(getType()).getQuantity();160      unsigned char *Payload =161          ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);162      setPtr((void *)Payload);163    }164  }165}166 167Value::Value(const Value &RHS)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 185Value &Value::operator=(const Value &RHS) {186  if (IsManuallyAlloc)187    ValueStorage::getFromPayload(getPtr())->Release();188 189  Interp = RHS.Interp;190  OpaqueType = RHS.OpaqueType;191  Data = RHS.Data;192  ValueKind = RHS.ValueKind;193  IsManuallyAlloc = RHS.IsManuallyAlloc;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 216void Value::clear() {217  if (IsManuallyAlloc)218    ValueStorage::getFromPayload(getPtr())->Release();219  ValueKind = K_Unspecified;220  OpaqueType = nullptr;221  Interp = nullptr;222  IsManuallyAlloc = false;223}224 225Value::~Value() { clear(); }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 237QualType Value::getType() const {238  return QualType::getFromOpaquePtr(OpaqueType);239}240 241const Interpreter &Value::getInterpreter() const {242  assert(Interp != nullptr &&243         "Can't get interpreter from a default constructed value");244  return *Interp;245}246 247const ASTContext &Value::getASTContext() const {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 base261// 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` is270  // 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 clang283