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