blob: cad171e60c1730f4869abd255cf892d67552ae74 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210#elif USE_SIMULATOR && V8_TARGET_ARCH_MIPS64
211 uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
212 int64_t p3 = 0, int64_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
217 template <typename R, typename F>
218 R DoCall(F* f) {
219 return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
220 }
221 template <typename R, typename F, typename P1>
222 R DoCall(F* f, P1 p1) {
223 return ReturnValueTraits<R>::Cast(
224 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
225 }
226 template <typename R, typename F, typename P1, typename P2>
227 R DoCall(F* f, P1 p1, P2 p2) {
228 return ReturnValueTraits<R>::Cast(
229 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
230 ParameterTraits<P2>::Cast(p2)));
231 }
232 template <typename R, typename F, typename P1, typename P2, typename P3>
233 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
234 return ReturnValueTraits<R>::Cast(CallSimulator(
235 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
236 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
237 }
238 template <typename R, typename F, typename P1, typename P2, typename P3,
239 typename P4>
240 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
241 return ReturnValueTraits<R>::Cast(CallSimulator(
242 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
243 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
244 ParameterTraits<P4>::Cast(p4)));
245 }
246#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
248 int32_t p3 = 0, int32_t p4 = 0) {
249 Simulator* simulator = Simulator::current(isolate_);
250 return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
251 }
252 template <typename R, typename F>
253 R DoCall(F* f) {
254 return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
255 }
256 template <typename R, typename F, typename P1>
257 R DoCall(F* f, P1 p1) {
258 return ReturnValueTraits<R>::Cast(
259 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
260 }
261 template <typename R, typename F, typename P1, typename P2>
262 R DoCall(F* f, P1 p1, P2 p2) {
263 return ReturnValueTraits<R>::Cast(
264 CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
265 ParameterTraits<P2>::Cast(p2)));
266 }
267 template <typename R, typename F, typename P1, typename P2, typename P3>
268 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
269 return ReturnValueTraits<R>::Cast(CallSimulator(
270 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
271 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
272 }
273 template <typename R, typename F, typename P1, typename P2, typename P3,
274 typename P4>
275 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
276 return ReturnValueTraits<R>::Cast(CallSimulator(
277 FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
278 ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
279 ParameterTraits<P4>::Cast(p4)));
280 }
281#else
282 template <typename R, typename F>
283 R DoCall(F* f) {
284 return f();
285 }
286 template <typename R, typename F, typename P1>
287 R DoCall(F* f, P1 p1) {
288 return f(p1);
289 }
290 template <typename R, typename F, typename P1, typename P2>
291 R DoCall(F* f, P1 p1, P2 p2) {
292 return f(p1, p2);
293 }
294 template <typename R, typename F, typename P1, typename P2, typename P3>
295 R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
296 return f(p1, p2, p3);
297 }
298 template <typename R, typename F, typename P1, typename P2, typename P3,
299 typename P4>
300 R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
301 return f(p1, p2, p3, p4);
302 }
303#endif
304
305#ifndef DEBUG
306 void VerifyParameters0() {}
307
308 template <typename P1>
309 void VerifyParameters1() {}
310
311 template <typename P1, typename P2>
312 void VerifyParameters2() {}
313
314 template <typename P1, typename P2, typename P3>
315 void VerifyParameters3() {}
316
317 template <typename P1, typename P2, typename P3, typename P4>
318 void VerifyParameters4() {}
319#else
320 void VerifyParameters0() { VerifyParameters(0, NULL); }
321
322 template <typename P1>
323 void VerifyParameters1() {
324 MachineType parameters[] = {ReturnValueTraits<P1>::Representation()};
325 VerifyParameters(arraysize(parameters), parameters);
326 }
327
328 template <typename P1, typename P2>
329 void VerifyParameters2() {
330 MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
331 ReturnValueTraits<P2>::Representation()};
332 VerifyParameters(arraysize(parameters), parameters);
333 }
334
335 template <typename P1, typename P2, typename P3>
336 void VerifyParameters3() {
337 MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
338 ReturnValueTraits<P2>::Representation(),
339 ReturnValueTraits<P3>::Representation()};
340 VerifyParameters(arraysize(parameters), parameters);
341 }
342
343 template <typename P1, typename P2, typename P3, typename P4>
344 void VerifyParameters4() {
345 MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
346 ReturnValueTraits<P2>::Representation(),
347 ReturnValueTraits<P3>::Representation(),
348 ReturnValueTraits<P4>::Representation()};
349 VerifyParameters(arraysize(parameters), parameters);
350 }
351#endif
352
353 // TODO(dcarney): replace Call() in CallHelper2 with these.
354 template <typename R>
355 R Call0() {
356 typedef R V8_CDECL FType();
357 VerifyParameters0();
358 return DoCall<R>(FUNCTION_CAST<FType*>(Generate()));
359 }
360
361 template <typename R, typename P1>
362 R Call1(P1 p1) {
363 typedef R V8_CDECL FType(P1);
364 VerifyParameters1<P1>();
365 return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1);
366 }
367
368 template <typename R, typename P1, typename P2>
369 R Call2(P1 p1, P2 p2) {
370 typedef R V8_CDECL FType(P1, P2);
371 VerifyParameters2<P1, P2>();
372 return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2);
373 }
374
375 template <typename R, typename P1, typename P2, typename P3>
376 R Call3(P1 p1, P2 p2, P3 p3) {
377 typedef R V8_CDECL FType(P1, P2, P3);
378 VerifyParameters3<P1, P2, P3>();
379 return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
380 }
381
382 template <typename R, typename P1, typename P2, typename P3, typename P4>
383 R Call4(P1 p1, P2 p2, P3 p3, P4 p4) {
384 typedef R V8_CDECL FType(P1, P2, P3, P4);
385 VerifyParameters4<P1, P2, P3, P4>();
386 return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
387 }
388
389 template <typename R, typename C>
390 friend class CallHelper2;
391 Isolate* isolate_;
392};
393
394
395// TODO(dcarney): replace CallHelper with CallHelper2 and rename.
396template <typename R, typename C>
397class CallHelper2 {
398 public:
399 R Call() { return helper()->template Call0<R>(); }
400
401 template <typename P1>
402 R Call(P1 p1) {
403 return helper()->template Call1<R>(p1);
404 }
405
406 template <typename P1, typename P2>
407 R Call(P1 p1, P2 p2) {
408 return helper()->template Call2<R>(p1, p2);
409 }
410
411 template <typename P1, typename P2, typename P3>
412 R Call(P1 p1, P2 p2, P3 p3) {
413 return helper()->template Call3<R>(p1, p2, p3);
414 }
415
416 template <typename P1, typename P2, typename P3, typename P4>
417 R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
418 return helper()->template Call4<R>(p1, p2, p3, p4);
419 }
420
421 private:
422 CallHelper* helper() { return static_cast<C*>(this); }
423};
424
425} // namespace compiler
426} // namespace internal
427} // namespace v8
428
429#endif // V8_CCTEST_COMPILER_CALL_TESTER_H_