-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reland [clang-repl] Introduce Value to capture expression results
This reverts commit 7158fd3. * Fixes endianness issue on big endian machines like PowerPC-bl * Disable tests on platforms that having trouble to support JIT Signed-off-by: Jun Zhang <jun@junz.org>
- Loading branch information
Showing
12 changed files
with
1,286 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
//===--- Value.h - Definition of interpreter value --------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Value is a lightweight struct that is used for carrying execution results in | ||
// clang-repl. It's a special runtime that acts like a messager between compiled | ||
// code and interpreted code. This makes it possible to exchange interesting | ||
// information between the compiled & interpreted world. | ||
// | ||
// A typical usage is like the below: | ||
// | ||
// Value V; | ||
// Interp.ParseAndExecute("int x = 42;"); | ||
// Interp.ParseAndExecute("x", &V); | ||
// V.getType(); // <-- Yields a clang::QualType. | ||
// V.getInt(); // <-- Yields 42. | ||
// | ||
// The current design is still highly experimental and nobody should rely on the | ||
// API being stable because we're hopefully going to make significant changes to | ||
// it in the relatively near future. For example, Value also intends to be used | ||
// as an exchange token for JIT support enabling remote execution on the embed | ||
// devices where the JIT infrastructure cannot fit. To support that we will need | ||
// to split the memory storage in a different place and perhaps add a resource | ||
// header is similar to intrinsics headers which have stricter performance | ||
// constraints. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_INTERPRETER_VALUE_H | ||
#define LLVM_CLANG_INTERPRETER_VALUE_H | ||
|
||
#include <cstdint> | ||
// NOTE: Since the REPL itself could also include this runtime, extreme caution | ||
// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW | ||
// HEADERS, like <string>, <memory> and etc. (That pulls a large number of | ||
// tokens and will impact the runtime performance of the REPL) | ||
|
||
namespace llvm { | ||
class raw_ostream; | ||
|
||
} // namespace llvm | ||
|
||
namespace clang { | ||
|
||
class ASTContext; | ||
class Interpreter; | ||
class QualType; | ||
|
||
#if __has_attribute(visibility) && \ | ||
(!(defined(_WIN32) || defined(__CYGWIN__)) || \ | ||
(defined(__MINGW32__) && defined(__clang__))) | ||
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS) | ||
#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default"))) | ||
#else | ||
#define REPL_EXTERNAL_VISIBILITY | ||
#endif | ||
#else | ||
#if defined(_WIN32) | ||
#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport) | ||
#endif | ||
#endif | ||
|
||
#define REPL_BUILTIN_TYPES \ | ||
X(bool, Bool) \ | ||
X(char, Char_S) \ | ||
X(signed char, SChar) \ | ||
X(unsigned char, UChar) \ | ||
X(short, Short) \ | ||
X(unsigned short, UShort) \ | ||
X(int, Int) \ | ||
X(unsigned int, UInt) \ | ||
X(long, Long) \ | ||
X(unsigned long, ULong) \ | ||
X(long long, LongLong) \ | ||
X(unsigned long long, ULongLong) \ | ||
X(float, Float) \ | ||
X(double, Double) \ | ||
X(long double, LongDouble) | ||
|
||
class REPL_EXTERNAL_VISIBILITY Value { | ||
union Storage { | ||
#define X(type, name) type m_##name; | ||
REPL_BUILTIN_TYPES | ||
#undef X | ||
void *m_Ptr; | ||
}; | ||
|
||
public: | ||
enum Kind { | ||
#define X(type, name) K_##name, | ||
REPL_BUILTIN_TYPES | ||
#undef X | ||
|
||
K_Void, | ||
K_PtrOrObj, | ||
K_Unspecified | ||
}; | ||
|
||
Value() = default; | ||
Value(Interpreter *In, void *Ty); | ||
Value(const Value &RHS); | ||
Value(Value &&RHS) noexcept; | ||
Value &operator=(const Value &RHS); | ||
Value &operator=(Value &&RHS) noexcept; | ||
~Value(); | ||
|
||
void printType(llvm::raw_ostream &Out) const; | ||
void printData(llvm::raw_ostream &Out) const; | ||
void print(llvm::raw_ostream &Out) const; | ||
void dump() const; | ||
void clear(); | ||
|
||
ASTContext &getASTContext(); | ||
const ASTContext &getASTContext() const; | ||
Interpreter &getInterpreter(); | ||
const Interpreter &getInterpreter() const; | ||
QualType getType() const; | ||
|
||
bool isValid() const { return ValueKind != K_Unspecified; } | ||
bool isVoid() const { return ValueKind == K_Void; } | ||
bool hasValue() const { return isValid() && !isVoid(); } | ||
bool isManuallyAlloc() const { return IsManuallyAlloc; } | ||
Kind getKind() const { return ValueKind; } | ||
void setKind(Kind K) { ValueKind = K; } | ||
void setOpaqueType(void *Ty) { OpaqueType = Ty; } | ||
|
||
void *getPtr() const; | ||
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; } | ||
|
||
#define X(type, name) \ | ||
void set##name(type Val) { Data.m_##name = Val; } \ | ||
type get##name() const { return Data.m_##name; } | ||
REPL_BUILTIN_TYPES | ||
#undef X | ||
|
||
/// \brief Get the value with cast. | ||
// | ||
/// Get the value cast to T. This is similar to reinterpret_cast<T>(value), | ||
/// casting the value of builtins (except void), enums and pointers. | ||
/// Values referencing an object are treated as pointers to the object. | ||
template <typename T> T convertTo() const { | ||
return convertFwd<T>::cast(*this); | ||
} | ||
|
||
protected: | ||
bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; } | ||
|
||
/// \brief Get to the value with type checking casting the underlying | ||
/// stored value to T. | ||
template <typename T> T as() const { | ||
switch (ValueKind) { | ||
default: | ||
return T(); | ||
#define X(type, name) \ | ||
case Value::K_##name: \ | ||
return (T)Data.m_##name; | ||
REPL_BUILTIN_TYPES | ||
#undef X | ||
} | ||
} | ||
|
||
// Allow convertTo to be partially specialized. | ||
template <typename T> struct convertFwd { | ||
static T cast(const Value &V) { | ||
if (V.isPointerOrObjectType()) | ||
return (T)(uintptr_t)V.as<void *>(); | ||
if (!V.isValid() || V.isVoid()) { | ||
return T(); | ||
} | ||
return V.as<T>(); | ||
} | ||
}; | ||
|
||
template <typename T> struct convertFwd<T *> { | ||
static T *cast(const Value &V) { | ||
if (V.isPointerOrObjectType()) | ||
return (T *)(uintptr_t)V.as<void *>(); | ||
return nullptr; | ||
} | ||
}; | ||
|
||
Interpreter *Interp = nullptr; | ||
void *OpaqueType = nullptr; | ||
Storage Data; | ||
Kind ValueKind = K_Unspecified; | ||
bool IsManuallyAlloc = false; | ||
}; | ||
|
||
template <> inline void *Value::as() const { | ||
if (isPointerOrObjectType()) | ||
return Data.m_Ptr; | ||
return (void *)as<uintptr_t>(); | ||
} | ||
|
||
} // namespace clang | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.