1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_CCTEST_COMPILER_CALL_TESTER_H_
6 #define V8_CCTEST_COMPILER_CALL_TESTER_H_
7
8 #include "src/simulator.h"
9 #include "test/cctest/compiler/c-signature.h"
10
11 #if V8_TARGET_ARCH_IA32
12 #if __GNUC__
13 #define V8_CDECL __attribute__((cdecl))
14 #else
15 #define V8_CDECL __cdecl
16 #endif
17 #else
18 #define V8_CDECL
19 #endif
20
21 namespace v8 {
22 namespace internal {
23 namespace compiler {
24
25 template <typename R>
CastReturnValue(uintptr_t r)26 inline R CastReturnValue(uintptr_t r) {
27 return reinterpret_cast<R>(r);
28 }
29
30 template <>
CastReturnValue(uintptr_t r)31 inline void CastReturnValue(uintptr_t r) {}
32
33 template <>
CastReturnValue(uintptr_t r)34 inline bool CastReturnValue(uintptr_t r) {
35 return static_cast<bool>(r);
36 }
37
38 template <>
CastReturnValue(uintptr_t r)39 inline int32_t CastReturnValue(uintptr_t r) {
40 return static_cast<int32_t>(r);
41 }
42
43 template <>
CastReturnValue(uintptr_t r)44 inline uint32_t CastReturnValue(uintptr_t r) {
45 return static_cast<uint32_t>(r);
46 }
47
48 template <>
CastReturnValue(uintptr_t r)49 inline int64_t CastReturnValue(uintptr_t r) {
50 return static_cast<int64_t>(r);
51 }
52
53 template <>
CastReturnValue(uintptr_t r)54 inline uint64_t CastReturnValue(uintptr_t r) {
55 return static_cast<uint64_t>(r);
56 }
57
58 template <>
CastReturnValue(uintptr_t r)59 inline int16_t CastReturnValue(uintptr_t r) {
60 return static_cast<int16_t>(r);
61 }
62
63 template <>
CastReturnValue(uintptr_t r)64 inline uint16_t CastReturnValue(uintptr_t r) {
65 return static_cast<uint16_t>(r);
66 }
67
68 template <>
CastReturnValue(uintptr_t r)69 inline int8_t CastReturnValue(uintptr_t r) {
70 return static_cast<int8_t>(r);
71 }
72
73 template <>
CastReturnValue(uintptr_t r)74 inline uint8_t CastReturnValue(uintptr_t r) {
75 return static_cast<uint8_t>(r);
76 }
77
78 template <>
CastReturnValue(uintptr_t r)79 inline double CastReturnValue(uintptr_t r) {
80 UNREACHABLE();
81 return 0.0;
82 }
83
84 template <typename R>
85 struct ParameterTraits {
CastParameterTraits86 static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
87 };
88
89 template <>
90 struct ParameterTraits<int*> {
91 static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
92 };
93
94 template <typename T>
95 struct ParameterTraits<T*> {
96 static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
97 };
98
99
100 #if !V8_TARGET_ARCH_32_BIT
101
102 // Additional template specialization required for mips64 to sign-extend
103 // parameters defined by calling convention.
104 template <>
105 struct ParameterTraits<int32_t> {
106 static int64_t Cast(int32_t r) { return static_cast<int64_t>(r); }
107 };
108
109 #if !V8_TARGET_ARCH_PPC64
110 template <>
111 struct ParameterTraits<uint32_t> {
112 static int64_t Cast(uint32_t r) {
113 return static_cast<int64_t>(static_cast<int32_t>(r));
114 }
115 };
116 #endif
117
118 #endif // !V8_TARGET_ARCH_64_BIT
119
120
121 template <typename R>
122 class CallHelper {
123 public:
124 explicit CallHelper(Isolate* isolate, MachineSignature* csig)
125 : csig_(csig), isolate_(isolate) {
126 USE(isolate_);
127 }
128 virtual ~CallHelper() {}
129
130 R Call() {
131 typedef R V8_CDECL FType();
132 CSignature::VerifyParams(csig_);
133 return DoCall(FUNCTION_CAST<FType*>(Generate()));
134 }
135
136 template <typename P1>
137 R Call(P1 p1) {
138 typedef R V8_CDECL FType(P1);
139 CSignature::VerifyParams<P1>(csig_);
140 return DoCall(FUNCTION_CAST<FType*>(Generate()), p1);
141 }
142
143 template <typename P1, typename P2>
144 R Call(P1 p1, P2 p2) {
145 typedef R V8_CDECL FType(P1, P2);
146 CSignature::VerifyParams<P1, P2>(csig_);
147 return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2);
148 }
149
150 template <typename P1, typename P2, typename P3>
151 R Call(P1 p1, P2 p2, P3 p3) {
152 typedef R V8_CDECL FType(P1, P2, P3);
153 CSignature::VerifyParams<P1, P2, P3>(csig_);
154 return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
155 }
156
157 template <typename P1, typename P2, typename P3, typename P4>
158 R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
159 typedef R V8_CDECL FType(P1, P2, P3, P4);
160 CSignature::VerifyParams<P1, P2, P3, P4>(csig_);
161 return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
162 }
163
164 template <typename P1, typename P2, typename P3, typename P4, typename P5>
165 R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
166 typedef R V8_CDECL FType(P1, P2, P3, P4, P5);
167 CSignature::VerifyParams<P1, P2, P3, P4, P5>(csig_);
168 return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4, p5);
169 }
170
171 protected:
172 MachineSignature* csig_;
173
174 virtual byte* Generate() = 0;
175
176 private:
177 #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
178 uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
179 Simulator* simulator = Simulator::current(isolate_);
180 return static_cast<uintptr_t>(simulator->CallInt64(f, args));
181 }
182
183 template <typename F>
184 R DoCall(F* f) {
185 Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
186 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
187 }
188 template <typename F, typename P1>
189 R DoCall(F* f, P1 p1) {
190 Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
191 Simulator::CallArgument::End()};
192 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
193 }
194 template <typename F, typename P1, typename P2>
195 R DoCall(F* f, P1 p1, P2 p2) {
196 Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
197 Simulator::CallArgument(p2),
198 Simulator::CallArgument::End()};
199 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
200 }
201 template <typename F, typename P1, typename P2, typename P3>
202 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
203 Simulator::CallArgument args[] = {
204 Simulator::CallArgument(p1), Simulator::CallArgument(p2),
205 Simulator::CallArgument(p3), Simulator::CallArgument::End()};
206 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
207 }
208 template <typename F, typename P1, typename P2, typename P3, typename P4>
209 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
210 Simulator::CallArgument args[] = {
211 Simulator::CallArgument(p1), Simulator::CallArgument(p2),
212 Simulator::CallArgument(p3), Simulator::CallArgument(p4),
213 Simulator::CallArgument::End()};
214 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
215 }
216 template <typename F, typename P1, typename P2, typename P3, typename P4,
217 typename P5>
218 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
219 Simulator::CallArgument args[] = {
220 Simulator::CallArgument(p1), Simulator::CallArgument(p2),
221 Simulator::CallArgument(p3), Simulator::CallArgument(p4),
222 Simulator::CallArgument(p5), Simulator::CallArgument::End()};
223 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
224 }
225 #elif USE_SIMULATOR && \
226 (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X)
227 uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
228 int64_t p3 = 0, int64_t p4 = 0, int64_t p5 = 0) {
229 Simulator* simulator = Simulator::current(isolate_);
230 return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
231 }
232
233
234 template <typename F>
235 R DoCall(F* f) {
236 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
237 }
238 template <typename F, typename P1>
239 R DoCall(F* f, P1 p1) {
240 return CastReturnValue<R>(
241 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
242 }
243 template <typename F, typename P1, typename P2>
244 R DoCall(F* f, P1 p1, P2 p2) {
245 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
246 ParameterTraits<P1>::Cast(p1),
247 ParameterTraits<P2>::Cast(p2)));
248 }
249 template <typename F, typename P1, typename P2, typename P3>
250 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
251 return CastReturnValue<R>(CallSimulator(
252 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
253 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
254 }
255 template <typename F, typename P1, typename P2, typename P3, typename P4>
256 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
257 return CastReturnValue<R>(CallSimulator(
258 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
259 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
260 ParameterTraits<P4>::Cast(p4)));
261 }
262 template <typename F, typename P1, typename P2, typename P3, typename P4,
263 typename P5>
264 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
265 return CastReturnValue<R>(CallSimulator(
266 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
267 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
268 ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
269 }
270 #elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || \
271 V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390)
272 uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
273 int32_t p3 = 0, int32_t p4 = 0, int32_t p5 = 0) {
274 Simulator* simulator = Simulator::current(isolate_);
275 return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
276 }
277 template <typename F>
278 R DoCall(F* f) {
279 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
280 }
281 template <typename F, typename P1>
282 R DoCall(F* f, P1 p1) {
283 return CastReturnValue<R>(
284 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
285 }
286 template <typename F, typename P1, typename P2>
287 R DoCall(F* f, P1 p1, P2 p2) {
288 return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
289 ParameterTraits<P1>::Cast(p1),
290 ParameterTraits<P2>::Cast(p2)));
291 }
292 template <typename F, typename P1, typename P2, typename P3>
293 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
294 return CastReturnValue<R>(CallSimulator(
295 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
296 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
297 }
298 template <typename F, typename P1, typename P2, typename P3, typename P4>
299 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
300 return CastReturnValue<R>(CallSimulator(
301 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
302 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
303 ParameterTraits<P4>::Cast(p4)));
304 }
305 template <typename F, typename P1, typename P2, typename P3, typename P4,
306 typename P5>
307 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
308 return CastReturnValue<R>(CallSimulator(
309 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
310 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
311 ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
312 }
313 #else
314 template <typename F>
315 R DoCall(F* f) {
316 return f();
317 }
318 template <typename F, typename P1>
319 R DoCall(F* f, P1 p1) {
320 return f(p1);
321 }
322 template <typename F, typename P1, typename P2>
323 R DoCall(F* f, P1 p1, P2 p2) {
324 return f(p1, p2);
325 }
326 template <typename F, typename P1, typename P2, typename P3>
327 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
328 return f(p1, p2, p3);
329 }
330 template <typename F, typename P1, typename P2, typename P3, typename P4>
331 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
332 return f(p1, p2, p3, p4);
333 }
334 template <typename F, typename P1, typename P2, typename P3, typename P4,
335 typename P5>
336 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
337 return f(p1, p2, p3, p4, p5);
338 }
339 #endif
340
341 Isolate* isolate_;
342 };
343
344 // A call helper that calls the given code object assuming C calling convention.
345 template <typename T>
346 class CodeRunner : public CallHelper<T> {
347 public:
348 CodeRunner(Isolate* isolate, Handle<Code> code, MachineSignature* csig)
349 : CallHelper<T>(isolate, csig), code_(code) {}
350 virtual ~CodeRunner() {}
351
352 virtual byte* Generate() { return code_->entry(); }
353
354 private:
355 Handle<Code> code_;
356 };
357
358
359 } // namespace compiler
360 } // namespace internal
361 } // namespace v8
362
363 #endif // V8_CCTEST_COMPILER_CALL_TESTER_H_
364