diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -11,6 +11,7 @@ #include "Opcode.h" #include "Program.h" #include "clang/AST/DeclCXX.h" +#include using namespace clang; using namespace clang::interp; @@ -122,29 +123,48 @@ return false; } +/// Helper to write bytecode and bail out if 32-bit offsets become invalid. +/// Pointers will be automatically marshalled as 32-bit IDs. +template +static std::enable_if_t::value, void> +emit(Program &P, std::vector &Code, const T &Val, bool &Success) { + size_t Size = sizeof(Val); + if (Code.size() + Size > std::numeric_limits::max()) { + Success = false; + return; + } + + const char *Data = reinterpret_cast(&Val); + Code.insert(Code.end(), Data, Data + Size); +} + +template +static std::enable_if_t::value, void> +emit(Program &P, std::vector &Code, const T &Val, bool &Success) { + size_t Size = sizeof(uint32_t); + if (Code.size() + Size > std::numeric_limits::max()) { + Success = false; + return; + } + + uint32_t ID = P.getOrCreateNativePointer(Val); + const char *Data = reinterpret_cast(&ID); + Code.insert(Code.end(), Data, Data + Size); +} + template bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { bool Success = true; - /// Helper to write bytecode and bail out if 32-bit offsets become invalid. - auto emit = [this, &Success](const char *Data, size_t Size) { - if (Code.size() + Size > std::numeric_limits::max()) { - Success = false; - return; - } - Code.insert(Code.end(), Data, Data + Size); - }; - /// The opcode is followed by arguments. The source info is /// attached to the address after the opcode. - emit(reinterpret_cast(&Op), sizeof(Opcode)); + emit(P, Code, Op, Success); if (SI) SrcMap.emplace_back(Code.size(), SI); /// The initializer list forces the expression to be evaluated /// for each argument in the variadic template, in order. - (void)std::initializer_list{ - (emit(reinterpret_cast(&Args), sizeof(Args)), 0)...}; + (void)std::initializer_list{(emit(P, Code, Args, Success), 0)...}; return Success; } diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -21,6 +21,19 @@ using namespace clang; using namespace clang::interp; +template +inline std::enable_if_t::value, T> ReadArg(Program &P, + CodePtr OpPC) { + return OpPC.read(); +} + +template +inline std::enable_if_t::value, T> ReadArg(Program &P, + CodePtr OpPC) { + uint32_t ID = OpPC.read(); + return reinterpret_cast(P.getNativePointer(ID)); +} + LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -13,8 +13,6 @@ #ifndef LLVM_CLANG_AST_INTERP_INTERP_H #define LLVM_CLANG_AST_INTERP_INTERP_H -#include -#include #include "Function.h" #include "InterpFrame.h" #include "InterpStack.h" @@ -30,6 +28,9 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Endian.h" +#include +#include +#include namespace clang { namespace interp { @@ -949,6 +950,23 @@ return true; } +//===----------------------------------------------------------------------===// +// Read opcode arguments +//===----------------------------------------------------------------------===// + +template +inline std::enable_if_t::value, T> ReadArg(InterpState &S, + CodePtr OpPC) { + return OpPC.read(); +} + +template +inline std::enable_if_t::value, T> ReadArg(InterpState &S, + CodePtr OpPC) { + uint32_t ID = OpPC.read(); + return reinterpret_cast(S.P.getNativePointer(ID)); +} + /// Interpreter entry point. bool Interpret(InterpState &S, APValue &Result); diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -44,6 +44,12 @@ public: Program(Context &Ctx) : Ctx(Ctx) {} + /// Marshals a native pointer to an ID for embedding in bytecode. + unsigned getOrCreateNativePointer(const void *Ptr); + + /// Returns the value of a marshalled native pointer. + const void *getNativePointer(unsigned Idx); + /// Emits a string literal among global data. unsigned createGlobalString(const StringLiteral *S); @@ -143,6 +149,11 @@ /// Function relocation locations. llvm::DenseMap> Relocs; + /// Native pointers referenced by bytecode. + std::vector NativePointers; + /// Cached native pointer indices. + llvm::DenseMap NativePointerIndices; + /// Custom allocator for global storage. using PoolAllocTy = llvm::BumpPtrAllocatorImpl; diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -18,6 +18,21 @@ using namespace clang; using namespace clang::interp; +unsigned Program::getOrCreateNativePointer(const void *Ptr) { + auto It = NativePointerIndices.find(Ptr); + if (It != NativePointerIndices.end()) + return It->second; + + unsigned Idx = NativePointers.size(); + NativePointers.push_back(Ptr); + NativePointerIndices[Ptr] = Idx; + return Idx; +} + +const void *Program::getNativePointer(unsigned Idx) { + return NativePointers[Idx]; +} + unsigned Program::createGlobalString(const StringLiteral *S) { const size_t CharWidth = S->getCharByteWidth(); const size_t BitWidth = CharWidth * Ctx.getCharBit(); diff --git a/clang/lib/AST/Interp/Source.h b/clang/lib/AST/Interp/Source.h --- a/clang/lib/AST/Interp/Source.h +++ b/clang/lib/AST/Interp/Source.h @@ -44,8 +44,9 @@ bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; } /// Reads data and advances the pointer. - template T read() { - T Value = ReadHelper(Ptr); + template std::enable_if_t::value, T> read() { + using namespace llvm::support; + T Value = endian::read(Ptr); Ptr += sizeof(T); return Value; } @@ -54,22 +55,6 @@ /// Constructor used by Function to generate pointers. CodePtr(const char *Ptr) : Ptr(Ptr) {} - /// Helper to decode a value or a pointer. - template - static std::enable_if_t::value, T> - ReadHelper(const char *Ptr) { - using namespace llvm::support; - return endian::read(Ptr); - } - - template - static std::enable_if_t::value, T> - ReadHelper(const char *Ptr) { - using namespace llvm::support; - auto Punned = endian::read(Ptr); - return reinterpret_cast(Punned); - } - private: friend class Function; diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp --- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp +++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp @@ -124,7 +124,7 @@ for (size_t I = 0, N = Args.size(); I < N; ++I) { OS << " auto V" << I; OS << " = "; - OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n"; + OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n"; } // Emit a call to the template method and pass arguments. @@ -161,8 +161,10 @@ OS << " PrintName(\"" << ID << "\");\n"; OS << " OS << \"\\t\""; - for (auto *Arg : R->getValueAsListOfDefs("Args")) - OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \""; + for (auto *Arg : R->getValueAsListOfDefs("Args")) { + OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)"; + OS << " << \" \""; + } OS << " << \"\\n\";\n"; OS << " continue;\n";