1//===--- Value.h - Definition of interpreter value --------------*- 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// Value is a lightweight struct that is used for carrying execution results in
10// clang-repl. It's a special runtime that acts like a messager between compiled
11// code and interpreted code. This makes it possible to exchange interesting
12// information between the compiled & interpreted world.
13//
14// A typical usage is like the below:
15//
16// Value V;
17// Interp.ParseAndExecute("int x = 42;");
18// Interp.ParseAndExecute("x", &V);
19// V.getType(); // <-- Yields a clang::QualType.
20// V.getInt(); // <-- Yields 42.
21//
22// The current design is still highly experimental and nobody should rely on the
23// API being stable because we're hopefully going to make significant changes to
24// it in the relatively near future. For example, Value also intends to be used
25// as an exchange token for JIT support enabling remote execution on the embed
26// devices where the JIT infrastructure cannot fit. To support that we will need
27// to split the memory storage in a different place and perhaps add a resource
28// header is similar to intrinsics headers which have stricter performance
29// constraints.
30//
31//===----------------------------------------------------------------------===//
32
33#ifndef LLVM_CLANG_INTERPRETER_VALUE_H
34#define LLVM_CLANG_INTERPRETER_VALUE_H
35
36#include "llvm/Config/llvm-config.h" // for LLVM_BUILD_LLVM_DYLIB, LLVM_BUILD_SHARED_LIBS
37#include "llvm/Support/Compiler.h"
38#include <cassert>
39#include <cstdint>
40
41// NOTE: Since the REPL itself could also include this runtime, extreme caution
42// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW
43// HEADERS, like <string>, <memory> and etc. (That pulls a large number of
44// tokens and will impact the runtime performance of the REPL)
45
46namespace llvm {
47class raw_ostream;
48
49} // namespace llvm
50
51namespace clang {
52
53class ASTContext;
54class Interpreter;
55class QualType;
56
57#if defined(_WIN32)
58// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
59// at runtime. On Windows, this requires them to be exported from any of the
60// modules loaded at runtime. Marking them as dllexport achieves this; both
61// for DLLs (that normally export symbols as part of their interface) and for
62// EXEs (that normally don't export anything).
63// For a build with libclang-cpp.dll, this doesn't make any difference - the
64// functions would have been exported anyway. But for cases when these are
65// statically linked into an EXE, it makes sure that they're exported.
66#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
67#elif __has_attribute(visibility)
68#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
69#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
70#else
71#define REPL_EXTERNAL_VISIBILITY
72#endif
73#else
74#define REPL_EXTERNAL_VISIBILITY
75#endif
76
77#define REPL_BUILTIN_TYPES \
78 X(bool, Bool) \
79 X(char, Char_S) \
80 X(signed char, SChar) \
81 X(unsigned char, Char_U) \
82 X(unsigned char, UChar) \
83 X(short, Short) \
84 X(unsigned short, UShort) \
85 X(int, Int) \
86 X(unsigned int, UInt) \
87 X(long, Long) \
88 X(unsigned long, ULong) \
89 X(long long, LongLong) \
90 X(unsigned long long, ULongLong) \
91 X(float, Float) \
92 X(double, Double) \
93 X(long double, LongDouble)
94
95class REPL_EXTERNAL_VISIBILITY Value {
96 union Storage {
97#define X(type, name) type m_##name;
98 REPL_BUILTIN_TYPES
99#undef X
100 void *m_Ptr;
101 unsigned char m_RawBits[sizeof(long double)]; // widest typed member
102 };
103
104public:
105 enum Kind {
106#define X(type, name) K_##name,
107 REPL_BUILTIN_TYPES
108#undef X
109
110 K_Void,
111 K_PtrOrObj,
112 K_Unspecified
113 };
114
115 Value() = default;
116 Value(const Interpreter *In, void *Ty);
117 Value(const Value &RHS);
118 Value(Value &&RHS) noexcept;
119 Value &operator=(const Value &RHS);
120 Value &operator=(Value &&RHS) noexcept;
121 ~Value();
122
123 void printType(llvm::raw_ostream &Out) const;
124 void printData(llvm::raw_ostream &Out) const;
125 void print(llvm::raw_ostream &Out) const;
126 void dump() const;
127 void clear();
128
129 const ASTContext &getASTContext() const;
130 const Interpreter &getInterpreter() const;
131 QualType getType() const;
132
133 bool isValid() const { return ValueKind != K_Unspecified; }
134 bool isVoid() const { return ValueKind == K_Void; }
135 bool hasValue() const { return isValid() && !isVoid(); }
136 bool isManuallyAlloc() const { return IsManuallyAlloc; }
137 Kind getKind() const { return ValueKind; }
138 void setKind(Kind K) { ValueKind = K; }
139 void setOpaqueType(void *Ty) { OpaqueType = Ty; }
140
141 void *getPtr() const;
142 void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
143 /// Copy `NBytes` bytes from `Ptr` into the raw storage. Default copies
144 /// the full Storage width. Used by the value printer to read a single
145 /// array element through a typed lens without an extra heap allocation.
146 void setRawBits(void *Ptr, unsigned NBytes = sizeof(Storage));
147
148#define X(type, name) \
149 void set##name(type Val) { Data.m_##name = Val; } \
150 type get##name() const { return Data.m_##name; }
151 REPL_BUILTIN_TYPES
152#undef X
153
154 /// \brief Get the value with cast.
155 //
156 /// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
157 /// casting the value of builtins (except void), enums and pointers.
158 /// Values referencing an object are treated as pointers to the object.
159 template <typename T> T convertTo() const {
160 return convertFwd<T>::cast(*this);
161 }
162
163protected:
164 bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; }
165
166 /// \brief Get to the value with type checking casting the underlying
167 /// stored value to T.
168 template <typename T> T as() const {
169 switch (ValueKind) {
170 default:
171 return T();
172#define X(type, name) \
173 case Value::K_##name: \
174 return (T)Data.m_##name;
175 REPL_BUILTIN_TYPES
176#undef X
177 }
178 }
179
180 // Allow convertTo to be partially specialized.
181 template <typename T> struct convertFwd {
182 static T cast(const Value &V) {
183 if (V.isPointerOrObjectType())
184 return (T)(uintptr_t)V.as<void *>();
185 if (!V.isValid() || V.isVoid()) {
186 return T();
187 }
188 return V.as<T>();
189 }
190 };
191
192 template <typename T> struct convertFwd<T *> {
193 static T *cast(const Value &V) {
194 if (V.isPointerOrObjectType())
195 return (T *)(uintptr_t)V.as<void *>();
196 return nullptr;
197 }
198 };
199
200 const Interpreter *Interp = nullptr;
201 void *OpaqueType = nullptr;
202 Storage Data;
203 Kind ValueKind = K_Unspecified;
204 bool IsManuallyAlloc = false;
205};
206
207template <> inline void *Value::as() const {
208 if (isPointerOrObjectType())
209 return Data.m_Ptr;
210 return (void *)as<uintptr_t>();
211}
212} // namespace clang
213#endif
214