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 template <>
110 struct ParameterTraits<uint32_t> {
111   static int64_t Cast(uint32_t r) {
112     return static_cast<int64_t>(static_cast<int32_t>(r));
113   }
114 };
115 
116 #endif  // !V8_TARGET_ARCH_64_BIT
117 
118 
119 template <typename R>
120 class CallHelper {
121  public:
122   explicit CallHelper(Isolate* isolate, CSignature* csig)
123       : csig_(csig), isolate_(isolate) {
124     USE(isolate_);
125   }
126   virtual ~CallHelper() {}
127 
128   R Call() {
129     typedef R V8_CDECL FType();
130     csig_->VerifyParams();
131     return DoCall(FUNCTION_CAST<FType*>(Generate()));
132   }
133 
134   template <typename P1>
135   R Call(P1 p1) {
136     typedef R V8_CDECL FType(P1);
137     csig_->VerifyParams<P1>();
138     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1);
139   }
140 
141   template <typename P1, typename P2>
142   R Call(P1 p1, P2 p2) {
143     typedef R V8_CDECL FType(P1, P2);
144     csig_->VerifyParams<P1, P2>();
145     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2);
146   }
147 
148   template <typename P1, typename P2, typename P3>
149   R Call(P1 p1, P2 p2, P3 p3) {
150     typedef R V8_CDECL FType(P1, P2, P3);
151     csig_->VerifyParams<P1, P2, P3>();
152     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
153   }
154 
155   template <typename P1, typename P2, typename P3, typename P4>
156   R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
157     typedef R V8_CDECL FType(P1, P2, P3, P4);
158     csig_->VerifyParams<P1, P2, P3, P4>();
159     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
160   }
161 
162   template <typename P1, typename P2, typename P3, typename P4, typename P5>
163   R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
164     typedef R V8_CDECL FType(P1, P2, P3, P4, P5);
165     csig_->VerifyParams<P1, P2, P3, P4, P5>();
166     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4, p5);
167   }
168 
169  protected:
170   CSignature* csig_;
171 
172   virtual byte* Generate() = 0;
173 
174  private:
175 #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
176   uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
177     Simulator* simulator = Simulator::current(isolate_);
178     return static_cast<uintptr_t>(simulator->CallInt64(f, args));
179   }
180 
181   template <typename F>
182   R DoCall(F* f) {
183     Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
184     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
185   }
186   template <typename F, typename P1>
187   R DoCall(F* f, P1 p1) {
188     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
189                                       Simulator::CallArgument::End()};
190     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
191   }
192   template <typename F, typename P1, typename P2>
193   R DoCall(F* f, P1 p1, P2 p2) {
194     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
195                                       Simulator::CallArgument(p2),
196                                       Simulator::CallArgument::End()};
197     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
198   }
199   template <typename F, typename P1, typename P2, typename P3>
200   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
201     Simulator::CallArgument args[] = {
202         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
203         Simulator::CallArgument(p3), Simulator::CallArgument::End()};
204     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
205   }
206   template <typename F, typename P1, typename P2, typename P3, typename P4>
207   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
208     Simulator::CallArgument args[] = {
209         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
210         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
211         Simulator::CallArgument::End()};
212     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
213   }
214   template <typename F, typename P1, typename P2, typename P3, typename P4,
215             typename P5>
216   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
217     Simulator::CallArgument args[] = {
218         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
219         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
220         Simulator::CallArgument(p5), Simulator::CallArgument::End()};
221     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
222   }
223 #elif USE_SIMULATOR && (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64)
224   uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
225                           int64_t p3 = 0, int64_t p4 = 0, int64_t p5 = 0) {
226     Simulator* simulator = Simulator::current(isolate_);
227     return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
228   }
229 
230 
231   template <typename F>
232   R DoCall(F* f) {
233     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
234   }
235   template <typename F, typename P1>
236   R DoCall(F* f, P1 p1) {
237     return CastReturnValue<R>(
238         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
239   }
240   template <typename F, typename P1, typename P2>
241   R DoCall(F* f, P1 p1, P2 p2) {
242     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
243                                             ParameterTraits<P1>::Cast(p1),
244                                             ParameterTraits<P2>::Cast(p2)));
245   }
246   template <typename F, typename P1, typename P2, typename P3>
247   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
248     return CastReturnValue<R>(CallSimulator(
249         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
250         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
251   }
252   template <typename F, typename P1, typename P2, typename P3, typename P4>
253   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
254     return CastReturnValue<R>(CallSimulator(
255         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
256         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
257         ParameterTraits<P4>::Cast(p4)));
258   }
259   template <typename F, typename P1, typename P2, typename P3, typename P4,
260             typename P5>
261   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
262     return CastReturnValue<R>(CallSimulator(
263         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
264         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
265         ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
266   }
267 #elif USE_SIMULATOR && \
268     (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_PPC)
269   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
270                           int32_t p3 = 0, int32_t p4 = 0, int32_t p5 = 0) {
271     Simulator* simulator = Simulator::current(isolate_);
272     return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
273   }
274   template <typename F>
275   R DoCall(F* f) {
276     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
277   }
278   template <typename F, typename P1>
279   R DoCall(F* f, P1 p1) {
280     return CastReturnValue<R>(
281         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
282   }
283   template <typename F, typename P1, typename P2>
284   R DoCall(F* f, P1 p1, P2 p2) {
285     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
286                                             ParameterTraits<P1>::Cast(p1),
287                                             ParameterTraits<P2>::Cast(p2)));
288   }
289   template <typename F, typename P1, typename P2, typename P3>
290   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
291     return CastReturnValue<R>(CallSimulator(
292         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
293         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
294   }
295   template <typename F, typename P1, typename P2, typename P3, typename P4>
296   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
297     return CastReturnValue<R>(CallSimulator(
298         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
299         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
300         ParameterTraits<P4>::Cast(p4)));
301   }
302   template <typename F, typename P1, typename P2, typename P3, typename P4,
303             typename P5>
304   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
305     return CastReturnValue<R>(CallSimulator(
306         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
307         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
308         ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
309   }
310 #else
311   template <typename F>
312   R DoCall(F* f) {
313     return f();
314   }
315   template <typename F, typename P1>
316   R DoCall(F* f, P1 p1) {
317     return f(p1);
318   }
319   template <typename F, typename P1, typename P2>
320   R DoCall(F* f, P1 p1, P2 p2) {
321     return f(p1, p2);
322   }
323   template <typename F, typename P1, typename P2, typename P3>
324   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
325     return f(p1, p2, p3);
326   }
327   template <typename F, typename P1, typename P2, typename P3, typename P4>
328   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
329     return f(p1, p2, p3, p4);
330   }
331   template <typename F, typename P1, typename P2, typename P3, typename P4,
332             typename P5>
333   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
334     return f(p1, p2, p3, p4, p5);
335   }
336 #endif
337 
338   Isolate* isolate_;
339 };
340 
341 // A call helper that calls the given code object assuming C calling convention.
342 template <typename T>
343 class CodeRunner : public CallHelper<T> {
344  public:
345   CodeRunner(Isolate* isolate, Handle<Code> code, CSignature* csig)
346       : CallHelper<T>(isolate, csig), code_(code) {}
347   virtual ~CodeRunner() {}
348 
349   virtual byte* Generate() { return code_->entry(); }
350 
351  private:
352   Handle<Code> code_;
353 };
354 
355 
356 }  // namespace compiler
357 }  // namespace internal
358 }  // namespace v8
359 
360 #endif  // V8_CCTEST_COMPILER_CALL_TESTER_H_
361