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 #include "runtime/include/cframe.h"
17 #include "compiler/code_info/code_info.h"
18 #include "runtime/include/runtime.h"
19 #include "runtime/include/stack_walker.h"
20 #include "utils/regmask.h"
21
22 namespace panda {
23
IsNativeMethod() const24 bool CFrame::IsNativeMethod() const
25 {
26 return GetMethod()->IsNative();
27 }
28
29 template <bool need_pack>
GetVRegValueInternal(const VRegInfo & vreg,const compiler::CodeInfo & code_info,SlotType ** callee_stack) const30 interpreter::VRegister CFrame::GetVRegValueInternal(const VRegInfo &vreg, const compiler::CodeInfo &code_info,
31 SlotType **callee_stack) const
32 {
33 switch (vreg.GetLocation()) {
34 case VRegInfo::Location::SLOT:
35 return GetVRegValueSlot<need_pack>(vreg);
36 case VRegInfo::Location::REGISTER:
37 case VRegInfo::Location::FP_REGISTER:
38 return GetVRegValueRegister<need_pack>(vreg, callee_stack);
39 case VRegInfo::Location::CONSTANT:
40 return GetVRegValueConstant<need_pack>(vreg, code_info);
41 default:
42 return interpreter::VRegister {};
43 }
44 }
45
46 template interpreter::VRegister CFrame::GetVRegValueInternal<true>(const VRegInfo &vreg,
47 const compiler::CodeInfo &code_info,
48 SlotType **callee_stack) const;
49 template interpreter::VRegister CFrame::GetVRegValueInternal<false>(const VRegInfo &vreg,
50 const compiler::CodeInfo &code_info,
51 SlotType **callee_stack) const;
52
53 template void CFrame::SetVRegValue<true>(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack);
54 template void CFrame::SetVRegValue<false>(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack);
55
GetPackValue(VRegInfo::Type type,uint64_t val) const56 uint64_t CFrame::GetPackValue(VRegInfo::Type type, uint64_t val) const
57 {
58 if (type == VRegInfo::Type::ANY) {
59 return val;
60 }
61 if (type == VRegInfo::Type::FLOAT64) {
62 return coretypes::TaggedValue::GetDoubleTaggedValue(val);
63 }
64 if (type == VRegInfo::Type::INT32) {
65 return coretypes::TaggedValue::GetIntTaggedValue(val);
66 }
67 if (type == VRegInfo::Type::BOOL) {
68 return coretypes::TaggedValue::GetBoolTaggedValue(val);
69 }
70 if (type == VRegInfo::Type::OBJECT) {
71 return coretypes::TaggedValue::GetObjectTaggedValue(val);
72 }
73 UNREACHABLE();
74 return val;
75 }
76
77 template <bool need_pack>
GetVRegValueSlot(const VRegInfo & vreg) const78 interpreter::VRegister CFrame::GetVRegValueSlot(const VRegInfo &vreg) const
79 {
80 interpreter::VRegister res_reg;
81 uint64_t val = GetValueFromSlot(vreg.GetValue());
82 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
83 if constexpr (!ArchTraits<ARCH>::IS_64_BITS) {
84 if (vreg.Has64BitValue()) {
85 ASSERT(!vreg.IsObject());
86 val |= static_cast<uint64_t>(GetValueFromSlot(helpers::ToSigned(vreg.GetValue()) - 1)) << BITS_PER_UINT32;
87 }
88 }
89 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
90 if constexpr (need_pack) {
91 val = GetPackValue(vreg.GetType(), val);
92 }
93 res_reg.Set(val);
94 return res_reg;
95 }
96
97 template <bool need_pack>
GetVRegValueRegister(const VRegInfo & vreg,SlotType ** callee_stack) const98 interpreter::VRegister CFrame::GetVRegValueRegister(const VRegInfo &vreg, SlotType **callee_stack) const
99 {
100 interpreter::VRegister res_reg;
101 bool is_fp = vreg.GetLocation() == VRegInfo::Location::FP_REGISTER;
102 if ((GetCallerRegsMask(ARCH, is_fp) & (1U << vreg.GetValue())).Any()) {
103 CFrameLayout fl(ARCH, 0);
104 RegMask mask(GetCallerRegsMask(RUNTIME_ARCH, is_fp));
105 auto reg_num = mask.GetDistanceFromTail(vreg.GetValue());
106 reg_num = fl.GetCallerLastSlot(is_fp) - reg_num;
107 uint64_t val = GetValueFromSlot(reg_num);
108 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-magic-numbers,readability-braces-around-statements)
109 if constexpr (!ArchTraits<ARCH>::IS_64_BITS) {
110 if (vreg.Has64BitValue()) {
111 ASSERT(!vreg.IsObject());
112 val |= static_cast<uint64_t>(GetValueFromSlot(static_cast<int>(reg_num) - 1)) << BITS_PER_UINT32;
113 }
114 }
115 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
116 if constexpr (need_pack) {
117 val = GetPackValue(vreg.GetType(), val);
118 }
119 res_reg.Set(val);
120 return res_reg;
121 }
122
123 uint64_t val = ReadCalleeSavedRegister(vreg.GetValue(), is_fp, callee_stack);
124 if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) {
125 val |= static_cast<uint64_t>(ReadCalleeSavedRegister(vreg.GetValue() + 1, is_fp, callee_stack))
126 << BITS_PER_UINT32;
127 }
128 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
129 if constexpr (need_pack) {
130 val = GetPackValue(vreg.GetType(), val);
131 }
132 if (is_fp) {
133 res_reg.Set(val);
134 if (vreg.Has64BitValue()) {
135 res_reg.Set(bit_cast<double>(val));
136 return res_reg;
137 }
138 res_reg.Set(bit_cast<float>(static_cast<uint32_t>(val)));
139 return res_reg;
140 }
141 res_reg.Set(val);
142 return res_reg;
143 }
144
145 template <bool need_pack>
GetVRegValueConstant(const VRegInfo & vreg,const compiler::CodeInfo & code_info) const146 interpreter::VRegister CFrame::GetVRegValueConstant(const VRegInfo &vreg, const compiler::CodeInfo &code_info) const
147 {
148 interpreter::VRegister res_reg;
149 auto val = code_info.GetConstant(vreg);
150 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
151 if constexpr (need_pack) {
152 val = GetPackValue(vreg.GetType(), val);
153 }
154 res_reg.Set(val);
155 return res_reg;
156 }
157
158 template <bool need_pack>
SetVRegValue(const VRegInfo & vreg,uint64_t value,SlotType ** callee_stack)159 void CFrame::SetVRegValue(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack)
160 {
161 auto location_value = static_cast<int>(vreg.GetValue());
162 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
163 if constexpr (need_pack) {
164 value = GetPackValue(vreg.GetType(), value);
165 }
166 switch (vreg.GetLocation()) {
167 case VRegInfo::Location::SLOT: {
168 SetValueToSlot(location_value, value);
169 if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) {
170 SetValueToSlot(location_value - 1, value >> BITS_PER_UINT32);
171 }
172 break;
173 }
174 case VRegInfo::Location::REGISTER:
175 case VRegInfo::Location::FP_REGISTER: {
176 bool is_fp = vreg.GetLocation() == VRegInfo::Location::FP_REGISTER;
177 if ((GetCallerRegsMask(ARCH, is_fp) & (1U << vreg.GetValue())).Any()) {
178 CFrameLayout fl(ARCH, 0);
179 auto reg_num = location_value - GetFirstCallerReg(ARCH, is_fp);
180 reg_num = fl.GetCallerLastSlot(is_fp) - reg_num;
181 SetValueToSlot(reg_num, value);
182 if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) {
183 SetValueToSlot(static_cast<int>(reg_num) - 1, value >> BITS_PER_UINT32);
184 }
185 break;
186 }
187 WriteCalleeSavedRegister(location_value, value, is_fp, callee_stack);
188 // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements)
189 if constexpr (!ArchTraits<ARCH>::IS_64_BITS) {
190 if (vreg.Has64BitValue()) {
191 WriteCalleeSavedRegister(location_value + 1, value >> BITS_PER_UINT32, is_fp, callee_stack);
192 }
193 break;
194 }
195 break;
196 }
197 case VRegInfo::Location::CONSTANT:
198 ASSERT(false && "Modifying constants is not permitted"); // NOLINT(misc-static-assert)
199 break;
200 default:
201 UNREACHABLE();
202 }
203 }
204
Dump(const CodeInfo & code_info,std::ostream & os)205 void CFrame::Dump(const CodeInfo &code_info, std::ostream &os)
206 {
207 auto max_slot = code_info.GetHeader().GetFrameSize();
208 Dump(os, max_slot);
209 }
210
Dump(std::ostream & os,uint32_t max_slot)211 void CFrame::Dump(std::ostream &os, uint32_t max_slot)
212 {
213 if (IsNative()) {
214 os << "NATIVE CFRAME: fp=" << fp_ << std::endl;
215 return;
216 }
217 auto spill_start_slot = GetCalleeRegsCount(ARCH, false) + GetCalleeRegsCount(ARCH, true) +
218 GetCallerRegsCount(ARCH, false) + GetCallerRegsCount(ARCH, true);
219 max_slot = (max_slot > spill_start_slot) ? (max_slot - spill_start_slot) : 0;
220
221 auto print_mem = [](std::ostream &stream, void *addr, std::string_view dscr, uintptr_t value) {
222 constexpr size_t WIDTH = 16;
223 stream << ' ' << addr << ": " << std::setw(WIDTH) << std::setfill(' ') << dscr << " 0x" << std::hex << value
224 << std::dec << std::endl;
225 };
226 os << "****************************************\n";
227 os << "* CFRAME: fp=" << fp_ << ", max_spill_slot=" << max_slot << '\n';
228 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
229 print_mem(os, fp_ - CFrameLayout::LrSlot::Start(), "lr", GetLr());
230 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
231 print_mem(os, fp_ - CFrameLayout::PrevFrameSlot::Start(), "prev", reinterpret_cast<uintptr_t>(GetPrevFrame()));
232 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
233 print_mem(os, fp_ - CFrameLayout::MethodSlot::Start(), "method", reinterpret_cast<uintptr_t>(GetMethod()));
234 PandaString dscr;
235 size_t slot = 0;
236 DumpCalleeRegs(os, print_mem, &dscr, &slot);
237 DumpCalleeFPRegs(os, print_mem, &dscr, &slot);
238 DumpCallerRegs(os, print_mem, &dscr, &slot);
239 DumpCallerFPRegs(os, print_mem, &dscr, &slot);
240 DumpLocals(os, print_mem, &dscr, &slot, max_slot);
241
242 os << "* CFRAME END\n";
243 os << "****************************************\n";
244 }
245
DumpCalleeRegs(std::ostream & os,MemPrinter print_mem,PandaString * dscr,size_t * slot)246 void CFrame::DumpCalleeRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot)
247 {
248 os << " [Callee saved registers]\n";
249 for (auto i = panda::helpers::ToSigned(GetLastCalleeReg(ARCH, false));
250 i >= panda::helpers::ToSigned(GetFirstCalleeReg(ARCH, false)); i--, (*slot)++) {
251 *dscr = "x" + ToPandaString(i) + ":" + ToPandaString(*slot);
252 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
253 print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot));
254 }
255 }
256
DumpCalleeFPRegs(std::ostream & os,MemPrinter print_mem,PandaString * dscr,size_t * slot)257 void CFrame::DumpCalleeFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot)
258 {
259 os << " [Callee saved FP registers]\n";
260 for (auto i = panda::helpers::ToSigned(GetLastCalleeReg(ARCH, true));
261 i >= panda::helpers::ToSigned(GetFirstCalleeReg(ARCH, true)); i--, (*slot)++) {
262 *dscr = "d" + ToPandaString(i) + ":" + ToPandaString(*slot);
263 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
264 print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot));
265 }
266 }
267
DumpCallerRegs(std::ostream & os,MemPrinter print_mem,PandaString * dscr,size_t * slot)268 void CFrame::DumpCallerRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot)
269 {
270 os << " [Caller saved registers] " << GetLastCallerReg(ARCH, false) << " " << GetFirstCallerReg(ARCH, false)
271 << "\n";
272 for (auto i = panda::helpers::ToSigned(GetLastCallerReg(ARCH, false));
273 i >= panda::helpers::ToSigned(GetFirstCallerReg(ARCH, false)); i--, (*slot)++) {
274 *dscr = "x" + ToPandaString(i) + ":" + ToPandaString(*slot);
275 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
276 print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot));
277 }
278 }
279
DumpCallerFPRegs(std::ostream & os,MemPrinter print_mem,PandaString * dscr,size_t * slot)280 void CFrame::DumpCallerFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot)
281 {
282 os << " [Caller saved FP registers]\n";
283 for (auto i = panda::helpers::ToSigned(GetLastCallerReg(ARCH, true));
284 i >= panda::helpers::ToSigned(GetFirstCallerReg(ARCH, true)); i--, (*slot)++) {
285 *dscr = "d" + ToPandaString(i) + ":" + ToPandaString(*slot);
286 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
287 print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot));
288 }
289 }
290
DumpLocals(std::ostream & os,MemPrinter print_mem,PandaString * dscr,size_t * slot,int32_t max_slot)291 void CFrame::DumpLocals(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot, int32_t max_slot)
292 {
293 os << " [Locals]\n";
294 for (auto i = 0; i <= max_slot; i++, (*slot)++) {
295 *dscr = "s" + ToPandaString(i) + ":" + ToPandaString(*slot);
296 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
297 print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot));
298 }
299 }
300
301 } // namespace panda
302