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