• 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_RUNTIME_TESTS_INVOCATION_HELPER_H_
17 #define PANDA_RUNTIME_TESTS_INVOCATION_HELPER_H_
18 
19 #include <cstdint>
20 #include <type_traits>
21 
22 #include "bridge/bridge.h"
23 #include "include/managed_thread.h"
24 #include "arch/helpers.h"
25 #include "libpandafile/shorty_iterator.h"
26 
27 namespace panda::test {
28 
29 const void *GetInvokeHelperImpl();
30 
31 template <typename T>
GetInvokeHelper()32 auto GetInvokeHelper()
33 {
34     using Fn = T (*)(const uint8_t *, const uint8_t *, const uint8_t *, size_t, panda::ManagedThread *);
35     return reinterpret_cast<Fn>(const_cast<void *>(GetInvokeHelperImpl()));
36 }
37 
WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *,size_t)38 inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *, size_t) {}
39 
40 template <typename T, typename... Args>
41 inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, T arg, Args... args);
42 
43 template <typename... Args>
WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> * writer,size_t nfloats,float arg,Args...args)44 inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, float arg, Args... args)
45 {
46     writer->Write(arg);
47     WriteArgImpl(writer, nfloats + 1, args...);
48 }
49 
50 template <typename T, typename... Args>
WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> * writer,size_t nfloats,T arg,Args...args)51 inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, T arg, Args... args)
52 {
53     if (RUNTIME_ARCH == Arch::AARCH32 && std::is_same_v<double, T>) {
54         // JIT compiler doesn't pack floats according armhf ABI. So in the following case:
55         //
56         // void foo(f32 a0, f64 a1, f32 a2)
57         //
58         // Arguments will be passed in the following registers:
59         // a0 - s0
60         // a1 - d1
61         // a2 - s4
62         //
63         // But according to armhf ABI a0 and a2 should be packed into d0:
64         // a0 - s0
65         // a1 - d1
66         // a2 - s1
67         //
68         // So write additional float if necessary to prevent packing
69         if ((nfloats & 0x1) != 0) {
70             nfloats += 1;
71             writer->Write(0.0f);
72         }
73     }
74     writer->Write(arg);
75     WriteArgImpl(writer, nfloats, args...);
76 }
77 
78 template <class T, typename... Args>
WriteArg(arch::ArgWriter<RUNTIME_ARCH> * writer,T arg,Args...args)79 inline void WriteArg(arch::ArgWriter<RUNTIME_ARCH> *writer, T arg, Args... args)
80 {
81     WriteArgImpl(writer, 0, arg, args...);
82 }
83 
84 template <typename T>
InvokeEntryPoint(Method * method)85 inline T InvokeEntryPoint(Method *method)
86 {
87     PandaVector<uint8_t> gpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
88     Span<uint8_t> gprs(gpr_data.data(), gpr_data.size());
89     PandaVector<uint8_t> fpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
90     Span<uint8_t> fprs(fpr_data.data(), fpr_data.size());
91     PandaVector<uint8_t> stack;
92     arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
93     writer.Write(method);
94 
95     ManagedThread *thread = ManagedThread::GetCurrent();
96     return GetInvokeHelper<T>()(gpr_data.data(), fpr_data.data(), stack.data(), 0, thread);
97 }
98 
99 template <typename T, typename... Args>
InvokeEntryPoint(Method * method,Args...args)100 inline T InvokeEntryPoint(Method *method, Args... args)
101 {
102     arch::ArgCounter<RUNTIME_ARCH> counter;
103     counter.Count<Method *>();
104     if (!method->IsStatic()) {
105         counter.Count<ObjectHeader *>();
106     }
107     panda_file::ShortyIterator it(method->GetShorty());
108     ++it;  // skip return type
109     while (it != panda_file::ShortyIterator()) {
110         switch ((*it).GetId()) {
111             case panda_file::Type::TypeId::U1:
112             case panda_file::Type::TypeId::U8:
113             case panda_file::Type::TypeId::I8:
114             case panda_file::Type::TypeId::I16:
115             case panda_file::Type::TypeId::U16:
116             case panda_file::Type::TypeId::I32:
117             case panda_file::Type::TypeId::U32:
118                 counter.Count<int32_t>();
119                 break;
120             case panda_file::Type::TypeId::F32:
121                 counter.Count<float>();
122                 break;
123             case panda_file::Type::TypeId::F64:
124                 counter.Count<double>();
125                 break;
126             case panda_file::Type::TypeId::I64:
127             case panda_file::Type::TypeId::U64:
128                 counter.Count<int64_t>();
129                 break;
130             case panda_file::Type::TypeId::REFERENCE:
131                 counter.Count<ObjectHeader *>();
132                 break;
133             case panda_file::Type::TypeId::TAGGED:
134                 counter.Count<DecodedTaggedValue>();
135                 break;
136             default:
137                 UNREACHABLE();
138         }
139         ++it;
140     }
141 
142     PandaVector<uint8_t> gpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
143     Span<uint8_t> gprs(gpr_data.data(), gpr_data.size());
144     PandaVector<uint8_t> fpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
145     Span<uint8_t> fprs(fpr_data.data(), fpr_data.size());
146     PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
147     arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
148     writer.Write(method);
149     WriteArg(&writer, args...);
150 
151     ManagedThread *thread = ManagedThread::GetCurrent();
152     return GetInvokeHelper<T>()(gpr_data.data(), fpr_data.data(), stack.data(), counter.GetStackSize(), thread);
153 }
154 
155 template <typename... Args>
InvokeDynEntryPoint(Method * method,uint32_t num_args,Args...args)156 DecodedTaggedValue InvokeDynEntryPoint(Method *method, uint32_t num_args, Args... args)
157 {
158     arch::ArgCounter<RUNTIME_ARCH> counter;
159     counter.Count<Method *>();
160     counter.Count<uint32_t>();
161     for (uint32_t i = 0; i <= num_args; ++i) {
162         counter.Count<DecodedTaggedValue>();
163     }
164 
165     PandaVector<uint8_t> gpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
166     Span<uint8_t> gprs(gpr_data.data(), gpr_data.size());
167     PandaVector<uint8_t> fpr_data(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
168     Span<uint8_t> fprs(fpr_data.data(), fpr_data.size());
169     PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
170     arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
171     writer.Write(method);
172     writer.Write(num_args);
173     WriteArg(&writer, args...);
174 
175     ManagedThread *thread = ManagedThread::GetCurrent();
176     return GetInvokeHelper<DecodedTaggedValue>()(gpr_data.data(), fpr_data.data(), stack.data(), counter.GetStackSize(),
177                                                  thread);
178 }
179 
180 }  // namespace panda::test
181 
182 #endif  // PANDA_RUNTIME_TESTS_INVOCATION_HELPER_H_
183