1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PANDA_RUNTIME_STACK_WALKER_INL_H
17 #define PANDA_RUNTIME_STACK_WALKER_INL_H
18
19 #include "stack_walker.h"
20 #include "runtime/include/cframe_iterators.h"
21 #include "compiler/code_info/code_info.h"
22
23 namespace panda {
24
25 template <bool objects, bool with_reg_info, class VRegRef, typename Func>
26 // NOLINTNEXTLINE(google-runtime-references)
InvokeCallback(Func func,compiler::VRegInfo reg_info,VRegRef & vreg)27 bool InvokeCallback(Func func, [[maybe_unused]] compiler::VRegInfo reg_info, VRegRef &vreg)
28 {
29 if (objects && !vreg.HasObject()) {
30 return true;
31 }
32 if constexpr (with_reg_info) { // NOLINT
33 if (!func(reg_info, vreg)) {
34 return false;
35 }
36 } else { // NOLINT
37 if (!func(vreg)) {
38 return false;
39 }
40 }
41 return true;
42 }
43
44 template <bool with_reg_info, typename Func>
IterateAllRegsForCFrame(Func func)45 bool StackWalker::IterateAllRegsForCFrame(Func func)
46 {
47 auto &cframe = GetCFrame();
48 const auto regs =
49 code_info_.GetVRegList(stackmap_, inline_depth_, mem::InternalAllocator<>::GetInternalAllocatorFromRuntime());
50
51 for (auto ®_info : regs) {
52 if (!reg_info.IsLive()) {
53 continue;
54 }
55 interpreter::VRegister vreg0;
56 interpreter::VRegister vreg1;
57 interpreter::StaticVRegisterRef res_reg(&vreg0, &vreg1);
58 cframe.GetVRegValue(reg_info, code_info_, callee_stack_.stack.data(), res_reg);
59 if (!InvokeCallback<false, with_reg_info>(func, reg_info, res_reg)) {
60 return false;
61 }
62 }
63
64 return true;
65 }
66
67 template <bool objects, bool with_reg_info, typename Func>
IterateRegsForCFrameStatic(Func func)68 bool StackWalker::IterateRegsForCFrameStatic(Func func)
69 {
70 ASSERT(IsCFrame());
71 ASSERT(!IsDynamicMethod());
72 auto &cframe = GetCFrame();
73
74 if (cframe.IsNativeMethod()) {
75 for (auto reg_info : CFrameStaticNativeMethodIterator<RUNTIME_ARCH>::MakeRange(&cframe)) {
76 interpreter::VRegister vreg0;
77 interpreter::VRegister vreg1;
78 interpreter::StaticVRegisterRef res_reg(&vreg0, &vreg1);
79 cframe.GetVRegValue(reg_info, code_info_, callee_stack_.stack.data(), res_reg);
80 if (!InvokeCallback<objects, with_reg_info>(func, reg_info, res_reg)) {
81 return false;
82 }
83 }
84 return true;
85 }
86
87 if (objects) {
88 code_info_.EnumerateStaticRoots(stackmap_, [this, &cframe, &func](VRegInfo reg_info) {
89 interpreter::VRegister vreg0;
90 interpreter::VRegister vreg1;
91 interpreter::StaticVRegisterRef res_reg(&vreg0, &vreg1);
92 cframe.GetVRegValue(reg_info, code_info_, callee_stack_.stack.data(), res_reg);
93 return !res_reg.HasObject() || InvokeCallback<objects, with_reg_info>(func, reg_info, res_reg);
94 });
95 return true;
96 }
97
98 return IterateAllRegsForCFrame<with_reg_info>(func);
99 }
100
101 template <bool objects, bool with_reg_info, typename Func>
IterateRegsForCFrameDynamic(Func func)102 bool StackWalker::IterateRegsForCFrameDynamic(Func func)
103 {
104 ASSERT(IsCFrame());
105 ASSERT(IsDynamicMethod());
106 auto &cframe = GetCFrame();
107
108 if (cframe.IsNativeMethod()) {
109 for (auto reg_info : CFrameDynamicNativeMethodIterator<RUNTIME_ARCH>::MakeRange(&cframe)) {
110 interpreter::VRegister vreg0;
111 interpreter::DynamicVRegisterRef res_reg(&vreg0);
112 cframe.GetVRegValue(reg_info, code_info_, callee_stack_.stack.data(), res_reg);
113 if (!InvokeCallback<objects, with_reg_info>(func, reg_info, res_reg)) {
114 return false;
115 }
116 }
117 return true;
118 }
119
120 if (objects) {
121 code_info_.EnumerateDynamicRoots(stackmap_, [this, &cframe, &func](VRegInfo reg_info) {
122 interpreter::VRegister vreg0;
123 interpreter::DynamicVRegisterRef res_reg(&vreg0);
124 cframe.GetVRegValue(reg_info, code_info_, callee_stack_.stack.data(), res_reg);
125 return !res_reg.HasObject() || InvokeCallback<objects, with_reg_info>(func, reg_info, res_reg);
126 });
127 return true;
128 }
129
130 return IterateAllRegsForCFrame<with_reg_info>(func);
131 }
132
133 template <bool objects, bool with_reg_info, StackWalker::VRegInfo::Type obj_type,
134 StackWalker::VRegInfo::Type primitive_type, class F, typename Func>
IterateRegsForIFrameInternal(F frame_handler,Func func)135 bool StackWalker::IterateRegsForIFrameInternal(F frame_handler, Func func)
136 {
137 for (size_t i = 0; i < frame_handler.GetSize(); i++) {
138 auto vreg = frame_handler.GetVReg(i);
139 if (objects && !vreg.HasObject()) {
140 continue;
141 }
142 auto type = vreg.HasObject() ? obj_type : primitive_type;
143 VRegInfo reg_info(0, VRegInfo::Location::SLOT, type, false, i);
144 if (!InvokeCallback<objects, with_reg_info>(func, reg_info, vreg)) {
145 return false;
146 }
147 }
148
149 auto acc = frame_handler.GetAccAsVReg();
150 auto type = acc.HasObject() ? obj_type : primitive_type;
151 VRegInfo reg_info(0, VRegInfo::Location::SLOT, type, true, 0);
152 return InvokeCallback<objects, with_reg_info>(func, reg_info, acc);
153 }
154
155 template <bool objects, bool with_reg_info, typename Func>
IterateRegsForIFrame(Func func)156 bool StackWalker::IterateRegsForIFrame(Func func)
157 {
158 auto frame = GetIFrame();
159 if (frame->IsDynamic()) {
160 DynamicFrameHandler frame_handler(frame);
161 return IterateRegsForIFrameInternal<objects, with_reg_info, VRegInfo::Type::ANY, VRegInfo::Type::ANY>(
162 frame_handler, func);
163 }
164 StaticFrameHandler frame_handler(frame);
165 return IterateRegsForIFrameInternal<objects, with_reg_info, VRegInfo::Type::OBJECT, VRegInfo::Type::INT64>(
166 frame_handler, func);
167 }
168
169 template <bool objects, bool with_reg_info, typename Func>
IterateRegs(Func func)170 bool StackWalker::IterateRegs(Func func)
171 {
172 if (IsCFrame()) {
173 if (IsDynamicMethod()) {
174 return IterateRegsForCFrameDynamic<objects, with_reg_info>(func);
175 }
176 return IterateRegsForCFrameStatic<objects, with_reg_info>(func);
177 }
178 return IterateRegsForIFrame<objects, with_reg_info>(func);
179 }
180
181 } // namespace panda
182
183 #endif // PANDA_RUNTIME_STACK_WALKER_INL_H
184