1 /**
2 * Copyright (c) 2021-2024 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 ark::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, ark::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 void CountMethodTypes(panda_file::ShortyIterator &it, arch::ArgCounter<RUNTIME_ARCH> counter);
101
102 template <typename T, typename... Args>
InvokeEntryPoint(Method * method,Args...args)103 T InvokeEntryPoint(Method *method, Args... args)
104 {
105 arch::ArgCounter<RUNTIME_ARCH> counter;
106 counter.Count<Method *>();
107 if (!method->IsStatic()) {
108 counter.Count<ObjectHeader *>();
109 }
110 panda_file::ShortyIterator it(method->GetShorty());
111 ++it; // skip return type
112 while (it != panda_file::ShortyIterator()) {
113 CountMethodTypes(it, counter);
114 ++it;
115 }
116
117 PandaVector<uint8_t> gprData(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
118 Span<uint8_t> gprs(gprData.data(), gprData.size());
119 PandaVector<uint8_t> fprData(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
120 Span<uint8_t> fprs(fprData.data(), fprData.size());
121 PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
122 arch::ArgWriter<RUNTIME_ARCH> writer(gprs, fprs, stack.data());
123 writer.Write(method);
124 WriteArg(&writer, args...);
125
126 ManagedThread *thread = ManagedThread::GetCurrent();
127 return GetInvokeHelper<T>()(gprData.data(), fprData.data(), stack.data(), counter.GetStackSize(), thread);
128 }
129
130 template <typename... Args>
InvokeDynEntryPoint(Method * method,uint32_t numArgs,Args...args)131 coretypes::TaggedValue InvokeDynEntryPoint(Method *method, uint32_t numArgs, Args... args)
132 {
133 arch::ArgCounter<RUNTIME_ARCH> counter;
134 counter.Count<Method *>();
135 counter.Count<uint32_t>();
136 for (uint32_t i = 0; i <= numArgs; ++i) {
137 counter.Count<coretypes::TaggedValue>();
138 }
139
140 PandaVector<uint8_t> gprData(arch::ExtArchTraits<RUNTIME_ARCH>::GP_ARG_NUM_BYTES);
141 Span<uint8_t> gprs(gprData.data(), gprData.size());
142 PandaVector<uint8_t> fprData(arch::ExtArchTraits<RUNTIME_ARCH>::FP_ARG_NUM_BYTES);
143 Span<uint8_t> fprs(fprData.data(), fprData.size());
144 PandaVector<uint8_t> stack(counter.GetStackSpaceSize());
145 arch::ArgWriter<RUNTIME_ARCH> writer(gprs, fprs, stack.data());
146 writer.Write(method);
147 writer.Write(numArgs);
148 WriteArg(&writer, args...);
149
150 ManagedThread *thread = ManagedThread::GetCurrent();
151 return GetInvokeHelper<coretypes::TaggedValue>()(gprData.data(), fprData.data(), stack.data(),
152 counter.GetStackSize(), thread);
153 }
154
155 } // namespace ark::test
156
157 #endif // PANDA_RUNTIME_TESTS_INVOCATION_HELPER_H_
158