clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
210 lines
7.4 KiB
C++
210 lines
7.4 KiB
C++
//===--- Value.h - Definition of interpreter value --------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Value is a lightweight struct that is used for carrying execution results in
|
|
// clang-repl. It's a special runtime that acts like a messager between compiled
|
|
// code and interpreted code. This makes it possible to exchange interesting
|
|
// information between the compiled & interpreted world.
|
|
//
|
|
// A typical usage is like the below:
|
|
//
|
|
// Value V;
|
|
// Interp.ParseAndExecute("int x = 42;");
|
|
// Interp.ParseAndExecute("x", &V);
|
|
// V.getType(); // <-- Yields a clang::QualType.
|
|
// V.getInt(); // <-- Yields 42.
|
|
//
|
|
// The current design is still highly experimental and nobody should rely on the
|
|
// API being stable because we're hopefully going to make significant changes to
|
|
// it in the relatively near future. For example, Value also intends to be used
|
|
// as an exchange token for JIT support enabling remote execution on the embed
|
|
// devices where the JIT infrastructure cannot fit. To support that we will need
|
|
// to split the memory storage in a different place and perhaps add a resource
|
|
// header is similar to intrinsics headers which have stricter performance
|
|
// constraints.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_INTERPRETER_VALUE_H
|
|
#define LLVM_CLANG_INTERPRETER_VALUE_H
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
#include <cstdint>
|
|
|
|
// NOTE: Since the REPL itself could also include this runtime, extreme caution
|
|
// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW
|
|
// HEADERS, like <string>, <memory> and etc. (That pulls a large number of
|
|
// tokens and will impact the runtime performance of the REPL)
|
|
|
|
namespace llvm {
|
|
class raw_ostream;
|
|
|
|
} // namespace llvm
|
|
|
|
namespace clang {
|
|
|
|
class ASTContext;
|
|
class Interpreter;
|
|
class QualType;
|
|
|
|
#if defined(_WIN32)
|
|
// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
|
|
// at runtime. On Windows, this requires them to be exported from any of the
|
|
// modules loaded at runtime. Marking them as dllexport achieves this; both
|
|
// for DLLs (that normally export symbols as part of their interface) and for
|
|
// EXEs (that normally don't export anything).
|
|
// For a build with libclang-cpp.dll, this doesn't make any difference - the
|
|
// functions would have been exported anyway. But for cases when these are
|
|
// statically linked into an EXE, it makes sure that they're exported.
|
|
#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
|
|
#elif __has_attribute(visibility)
|
|
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
|
|
#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
|
|
#else
|
|
#define REPL_EXTERNAL_VISIBILITY
|
|
#endif
|
|
#else
|
|
#define REPL_EXTERNAL_VISIBILITY
|
|
#endif
|
|
|
|
#define REPL_BUILTIN_TYPES \
|
|
X(bool, Bool) \
|
|
X(char, Char_S) \
|
|
X(signed char, SChar) \
|
|
X(unsigned char, Char_U) \
|
|
X(unsigned char, UChar) \
|
|
X(short, Short) \
|
|
X(unsigned short, UShort) \
|
|
X(int, Int) \
|
|
X(unsigned int, UInt) \
|
|
X(long, Long) \
|
|
X(unsigned long, ULong) \
|
|
X(long long, LongLong) \
|
|
X(unsigned long long, ULongLong) \
|
|
X(float, Float) \
|
|
X(double, Double) \
|
|
X(long double, LongDouble)
|
|
|
|
class REPL_EXTERNAL_VISIBILITY Value {
|
|
union Storage {
|
|
#define X(type, name) type m_##name;
|
|
REPL_BUILTIN_TYPES
|
|
#undef X
|
|
void *m_Ptr;
|
|
};
|
|
|
|
public:
|
|
enum Kind {
|
|
#define X(type, name) K_##name,
|
|
REPL_BUILTIN_TYPES
|
|
#undef X
|
|
|
|
K_Void,
|
|
K_PtrOrObj,
|
|
K_Unspecified
|
|
};
|
|
|
|
Value() = default;
|
|
Value(Interpreter *In, void *Ty);
|
|
Value(const Value &RHS);
|
|
Value(Value &&RHS) noexcept;
|
|
Value &operator=(const Value &RHS);
|
|
Value &operator=(Value &&RHS) noexcept;
|
|
~Value();
|
|
|
|
void printType(llvm::raw_ostream &Out) const;
|
|
void printData(llvm::raw_ostream &Out) const;
|
|
void print(llvm::raw_ostream &Out) const;
|
|
void dump() const;
|
|
void clear();
|
|
|
|
ASTContext &getASTContext();
|
|
const ASTContext &getASTContext() const;
|
|
Interpreter &getInterpreter();
|
|
const Interpreter &getInterpreter() const;
|
|
QualType getType() const;
|
|
|
|
bool isValid() const { return ValueKind != K_Unspecified; }
|
|
bool isVoid() const { return ValueKind == K_Void; }
|
|
bool hasValue() const { return isValid() && !isVoid(); }
|
|
bool isManuallyAlloc() const { return IsManuallyAlloc; }
|
|
Kind getKind() const { return ValueKind; }
|
|
void setKind(Kind K) { ValueKind = K; }
|
|
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
|
|
|
|
void *getPtr() const;
|
|
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
|
|
|
|
#define X(type, name) \
|
|
void set##name(type Val) { Data.m_##name = Val; } \
|
|
type get##name() const { return Data.m_##name; }
|
|
REPL_BUILTIN_TYPES
|
|
#undef X
|
|
|
|
/// \brief Get the value with cast.
|
|
//
|
|
/// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
|
|
/// casting the value of builtins (except void), enums and pointers.
|
|
/// Values referencing an object are treated as pointers to the object.
|
|
template <typename T> T convertTo() const {
|
|
return convertFwd<T>::cast(*this);
|
|
}
|
|
|
|
protected:
|
|
bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; }
|
|
|
|
/// \brief Get to the value with type checking casting the underlying
|
|
/// stored value to T.
|
|
template <typename T> T as() const {
|
|
switch (ValueKind) {
|
|
default:
|
|
return T();
|
|
#define X(type, name) \
|
|
case Value::K_##name: \
|
|
return (T)Data.m_##name;
|
|
REPL_BUILTIN_TYPES
|
|
#undef X
|
|
}
|
|
}
|
|
|
|
// Allow convertTo to be partially specialized.
|
|
template <typename T> struct convertFwd {
|
|
static T cast(const Value &V) {
|
|
if (V.isPointerOrObjectType())
|
|
return (T)(uintptr_t)V.as<void *>();
|
|
if (!V.isValid() || V.isVoid()) {
|
|
return T();
|
|
}
|
|
return V.as<T>();
|
|
}
|
|
};
|
|
|
|
template <typename T> struct convertFwd<T *> {
|
|
static T *cast(const Value &V) {
|
|
if (V.isPointerOrObjectType())
|
|
return (T *)(uintptr_t)V.as<void *>();
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
Interpreter *Interp = nullptr;
|
|
void *OpaqueType = nullptr;
|
|
Storage Data;
|
|
Kind ValueKind = K_Unspecified;
|
|
bool IsManuallyAlloc = false;
|
|
};
|
|
|
|
template <> inline void *Value::as() const {
|
|
if (isPointerOrObjectType())
|
|
return Data.m_Ptr;
|
|
return (void *)as<uintptr_t>();
|
|
}
|
|
|
|
} // namespace clang
|
|
#endif
|