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
22namespace v8 {
23namespace internal {
24namespace compiler {
25
26// TODO(titzer): use c-signature.h instead of ReturnValueTraits
27template <typename R>
28struct ReturnValueTraits {
29  static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); }
30  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
40template <>
41struct 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
46template <>
47struct ReturnValueTraits<void> {
48  static void Cast(uintptr_t r) {}
49  static MachineType Representation() { return kMachPtr; }
50};
51
52template <>
53struct ReturnValueTraits<bool> {
54  static bool Cast(uintptr_t r) { return static_cast<bool>(r); }
55  static MachineType Representation() { return kRepBit; }
56};
57
58template <>
59struct 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
64template <>
65struct 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
70template <>
71struct 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
76template <>
77struct 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
82template <>
83struct 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
88template <>
89struct 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
94template <>
95struct 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
100template <>
101struct 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
106template <>
107struct 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
116template <typename R>
117struct ParameterTraits {
118  static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
119};
120
121template <>
122struct ParameterTraits<int*> {
123  static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
124};
125
126template <typename T>
127struct ParameterTraits<T*> {
128  static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
129};
130
131class 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.
360template <typename R, typename C>
361class 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