• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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