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