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