• 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> * /* 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