• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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