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