• 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 #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 panda {
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 cframe_layout(arch, 0);
41 
42         const ptrdiff_t IN_REGS_START_SLOT = cframe_layout.GetCallerRegsStartSlot() -
43                                              cframe_layout.GetStackStartSlot()
44                                              // skipped the slot to align the stack
45                                              + ((arch == Arch::X86_64) ? 1 : 0);
46         const ptrdiff_t IN_STACK_START_SLOT = cframe_layout.GetStackArgsStartSlot() - cframe_layout.GetStackStartSlot();
47 
48         ptrdiff_t fp_end_slot = IN_REGS_START_SLOT - 1;
49         ptrdiff_t fp_begin_slot = fp_end_slot + ARG_FP_REGS_COUNG;
50         ptrdiff_t gpr_end_slot = fp_begin_slot;
51         ptrdiff_t gpr_begin_slot = gpr_end_slot + ARG_GP_REGS_COUNG;
52         ptrdiff_t stack_begin_slot = IN_STACK_START_SLOT + 1;
53 
54         Method *method = cframe->GetMethod();
55         bool is_static = method->IsStatic();
56         if (!is_static) {
57             --gpr_begin_slot;  // skip Method*
58         }
59 
60         uint32_t num_args = method->GetNumArgs();
61         uint32_t vreg_num = num_args + (is_static ? 1 : 0);
62 
63         return Range<CFrameStaticNativeMethodIterator>(
64             CFrameStaticNativeMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, gpr_end_slot,
65                                              fp_begin_slot + 1, fp_end_slot, stack_begin_slot),
66             CFrameStaticNativeMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0));
67     }
68 
69     VRegInfo operator*()
70     {
71         return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_);
72     }
73 
74     auto operator++()
75     {
76         if (++vreg_index_ >= vreg_num_) {
77             return *this;
78         }
79 
80         // Update vreg_type_
81         vreg_type_ = ConvertType(*shorty_it_);
82         ++shorty_it_;
83 
84         // Update current_slot_
85         if (vreg_type_ == VRegInfo::Type::FLOAT32 || vreg_type_ == VRegInfo::Type::FLOAT64) {
86             if ((fp_current_slot_ - 1) > fp_end_slot_) {
87                 --fp_current_slot_;
88                 current_slot_ = fp_current_slot_;
89             } else {
90                 --stack_current_slot_;
91                 current_slot_ = stack_current_slot_;
92             }
93         } else {
94             if ((gpr_current_slot_ - 1) > gpr_end_slot_) {
95                 --gpr_current_slot_;
96                 current_slot_ = gpr_current_slot_;
97             } else {
98                 --stack_current_slot_;
99                 current_slot_ = stack_current_slot_;
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 vreg_index_ == it.vreg_index_;
116     }
117 
118     bool operator!=(const CFrameStaticNativeMethodIterator &it) const
119     {
120         return !(*this == it);
121     }
122 
123 private:
CFrameStaticNativeMethodIterator(uint32_t vreg_index,uint32_t vreg_num,const uint16_t * shorty,ptrdiff_t gpr_begin_slot,ptrdiff_t gpr_end_slot,ptrdiff_t fp_begin_slot,ptrdiff_t fp_end_slot,ptrdiff_t stack_current_slot)124     CFrameStaticNativeMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty,
125                                      ptrdiff_t gpr_begin_slot, ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot,
126                                      ptrdiff_t fp_end_slot, ptrdiff_t stack_current_slot)
127         : vreg_index_(vreg_index),
128           vreg_num_(vreg_num),
129           shorty_it_(shorty),
130           current_slot_(gpr_begin_slot),
131           gpr_current_slot_(gpr_begin_slot),
132           gpr_end_slot_(gpr_end_slot),
133           fp_current_slot_(fp_begin_slot),
134           fp_end_slot_(fp_end_slot),
135           stack_current_slot_(stack_current_slot)
136     {
137         ++shorty_it_;  // 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 vreg_index_;
171     uint32_t vreg_num_;
172     panda_file::ShortyIterator shorty_it_;
173     ptrdiff_t current_slot_;
174     ptrdiff_t gpr_current_slot_;
175     ptrdiff_t gpr_end_slot_;
176     ptrdiff_t fp_current_slot_;
177     ptrdiff_t fp_end_slot_;
178     ptrdiff_t stack_current_slot_;
179     VRegInfo::Type vreg_type_ = 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 gpr_begin_slot = GPR_BEGIN_SLOT;
202         Method *method = cframe->GetMethod();
203         bool is_static = method->IsStatic();
204         if (!is_static) {
205             --gpr_begin_slot;  // skip Method*
206         }
207 
208         uint32_t num_args = method->GetNumArgs();
209         uint32_t vreg_num = num_args + (is_static ? 1 : 0);
210 
211         return Range<CFrameStaticNativeMethodIterator>(
212             CFrameStaticNativeMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT,
213                                              FP_BEGIN_SLOT, FP_END_SLOT, STACK_BEGIN_SLOT),
214             CFrameStaticNativeMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0));
215     }
216 
217     VRegInfo operator*()
218     {
219         return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_);
220     }
221 
GetSlotsCountForType(VRegInfo::Type vreg_type)222     uint32_t GetSlotsCountForType(VRegInfo::Type vreg_type)
223     {
224         static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4);  // 4 bytes -- register size on AARCH32
225 
226         if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64) {
227             return 2;  // 2 slots
228         }
229         return 1;
230     }
231 
232     auto operator++()
233     {
234         if (++vreg_index_ >= vreg_num_) {
235             return *this;
236         }
237 
238         // Update type
239         vreg_type_ = ConvertType(*shorty_it_);
240         ++shorty_it_;
241 
242         // Update slots
243         auto inc = static_cast<ptrdiff_t>(GetSlotsCountForType(vreg_type_));
244         ASSERT(inc == 1 || inc == 2);  // 1 or 2 slots
245         if (inc == 1) {
246             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
247                 if (vreg_type_ == VRegInfo::Type::FLOAT32) {  // in this case one takes 1 slots
248                     return HandleHardFloat();
249                 }
250             }
251             if ((gpr_current_slot_ - 1) > gpr_end_slot_) {
252                 --gpr_current_slot_;
253                 current_slot_ = gpr_current_slot_;
254             } else {
255                 gpr_current_slot_ = gpr_end_slot_;
256 
257                 --stack_current_slot_;
258                 current_slot_ = stack_current_slot_;
259             }
260         } else {
261             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
262                 if (vreg_type_ == VRegInfo::Type::FLOAT64) {  // in this case one takes 2 slots
263                     return HandleHardDouble();
264                 }
265             }
266             gpr_current_slot_ = RoundUp(gpr_current_slot_ - 1, 2) - 1;  // 2
267             if (gpr_current_slot_ > gpr_end_slot_) {
268                 current_slot_ = gpr_current_slot_;
269                 gpr_current_slot_ -= 1;
270             } else {
271                 stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2) - 1;  // 2
272                 current_slot_ = stack_current_slot_;
273                 stack_current_slot_ -= 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 vreg_index_ == it.vreg_index_;
290     }
291 
292     bool operator!=(const CFrameStaticNativeMethodIterator &it) const
293     {
294         return !(*this == it);
295     }
296 
297 private:
CFrameStaticNativeMethodIterator(uint32_t vreg_index,uint32_t vreg_num,const uint16_t * shorty,ptrdiff_t gpr_begin_slot,ptrdiff_t gpr_end_slot,ptrdiff_t fp_begin_slot,ptrdiff_t fp_end_slot,ptrdiff_t stack_current_slot)298     CFrameStaticNativeMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty,
299                                      ptrdiff_t gpr_begin_slot, ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot,
300                                      ptrdiff_t fp_end_slot, ptrdiff_t stack_current_slot)
301         : vreg_index_(vreg_index),
302           vreg_num_(vreg_num),
303           shorty_it_(shorty),
304           current_slot_(gpr_begin_slot),
305           gpr_current_slot_(gpr_begin_slot),
306           gpr_end_slot_(gpr_end_slot),
307           fp_current_slot_(fp_begin_slot),
308           fp_end_slot_(fp_end_slot),
309           stack_current_slot_(stack_current_slot)
310     {
311         ++shorty_it_;  // 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(vreg_type_ == VRegInfo::Type::FLOAT32);
346         if (fp_current_slot_ > fp_end_slot_) {
347             current_slot_ = fp_current_slot_;
348             --fp_current_slot_;
349         } else {
350             --stack_current_slot_;
351             current_slot_ = stack_current_slot_;
352         }
353         return *this;
354     }
355 
HandleHardDouble()356     CFrameStaticNativeMethodIterator &HandleHardDouble()
357     {
358         ASSERT(vreg_type_ == VRegInfo::Type::FLOAT64);
359         fp_current_slot_ = static_cast<ptrdiff_t>(RoundDown(static_cast<uintptr_t>(fp_current_slot_) + 1, 2U) - 1);
360         if (fp_current_slot_ > fp_end_slot_) {
361             current_slot_ = fp_current_slot_;
362             fp_current_slot_ -= 2U;
363         } else {
364             stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2U) - 1;
365             current_slot_ = stack_current_slot_;
366             stack_current_slot_ -= 1;
367         }
368         return *this;
369     }
370 
371 private:
372     uint32_t vreg_index_;
373     uint32_t vreg_num_;
374     panda_file::ShortyIterator shorty_it_;
375     ptrdiff_t current_slot_;
376     ptrdiff_t gpr_current_slot_;
377     ptrdiff_t gpr_end_slot_;
378     ptrdiff_t fp_current_slot_;
379     ptrdiff_t fp_end_slot_;
380     ptrdiff_t stack_current_slot_;
381     VRegInfo::Type vreg_type_ = 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 arg_regs_count = arch::ExtArchTraits<arch>::NUM_GP_ARG_REGS;
393         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
394         Span<SlotType> callers(cframe->GetCallerSaveStack() - arg_regs_count, arg_regs_count);
395         // In dynamic methods the first two args are Method* method and uint32_t num_args
396         // Read num_args
397         auto num_args = static_cast<uint32_t>(callers[1]);
398         ++num_args;  // count function object
399         size_t num_arg_slots = num_args * sizeof(interpreter::VRegister) / sizeof(SlotType);
400 
401         CFrameLayout cframe_layout(arch, 0);
402         size_t caller_end_slot = cframe_layout.GetCallerRegsStartSlot();
403         size_t caller_start_slot = caller_end_slot + arg_regs_count;
404         size_t gpr_arg_start_slot = caller_start_slot - 2;  // skip Method and num_args, 2 - offset
405         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
406         if constexpr (arch != Arch::X86_64) {
407             gpr_arg_start_slot = RoundDown(gpr_arg_start_slot, sizeof(interpreter::VRegister) / sizeof(SlotType));
408         }
409         size_t num_gpr_arg_slots = std::min(gpr_arg_start_slot - caller_end_slot, num_arg_slots);
410 
411         size_t num_stack_arg_slots = num_arg_slots - num_gpr_arg_slots;
412         ptrdiff_t stack_arg_start_slot = cframe_layout.GetStackArgsStartSlot();
413         ptrdiff_t stack_arg_end_slot = stack_arg_start_slot - num_stack_arg_slots;
414 
415         // Since all stack slots are calculated relative STACK_START_SLOT
416         // subtract it from each value
417         ptrdiff_t stack_start_slot = cframe_layout.GetStackStartSlot();
418         gpr_arg_start_slot -= stack_start_slot;
419         caller_end_slot -= stack_start_slot;
420         stack_arg_start_slot -= stack_start_slot;
421         stack_arg_end_slot -= stack_start_slot;
422         return Range<CFrameDynamicNativeMethodIterator>(
423             CFrameDynamicNativeMethodIterator(cframe, gpr_arg_start_slot - 1, caller_end_slot - 1, stack_arg_start_slot,
424                                               stack_arg_end_slot),
425             CFrameDynamicNativeMethodIterator(cframe, caller_end_slot - 1, caller_end_slot - 1, stack_arg_end_slot,
426                                               stack_arg_end_slot));
427     }
428 
429     VRegInfo operator*()
430     {
431         if (gpr_start_slot_ > gpr_end_slot_) {
432             return VRegInfo(gpr_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_);
433         }
434         ASSERT(stack_start_slot_ > stack_end_slot_);
435         return VRegInfo(stack_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_);
436     }
437 
438     CFrameDynamicNativeMethodIterator &operator++()
439     {
440         size_t inc = sizeof(interpreter::VRegister) / sizeof(SlotType);
441         if (gpr_start_slot_ > gpr_end_slot_) {
442             gpr_start_slot_ -= inc;
443             ++vreg_num_;
444         } else if (stack_start_slot_ > stack_end_slot_) {
445             stack_start_slot_ -= inc;
446             ++vreg_num_;
447         }
448         return *this;
449     }
450 
451     // NOLINTNEXTLINE(cert-dcl21-cpp)
452     CFrameDynamicNativeMethodIterator operator++(int)
453     {
454         auto res = *this;
455         this->operator++();
456         return res;
457     }
458 
459     bool operator==(const CFrameDynamicNativeMethodIterator &it) const
460     {
461         return gpr_start_slot_ == it.gpr_start_slot_ && stack_start_slot_ == it.stack_start_slot_;
462     }
463 
464     bool operator!=(const CFrameDynamicNativeMethodIterator &it) const
465     {
466         return !(*this == it);
467     }
468 
469 private:
CFrameDynamicNativeMethodIterator(CFrame * cframe,ptrdiff_t gpr_start_slot,ptrdiff_t gpr_end_slot,ptrdiff_t stack_start_slot,ptrdiff_t stack_end_slot)470     CFrameDynamicNativeMethodIterator(CFrame *cframe, ptrdiff_t gpr_start_slot, ptrdiff_t gpr_end_slot,
471                                       ptrdiff_t stack_start_slot, ptrdiff_t stack_end_slot)
472         : cframe_(cframe),
473           gpr_start_slot_(gpr_start_slot),
474           gpr_end_slot_(gpr_end_slot),
475           stack_start_slot_(stack_start_slot),
476           stack_end_slot_(stack_end_slot)
477     {
478     }
479 
480 private:
481     CFrame *cframe_;
482     uint32_t vreg_num_ = 0;
483     ptrdiff_t gpr_start_slot_;
484     ptrdiff_t gpr_end_slot_;
485     ptrdiff_t stack_start_slot_;
486     ptrdiff_t stack_end_slot_;
487 };
488 
489 }  // namespace panda
490 
491 #endif  // PANDA_CFRAME_ITERATORS
492