Coverage Report

Created: 2024-01-17 10:31

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