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