• 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 #ifndef PANDA_CFRAME_ITERATORS_H
17 #define PANDA_CFRAME_ITERATORS_H
18 
19 #include "libpandabase/utils/arch.h"
20 #include "libpandabase/utils/range.h"
21 #include "libpandafile/shorty_iterator.h"
22 #include "runtime/arch/helpers.h"
23 #include "runtime/include/cframe.h"
24 #include "runtime/include/method.h"
25 #include "utils/bit_utils.h"
26 
27 namespace ark {
28 
29 template <Arch ARCH = RUNTIME_ARCH>
30 class CFrameStaticNativeMethodIterator {
31     using SlotType = typename CFrame::SlotType;
32     using VRegInfo = compiler::VRegInfo;
33 
34     static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<ARCH>::NUM_FP_ARG_REGS;
35     static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<ARCH>::NUM_GP_ARG_REGS;
36 
37 public:
MakeRange(CFrame * cframe)38     static auto MakeRange(CFrame *cframe)
39     {
40         CFrameLayout cframeLayout(ARCH, 0);
41 
42         const ptrdiff_t inRegsStartSlot = static_cast<int64_t>(cframeLayout.GetCallerRegsStartSlot()) -
43                                           cframeLayout.GetStackStartSlot()
44                                           // skipped the slot to align the stack
45                                           + ((ARCH == Arch::X86_64) ? 1 : 0);
46         const ptrdiff_t inStackStartSlot = cframeLayout.GetStackArgsStartSlot() - cframeLayout.GetStackStartSlot();
47 
48         ptrdiff_t fpEndSlot = inRegsStartSlot - 1;
49         ptrdiff_t fpBeginSlot = fpEndSlot + ARG_FP_REGS_COUNG;
50         ptrdiff_t gprEndSlot = fpBeginSlot;
51         ptrdiff_t gprBeginSlot = gprEndSlot + ARG_GP_REGS_COUNG;
52         ptrdiff_t stackBeginSlot = inStackStartSlot + 1;
53 
54         Method *method = cframe->GetMethod();
55         bool isStatic = method->IsStatic();
56         if (!isStatic) {
57             --gprBeginSlot;  // skip Method*
58         }
59 
60         uint32_t numArgs = method->GetNumArgs();
61         uint32_t vregNum = numArgs + (isStatic ? 1 : 0);
62 
63         return Range<CFrameStaticNativeMethodIterator>(
64             CFrameStaticNativeMethodIterator(0, vregNum, method->GetShorty(), gprBeginSlot, gprEndSlot, fpBeginSlot + 1,
65                                              fpEndSlot, stackBeginSlot),
66             CFrameStaticNativeMethodIterator(vregNum, vregNum, method->GetShorty(), 0, 0, 0, 0, 0));
67     }
68 
69     VRegInfo operator*()
70     {
71         return VRegInfo(currentSlot_, VRegInfo::Location::SLOT, vregType_, VRegInfo::VRegType::VREG, vregIndex_);
72     }
73 
74     auto operator++()
75     {
76         if (++vregIndex_ >= vregNum_) {
77             return *this;
78         }
79 
80         // Update vreg_type_
81         vregType_ = ConvertType(*shortyIt_);
82         ++shortyIt_;
83 
84         // Update current_slot_
85         if (vregType_ == VRegInfo::Type::FLOAT32 || vregType_ == VRegInfo::Type::FLOAT64) {
86             if ((fpCurrentSlot_ - 1) > fpEndSlot_) {
87                 --fpCurrentSlot_;
88                 currentSlot_ = fpCurrentSlot_;
89             } else {
90                 --stackCurrentSlot_;
91                 currentSlot_ = stackCurrentSlot_;
92             }
93         } else {
94             if ((gprCurrentSlot_ - 1) > gprEndSlot_) {
95                 --gprCurrentSlot_;
96                 currentSlot_ = gprCurrentSlot_;
97             } else {
98                 --stackCurrentSlot_;
99                 currentSlot_ = stackCurrentSlot_;
100             }
101         }
102 
103         return *this;
104     }
105 
106     auto operator++(int)  // NOLINT(cert-dcl21-cpp)
107     {
108         auto res = *this;
109         this->operator++();
110         return res;
111     }
112 
113     bool operator==(const CFrameStaticNativeMethodIterator &it) const
114     {
115         return vregIndex_ == it.vregIndex_;
116     }
117 
118     bool operator!=(const CFrameStaticNativeMethodIterator &it) const
119     {
120         return !(*this == it);
121     }
122 
123 private:
CFrameStaticNativeMethodIterator(uint32_t vregIndex,uint32_t vregNum,const uint16_t * shorty,ptrdiff_t gprBeginSlot,ptrdiff_t gprEndSlot,ptrdiff_t fpBeginSlot,ptrdiff_t fpEndSlot,ptrdiff_t stackCurrentSlot)124     CFrameStaticNativeMethodIterator(uint32_t vregIndex, uint32_t vregNum, const uint16_t *shorty,
125                                      ptrdiff_t gprBeginSlot, ptrdiff_t gprEndSlot, ptrdiff_t fpBeginSlot,
126                                      ptrdiff_t fpEndSlot, ptrdiff_t stackCurrentSlot)
127         : vregIndex_(vregIndex),
128           vregNum_(vregNum),
129           shortyIt_(shorty),
130           currentSlot_(gprBeginSlot),
131           gprCurrentSlot_(gprBeginSlot),
132           gprEndSlot_(gprEndSlot),
133           fpCurrentSlot_(fpBeginSlot),
134           fpEndSlot_(fpEndSlot),
135           stackCurrentSlot_(stackCurrentSlot)
136     {
137         ++shortyIt_;  // skip return value
138     }
139 
ConvertType(panda_file::Type type)140     VRegInfo::Type ConvertType(panda_file::Type type) const
141     {
142         switch (type.GetId()) {
143             case panda_file::Type::TypeId::U1:
144                 return VRegInfo::Type::BOOL;
145             case panda_file::Type::TypeId::I8:
146             case panda_file::Type::TypeId::U8:
147             case panda_file::Type::TypeId::I16:
148             case panda_file::Type::TypeId::U16:
149             case panda_file::Type::TypeId::I32:
150             case panda_file::Type::TypeId::U32:
151                 return VRegInfo::Type::INT32;
152             case panda_file::Type::TypeId::F32:
153                 return VRegInfo::Type::FLOAT32;
154             case panda_file::Type::TypeId::F64:
155                 return VRegInfo::Type::FLOAT64;
156             case panda_file::Type::TypeId::I64:
157             case panda_file::Type::TypeId::U64:
158                 return VRegInfo::Type::INT64;
159             case panda_file::Type::TypeId::REFERENCE:
160                 return VRegInfo::Type::OBJECT;
161             case panda_file::Type::TypeId::TAGGED:
162                 return VRegInfo::Type::INT64;
163             default:
164                 UNREACHABLE();
165         }
166         return VRegInfo::Type::INT32;
167     }
168 
169 private:
170     uint32_t vregIndex_;
171     uint32_t vregNum_;
172     panda_file::ShortyIterator shortyIt_;
173     ptrdiff_t currentSlot_;
174     ptrdiff_t gprCurrentSlot_;
175     ptrdiff_t gprEndSlot_;
176     ptrdiff_t fpCurrentSlot_;
177     ptrdiff_t fpEndSlot_;
178     ptrdiff_t stackCurrentSlot_;
179     VRegInfo::Type vregType_ = VRegInfo::Type::OBJECT;
180 };
181 
182 template <>
183 class CFrameStaticNativeMethodIterator<Arch::AARCH32> {
184     using SlotType = typename CFrame::SlotType;
185     using VRegInfo = compiler::VRegInfo;
186 
187     static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_FP_ARG_REGS;
188     static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_GP_ARG_REGS;
189 
190     static constexpr ptrdiff_t IN_REGS_START_SLOT = 24;
191     static constexpr ptrdiff_t IN_STACK_START_SLOT = -11;
192     static constexpr ptrdiff_t FP_END_SLOT = IN_REGS_START_SLOT - 1;
193     static constexpr ptrdiff_t FP_BEGIN_SLOT = FP_END_SLOT + ARG_FP_REGS_COUNG;
194     static constexpr ptrdiff_t GPR_END_SLOT = FP_BEGIN_SLOT;
195     static constexpr ptrdiff_t GPR_BEGIN_SLOT = GPR_END_SLOT + ARG_GP_REGS_COUNG;
196     static constexpr ptrdiff_t STACK_BEGIN_SLOT = IN_STACK_START_SLOT + 1;
197 
198 public:
MakeRange(CFrame * cframe)199     static auto MakeRange(CFrame *cframe)
200     {
201         ptrdiff_t gprBeginSlot = GPR_BEGIN_SLOT;
202         Method *method = cframe->GetMethod();
203         bool isStatic = method->IsStatic();
204         if (!isStatic) {
205             --gprBeginSlot;  // skip Method*
206         }
207 
208         uint32_t numArgs = method->GetNumArgs();
209         uint32_t vregNum = numArgs + (isStatic ? 1 : 0);
210 
211         return Range<CFrameStaticNativeMethodIterator>(
212             CFrameStaticNativeMethodIterator(0, vregNum, method->GetShorty(), gprBeginSlot, GPR_END_SLOT, FP_BEGIN_SLOT,
213                                              FP_END_SLOT, STACK_BEGIN_SLOT),
214             CFrameStaticNativeMethodIterator(vregNum, vregNum, method->GetShorty(), 0, 0, 0, 0, 0));
215     }
216 
217     VRegInfo operator*()
218     {
219         return VRegInfo(currentSlot_, VRegInfo::Location::SLOT, vregType_, VRegInfo::VRegType::VREG, vregIndex_);
220     }
221 
GetSlotsCountForType(VRegInfo::Type vregType)222     uint32_t GetSlotsCountForType(VRegInfo::Type vregType)
223     {
224         static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4);  // 4 bytes -- register size on AARCH32
225 
226         if (vregType == VRegInfo::Type::INT64 || vregType == VRegInfo::Type::FLOAT64) {
227             return 2;  // 2 slots
228         }
229         return 1;
230     }
231 
232     auto operator++()
233     {
234         if (++vregIndex_ >= vregNum_) {
235             return *this;
236         }
237 
238         // Update type
239         vregType_ = ConvertType(*shortyIt_);
240         ++shortyIt_;
241 
242         // Update slots
243         auto inc = static_cast<ptrdiff_t>(GetSlotsCountForType(vregType_));
244         ASSERT(inc == 1 || inc == 2);  // 1 or 2 slots
245         if (inc == 1) {
246             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
247                 if (vregType_ == VRegInfo::Type::FLOAT32) {  // in this case one takes 1 slots
248                     return HandleHardFloat();
249                 }
250             }
251             if ((gprCurrentSlot_ - 1) > gprEndSlot_) {
252                 --gprCurrentSlot_;
253                 currentSlot_ = gprCurrentSlot_;
254             } else {
255                 gprCurrentSlot_ = gprEndSlot_;
256 
257                 --stackCurrentSlot_;
258                 currentSlot_ = stackCurrentSlot_;
259             }
260         } else {
261             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
262                 if (vregType_ == VRegInfo::Type::FLOAT64) {  // in this case one takes 2 slots
263                     return HandleHardDouble();
264                 }
265             }
266             gprCurrentSlot_ = RoundUp(gprCurrentSlot_ - 1, 2) - 1;  // 2
267             if (gprCurrentSlot_ > gprEndSlot_) {
268                 currentSlot_ = gprCurrentSlot_;
269                 gprCurrentSlot_ -= 1;
270             } else {
271                 stackCurrentSlot_ = RoundUp(stackCurrentSlot_ - 1, 2) - 1;  // 2
272                 currentSlot_ = stackCurrentSlot_;
273                 stackCurrentSlot_ -= 1;
274             }
275         }
276 
277         return *this;
278     }
279 
280     auto operator++(int)  // NOLINT(cert-dcl21-cpp)
281     {
282         auto res = *this;
283         this->operator++();
284         return res;
285     }
286 
287     bool operator==(const CFrameStaticNativeMethodIterator &it) const
288     {
289         return vregIndex_ == it.vregIndex_;
290     }
291 
292     bool operator!=(const CFrameStaticNativeMethodIterator &it) const
293     {
294         return !(*this == it);
295     }
296 
297 private:
CFrameStaticNativeMethodIterator(uint32_t vregIndex,uint32_t vregNum,const uint16_t * shorty,ptrdiff_t gprBeginSlot,ptrdiff_t gprEndSlot,ptrdiff_t fpBeginSlot,ptrdiff_t fpEndSlot,ptrdiff_t stackCurrentSlot)298     CFrameStaticNativeMethodIterator(uint32_t vregIndex, uint32_t vregNum, const uint16_t *shorty,
299                                      ptrdiff_t gprBeginSlot, ptrdiff_t gprEndSlot, ptrdiff_t fpBeginSlot,
300                                      ptrdiff_t fpEndSlot, ptrdiff_t stackCurrentSlot)
301         : vregIndex_(vregIndex),
302           vregNum_(vregNum),
303           shortyIt_(shorty),
304           currentSlot_(gprBeginSlot),
305           gprCurrentSlot_(gprBeginSlot),
306           gprEndSlot_(gprEndSlot),
307           fpCurrentSlot_(fpBeginSlot),
308           fpEndSlot_(fpEndSlot),
309           stackCurrentSlot_(stackCurrentSlot)
310     {
311         ++shortyIt_;  // skip return value
312     }
313 
ConvertType(panda_file::Type type)314     VRegInfo::Type ConvertType(panda_file::Type type) const
315     {
316         switch (type.GetId()) {
317             case panda_file::Type::TypeId::U1:
318                 return VRegInfo::Type::BOOL;
319             case panda_file::Type::TypeId::I8:
320             case panda_file::Type::TypeId::U8:
321             case panda_file::Type::TypeId::I16:
322             case panda_file::Type::TypeId::U16:
323             case panda_file::Type::TypeId::I32:
324             case panda_file::Type::TypeId::U32:
325                 return VRegInfo::Type::INT32;
326             case panda_file::Type::TypeId::F32:
327                 return VRegInfo::Type::FLOAT32;
328             case panda_file::Type::TypeId::F64:
329                 return VRegInfo::Type::FLOAT64;
330             case panda_file::Type::TypeId::I64:
331             case panda_file::Type::TypeId::U64:
332                 return VRegInfo::Type::INT64;
333             case panda_file::Type::TypeId::REFERENCE:
334                 return VRegInfo::Type::OBJECT;
335             case panda_file::Type::TypeId::TAGGED:
336                 return VRegInfo::Type::INT64;
337             default:
338                 UNREACHABLE();
339         }
340         return VRegInfo::Type::INT32;
341     }
342 
HandleHardFloat()343     CFrameStaticNativeMethodIterator &HandleHardFloat()
344     {
345         ASSERT(vregType_ == VRegInfo::Type::FLOAT32);
346         if (fpCurrentSlot_ > fpEndSlot_) {
347             currentSlot_ = fpCurrentSlot_;
348             --fpCurrentSlot_;
349         } else {
350             --stackCurrentSlot_;
351             currentSlot_ = stackCurrentSlot_;
352         }
353         return *this;
354     }
355 
HandleHardDouble()356     CFrameStaticNativeMethodIterator &HandleHardDouble()
357     {
358         ASSERT(vregType_ == VRegInfo::Type::FLOAT64);
359         fpCurrentSlot_ = static_cast<ptrdiff_t>(RoundDown(static_cast<uintptr_t>(fpCurrentSlot_) + 1, 2U) - 1);
360         if (fpCurrentSlot_ > fpEndSlot_) {
361             currentSlot_ = fpCurrentSlot_;
362             fpCurrentSlot_ -= 2U;
363         } else {
364             stackCurrentSlot_ = RoundUp(stackCurrentSlot_ - 1, 2U) - 1;
365             currentSlot_ = stackCurrentSlot_;
366             stackCurrentSlot_ -= 1;
367         }
368         return *this;
369     }
370 
371 private:
372     uint32_t vregIndex_;
373     uint32_t vregNum_;
374     panda_file::ShortyIterator shortyIt_;
375     ptrdiff_t currentSlot_;
376     ptrdiff_t gprCurrentSlot_;
377     ptrdiff_t gprEndSlot_;
378     ptrdiff_t fpCurrentSlot_;
379     ptrdiff_t fpEndSlot_;
380     ptrdiff_t stackCurrentSlot_;
381     VRegInfo::Type vregType_ = VRegInfo::Type::OBJECT;
382 };
383 
384 template <Arch ARCH = RUNTIME_ARCH>
385 class CFrameDynamicNativeMethodIterator {
386     using SlotType = typename CFrame::SlotType;
387     using VRegInfo = compiler::VRegInfo;
388 
389 public:
MakeRange(CFrame * cframe)390     static auto MakeRange(CFrame *cframe)
391     {
392         size_t constexpr GPR_ARGS_MAX = arch::ExtArchTraits<ARCH>::NUM_GP_ARG_REGS;
393         size_t constexpr GPR_ARGS_INTERNAL = 2U;  // Depends on dyn callconv
394         size_t constexpr GPR_FN_ARGS_NUM = 0U;    // Depends on dyn callconv
395         CFrameLayout cframeLayout(ARCH, 0);
396 
397         ptrdiff_t const gprEndSlot =
398             static_cast<int64_t>(cframeLayout.GetCallerRegsStartSlot()) - 1 - cframeLayout.GetStackStartSlot();
399         ptrdiff_t const gprStartSlot = gprEndSlot + GPR_ARGS_MAX;
400 
401         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
402         Span<SlotType const> gprSlots(cframe->GetValuePtrFromSlot(gprStartSlot), GPR_ARGS_MAX);
403 
404         auto const actualArgsNum = static_cast<uint32_t>(gprSlots[1]);
405         auto const stackArgsNum = actualArgsNum - GPR_FN_ARGS_NUM;
406 
407         ptrdiff_t const gprTaggedEndSlot = gprEndSlot + GPR_ARGS_INTERNAL;
408         ptrdiff_t const gprTaggedStartSlot = gprTaggedEndSlot + GPR_FN_ARGS_NUM;
409 
410         ptrdiff_t const stackStartSlot = cframeLayout.GetStackArgsStartSlot() - cframeLayout.GetStackStartSlot();
411         ptrdiff_t const stackEndSlot = stackStartSlot - stackArgsNum;
412 
413         return Range<CFrameDynamicNativeMethodIterator>(
414             CFrameDynamicNativeMethodIterator(cframe, gprTaggedStartSlot, gprTaggedEndSlot, stackStartSlot,
415                                               stackEndSlot),
416             CFrameDynamicNativeMethodIterator(cframe, gprTaggedEndSlot, gprTaggedEndSlot, stackEndSlot, stackEndSlot));
417     }
418 
419     VRegInfo operator*()
420     {
421         if (gprStartSlot_ > gprEndSlot_) {
422             return VRegInfo(gprStartSlot_, VRegInfo::Location::SLOT, VRegInfo::Type::ANY, VRegInfo::VRegType::VREG,
423                             vregNum_);
424         }
425         ASSERT(stackStartSlot_ > stackEndSlot_);
426         return VRegInfo(stackStartSlot_, VRegInfo::Location::SLOT, VRegInfo::Type::ANY, VRegInfo::VRegType::VREG,
427                         vregNum_);
428     }
429 
430     CFrameDynamicNativeMethodIterator &operator++()
431     {
432         auto inc = static_cast<int64_t>(sizeof(interpreter::VRegister) / sizeof(SlotType));
433         if (gprStartSlot_ > gprEndSlot_) {
434             gprStartSlot_ -= inc;
435             ++vregNum_;
436         } else if (stackStartSlot_ > stackEndSlot_) {
437             stackStartSlot_ -= inc;
438             ++vregNum_;
439         }
440         return *this;
441     }
442 
443     // NOLINTNEXTLINE(cert-dcl21-cpp)
444     CFrameDynamicNativeMethodIterator operator++(int)
445     {
446         auto res = *this;
447         this->operator++();
448         return res;
449     }
450 
451     bool operator==(const CFrameDynamicNativeMethodIterator &it) const
452     {
453         return gprStartSlot_ == it.gprStartSlot_ && stackStartSlot_ == it.stackStartSlot_;
454     }
455 
456     bool operator!=(const CFrameDynamicNativeMethodIterator &it) const
457     {
458         return !(*this == it);
459     }
460 
461 private:
CFrameDynamicNativeMethodIterator(CFrame * cframe,ptrdiff_t gprStartSlot,ptrdiff_t gprEndSlot,ptrdiff_t stackStartSlot,ptrdiff_t stackEndSlot)462     CFrameDynamicNativeMethodIterator(CFrame *cframe, ptrdiff_t gprStartSlot, ptrdiff_t gprEndSlot,
463                                       ptrdiff_t stackStartSlot, ptrdiff_t stackEndSlot)
464         : cframe_(cframe),
465           gprStartSlot_(gprStartSlot),
466           gprEndSlot_(gprEndSlot),
467           stackStartSlot_(stackStartSlot),
468           stackEndSlot_(stackEndSlot)
469     {
470     }
471 
472 private:
473     CFrame *cframe_;
474     uint32_t vregNum_ = 0;
475     ptrdiff_t gprStartSlot_;
476     ptrdiff_t gprEndSlot_;
477     ptrdiff_t stackStartSlot_;
478     ptrdiff_t stackEndSlot_;
479 };
480 
481 }  // namespace ark
482 
483 #endif  // PANDA_CFRAME_ITERATORS
484