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> * /* unused */, size_t /* unused */) {}
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 // NOLINTNEXTLINE(hicpp-signed-bitwise)
70 if ((nfloats & 0x1) != 0) {
71 nfloats += 1;
72 writer->Write(0.0F);
73 }
74 }
75 writer->Write(arg);
76 WriteArgImpl(writer, nfloats, args...);
77 }
78
79 template <class T, typename... Args>
WriteArg(arch::ArgWriter<RUNTIME_ARCH> * writer,T arg,Args...args)80 inline void WriteArg(arch::ArgWriter<RUNTIME_ARCH> *writer, T arg, Args... args)
81 {
82 WriteArgImpl(writer, 0, arg, args...);
83 }
84
85 template <typename T>
InvokeEntryPoint(Method * method)86 inline T InvokeEntryPoint(Method *method)
87 {
88 PandaVector<uint8_t> gprData(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
89 Span<uint8_t> gprs(gprData.data(), gprData.size());
90 PandaVector<uint8_t> fprData(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
91 Span<uint8_t> fprs(fprData.data(), fprData.size());
92 PandaVector<uint8_t> stack;
93 arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
94 writer.Write(method);
95
96 ManagedThread *thread = ManagedThread::GetCurrent();
97 return GetInvokeHelper<T>()(gprData.data(), fprData.data(), stack.data(), 0, thread);
98 }
99
100 template <typename T, typename... Args>
InvokeEntryPoint(Method * method,Args...args)101 inline T InvokeEntryPoint(Method *method, Args... args)
102 {
103 arch::ArgCounter<RUNTIME_ARCH> counter;
104 counter.Count<Method *>();
105 if (!method->IsStatic()) {
106 counter.Count<ObjectHeader *>();
107 }
108 panda_file::ShortyIterator it(method->GetShorty());
109 ++it; // skip return type
110 while (it != panda_file::ShortyIterator()) {
111 switch ((*it).GetId()) {
112 case panda_file::Type::TypeId::U1:
113 case panda_file::Type::TypeId::U8:
114 case panda_file::Type::TypeId::I8:
115 case panda_file::Type::TypeId::I16:
116 case panda_file::Type::TypeId::U16:
117 case panda_file::Type::TypeId::I32:
118 case panda_file::Type::TypeId::U32:
119 counter.Count<int32_t>();
120 break;
121 case panda_file::Type::TypeId::F32:
122 counter.Count<float>();
123 break;
124 case panda_file::Type::TypeId::F64:
125 counter.Count<double>();
126 break;
127 case panda_file::Type::TypeId::I64:
128 case panda_file::Type::TypeId::U64:
129 counter.Count<int64_t>();
130 break;
131 case panda_file::Type::TypeId::REFERENCE:
132 counter.Count<ObjectHeader *>();
133 break;
134 case panda_file::Type::TypeId::TAGGED:
135 counter.Count<coretypes::TaggedValue>();
136 break;
137 default:
138 UNREACHABLE();
139 }
140 ++it;
141 }
142
143 PandaVector<uint8_t> gprData(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
144 Span<uint8_t> gprs(gprData.data(), gprData.size());
145 PandaVector<uint8_t> fprData(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
146 Span<uint8_t> fprs(fprData.data(), fprData.size());
147 PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
148 arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
149 writer.Write(method);
150 WriteArg(&writer, args...);
151
152 ManagedThread *thread = ManagedThread::GetCurrent();
153 return GetInvokeHelper<T>()(gprData.data(), fprData.data(), stack.data(), counter.GetStackSize(), thread);
154 }
155
156 template <typename... Args>
InvokeDynEntryPoint(Method * method,uint32_t numArgs,Args...args)157 coretypes::TaggedValue InvokeDynEntryPoint(Method *method, uint32_t numArgs, Args... args)
158 {
159 arch::ArgCounter<RUNTIME_ARCH> counter;
160 counter.Count<Method *>();
161 counter.Count<uint32_t>();
162 for (uint32_t i = 0; i <= numArgs; ++i) {
163 counter.Count<coretypes::TaggedValue>();
164 }
165
166 PandaVector<uint8_t> gprData(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
167 Span<uint8_t> gprs(gprData.data(), gprData.size());
168 PandaVector<uint8_t> fprData(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
169 Span<uint8_t> fprs(fprData.data(), fprData.size());
170 PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
171 arch::ArgWriter<RUNTIME_ARCH> writer(&gprs, &fprs, stack.data());
172 writer.Write(method);
173 writer.Write(numArgs);
174 WriteArg(&writer, args...);
175
176 ManagedThread *thread = ManagedThread::GetCurrent();
177 return GetInvokeHelper<coretypes::TaggedValue>()(gprData.data(), fprData.data(), stack.data(),
178 counter.GetStackSize(), thread);
179 }
180
181 } // namespace panda::test
182
183 #endif // PANDA_RUNTIME_TESTS_INVOCATION_HELPER_H
184