xref: /llvm-project/clang/include/clang/Interpreter/Value.h (revision b8d6885ff67efbc3142a2b49506ed0cc2b95e054)
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 <cstdint>
39 
40 // NOTE: Since the REPL itself could also include this runtime, extreme caution
41 // should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW
42 // HEADERS, like <string>, <memory> and etc. (That pulls a large number of
43 // tokens and will impact the runtime performance of the REPL)
44 
45 namespace llvm {
46 class raw_ostream;
47 
48 } // namespace llvm
49 
50 namespace clang {
51 
52 class ASTContext;
53 class Interpreter;
54 class QualType;
55 
56 #if defined(_WIN32)
57 // REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
58 // at runtime. On Windows, this requires them to be exported from any of the
59 // modules loaded at runtime. Marking them as dllexport achieves this; both
60 // for DLLs (that normally export symbols as part of their interface) and for
61 // EXEs (that normally don't export anything).
62 // For a build with libclang-cpp.dll, this doesn't make any difference - the
63 // functions would have been exported anyway. But for cases when these are
64 // statically linked into an EXE, it makes sure that they're exported.
65 #define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
66 #elif __has_attribute(visibility)
67 #if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
68 #define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
69 #else
70 #define REPL_EXTERNAL_VISIBILITY
71 #endif
72 #else
73 #define REPL_EXTERNAL_VISIBILITY
74 #endif
75 
76 #define REPL_BUILTIN_TYPES                                                     \
77   X(bool, Bool)                                                                \
78   X(char, Char_S)                                                              \
79   X(signed char, SChar)                                                        \
80   X(unsigned char, Char_U)                                                     \
81   X(unsigned char, UChar)                                                      \
82   X(short, Short)                                                              \
83   X(unsigned short, UShort)                                                    \
84   X(int, Int)                                                                  \
85   X(unsigned int, UInt)                                                        \
86   X(long, Long)                                                                \
87   X(unsigned long, ULong)                                                      \
88   X(long long, LongLong)                                                       \
89   X(unsigned long long, ULongLong)                                             \
90   X(float, Float)                                                              \
91   X(double, Double)                                                            \
92   X(long double, LongDouble)
93 
94 class REPL_EXTERNAL_VISIBILITY Value {
95   union Storage {
96 #define X(type, name) type m_##name;
97     REPL_BUILTIN_TYPES
98 #undef X
99     void *m_Ptr;
100   };
101 
102 public:
103   enum Kind {
104 #define X(type, name) K_##name,
105     REPL_BUILTIN_TYPES
106 #undef X
107 
108     K_Void,
109     K_PtrOrObj,
110     K_Unspecified
111   };
112 
113   Value() = default;
114   Value(Interpreter *In, void *Ty);
115   Value(const Value &RHS);
116   Value(Value &&RHS) noexcept;
117   Value &operator=(const Value &RHS);
118   Value &operator=(Value &&RHS) noexcept;
119   ~Value();
120 
121   void printType(llvm::raw_ostream &Out) const;
122   void printData(llvm::raw_ostream &Out) const;
123   void print(llvm::raw_ostream &Out) const;
124   void dump() const;
125   void clear();
126 
127   ASTContext &getASTContext();
128   const ASTContext &getASTContext() const;
129   Interpreter &getInterpreter();
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 
144 #define X(type, name)                                                          \
145   void set##name(type Val) { Data.m_##name = Val; }                            \
146   type get##name() const { return Data.m_##name; }
147   REPL_BUILTIN_TYPES
148 #undef X
149 
150   /// \brief Get the value with cast.
151   //
152   /// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
153   /// casting the value of builtins (except void), enums and pointers.
154   /// Values referencing an object are treated as pointers to the object.
155   template <typename T> T convertTo() const {
156     return convertFwd<T>::cast(*this);
157   }
158 
159 protected:
160   bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; }
161 
162   /// \brief Get to the value with type checking casting the underlying
163   /// stored value to T.
164   template <typename T> T as() const {
165     switch (ValueKind) {
166     default:
167       return T();
168 #define X(type, name)                                                          \
169   case Value::K_##name:                                                        \
170     return (T)Data.m_##name;
171       REPL_BUILTIN_TYPES
172 #undef X
173     }
174   }
175 
176   // Allow convertTo to be partially specialized.
177   template <typename T> struct convertFwd {
178     static T cast(const Value &V) {
179       if (V.isPointerOrObjectType())
180         return (T)(uintptr_t)V.as<void *>();
181       if (!V.isValid() || V.isVoid()) {
182         return T();
183       }
184       return V.as<T>();
185     }
186   };
187 
188   template <typename T> struct convertFwd<T *> {
189     static T *cast(const Value &V) {
190       if (V.isPointerOrObjectType())
191         return (T *)(uintptr_t)V.as<void *>();
192       return nullptr;
193     }
194   };
195 
196   Interpreter *Interp = nullptr;
197   void *OpaqueType = nullptr;
198   Storage Data;
199   Kind ValueKind = K_Unspecified;
200   bool IsManuallyAlloc = false;
201 };
202 
203 template <> inline void *Value::as() const {
204   if (isPointerOrObjectType())
205     return Data.m_Ptr;
206   return (void *)as<uintptr_t>();
207 }
208 
209 } // namespace clang
210 #endif
211