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