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/v8.h"
9 
10 #include "src/simulator.h"
11 
12 #if V8_TARGET_ARCH_IA32
13 #if __GNUC__
14 #define V8_CDECL __attribute__((cdecl))
15 #else
16 #define V8_CDECL __cdecl
17 #endif
18 #else
19 #define V8_CDECL
20 #endif
21 
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25 
26 // TODO(titzer): use c-signature.h instead of ReturnValueTraits
27 template <typename R>
28 struct ReturnValueTraits {
CastReturnValueTraits29   static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); }
RepresentationReturnValueTraits30   static MachineType Representation() {
31     // TODO(dcarney): detect when R is of a subclass of Object* instead of this
32     // type check.
33     while (false) {
34       *(static_cast<Object* volatile*>(0)) = static_cast<R>(0);
35     }
36     return kMachAnyTagged;
37   }
38 };
39 
40 template <>
41 struct ReturnValueTraits<int32_t*> {
42   static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); }
43   static MachineType Representation() { return kMachPtr; }
44 };
45 
46 template <>
47 struct ReturnValueTraits<void> {
48   static void Cast(uintptr_t r) {}
49   static MachineType Representation() { return kMachPtr; }
50 };
51 
52 template <>
53 struct ReturnValueTraits<bool> {
54   static bool Cast(uintptr_t r) { return static_cast<bool>(r); }
55   static MachineType Representation() { return kRepBit; }
56 };
57 
58 template <>
59 struct ReturnValueTraits<int32_t> {
60   static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); }
61   static MachineType Representation() { return kMachInt32; }
62 };
63 
64 template <>
65 struct ReturnValueTraits<uint32_t> {
66   static uint32_t Cast(uintptr_t r) { return static_cast<uint32_t>(r); }
67   static MachineType Representation() { return kMachUint32; }
68 };
69 
70 template <>
71 struct ReturnValueTraits<int64_t> {
72   static int64_t Cast(uintptr_t r) { return static_cast<int64_t>(r); }
73   static MachineType Representation() { return kMachInt64; }
74 };
75 
76 template <>
77 struct ReturnValueTraits<uint64_t> {
78   static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); }
79   static MachineType Representation() { return kMachUint64; }
80 };
81 
82 template <>
83 struct ReturnValueTraits<int16_t> {
84   static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); }
85   static MachineType Representation() { return kMachInt16; }
86 };
87 
88 template <>
89 struct ReturnValueTraits<uint16_t> {
90   static uint16_t Cast(uintptr_t r) { return static_cast<uint16_t>(r); }
91   static MachineType Representation() { return kMachUint16; }
92 };
93 
94 template <>
95 struct ReturnValueTraits<int8_t> {
96   static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); }
97   static MachineType Representation() { return kMachInt8; }
98 };
99 
100 template <>
101 struct ReturnValueTraits<uint8_t> {
102   static uint8_t Cast(uintptr_t r) { return static_cast<uint8_t>(r); }
103   static MachineType Representation() { return kMachUint8; }
104 };
105 
106 template <>
107 struct ReturnValueTraits<double> {
108   static double Cast(uintptr_t r) {
109     UNREACHABLE();
110     return 0.0;
111   }
112   static MachineType Representation() { return kMachFloat64; }
113 };
114 
115 
116 template <typename R>
117 struct ParameterTraits {
118   static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
119 };
120 
121 template <>
122 struct ParameterTraits<int*> {
123   static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
124 };
125 
126 template <typename T>
127 struct ParameterTraits<T*> {
128   static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
129 };
130 
131 class CallHelper {
132  public:
133   explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig)
134       : machine_sig_(machine_sig), isolate_(isolate) {
135     USE(isolate_);
136   }
137   virtual ~CallHelper() {}
138 
139   static MachineSignature* MakeMachineSignature(
140       Zone* zone, MachineType return_type, MachineType p0 = kMachNone,
141       MachineType p1 = kMachNone, MachineType p2 = kMachNone,
142       MachineType p3 = kMachNone, MachineType p4 = kMachNone) {
143     // Count the number of parameters.
144     size_t param_count = 5;
145     MachineType types[] = {p0, p1, p2, p3, p4};
146     while (param_count > 0 && types[param_count - 1] == kMachNone)
147       param_count--;
148     size_t return_count = return_type == kMachNone ? 0 : 1;
149 
150     // Build the machine signature.
151     MachineSignature::Builder builder(zone, return_count, param_count);
152     if (return_count > 0) builder.AddReturn(return_type);
153     for (size_t i = 0; i < param_count; i++) {
154       builder.AddParam(types[i]);
155     }
156     return builder.Build();
157   }
158 
159  protected:
160   MachineSignature* machine_sig_;
161   void VerifyParameters(size_t parameter_count, MachineType* parameter_types) {
162     CHECK(machine_sig_->parameter_count() == parameter_count);
163     for (size_t i = 0; i < parameter_count; i++) {
164       CHECK_EQ(machine_sig_->GetParam(i), parameter_types[i]);
165     }
166   }
167   virtual byte* Generate() = 0;
168 
169  private:
170 #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
171   uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
172     Simulator* simulator = Simulator::current(isolate_);
173     return static_cast<uintptr_t>(simulator->CallInt64(f, args));
174   }
175 
176   template <typename R, typename F>
177   R DoCall(F* f) {
178     Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
179     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
180   }
181   template <typename R, typename F, typename P1>
182   R DoCall(F* f, P1 p1) {
183     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
184                                       Simulator::CallArgument::End()};
185     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
186   }
187   template <typename R, typename F, typename P1, typename P2>
188   R DoCall(F* f, P1 p1, P2 p2) {
189     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
190                                       Simulator::CallArgument(p2),
191                                       Simulator::CallArgument::End()};
192     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
193   }
194   template <typename R, typename F, typename P1, typename P2, typename P3>
195   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
196     Simulator::CallArgument args[] = {
197         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
198         Simulator::CallArgument(p3), Simulator::CallArgument::End()};
199     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
200   }
201   template <typename R, typename F, typename P1, typename P2, typename P3,
202             typename P4>
203   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
204     Simulator::CallArgument args[] = {
205         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
206         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
207         Simulator::CallArgument::End()};
208     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
209   }
210 #elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
211   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
212                           int32_t p3 = 0, int32_t p4 = 0) {
213     Simulator* simulator = Simulator::current(isolate_);
214     return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
215   }
216   template <typename R, typename F>
217   R DoCall(F* f) {
218     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
219   }
220   template <typename R, typename F, typename P1>
221   R DoCall(F* f, P1 p1) {
222     return ReturnValueTraits<R>::Cast(
223         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
224   }
225   template <typename R, typename F, typename P1, typename P2>
226   R DoCall(F* f, P1 p1, P2 p2) {
227     return ReturnValueTraits<R>::Cast(
228         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
229                       ParameterTraits<P2>::Cast(p2)));
230   }
231   template <typename R, typename F, typename P1, typename P2, typename P3>
232   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
233     return ReturnValueTraits<R>::Cast(CallSimulator(
234         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
235         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
236   }
237   template <typename R, typename F, typename P1, typename P2, typename P3,
238             typename P4>
239   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
240     return ReturnValueTraits<R>::Cast(CallSimulator(
241         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
242         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
243         ParameterTraits<P4>::Cast(p4)));
244   }
245 #else
246   template <typename R, typename F>
247   R DoCall(F* f) {
248     return f();
249   }
250   template <typename R, typename F, typename P1>
251   R DoCall(F* f, P1 p1) {
252     return f(p1);
253   }
254   template <typename R, typename F, typename P1, typename P2>
255   R DoCall(F* f, P1 p1, P2 p2) {
256     return f(p1, p2);
257   }
258   template <typename R, typename F, typename P1, typename P2, typename P3>
259   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
260     return f(p1, p2, p3);
261   }
262   template <typename R, typename F, typename P1, typename P2, typename P3,
263             typename P4>
264   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
265     return f(p1, p2, p3, p4);
266   }
267 #endif
268 
269 #ifndef DEBUG
270   void VerifyParameters0() {}
271 
272   template <typename P1>
273   void VerifyParameters1() {}
274 
275   template <typename P1, typename P2>
276   void VerifyParameters2() {}
277 
278   template <typename P1, typename P2, typename P3>
279   void VerifyParameters3() {}
280 
281   template <typename P1, typename P2, typename P3, typename P4>
282   void VerifyParameters4() {}
283 #else
284   void VerifyParameters0() { VerifyParameters(0, NULL); }
285 
286   template <typename P1>
287   void VerifyParameters1() {
288     MachineType parameters[] = {ReturnValueTraits<P1>::Representation()};
289     VerifyParameters(arraysize(parameters), parameters);
290   }
291 
292   template <typename P1, typename P2>
293   void VerifyParameters2() {
294     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
295                                 ReturnValueTraits<P2>::Representation()};
296     VerifyParameters(arraysize(parameters), parameters);
297   }
298 
299   template <typename P1, typename P2, typename P3>
300   void VerifyParameters3() {
301     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
302                                 ReturnValueTraits<P2>::Representation(),
303                                 ReturnValueTraits<P3>::Representation()};
304     VerifyParameters(arraysize(parameters), parameters);
305   }
306 
307   template <typename P1, typename P2, typename P3, typename P4>
308   void VerifyParameters4() {
309     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
310                                 ReturnValueTraits<P2>::Representation(),
311                                 ReturnValueTraits<P3>::Representation(),
312                                 ReturnValueTraits<P4>::Representation()};
313     VerifyParameters(arraysize(parameters), parameters);
314   }
315 #endif
316 
317   // TODO(dcarney): replace Call() in CallHelper2 with these.
318   template <typename R>
319   R Call0() {
320     typedef R V8_CDECL FType();
321     VerifyParameters0();
322     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()));
323   }
324 
325   template <typename R, typename P1>
326   R Call1(P1 p1) {
327     typedef R V8_CDECL FType(P1);
328     VerifyParameters1<P1>();
329     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1);
330   }
331 
332   template <typename R, typename P1, typename P2>
333   R Call2(P1 p1, P2 p2) {
334     typedef R V8_CDECL FType(P1, P2);
335     VerifyParameters2<P1, P2>();
336     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2);
337   }
338 
339   template <typename R, typename P1, typename P2, typename P3>
340   R Call3(P1 p1, P2 p2, P3 p3) {
341     typedef R V8_CDECL FType(P1, P2, P3);
342     VerifyParameters3<P1, P2, P3>();
343     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
344   }
345 
346   template <typename R, typename P1, typename P2, typename P3, typename P4>
347   R Call4(P1 p1, P2 p2, P3 p3, P4 p4) {
348     typedef R V8_CDECL FType(P1, P2, P3, P4);
349     VerifyParameters4<P1, P2, P3, P4>();
350     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
351   }
352 
353   template <typename R, typename C>
354   friend class CallHelper2;
355   Isolate* isolate_;
356 };
357 
358 
359 // TODO(dcarney): replace CallHelper with CallHelper2 and rename.
360 template <typename R, typename C>
361 class CallHelper2 {
362  public:
363   R Call() { return helper()->template Call0<R>(); }
364 
365   template <typename P1>
366   R Call(P1 p1) {
367     return helper()->template Call1<R>(p1);
368   }
369 
370   template <typename P1, typename P2>
371   R Call(P1 p1, P2 p2) {
372     return helper()->template Call2<R>(p1, p2);
373   }
374 
375   template <typename P1, typename P2, typename P3>
376   R Call(P1 p1, P2 p2, P3 p3) {
377     return helper()->template Call3<R>(p1, p2, p3);
378   }
379 
380   template <typename P1, typename P2, typename P3, typename P4>
381   R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
382     return helper()->template Call4<R>(p1, p2, p3, p4);
383   }
384 
385  private:
386   CallHelper* helper() { return static_cast<C*>(this); }
387 };
388 
389 }  // namespace compiler
390 }  // namespace internal
391 }  // namespace v8
392 
393 #endif  // V8_CCTEST_COMPILER_CALL_TESTER_H_
394