1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
//===--- Program.h - Bytecode for the constexpr VM --------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Defines a program which organises and links multiple bytecode functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
#define LLVM_CLANG_AST_INTERP_PROGRAM_H
#include <map>
#include <vector>
#include "Function.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
#include "Source.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
namespace clang {
class RecordDecl;
class Expr;
class FunctionDecl;
class StringLiteral;
class VarDecl;
namespace interp {
class Context;
class Record;
/// The program contains and links the bytecode for all functions.
class Program {
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);
/// Returns a pointer to a global.
Pointer getPtrGlobal(unsigned Idx);
/// Returns the value of a global.
Block *getGlobal(unsigned Idx) {
assert(Idx < Globals.size());
return Globals[Idx]->block();
}
/// Finds a global's index.
llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
/// Returns or creates a global an creates an index to it.
llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
/// Returns or creates a dummy value for parameters.
llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
/// Creates a global and returns its index.
llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
/// Creates a global from a lifetime-extended temporary.
llvm::Optional<unsigned> createGlobal(const Expr *E);
/// Creates a new function from a code range.
template <typename... Ts>
Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
Funcs.insert({Def, std::unique_ptr<Function>(Func)});
return Func;
}
/// Creates an anonymous function.
template <typename... Ts>
Function *createFunction(Ts &&... Args) {
auto *Func = new Function(*this, std::forward<Ts>(Args)...);
AnonFuncs.emplace_back(Func);
return Func;
}
/// Returns a function.
Function *getFunction(const FunctionDecl *F);
/// Returns a pointer to a function if it exists and can be compiled.
/// If a function couldn't be compiled, an error is returned.
/// If a function was not yet defined, a null pointer is returned.
llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
/// Returns a record or creates one if it does not exist.
Record *getOrCreateRecord(const RecordDecl *RD);
/// Creates a descriptor for a primitive type.
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
bool IsConst = false,
bool IsTemporary = false,
bool IsMutable = false) {
return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
}
/// Creates a descriptor for a composite type.
Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false);
/// Context to manage declaration lifetimes.
class DeclScope {
public:
DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
~DeclScope() { P.endDeclaration(); }
private:
Program &P;
};
/// Returns the current declaration ID.
llvm::Optional<unsigned> getCurrentDecl() const {
if (CurrentDeclaration == NoDeclaration)
return llvm::Optional<unsigned>{};
return LastDeclaration;
}
private:
friend class DeclScope;
llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
bool IsStatic, bool IsExtern);
/// Reference to the VM context.
Context &Ctx;
/// Mapping from decls to cached bytecode functions.
llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
/// List of anonymous functions.
std::vector<std::unique_ptr<Function>> AnonFuncs;
/// Function relocation locations.
llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
/// Native pointers referenced by bytecode.
std::vector<const void *> NativePointers;
/// Cached native pointer indices.
llvm::DenseMap<const void *, unsigned> NativePointerIndices;
/// Custom allocator for global storage.
using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
/// Descriptor + storage for a global object.
///
/// Global objects never go out of scope, thus they do not track pointers.
class Global {
public:
/// Create a global descriptor for string literals.
template <typename... Tys>
Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
/// Allocates the global in the pool, reserving storate for data.
void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
return Alloc.Allocate(Meta + Data, alignof(void *));
}
/// Return a pointer to the data.
char *data() { return B.data(); }
/// Return a pointer to the block.
Block *block() { return &B; }
private:
/// Required metadata - does not actually track pointers.
Block B;
};
/// Allocator for globals.
PoolAllocTy Allocator;
/// Global objects.
std::vector<Global *> Globals;
/// Cached global indices.
llvm::DenseMap<const void *, unsigned> GlobalIndices;
/// Mapping from decls to record metadata.
llvm::DenseMap<const RecordDecl *, Record *> Records;
/// Dummy parameter to generate pointers from.
llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
/// Creates a new descriptor.
template <typename... Ts>
Descriptor *allocateDescriptor(Ts &&... Args) {
return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
}
/// No declaration ID.
static constexpr unsigned NoDeclaration = (unsigned)-1;
/// Last declaration ID.
unsigned LastDeclaration = 0;
/// Current declaration ID.
unsigned CurrentDeclaration = NoDeclaration;
/// Starts evaluating a declaration.
void startDeclaration(const VarDecl *Decl) {
LastDeclaration += 1;
CurrentDeclaration = LastDeclaration;
}
/// Ends a global declaration.
void endDeclaration() {
CurrentDeclaration = NoDeclaration;
}
public:
/// Dumps the disassembled bytecode to \c llvm::errs().
void dump() const;
void dump(llvm::raw_ostream &OS) const;
};
} // namespace interp
} // namespace clang
#endif
|