Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/InterpFrame.h
Line
Count
Source (jump to first uncovered line)
1
//===--- InterpFrame.h - Call Frame implementation for the 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 the class storing information about stack frames in the interpreter.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_CLANG_AST_INTERP_INTERPFRAME_H
14
#define LLVM_CLANG_AST_INTERP_INTERPFRAME_H
15
16
#include "Frame.h"
17
#include "Program.h"
18
#include <cstdint>
19
#include <vector>
20
21
namespace clang {
22
namespace interp {
23
class Function;
24
class InterpState;
25
class Pointer;
26
27
/// Frame storing local variables.
28
class InterpFrame final : public Frame {
29
public:
30
  /// The frame of the previous function.
31
  InterpFrame *Caller;
32
33
  /// Creates a new frame for a method call.
34
  InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
35
              CodePtr RetPC);
36
37
  /// Creates a new frame with the values that make sense.
38
  /// I.e., the caller is the current frame of S,
39
  /// the This() pointer is the current Pointer on the top of S's stack,
40
  /// and the RVO pointer is before that.
41
  InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC);
42
43
  /// Destroys the frame, killing all live pointers to stack slots.
44
  ~InterpFrame();
45
46
  /// Invokes the destructors for a scope.
47
  void destroy(unsigned Idx);
48
49
  /// Pops the arguments off the stack.
50
  void popArgs();
51
52
  /// Describes the frame with arguments for diagnostic purposes.
53
  void describe(llvm::raw_ostream &OS) const override;
54
55
  /// Returns the parent frame object.
56
  Frame *getCaller() const override;
57
58
  /// Returns the location of the call to the frame.
59
  SourceRange getCallRange() const override;
60
61
  /// Returns the caller.
62
  const FunctionDecl *getCallee() const override;
63
64
  /// Returns the current function.
65
0
  const Function *getFunction() const { return Func; }
66
67
  /// Returns the offset on the stack at which the frame starts.
68
0
  size_t getFrameOffset() const { return FrameOffset; }
69
70
  /// Returns the value of a local variable.
71
  template <typename T> const T &getLocal(unsigned Offset) const {
72
    return localRef<T>(Offset);
73
  }
74
75
  /// Mutates a local variable.
76
0
  template <typename T> void setLocal(unsigned Offset, const T &Value) {
77
0
    localRef<T>(Offset) = Value;
78
0
    localInlineDesc(Offset)->IsInitialized = true;
79
0
  }
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<8u, true> >(unsigned int, clang::interp::Integral<8u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<8u, false> >(unsigned int, clang::interp::Integral<8u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<16u, true> >(unsigned int, clang::interp::Integral<16u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<16u, false> >(unsigned int, clang::interp::Integral<16u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<32u, true> >(unsigned int, clang::interp::Integral<32u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<32u, false> >(unsigned int, clang::interp::Integral<32u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<64u, true> >(unsigned int, clang::interp::Integral<64u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Integral<64u, false> >(unsigned int, clang::interp::Integral<64u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::IntegralAP<false> >(unsigned int, clang::interp::IntegralAP<false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::IntegralAP<true> >(unsigned int, clang::interp::IntegralAP<true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Boolean>(unsigned int, clang::interp::Boolean const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Pointer>(unsigned int, clang::interp::Pointer const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::FunctionPointer>(unsigned int, clang::interp::FunctionPointer const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setLocal<clang::interp::Floating>(unsigned int, clang::interp::Floating const&)
80
81
  /// Returns a pointer to a local variables.
82
  Pointer getLocalPointer(unsigned Offset) const;
83
84
  /// Returns the value of an argument.
85
0
  template <typename T> const T &getParam(unsigned Offset) const {
86
0
    auto Pt = Params.find(Offset);
87
0
    if (Pt == Params.end()) {
88
0
      return stackRef<T>(Offset);
89
0
    } else {
90
0
      return Pointer(reinterpret_cast<Block *>(Pt->second.get())).deref<T>();
91
0
    }
92
0
  }
Unexecuted instantiation: clang::interp::Integral<8u, true> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<8u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<8u, false> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<8u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, true> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<16u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, false> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<16u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, true> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<32u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, false> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<32u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, true> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<64u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, false> const& clang::interp::InterpFrame::getParam<clang::interp::Integral<64u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<false> const& clang::interp::InterpFrame::getParam<clang::interp::IntegralAP<false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<true> const& clang::interp::InterpFrame::getParam<clang::interp::IntegralAP<true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Boolean const& clang::interp::InterpFrame::getParam<clang::interp::Boolean>(unsigned int) const
Unexecuted instantiation: clang::interp::Pointer const& clang::interp::InterpFrame::getParam<clang::interp::Pointer>(unsigned int) const
Unexecuted instantiation: clang::interp::FunctionPointer const& clang::interp::InterpFrame::getParam<clang::interp::FunctionPointer>(unsigned int) const
Unexecuted instantiation: clang::interp::Floating const& clang::interp::InterpFrame::getParam<clang::interp::Floating>(unsigned int) const
93
94
  /// Mutates a local copy of a parameter.
95
0
  template <typename T> void setParam(unsigned Offset, const T &Value) {
96
0
     getParamPointer(Offset).deref<T>() = Value;
97
0
  }
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<8u, true> >(unsigned int, clang::interp::Integral<8u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<8u, false> >(unsigned int, clang::interp::Integral<8u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<16u, true> >(unsigned int, clang::interp::Integral<16u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<16u, false> >(unsigned int, clang::interp::Integral<16u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<32u, true> >(unsigned int, clang::interp::Integral<32u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<32u, false> >(unsigned int, clang::interp::Integral<32u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<64u, true> >(unsigned int, clang::interp::Integral<64u, true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Integral<64u, false> >(unsigned int, clang::interp::Integral<64u, false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::IntegralAP<false> >(unsigned int, clang::interp::IntegralAP<false> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::IntegralAP<true> >(unsigned int, clang::interp::IntegralAP<true> const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Boolean>(unsigned int, clang::interp::Boolean const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Pointer>(unsigned int, clang::interp::Pointer const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::FunctionPointer>(unsigned int, clang::interp::FunctionPointer const&)
Unexecuted instantiation: void clang::interp::InterpFrame::setParam<clang::interp::Floating>(unsigned int, clang::interp::Floating const&)
98
99
  /// Returns a pointer to an argument - lazily creates a block.
100
  Pointer getParamPointer(unsigned Offset);
101
102
  /// Returns the 'this' pointer.
103
0
  const Pointer &getThis() const { return This; }
104
105
  /// Returns the RVO pointer, if the Function has one.
106
0
  const Pointer &getRVOPtr() const { return RVOPtr; }
107
108
  /// Checks if the frame is a root frame - return should quit the interpreter.
109
0
  bool isRoot() const { return !Func; }
110
111
  /// Returns the PC of the frame's code start.
112
0
  CodePtr getPC() const { return Func->getCodeBegin(); }
113
114
  /// Returns the return address of the frame.
115
0
  CodePtr getRetPC() const { return RetPC; }
116
117
  /// Map a location to a source.
118
  virtual SourceInfo getSource(CodePtr PC) const;
119
  const Expr *getExpr(CodePtr PC) const;
120
  SourceLocation getLocation(CodePtr PC) const;
121
  SourceRange getRange(CodePtr PC) const;
122
123
0
  unsigned getDepth() const { return Depth; }
124
125
private:
126
  /// Returns an original argument from the stack.
127
0
  template <typename T> const T &stackRef(unsigned Offset) const {
128
0
    assert(Args);
129
0
    return *reinterpret_cast<const T *>(Args - ArgSize + Offset);
130
0
  }
Unexecuted instantiation: clang::interp::Integral<8u, true> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<8u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<8u, false> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<8u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, true> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<16u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, false> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<16u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, true> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<32u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, false> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<32u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, true> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<64u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, false> const& clang::interp::InterpFrame::stackRef<clang::interp::Integral<64u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<false> const& clang::interp::InterpFrame::stackRef<clang::interp::IntegralAP<false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<true> const& clang::interp::InterpFrame::stackRef<clang::interp::IntegralAP<true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Boolean const& clang::interp::InterpFrame::stackRef<clang::interp::Boolean>(unsigned int) const
Unexecuted instantiation: clang::interp::Pointer const& clang::interp::InterpFrame::stackRef<clang::interp::Pointer>(unsigned int) const
Unexecuted instantiation: clang::interp::FunctionPointer const& clang::interp::InterpFrame::stackRef<clang::interp::FunctionPointer>(unsigned int) const
Unexecuted instantiation: clang::interp::Floating const& clang::interp::InterpFrame::stackRef<clang::interp::Floating>(unsigned int) const
131
132
  /// Returns an offset to a local.
133
0
  template <typename T> T &localRef(unsigned Offset) const {
134
0
    return getLocalPointer(Offset).deref<T>();
135
0
  }
Unexecuted instantiation: clang::interp::Integral<8u, true>& clang::interp::InterpFrame::localRef<clang::interp::Integral<8u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<8u, false>& clang::interp::InterpFrame::localRef<clang::interp::Integral<8u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, true>& clang::interp::InterpFrame::localRef<clang::interp::Integral<16u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<16u, false>& clang::interp::InterpFrame::localRef<clang::interp::Integral<16u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, true>& clang::interp::InterpFrame::localRef<clang::interp::Integral<32u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<32u, false>& clang::interp::InterpFrame::localRef<clang::interp::Integral<32u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, true>& clang::interp::InterpFrame::localRef<clang::interp::Integral<64u, true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Integral<64u, false>& clang::interp::InterpFrame::localRef<clang::interp::Integral<64u, false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<false>& clang::interp::InterpFrame::localRef<clang::interp::IntegralAP<false> >(unsigned int) const
Unexecuted instantiation: clang::interp::IntegralAP<true>& clang::interp::InterpFrame::localRef<clang::interp::IntegralAP<true> >(unsigned int) const
Unexecuted instantiation: clang::interp::Boolean& clang::interp::InterpFrame::localRef<clang::interp::Boolean>(unsigned int) const
Unexecuted instantiation: clang::interp::Pointer& clang::interp::InterpFrame::localRef<clang::interp::Pointer>(unsigned int) const
Unexecuted instantiation: clang::interp::FunctionPointer& clang::interp::InterpFrame::localRef<clang::interp::FunctionPointer>(unsigned int) const
Unexecuted instantiation: clang::interp::Floating& clang::interp::InterpFrame::localRef<clang::interp::Floating>(unsigned int) const
136
137
  /// Returns a pointer to a local's block.
138
0
  Block *localBlock(unsigned Offset) const {
139
0
    return reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block));
140
0
  }
141
142
  /// Returns the inline descriptor of the local.
143
0
  InlineDescriptor *localInlineDesc(unsigned Offset) const {
144
0
    return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset);
145
0
  }
146
147
private:
148
  /// Reference to the interpreter state.
149
  InterpState &S;
150
  /// Depth of this frame.
151
  unsigned Depth;
152
  /// Reference to the function being executed.
153
  const Function *Func;
154
  /// Current object pointer for methods.
155
  Pointer This;
156
  /// Pointer the non-primitive return value gets constructed in.
157
  Pointer RVOPtr;
158
  /// Return address.
159
  CodePtr RetPC;
160
  /// The size of all the arguments.
161
  const unsigned ArgSize;
162
  /// Pointer to the arguments in the callee's frame.
163
  char *Args = nullptr;
164
  /// Fixed, initial storage for known local variables.
165
  std::unique_ptr<char[]> Locals;
166
  /// Offset on the stack at entry.
167
  const size_t FrameOffset;
168
  /// Mapping from arg offsets to their argument blocks.
169
  llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params;
170
};
171
172
} // namespace interp
173
} // namespace clang
174
175
#endif