Path: blob/main/contrib/llvm-project/clang/lib/Interpreter/Value.cpp
35233 views
//===------------ Value.cpp - Definition of interpreter value -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the class that used to represent a value in incremental9// C++.10//11//===----------------------------------------------------------------------===//1213#include "clang/Interpreter/Value.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/Type.h"16#include "clang/Interpreter/Interpreter.h"17#include "llvm/ADT/StringExtras.h"18#include "llvm/Support/ErrorHandling.h"19#include "llvm/Support/raw_os_ostream.h"20#include <cassert>21#include <cstdint>22#include <utility>2324namespace {2526// This is internal buffer maintained by Value, used to hold temporaries.27class ValueStorage {28public:29using DtorFunc = void (*)(void *);3031static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,32size_t ElementsSize) {33if (AllocSize < sizeof(Canary))34AllocSize = sizeof(Canary);35unsigned char *Buf =36new unsigned char[ValueStorage::getPayloadOffset() + AllocSize];37ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize);38std::memcpy(VS->getPayload(), Canary, sizeof(Canary));39return VS->getPayload();40}4142unsigned char *getPayload() { return Storage; }43const unsigned char *getPayload() const { return Storage; }4445static unsigned getPayloadOffset() {46static ValueStorage Dummy(nullptr, 0, 0);47return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);48}4950static ValueStorage *getFromPayload(void *Payload) {51ValueStorage *R = reinterpret_cast<ValueStorage *>(52(unsigned char *)Payload - getPayloadOffset());53return R;54}5556void Retain() { ++RefCnt; }5758void Release() {59assert(RefCnt > 0 && "Can't release if reference count is already zero");60if (--RefCnt == 0) {61// We have a non-trivial dtor.62if (Dtor && IsAlive()) {63assert(Elements && "We at least should have 1 element in Value");64size_t Stride = AllocSize / Elements;65for (size_t Idx = 0; Idx < Elements; ++Idx)66(*Dtor)(getPayload() + Idx * Stride);67}68delete[] reinterpret_cast<unsigned char *>(this);69}70}7172// Check whether the storage is valid by validating the canary bits.73// If someone accidentally write some invalid bits in the storage, the canary74// will be changed first, and `IsAlive` will return false then.75bool IsAlive() const {76return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0;77}7879private:80ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)81: RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),82AllocSize(AllocSize), Elements(ElementsNum) {}8384mutable unsigned RefCnt;85DtorFunc Dtor = nullptr;86size_t AllocSize = 0;87size_t Elements = 0;88unsigned char Storage[1];8990// These are some canary bits that are used for protecting the storage been91// damaged.92static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,930x2d, 0x23, 0x95, 0x91};94};95} // namespace9697namespace clang {9899static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) {100if (Ctx.hasSameType(QT, Ctx.VoidTy))101return Value::K_Void;102103if (const auto *ET = QT->getAs<EnumType>())104QT = ET->getDecl()->getIntegerType();105106const auto *BT = QT->getAs<BuiltinType>();107if (!BT || BT->isNullPtrType())108return Value::K_PtrOrObj;109110switch (QT->castAs<BuiltinType>()->getKind()) {111default:112assert(false && "Type not supported");113return Value::K_Unspecified;114#define X(type, name) \115case BuiltinType::name: \116return Value::K_##name;117REPL_BUILTIN_TYPES118#undef X119}120}121122Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {123setKind(ConvertQualTypeToKind(getASTContext(), getType()));124if (ValueKind == K_PtrOrObj) {125QualType Canon = getType().getCanonicalType();126if ((Canon->isPointerType() || Canon->isObjectType() ||127Canon->isReferenceType()) &&128(Canon->isRecordType() || Canon->isConstantArrayType() ||129Canon->isMemberPointerType())) {130IsManuallyAlloc = true;131// Compile dtor function.132Interpreter &Interp = getInterpreter();133void *DtorF = nullptr;134size_t ElementsSize = 1;135QualType DtorTy = getType();136137if (const auto *ArrTy =138llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) {139DtorTy = ArrTy->getElementType();140llvm::APInt ArrSize(sizeof(size_t) * 8, 1);141do {142ArrSize *= ArrTy->getSize();143ArrTy = llvm::dyn_cast<ConstantArrayType>(144ArrTy->getElementType().getTypePtr());145} while (ArrTy);146ElementsSize = static_cast<size_t>(ArrSize.getZExtValue());147}148if (const auto *RT = DtorTy->getAs<RecordType>()) {149if (CXXRecordDecl *CXXRD =150llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {151if (llvm::Expected<llvm::orc::ExecutorAddr> Addr =152Interp.CompileDtorCall(CXXRD))153DtorF = reinterpret_cast<void *>(Addr->getValue());154else155llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());156}157}158159size_t AllocSize =160getASTContext().getTypeSizeInChars(getType()).getQuantity();161unsigned char *Payload =162ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);163setPtr((void *)Payload);164}165}166}167168Value::Value(const Value &RHS)169: Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data),170ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) {171if (IsManuallyAlloc)172ValueStorage::getFromPayload(getPtr())->Retain();173}174175Value::Value(Value &&RHS) noexcept {176Interp = std::exchange(RHS.Interp, nullptr);177OpaqueType = std::exchange(RHS.OpaqueType, nullptr);178Data = RHS.Data;179ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);180IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);181182if (IsManuallyAlloc)183ValueStorage::getFromPayload(getPtr())->Release();184}185186Value &Value::operator=(const Value &RHS) {187if (IsManuallyAlloc)188ValueStorage::getFromPayload(getPtr())->Release();189190Interp = RHS.Interp;191OpaqueType = RHS.OpaqueType;192Data = RHS.Data;193ValueKind = RHS.ValueKind;194IsManuallyAlloc = RHS.IsManuallyAlloc;195196if (IsManuallyAlloc)197ValueStorage::getFromPayload(getPtr())->Retain();198199return *this;200}201202Value &Value::operator=(Value &&RHS) noexcept {203if (this != &RHS) {204if (IsManuallyAlloc)205ValueStorage::getFromPayload(getPtr())->Release();206207Interp = std::exchange(RHS.Interp, nullptr);208OpaqueType = std::exchange(RHS.OpaqueType, nullptr);209ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);210IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);211212Data = RHS.Data;213}214return *this;215}216217void Value::clear() {218if (IsManuallyAlloc)219ValueStorage::getFromPayload(getPtr())->Release();220ValueKind = K_Unspecified;221OpaqueType = nullptr;222Interp = nullptr;223IsManuallyAlloc = false;224}225226Value::~Value() { clear(); }227228void *Value::getPtr() const {229assert(ValueKind == K_PtrOrObj);230return Data.m_Ptr;231}232233QualType Value::getType() const {234return QualType::getFromOpaquePtr(OpaqueType);235}236237Interpreter &Value::getInterpreter() {238assert(Interp != nullptr &&239"Can't get interpreter from a default constructed value");240return *Interp;241}242243const Interpreter &Value::getInterpreter() const {244assert(Interp != nullptr &&245"Can't get interpreter from a default constructed value");246return *Interp;247}248249ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }250251const ASTContext &Value::getASTContext() const {252return getInterpreter().getASTContext();253}254255void Value::dump() const { print(llvm::outs()); }256257void Value::printType(llvm::raw_ostream &Out) const {258Out << "Not implement yet.\n";259}260void Value::printData(llvm::raw_ostream &Out) const {261Out << "Not implement yet.\n";262}263void Value::print(llvm::raw_ostream &Out) const {264assert(OpaqueType != nullptr && "Can't print default Value");265Out << "Not implement yet.\n";266}267268} // namespace clang269270271