• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_RUNTIME_INCLUDE_CFRAME_ITERATORS_H_
17 #define PANDA_RUNTIME_INCLUDE_CFRAME_ITERATORS_H_
18 
19 #include "libpandabase/utils/arch.h"
20 #include "libpandafile/shorty_iterator.h"
21 #include "runtime/arch/helpers.h"
22 #include "runtime/include/cframe.h"
23 #include "runtime/include/method.h"
24 #include "libpandafile/shorty_iterator.h"
25 #include "utils/bit_utils.h"
26 
27 namespace panda {
28 
29 template <typename It>
30 class Range {
31 public:
Range(It begin,It end)32     Range(It begin, It end) : begin_(begin), end_(end) {}
33 
begin()34     It begin()  // NOLINT(readability-identifier-naming)
35     {
36         return begin_;
37     }
38 
end()39     It end()  // NOLINT(readability-identifier-naming)
40     {
41         return end_;
42     }
43 
44 private:
45     It begin_;
46     It end_;
47 };
48 
49 template <Arch arch = RUNTIME_ARCH>
50 class CFrameJniMethodIterator {
51     using SlotType = typename CFrame::SlotType;
52 
53     static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<arch>::NUM_FP_ARG_REGS;
54     static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<arch>::NUM_GP_ARG_REGS;
55 
56 public:
MakeRange(CFrame * cframe)57     static auto MakeRange(CFrame *cframe)
58     {
59         CFrameLayout cframe_layout(arch, 0);
60 
61         const ptrdiff_t IN_REGS_START_SLOT =
62             cframe_layout.GetCallerRegsStartSlot() -
63             cframe_layout.GetStackStartSlot()
64             // skipped the slot to align the stack, CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK)
65             + (arch == Arch::X86_64 ? 1 : 0);
66         const ptrdiff_t IN_STACK_START_SLOT = cframe_layout.GetStackArgsStartSlot() - cframe_layout.GetStackStartSlot();
67 
68         ptrdiff_t fp_end_slot = IN_REGS_START_SLOT - 1;
69         ptrdiff_t fp_begin_slot = fp_end_slot + ARG_FP_REGS_COUNG;
70         ptrdiff_t gpr_end_slot = fp_begin_slot;
71         ptrdiff_t gpr_begin_slot = gpr_end_slot + ARG_GP_REGS_COUNG;
72         ptrdiff_t stack_begin_slot = IN_STACK_START_SLOT + 1;
73 
74         Method *method = cframe->GetMethod();
75         bool is_static = method->IsStatic();
76         if (!is_static) {
77             --gpr_begin_slot;  // skip Method*
78         }
79 
80         uint32_t num_args = method->GetNumArgs();
81         uint32_t vreg_num = num_args + (is_static ? 1 : 0);
82 
83         return Range<CFrameJniMethodIterator>(
84             CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, gpr_end_slot, fp_begin_slot + 1,
85                                     fp_end_slot, stack_begin_slot),
86             CFrameJniMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0));
87     }
88 
89     VRegInfo operator*()
90     {
91         return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_);
92     }
93 
94     auto operator++()
95     {
96         if (++vreg_index_ >= vreg_num_) {
97             return *this;
98         }
99 
100         // Update vreg_type_
101         vreg_type_ = ConvertType(*shorty_it_);
102         ++shorty_it_;
103 
104         // Update current_slot_
105         if (vreg_type_ == VRegInfo::Type::FLOAT32 || vreg_type_ == VRegInfo::Type::FLOAT64) {
106             if ((fp_current_slot_ - 1) > fp_end_slot_) {
107                 --fp_current_slot_;
108                 current_slot_ = fp_current_slot_;
109             } else {
110                 --stack_current_slot_;
111                 current_slot_ = stack_current_slot_;
112             }
113         } else {
114             if ((gpr_current_slot_ - 1) > gpr_end_slot_) {
115                 --gpr_current_slot_;
116                 current_slot_ = gpr_current_slot_;
117             } else {
118                 --stack_current_slot_;
119                 current_slot_ = stack_current_slot_;
120             }
121         }
122 
123         return *this;
124     }
125 
126     auto operator++(int)  // NOLINT(cert-dcl21-cpp)
127     {
128         auto res = *this;
129         this->operator++();
130         return res;
131     }
132 
133     bool operator==(const CFrameJniMethodIterator &it) const
134     {
135         return vreg_index_ == it.vreg_index_;
136     }
137 
138     bool operator!=(const CFrameJniMethodIterator &it) const
139     {
140         return !(*this == it);
141     }
142 
143 private:
CFrameJniMethodIterator(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)144     CFrameJniMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty, ptrdiff_t gpr_begin_slot,
145                             ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot, ptrdiff_t fp_end_slot,
146                             ptrdiff_t stack_current_slot)
147         : vreg_index_(vreg_index),
148           vreg_num_(vreg_num),
149           shorty_it_(shorty),
150           current_slot_(gpr_begin_slot),
151           gpr_current_slot_(gpr_begin_slot),
152           gpr_end_slot_(gpr_end_slot),
153           fp_current_slot_(fp_begin_slot),
154           fp_end_slot_(fp_end_slot),
155           stack_current_slot_(stack_current_slot)
156     {
157         ++shorty_it_;  // skip return value
158     }
159 
ConvertType(panda_file::Type type)160     VRegInfo::Type ConvertType(panda_file::Type type) const
161     {
162         switch (type.GetId()) {
163             case panda_file::Type::TypeId::U1:
164                 return VRegInfo::Type::BOOL;
165             case panda_file::Type::TypeId::I8:
166             case panda_file::Type::TypeId::U8:
167             case panda_file::Type::TypeId::I16:
168             case panda_file::Type::TypeId::U16:
169             case panda_file::Type::TypeId::I32:
170             case panda_file::Type::TypeId::U32:
171                 return VRegInfo::Type::INT32;
172             case panda_file::Type::TypeId::F32:
173                 return VRegInfo::Type::FLOAT32;
174             case panda_file::Type::TypeId::F64:
175                 return VRegInfo::Type::FLOAT64;
176             case panda_file::Type::TypeId::I64:
177             case panda_file::Type::TypeId::U64:
178                 return VRegInfo::Type::INT64;
179             case panda_file::Type::TypeId::REFERENCE:
180                 return VRegInfo::Type::OBJECT;
181             case panda_file::Type::TypeId::TAGGED:
182                 return VRegInfo::Type::INT64;
183             default:
184                 UNREACHABLE();
185         }
186         return VRegInfo::Type::INT32;
187     }
188 
189 private:
190     uint32_t vreg_index_;
191     uint32_t vreg_num_;
192     panda_file::ShortyIterator shorty_it_;
193     ptrdiff_t current_slot_;
194     ptrdiff_t gpr_current_slot_;
195     ptrdiff_t gpr_end_slot_;
196     ptrdiff_t fp_current_slot_;
197     ptrdiff_t fp_end_slot_;
198     ptrdiff_t stack_current_slot_;
199     VRegInfo::Type vreg_type_ = VRegInfo::Type::OBJECT;
200 };
201 
202 template <>
203 class CFrameJniMethodIterator<Arch::AARCH32> {
204     using SlotType = typename CFrame::SlotType;
205 
206     static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_FP_ARG_REGS;
207     static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_GP_ARG_REGS;
208 
209     static constexpr ptrdiff_t IN_REGS_START_SLOT = 24;
210     static constexpr ptrdiff_t IN_STACK_START_SLOT = -11;
211     static constexpr ptrdiff_t FP_END_SLOT = IN_REGS_START_SLOT - 1;
212     static constexpr ptrdiff_t FP_BEGIN_SLOT = FP_END_SLOT + ARG_FP_REGS_COUNG;
213     static constexpr ptrdiff_t GPR_END_SLOT = FP_BEGIN_SLOT;
214     static constexpr ptrdiff_t GPR_BEGIN_SLOT = GPR_END_SLOT + ARG_GP_REGS_COUNG;
215     static constexpr ptrdiff_t STACK_BEGIN_SLOT = IN_STACK_START_SLOT + 1;
216 
217 public:
MakeRange(CFrame * cframe)218     static auto MakeRange(CFrame *cframe)
219     {
220         ptrdiff_t gpr_begin_slot = GPR_BEGIN_SLOT;
221         Method *method = cframe->GetMethod();
222         bool is_static = method->IsStatic();
223         if (!is_static) {
224             --gpr_begin_slot;  // skip Method*
225         }
226 
227         uint32_t num_args = method->GetNumArgs();
228         uint32_t vreg_num = num_args + (is_static ? 1 : 0);
229 
230         return Range<CFrameJniMethodIterator>(
231             CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT, FP_BEGIN_SLOT,
232                                     FP_END_SLOT, STACK_BEGIN_SLOT),
233             CFrameJniMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0));
234     }
235 
236     VRegInfo operator*()
237     {
238         return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_);
239     }
240 
GetSlotsCountForType(VRegInfo::Type vreg_type)241     uint32_t GetSlotsCountForType(VRegInfo::Type vreg_type)
242     {
243         static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4);  // 4 bytes -- register size on AARCH32
244 
245         if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64) {
246             return 2;  // 2 slots
247         }
248         return 1;
249     }
250 
251     auto operator++()
252     {
253         if (++vreg_index_ >= vreg_num_) {
254             return *this;
255         }
256 
257         // Update type
258         vreg_type_ = ConvertType(*shorty_it_);
259         ++shorty_it_;
260 
261         // Update slots
262         ptrdiff_t inc = GetSlotsCountForType(vreg_type_);
263         ASSERT(inc == 1 || inc == 2);  // 1 or 2 slots
264         if (inc == 1) {
265             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
266                 if (vreg_type_ == VRegInfo::Type::FLOAT32) {  // in this case one takes 1 slots
267                     return HandleHardFloat();
268                 }
269             }
270             if ((gpr_current_slot_ - 1) > gpr_end_slot_) {
271                 --gpr_current_slot_;
272                 current_slot_ = gpr_current_slot_;
273             } else {
274                 gpr_current_slot_ = gpr_end_slot_;
275 
276                 --stack_current_slot_;
277                 current_slot_ = stack_current_slot_;
278             }
279         } else {
280             if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
281                 if (vreg_type_ == VRegInfo::Type::FLOAT64) {  // in this case one takes 2 slots
282                     return HandleHardDouble();
283                 }
284             }
285             gpr_current_slot_ = RoundUp(gpr_current_slot_ - 1, 2) - 1;  // 2
286             if (gpr_current_slot_ > gpr_end_slot_) {
287                 current_slot_ = gpr_current_slot_;
288                 gpr_current_slot_ -= 1;
289             } else {
290                 stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2) - 1;  // 2
291                 current_slot_ = stack_current_slot_;
292                 stack_current_slot_ -= 1;
293             }
294         }
295 
296         return *this;
297     }
298 
299     auto operator++(int)  // NOLINT(cert-dcl21-cpp)
300     {
301         auto res = *this;
302         this->operator++();
303         return res;
304     }
305 
306     bool operator==(const CFrameJniMethodIterator &it) const
307     {
308         return vreg_index_ == it.vreg_index_;
309     }
310 
311     bool operator!=(const CFrameJniMethodIterator &it) const
312     {
313         return !(*this == it);
314     }
315 
316 private:
CFrameJniMethodIterator(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)317     CFrameJniMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty, ptrdiff_t gpr_begin_slot,
318                             ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot, ptrdiff_t fp_end_slot,
319                             ptrdiff_t stack_current_slot)
320         : vreg_index_(vreg_index),
321           vreg_num_(vreg_num),
322           shorty_it_(shorty),
323           current_slot_(gpr_begin_slot),
324           gpr_current_slot_(gpr_begin_slot),
325           gpr_end_slot_(gpr_end_slot),
326           fp_current_slot_(fp_begin_slot),
327           fp_end_slot_(fp_end_slot),
328           stack_current_slot_(stack_current_slot)
329     {
330         ++shorty_it_;  // skip return value
331     }
332 
ConvertType(panda_file::Type type)333     VRegInfo::Type ConvertType(panda_file::Type type) const
334     {
335         switch (type.GetId()) {
336             case panda_file::Type::TypeId::U1:
337                 return VRegInfo::Type::BOOL;
338             case panda_file::Type::TypeId::I8:
339             case panda_file::Type::TypeId::U8:
340             case panda_file::Type::TypeId::I16:
341             case panda_file::Type::TypeId::U16:
342             case panda_file::Type::TypeId::I32:
343             case panda_file::Type::TypeId::U32:
344                 return VRegInfo::Type::INT32;
345             case panda_file::Type::TypeId::F32:
346                 return VRegInfo::Type::FLOAT32;
347             case panda_file::Type::TypeId::F64:
348                 return VRegInfo::Type::FLOAT64;
349             case panda_file::Type::TypeId::I64:
350             case panda_file::Type::TypeId::U64:
351                 return VRegInfo::Type::INT64;
352             case panda_file::Type::TypeId::REFERENCE:
353                 return VRegInfo::Type::OBJECT;
354             case panda_file::Type::TypeId::TAGGED:
355                 return VRegInfo::Type::INT64;
356             default:
357                 UNREACHABLE();
358         }
359         return VRegInfo::Type::INT32;
360     }
361 
HandleHardFloat()362     CFrameJniMethodIterator &HandleHardFloat()
363     {
364         ASSERT(vreg_type_ == VRegInfo::Type::FLOAT32);
365         if (fp_current_slot_ > fp_end_slot_) {
366             current_slot_ = fp_current_slot_;
367             --fp_current_slot_;
368         } else {
369             --stack_current_slot_;
370             current_slot_ = stack_current_slot_;
371         }
372         return *this;
373     }
374 
HandleHardDouble()375     CFrameJniMethodIterator &HandleHardDouble()
376     {
377         ASSERT(vreg_type_ == VRegInfo::Type::FLOAT64);
378         fp_current_slot_ = RoundDown(static_cast<uintptr_t>(fp_current_slot_) + 1, 2U) - 1;
379         if (fp_current_slot_ > fp_end_slot_) {
380             current_slot_ = fp_current_slot_;
381             fp_current_slot_ -= 2U;
382         } else {
383             stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2U) - 1;
384             current_slot_ = stack_current_slot_;
385             stack_current_slot_ -= 1;
386         }
387         return *this;
388     }
389 
390 private:
391     uint32_t vreg_index_;
392     uint32_t vreg_num_;
393     panda_file::ShortyIterator shorty_it_;
394     ptrdiff_t current_slot_;
395     ptrdiff_t gpr_current_slot_;
396     ptrdiff_t gpr_end_slot_;
397     ptrdiff_t fp_current_slot_;
398     ptrdiff_t fp_end_slot_;
399     ptrdiff_t stack_current_slot_;
400     VRegInfo::Type vreg_type_ = VRegInfo::Type::OBJECT;
401 };
402 
403 template <Arch arch = RUNTIME_ARCH>
404 class CFrameDynamicNativeMethodIterator {
405     using SlotType = typename CFrame::SlotType;
406 
407 public:
MakeRange(CFrame * cframe)408     static auto MakeRange(CFrame *cframe)
409     {
410         size_t arg_regs_count = arch::ExtArchTraits<arch>::NUM_GP_ARG_REGS;
411         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
412         Span<SlotType> callers(cframe->GetCallerSaveStack() - arg_regs_count, arg_regs_count);
413         // In dynamic methods the first two args are Method* method and uint32_t num_args
414         // Read num_args
415         auto num_args = static_cast<uint32_t>(callers[1]);
416         ++num_args;  // count function object
417         size_t num_arg_slots = num_args * sizeof(Frame::VRegister) / sizeof(SlotType);
418 
419         CFrameLayout cframe_layout(arch, 0);
420         size_t caller_end_slot = cframe_layout.GetCallerRegsStartSlot();
421         size_t caller_start_slot = caller_end_slot + arg_regs_count;
422         size_t gpr_arg_start_slot = caller_start_slot - 2;  // skip Method and num_args, 2 - offset
423         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
424         if constexpr (arch != Arch::X86_64) {
425             gpr_arg_start_slot = RoundDown(gpr_arg_start_slot, sizeof(Frame::VRegister) / sizeof(SlotType));
426         }
427         size_t num_gpr_arg_slots = std::min(gpr_arg_start_slot - caller_end_slot, num_arg_slots);
428 
429         size_t num_stack_arg_slots = num_arg_slots - num_gpr_arg_slots;
430         ptrdiff_t stack_arg_start_slot = cframe_layout.GetStackArgsStartSlot();
431         ptrdiff_t stack_arg_end_slot = stack_arg_start_slot - num_stack_arg_slots;
432 
433         // Since all stack slots are calculated relative STACK_START_SLOT
434         // subtract it from each value
435         ptrdiff_t stack_start_slot = cframe_layout.GetStackStartSlot();
436         gpr_arg_start_slot -= stack_start_slot;
437         caller_end_slot -= stack_start_slot;
438         stack_arg_start_slot -= stack_start_slot;
439         stack_arg_end_slot -= stack_start_slot;
440         return Range<CFrameDynamicNativeMethodIterator>(
441             CFrameDynamicNativeMethodIterator(cframe, gpr_arg_start_slot - 1, caller_end_slot - 1, stack_arg_start_slot,
442                                               stack_arg_end_slot),
443             CFrameDynamicNativeMethodIterator(cframe, caller_end_slot - 1, caller_end_slot - 1, stack_arg_end_slot,
444                                               stack_arg_end_slot));
445     }
446 
447     VRegInfo operator*()
448     {
449         if (gpr_start_slot_ > gpr_end_slot_) {
450             return VRegInfo(gpr_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_);
451         }
452         ASSERT(stack_start_slot_ > stack_end_slot_);
453         return VRegInfo(stack_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_);
454     }
455 
456     CFrameDynamicNativeMethodIterator &operator++()
457     {
458         size_t inc = sizeof(Frame::VRegister) / sizeof(SlotType);
459         if (gpr_start_slot_ > gpr_end_slot_) {
460             gpr_start_slot_ -= inc;
461             ++vreg_num_;
462         } else if (stack_start_slot_ > stack_end_slot_) {
463             stack_start_slot_ -= inc;
464             ++vreg_num_;
465         }
466         return *this;
467     }
468 
469     // NOLINTNEXTLINE(cert-dcl21-cpp)
470     CFrameDynamicNativeMethodIterator operator++(int)
471     {
472         auto res = *this;
473         this->operator++();
474         return res;
475     }
476 
477     bool operator==(const CFrameDynamicNativeMethodIterator &it) const
478     {
479         return gpr_start_slot_ == it.gpr_start_slot_ && stack_start_slot_ == it.stack_start_slot_;
480     }
481 
482     bool operator!=(const CFrameDynamicNativeMethodIterator &it) const
483     {
484         return !(*this == it);
485     }
486 
487 private:
CFrameDynamicNativeMethodIterator(CFrame * cframe,ptrdiff_t gpr_start_slot,ptrdiff_t gpr_end_slot,ptrdiff_t stack_start_slot,ptrdiff_t stack_end_slot)488     CFrameDynamicNativeMethodIterator(CFrame *cframe, ptrdiff_t gpr_start_slot, ptrdiff_t gpr_end_slot,
489                                       ptrdiff_t stack_start_slot, ptrdiff_t stack_end_slot)
490         : cframe_(cframe),
491           gpr_start_slot_(gpr_start_slot),
492           gpr_end_slot_(gpr_end_slot),
493           stack_start_slot_(stack_start_slot),
494           stack_end_slot_(stack_end_slot)
495     {
496     }
497 
498 private:
499     CFrame *cframe_;
500     uint32_t vreg_num_ = 0;
501     ptrdiff_t gpr_start_slot_;
502     ptrdiff_t gpr_end_slot_;
503     ptrdiff_t stack_start_slot_;
504     ptrdiff_t stack_end_slot_;
505 };
506 
507 }  // namespace panda
508 
509 #endif  // PANDA_RUNTIME_INCLUDE_CFRAME_ITERATORS_H_
510