Coverage Report

Created: 2021-09-21 08:58

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