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, Char_U) \ 80 X(unsigned char, UChar) \ 81 X(short, Short) \ 82 X(unsigned short, UShort) \ 83 X(int, Int) \ 84 X(unsigned int, UInt) \ 85 X(long, Long) \ 86 X(unsigned long, ULong) \ 87 X(long long, LongLong) \ 88 X(unsigned long long, ULongLong) \ 89 X(float, Float) \ 90 X(double, Double) \ 91 X(long double, LongDouble) 92 93 class REPL_EXTERNAL_VISIBILITY Value { 94 union Storage { 95 #define X(type, name) type m_##name; 96 REPL_BUILTIN_TYPES 97 #undef X 98 void *m_Ptr; 99 }; 100 101 public: 102 enum Kind { 103 #define X(type, name) K_##name, 104 REPL_BUILTIN_TYPES 105 #undef X 106 107 K_Void, 108 K_PtrOrObj, 109 K_Unspecified 110 }; 111 112 Value() = default; 113 Value(Interpreter *In, void *Ty); 114 Value(const Value &RHS); 115 Value(Value &&RHS) noexcept; 116 Value &operator=(const Value &RHS); 117 Value &operator=(Value &&RHS) noexcept; 118 ~Value(); 119 120 void printType(llvm::raw_ostream &Out) const; 121 void printData(llvm::raw_ostream &Out) const; 122 void print(llvm::raw_ostream &Out) const; 123 void dump() const; 124 void clear(); 125 126 ASTContext &getASTContext(); 127 const ASTContext &getASTContext() const; 128 Interpreter &getInterpreter(); 129 const Interpreter &getInterpreter() const; 130 QualType getType() const; 131 isValid()132 bool isValid() const { return ValueKind != K_Unspecified; } isVoid()133 bool isVoid() const { return ValueKind == K_Void; } hasValue()134 bool hasValue() const { return isValid() && !isVoid(); } isManuallyAlloc()135 bool isManuallyAlloc() const { return IsManuallyAlloc; } getKind()136 Kind getKind() const { return ValueKind; } setKind(Kind K)137 void setKind(Kind K) { ValueKind = K; } setOpaqueType(void * Ty)138 void setOpaqueType(void *Ty) { OpaqueType = Ty; } 139 140 void *getPtr() const; setPtr(void * Ptr)141 void setPtr(void *Ptr) { Data.m_Ptr = Ptr; } 142 143 #define X(type, name) \ 144 void set##name(type Val) { Data.m_##name = Val; } \ 145 type get##name() const { return Data.m_##name; } 146 REPL_BUILTIN_TYPES 147 #undef X 148 149 /// \brief Get the value with cast. 150 // 151 /// Get the value cast to T. This is similar to reinterpret_cast<T>(value), 152 /// casting the value of builtins (except void), enums and pointers. 153 /// Values referencing an object are treated as pointers to the object. convertTo()154 template <typename T> T convertTo() const { 155 return convertFwd<T>::cast(*this); 156 } 157 158 protected: isPointerOrObjectType()159 bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; } 160 161 /// \brief Get to the value with type checking casting the underlying 162 /// stored value to T. as()163 template <typename T> T as() const { 164 switch (ValueKind) { 165 default: 166 return T(); 167 #define X(type, name) \ 168 case Value::K_##name: \ 169 return (T)Data.m_##name; 170 REPL_BUILTIN_TYPES 171 #undef X 172 } 173 } 174 175 // Allow convertTo to be partially specialized. 176 template <typename T> struct convertFwd { castconvertFwd177 static T cast(const Value &V) { 178 if (V.isPointerOrObjectType()) 179 return (T)(uintptr_t)V.as<void *>(); 180 if (!V.isValid() || V.isVoid()) { 181 return T(); 182 } 183 return V.as<T>(); 184 } 185 }; 186 187 template <typename T> struct convertFwd<T *> { 188 static T *cast(const Value &V) { 189 if (V.isPointerOrObjectType()) 190 return (T *)(uintptr_t)V.as<void *>(); 191 return nullptr; 192 } 193 }; 194 195 Interpreter *Interp = nullptr; 196 void *OpaqueType = nullptr; 197 Storage Data; 198 Kind ValueKind = K_Unspecified; 199 bool IsManuallyAlloc = false; 200 }; 201 202 template <> inline void *Value::as() const { 203 if (isPointerOrObjectType()) 204 return Data.m_Ptr; 205 return (void *)as<uintptr_t>(); 206 } 207 208 } // namespace clang 209 #endif 210