1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | // This file contains test functions for the dart:ffi test cases. |
6 | // This file is not allowed to depend on any symbols from the embedder and is |
7 | // therefore not allowed to use `dart_api.h`. (The flutter/flutter integration |
8 | // tests will run dart tests using this library only.) |
9 | |
10 | #include <stddef.h> |
11 | #include <stdlib.h> |
12 | #include <sys/types.h> |
13 | |
14 | #include <cmath> |
15 | #include <iostream> |
16 | #include <limits> |
17 | |
18 | #if defined(_WIN32) |
19 | #define DART_EXPORT extern "C" __declspec(dllexport) |
20 | #else |
21 | #define DART_EXPORT \ |
22 | extern "C" __attribute__((visibility("default"))) __attribute((used)) |
23 | #endif |
24 | |
25 | namespace dart { |
26 | |
27 | #define CHECK(X) \ |
28 | if (!(X)) { \ |
29 | fprintf(stderr, "%s\n", "Check failed: " #X); \ |
30 | return 1; \ |
31 | } |
32 | |
33 | #define CHECK_EQ(X, Y) CHECK((X) == (Y)) |
34 | |
35 | //////////////////////////////////////////////////////////////////////////////// |
36 | // Tests for Dart -> native calls. |
37 | // |
38 | // Note: If this interface is changed please also update |
39 | // sdk/runtime/tools/dartfuzz/ffiapi.dart |
40 | |
41 | int32_t globalVar; |
42 | |
43 | DART_EXPORT void SetGlobalVar(int32_t v) { |
44 | globalVar = v; |
45 | } |
46 | |
47 | DART_EXPORT int32_t GetGlobalVar() { |
48 | return globalVar; |
49 | } |
50 | |
51 | // Sums two ints and adds 42. |
52 | // Simple function to test trampolines. |
53 | // Also used for testing argument exception on passing null instead of a Dart |
54 | // int. |
55 | DART_EXPORT int32_t SumPlus42(int32_t a, int32_t b) { |
56 | std::cout << "SumPlus42(" << a << ", " << b << ")\n" ; |
57 | const int32_t retval = 42 + a + b; |
58 | std::cout << "returning " << retval << "\n" ; |
59 | return retval; |
60 | } |
61 | |
62 | // Tests for sign and zero extension return values when passed to Dart. |
63 | DART_EXPORT uint8_t ReturnMaxUint8() { |
64 | return 0xff; |
65 | } |
66 | |
67 | DART_EXPORT uint16_t ReturnMaxUint16() { |
68 | return 0xffff; |
69 | } |
70 | |
71 | DART_EXPORT uint32_t ReturnMaxUint32() { |
72 | return 0xffffffff; |
73 | } |
74 | |
75 | DART_EXPORT int8_t ReturnMinInt8() { |
76 | return 0x80; |
77 | } |
78 | |
79 | DART_EXPORT int16_t ReturnMinInt16() { |
80 | return 0x8000; |
81 | } |
82 | |
83 | DART_EXPORT int32_t ReturnMinInt32() { |
84 | return 0x80000000; |
85 | } |
86 | |
87 | // Test that return values are truncated by callee before passed to Dart. |
88 | DART_EXPORT uint8_t ReturnMaxUint8v2() { |
89 | uint64_t v = 0xabcff; |
90 | // Truncated to 8 bits and zero extended, or truncated to 32 bits, depending |
91 | // on ABI. |
92 | return v; |
93 | } |
94 | |
95 | DART_EXPORT uint16_t ReturnMaxUint16v2() { |
96 | uint64_t v = 0xabcffff; |
97 | return v; |
98 | } |
99 | |
100 | DART_EXPORT uint32_t ReturnMaxUint32v2() { |
101 | uint64_t v = 0xabcffffffff; |
102 | return v; |
103 | } |
104 | |
105 | DART_EXPORT int8_t ReturnMinInt8v2() { |
106 | int64_t v = 0x8abc80; |
107 | return v; |
108 | } |
109 | |
110 | DART_EXPORT int16_t ReturnMinInt16v2() { |
111 | int64_t v = 0x8abc8000; |
112 | return v; |
113 | } |
114 | |
115 | DART_EXPORT int32_t ReturnMinInt32v2() { |
116 | int64_t v = 0x8abc80000000; |
117 | return v; |
118 | } |
119 | |
120 | // Test that arguments are truncated correctly. |
121 | DART_EXPORT intptr_t TakeMaxUint8(uint8_t x) { |
122 | std::cout << "TakeMaxUint8(" << static_cast<int>(x) << ")\n" ; |
123 | return x == 0xff ? 1 : 0; |
124 | } |
125 | |
126 | DART_EXPORT intptr_t TakeMaxUint16(uint16_t x) { |
127 | std::cout << "TakeMaxUint16(" << x << ")\n" ; |
128 | return x == 0xffff ? 1 : 0; |
129 | } |
130 | |
131 | DART_EXPORT intptr_t TakeMaxUint32(uint32_t x) { |
132 | std::cout << "TakeMaxUint32(" << x << ")\n" ; |
133 | return x == 0xffffffff ? 1 : 0; |
134 | } |
135 | |
136 | DART_EXPORT intptr_t TakeMinInt8(int8_t x) { |
137 | std::cout << "TakeMinInt8(" << static_cast<int>(x) << ")\n" ; |
138 | const int64_t expected = -0x80; |
139 | const int64_t received = x; |
140 | return expected == received ? 1 : 0; |
141 | } |
142 | |
143 | DART_EXPORT intptr_t TakeMinInt16(int16_t x) { |
144 | std::cout << "TakeMinInt16(" << x << ")\n" ; |
145 | const int64_t expected = -0x8000; |
146 | const int64_t received = x; |
147 | return expected == received ? 1 : 0; |
148 | } |
149 | |
150 | DART_EXPORT intptr_t TakeMinInt32(int32_t x) { |
151 | std::cout << "TakeMinInt32(" << x << ")\n" ; |
152 | const int64_t expected = INT32_MIN; |
153 | const int64_t received = x; |
154 | return expected == received ? 1 : 0; |
155 | } |
156 | |
157 | // Test that arguments are truncated correctly, including stack arguments |
158 | DART_EXPORT intptr_t TakeMaxUint8x10(uint8_t a, |
159 | uint8_t b, |
160 | uint8_t c, |
161 | uint8_t d, |
162 | uint8_t e, |
163 | uint8_t f, |
164 | uint8_t g, |
165 | uint8_t h, |
166 | uint8_t i, |
167 | uint8_t j) { |
168 | std::cout << "TakeMaxUint8x10(" << static_cast<int>(a) << ", " |
169 | << static_cast<int>(b) << ", " << static_cast<int>(c) << ", " |
170 | << static_cast<int>(d) << ", " << static_cast<int>(e) << ", " |
171 | << static_cast<int>(f) << ", " << static_cast<int>(g) << ", " |
172 | << static_cast<int>(h) << ", " << static_cast<int>(i) << ", " |
173 | << static_cast<int>(j) << ", " |
174 | << ")\n" ; |
175 | return (a == 0xff && b == 0xff && c == 0xff && d == 0xff && e == 0xff && |
176 | f == 0xff && g == 0xff && h == 0xff && i == 0xff && j == 0xff) |
177 | ? 1 |
178 | : 0; |
179 | } |
180 | |
181 | // Performs some computation on various sized signed ints. |
182 | // Used for testing value ranges for signed ints. |
183 | DART_EXPORT int64_t IntComputation(int8_t a, int16_t b, int32_t c, int64_t d) { |
184 | std::cout << "IntComputation(" << static_cast<int>(a) << ", " << b << ", " |
185 | << c << ", " << d << ")\n" ; |
186 | const int64_t retval = d - c + b - a; |
187 | std::cout << "returning " << retval << "\n" ; |
188 | return retval; |
189 | } |
190 | |
191 | // Used in regress_39044_test.dart. |
192 | DART_EXPORT int64_t Regress39044(int64_t a, int8_t b) { |
193 | std::cout << "Regress39044(" << a << ", " << static_cast<int>(b) << ")\n" ; |
194 | const int64_t retval = a - b; |
195 | std::cout << "returning " << retval << "\n" ; |
196 | return retval; |
197 | } |
198 | |
199 | DART_EXPORT intptr_t Regress40537(uint8_t x) { |
200 | std::cout << "Regress40537(" << static_cast<int>(x) << ")\n" ; |
201 | return x == 249 ? 1 : 0; |
202 | } |
203 | |
204 | DART_EXPORT intptr_t Regress40537Variant2(uint8_t x) { |
205 | std::cout << "Regress40537Variant2(" << static_cast<int>(x) << ")\n" ; |
206 | return x; |
207 | } |
208 | |
209 | DART_EXPORT uint8_t Regress40537Variant3(intptr_t x) { |
210 | std::cout << "Regress40537Variant3(" << static_cast<int>(x) << ")\n" ; |
211 | return x; |
212 | } |
213 | |
214 | // Performs some computation on various sized unsigned ints. |
215 | // Used for testing value ranges for unsigned ints. |
216 | DART_EXPORT int64_t UintComputation(uint8_t a, |
217 | uint16_t b, |
218 | uint32_t c, |
219 | uint64_t d) { |
220 | std::cout << "UintComputation(" << static_cast<int>(a) << ", " << b << ", " |
221 | << c << ", " << d << ")\n" ; |
222 | const uint64_t retval = d - c + b - a; |
223 | std::cout << "returning " << retval << "\n" ; |
224 | return retval; |
225 | } |
226 | |
227 | // Multiplies pointer sized intptr_t by three. |
228 | // Used for testing pointer sized parameter and return value. |
229 | DART_EXPORT intptr_t Times3(intptr_t a) { |
230 | std::cout << "Times3(" << a << ")\n" ; |
231 | const intptr_t retval = a * 3; |
232 | std::cout << "returning " << retval << "\n" ; |
233 | return retval; |
234 | } |
235 | |
236 | // Multiples a double by 1.337. |
237 | // Used for testing double parameter and return value. |
238 | // Also used for testing argument exception on passing null instead of a Dart |
239 | // double. |
240 | DART_EXPORT double Times1_337Double(double a) { |
241 | std::cout << "Times1_337Double(" << a << ")\n" ; |
242 | const double retval = a * 1.337; |
243 | std::cout << "returning " << retval << "\n" ; |
244 | return retval; |
245 | } |
246 | |
247 | // Multiples a float by 1.337. |
248 | // Used for testing float parameter and return value. |
249 | DART_EXPORT float Times1_337Float(float a) { |
250 | std::cout << "Times1_337Float(" << a << ")\n" ; |
251 | const float retval = a * 1.337f; |
252 | std::cout << "returning " << retval << "\n" ; |
253 | return retval; |
254 | } |
255 | |
256 | // Sums many ints. |
257 | // Used for testing calling conventions. With so many integers we are using all |
258 | // normal parameter registers and some stack slots. |
259 | DART_EXPORT intptr_t SumManyInts(intptr_t a, |
260 | intptr_t b, |
261 | intptr_t c, |
262 | intptr_t d, |
263 | intptr_t e, |
264 | intptr_t f, |
265 | intptr_t g, |
266 | intptr_t h, |
267 | intptr_t i, |
268 | intptr_t j) { |
269 | std::cout << "SumManyInts(" << a << ", " << b << ", " << c << ", " << d |
270 | << ", " << e << ", " << f << ", " << g << ", " << h << ", " << i |
271 | << ", " << j << ")\n" ; |
272 | const intptr_t retval = a + b + c + d + e + f + g + h + i + j; |
273 | std::cout << "returning " << retval << "\n" ; |
274 | return retval; |
275 | } |
276 | |
277 | // Sums many ints. |
278 | // Used for testing calling conventions. With small integers on stack slots we |
279 | // test stack alignment. |
280 | DART_EXPORT int16_t SumManySmallInts(int8_t a, |
281 | int16_t b, |
282 | int8_t c, |
283 | int16_t d, |
284 | int8_t e, |
285 | int16_t f, |
286 | int8_t g, |
287 | int16_t h, |
288 | int8_t i, |
289 | int16_t j) { |
290 | std::cout << "SumManySmallInts(" << static_cast<int>(a) << ", " << b << ", " |
291 | << static_cast<int>(c) << ", " << d << ", " << static_cast<int>(e) |
292 | << ", " << f << ", " << static_cast<int>(g) << ", " << h << ", " |
293 | << static_cast<int>(i) << ", " << j << ")\n" ; |
294 | const int16_t retval = a + b + c + d + e + f + g + h + i + j; |
295 | std::cout << "returning " << retval << "\n" ; |
296 | return retval; |
297 | } |
298 | |
299 | // Used for testing floating point argument backfilling on Arm32 in hardfp. |
300 | DART_EXPORT double SumFloatsAndDoubles(float a, double b, float c) { |
301 | std::cout << "SumFloatsAndDoubles(" << a << ", " << b << ", " << c << ")\n" ; |
302 | const double retval = a + b + c; |
303 | std::cout << "returning " << retval << "\n" ; |
304 | return retval; |
305 | } |
306 | |
307 | // Very many small integers, tests alignment on stack. |
308 | DART_EXPORT int16_t SumVeryManySmallInts(int8_t a01, |
309 | int16_t a02, |
310 | int8_t a03, |
311 | int16_t a04, |
312 | int8_t a05, |
313 | int16_t a06, |
314 | int8_t a07, |
315 | int16_t a08, |
316 | int8_t a09, |
317 | int16_t a10, |
318 | int8_t a11, |
319 | int16_t a12, |
320 | int8_t a13, |
321 | int16_t a14, |
322 | int8_t a15, |
323 | int16_t a16, |
324 | int8_t a17, |
325 | int16_t a18, |
326 | int8_t a19, |
327 | int16_t a20, |
328 | int8_t a21, |
329 | int16_t a22, |
330 | int8_t a23, |
331 | int16_t a24, |
332 | int8_t a25, |
333 | int16_t a26, |
334 | int8_t a27, |
335 | int16_t a28, |
336 | int8_t a29, |
337 | int16_t a30, |
338 | int8_t a31, |
339 | int16_t a32, |
340 | int8_t a33, |
341 | int16_t a34, |
342 | int8_t a35, |
343 | int16_t a36, |
344 | int8_t a37, |
345 | int16_t a38, |
346 | int8_t a39, |
347 | int16_t a40) { |
348 | std::cout << "SumVeryManySmallInts(" << static_cast<int>(a01) << ", " << a02 |
349 | << ", " << static_cast<int>(a03) << ", " << a04 << ", " |
350 | << static_cast<int>(a05) << ", " << a06 << ", " |
351 | << static_cast<int>(a07) << ", " << a08 << ", " |
352 | << static_cast<int>(a09) << ", " << a10 << ", " |
353 | << static_cast<int>(a11) << ", " << a12 << ", " |
354 | << static_cast<int>(a13) << ", " << a14 << ", " |
355 | << static_cast<int>(a15) << ", " << a16 << ", " |
356 | << static_cast<int>(a17) << ", " << a18 << ", " |
357 | << static_cast<int>(a19) << ", " << a20 << ", " |
358 | << static_cast<int>(a21) << ", " << a22 << ", " |
359 | << static_cast<int>(a23) << ", " << a24 << ", " |
360 | << static_cast<int>(a25) << ", " << a26 << ", " |
361 | << static_cast<int>(a27) << ", " << a28 << ", " |
362 | << static_cast<int>(a29) << ", " << a30 << ", " |
363 | << static_cast<int>(a31) << ", " << a32 << ", " |
364 | << static_cast<int>(a33) << ", " << a34 << ", " |
365 | << static_cast<int>(a35) << ", " << a36 << ", " |
366 | << static_cast<int>(a37) << ", " << a38 << ", " |
367 | << static_cast<int>(a39) << ", " << a40 << ")\n" ; |
368 | const int16_t retval = a01 + a02 + a03 + a04 + a05 + a06 + a07 + a08 + a09 + |
369 | a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + |
370 | a19 + a20 + a21 + a22 + a23 + a24 + a25 + a26 + a27 + |
371 | a28 + a29 + a30 + a31 + a32 + a33 + a34 + a35 + a36 + |
372 | a37 + a38 + a39 + a40; |
373 | std::cout << "returning " << retval << "\n" ; |
374 | return retval; |
375 | } |
376 | |
377 | // Very many floating points, tests alignment on stack, and packing in |
378 | // floating point registers in hardfp. |
379 | DART_EXPORT double SumVeryManyFloatsDoubles(float a01, |
380 | double a02, |
381 | float a03, |
382 | double a04, |
383 | float a05, |
384 | double a06, |
385 | float a07, |
386 | double a08, |
387 | float a09, |
388 | double a10, |
389 | float a11, |
390 | double a12, |
391 | float a13, |
392 | double a14, |
393 | float a15, |
394 | double a16, |
395 | float a17, |
396 | double a18, |
397 | float a19, |
398 | double a20, |
399 | float a21, |
400 | double a22, |
401 | float a23, |
402 | double a24, |
403 | float a25, |
404 | double a26, |
405 | float a27, |
406 | double a28, |
407 | float a29, |
408 | double a30, |
409 | float a31, |
410 | double a32, |
411 | float a33, |
412 | double a34, |
413 | float a35, |
414 | double a36, |
415 | float a37, |
416 | double a38, |
417 | float a39, |
418 | double a40) { |
419 | std::cout << "SumVeryManyFloatsDoubles(" << a01 << ", " << a02 << ", " << a03 |
420 | << ", " << a04 << ", " << a05 << ", " << a06 << ", " << a07 << ", " |
421 | << a08 << ", " << a09 << ", " << a10 << ", " << a11 << ", " << a12 |
422 | << ", " << a13 << ", " << a14 << ", " << a15 << ", " << a16 << ", " |
423 | << a17 << ", " << a18 << ", " << a19 << ", " << a20 << ", " << a21 |
424 | << ", " << a22 << ", " << a23 << ", " << a24 << ", " << a25 << ", " |
425 | << a26 << ", " << a27 << ", " << a28 << ", " << a29 << ", " << a30 |
426 | << ", " << a31 << ", " << a32 << ", " << a33 << ", " << a34 << ", " |
427 | << a35 << ", " << a36 << ", " << a37 << ", " << a38 << ", " << a39 |
428 | << ", " << a40 << ")\n" ; |
429 | const double retval = a01 + a02 + a03 + a04 + a05 + a06 + a07 + a08 + a09 + |
430 | a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + |
431 | a19 + a20 + a21 + a22 + a23 + a24 + a25 + a26 + a27 + |
432 | a28 + a29 + a30 + a31 + a32 + a33 + a34 + a35 + a36 + |
433 | a37 + a38 + a39 + a40; |
434 | std::cout << "returning " << retval << "\n" ; |
435 | return retval; |
436 | } |
437 | |
438 | // Sums an odd number of ints. |
439 | // Used for testing calling conventions. With so many arguments, and an odd |
440 | // number of arguments, we are testing stack alignment on various architectures. |
441 | DART_EXPORT intptr_t SumManyIntsOdd(intptr_t a, |
442 | intptr_t b, |
443 | intptr_t c, |
444 | intptr_t d, |
445 | intptr_t e, |
446 | intptr_t f, |
447 | intptr_t g, |
448 | intptr_t h, |
449 | intptr_t i, |
450 | intptr_t j, |
451 | intptr_t k) { |
452 | std::cout << "SumManyInts(" << a << ", " << b << ", " << c << ", " << d |
453 | << ", " << e << ", " << f << ", " << g << ", " << h << ", " << i |
454 | << ", " << j << ", " << k << ")\n" ; |
455 | const intptr_t retval = a + b + c + d + e + f + g + h + i + j + k; |
456 | std::cout << "returning " << retval << "\n" ; |
457 | return retval; |
458 | } |
459 | |
460 | // Sums many doubles. |
461 | // Used for testing calling conventions. With so many doubles we are using all |
462 | // xmm parameter registers and some stack slots. |
463 | DART_EXPORT double SumManyDoubles(double a, |
464 | double b, |
465 | double c, |
466 | double d, |
467 | double e, |
468 | double f, |
469 | double g, |
470 | double h, |
471 | double i, |
472 | double j) { |
473 | std::cout << "SumManyDoubles(" << a << ", " << b << ", " << c << ", " << d |
474 | << ", " << e << ", " << f << ", " << g << ", " << h << ", " << i |
475 | << ", " << j << ")\n" ; |
476 | const double retval = a + b + c + d + e + f + g + h + i + j; |
477 | std::cout << "returning " << retval << "\n" ; |
478 | return retval; |
479 | } |
480 | |
481 | // Sums many numbers. |
482 | // Used for testing calling conventions. With so many parameters we are using |
483 | // both registers and stack slots. |
484 | DART_EXPORT double SumManyNumbers(intptr_t a, |
485 | float b, |
486 | intptr_t c, |
487 | double d, |
488 | intptr_t e, |
489 | float f, |
490 | intptr_t g, |
491 | double h, |
492 | intptr_t i, |
493 | float j, |
494 | intptr_t k, |
495 | double l, |
496 | intptr_t m, |
497 | float n, |
498 | intptr_t o, |
499 | double p, |
500 | intptr_t q, |
501 | float r, |
502 | intptr_t s, |
503 | double t) { |
504 | std::cout << "SumManyNumbers(" << a << ", " << b << ", " << c << ", " << d |
505 | << ", " << e << ", " << f << ", " << g << ", " << h << ", " << i |
506 | << ", " << j << ", " << k << ", " << l << ", " << m << ", " << n |
507 | << ", " << o << ", " << p << ", " << q << ", " << r << ", " << s |
508 | << ", " << t << ")\n" ; |
509 | const double retval = a + b + c + d + e + f + g + h + i + j + k + l + m + n + |
510 | o + p + q + r + s + t; |
511 | std::cout << "returning " << retval << "\n" ; |
512 | return retval; |
513 | } |
514 | |
515 | // Assigns 1337 to the second element and returns the address of that element. |
516 | // Used for testing Pointer parameters and return values. |
517 | DART_EXPORT int64_t* Assign1337Index1(int64_t* a) { |
518 | std::cout << "Assign1337Index1(" << a << ")\n" ; |
519 | std::cout << "val[0] = " << a[0] << "\n" ; |
520 | std::cout << "val[1] = " << a[1] << "\n" ; |
521 | a[1] = 1337; |
522 | std::cout << "val[1] = " << a[1] << "\n" ; |
523 | int64_t* retval = a + 1; |
524 | std::cout << "returning " << retval << "\n" ; |
525 | return retval; |
526 | } |
527 | |
528 | struct Coord { |
529 | double x; |
530 | double y; |
531 | Coord* next; |
532 | }; |
533 | |
534 | // Transposes Coordinate by (10, 10) and returns next Coordinate. |
535 | // Used for testing struct pointer parameter, struct pointer return value, |
536 | // struct field access, and struct pointer field dereference. |
537 | DART_EXPORT Coord* TransposeCoordinate(Coord* coord) { |
538 | std::cout << "TransposeCoordinate(" << coord << " {" << coord->x << ", " |
539 | << coord->y << ", " << coord->next << "})\n" ; |
540 | coord->x = coord->x + 10.0; |
541 | coord->y = coord->y + 10.0; |
542 | std::cout << "returning " << coord->next << "\n" ; |
543 | return coord->next; |
544 | } |
545 | |
546 | // Takes a Coordinate array and returns a Coordinate pointer to the next |
547 | // element. |
548 | // Used for testing struct arrays. |
549 | DART_EXPORT Coord* CoordinateElemAt1(Coord* coord) { |
550 | std::cout << "CoordinateElemAt1(" << coord << ")\n" ; |
551 | std::cout << "sizeof(Coord): " << sizeof(Coord) << "\n" ; |
552 | std::cout << "coord[0] = {" << coord[0].x << ", " << coord[0].y << ", " |
553 | << coord[0].next << "}\n" ; |
554 | std::cout << "coord[1] = {" << coord[1].x << ", " << coord[1].y << ", " |
555 | << coord[1].next << "}\n" ; |
556 | Coord* retval = coord + 1; |
557 | std::cout << "returning " << retval << "\n" ; |
558 | return retval; |
559 | } |
560 | |
561 | typedef Coord* (*CoordUnOp)(Coord* coord); |
562 | |
563 | // Takes a Coordinate Function(Coordinate) and applies it three times to a |
564 | // Coordinate. |
565 | // Used for testing function pointers with structs. |
566 | DART_EXPORT Coord* CoordinateUnOpTrice(CoordUnOp unop, Coord* coord) { |
567 | std::cout << "CoordinateUnOpTrice(" << &unop << ", " << coord << ")\n" ; |
568 | Coord* retval = unop(unop(unop(coord))); |
569 | std::cout << "returning " << retval << "\n" ; |
570 | return retval; |
571 | } |
572 | |
573 | typedef intptr_t (*IntptrBinOp)(intptr_t a, intptr_t b); |
574 | |
575 | // Returns a closure. |
576 | // Note this closure is not properly marked as DART_EXPORT or extern "C". |
577 | // Used for testing passing a pointer to a closure to Dart. |
578 | // TODO(dacoharkes): is this a supported use case? |
579 | DART_EXPORT IntptrBinOp IntptrAdditionClosure() { |
580 | std::cout << "IntptrAdditionClosure()\n" ; |
581 | IntptrBinOp retval = [](intptr_t a, intptr_t b) { return a + b; }; |
582 | std::cout << "returning " << &retval << "\n" ; |
583 | return retval; |
584 | } |
585 | |
586 | // Applies an intptr binop function to 42 and 74. |
587 | // Used for testing passing a function pointer to C. |
588 | DART_EXPORT intptr_t ApplyTo42And74(IntptrBinOp binop) { |
589 | std::cout << "ApplyTo42And74()\n" ; |
590 | intptr_t retval = binop(42, 74); |
591 | std::cout << "returning " << retval << "\n" ; |
592 | return retval; |
593 | } |
594 | |
595 | // Returns next element in the array, unless a null pointer is passed. |
596 | // When a null pointer is passed, a null pointer is returned. |
597 | // Used for testing null pointers. |
598 | DART_EXPORT int64_t* NullableInt64ElemAt1(int64_t* a) { |
599 | std::cout << "NullableInt64ElemAt1(" << a << ")\n" ; |
600 | int64_t* retval; |
601 | if (a != nullptr) { |
602 | std::cout << "not null pointer, address: " << a << "\n" ; |
603 | retval = a + 1; |
604 | } else { |
605 | std::cout << "null pointer, address: " << a << "\n" ; |
606 | retval = nullptr; |
607 | } |
608 | std::cout << "returning " << retval << "\n" ; |
609 | return retval; |
610 | } |
611 | |
612 | // A struct designed to exercise all kinds of alignment rules. |
613 | // Note that offset32A (System V ia32) aligns doubles on 4 bytes while offset32B |
614 | // (Arm 32 bit and MSVC ia32) aligns on 8 bytes. |
615 | // TODO(37271): Support nested structs. |
616 | // TODO(37470): Add uncommon primitive data types when we want to support them. |
617 | struct VeryLargeStruct { |
618 | // size32 size64 offset32A offset32B offset64 |
619 | int8_t a; // 1 0 0 0 |
620 | int16_t b; // 2 2 2 2 |
621 | int32_t c; // 4 4 4 4 |
622 | int64_t d; // 8 8 8 8 |
623 | uint8_t e; // 1 16 16 16 |
624 | uint16_t f; // 2 18 18 18 |
625 | uint32_t g; // 4 20 20 20 |
626 | uint64_t h; // 8 24 24 24 |
627 | intptr_t i; // 4 8 32 32 32 |
628 | double j; // 8 36 40 40 |
629 | float k; // 4 44 48 48 |
630 | VeryLargeStruct* parent; // 4 8 48 52 56 |
631 | intptr_t numChildren; // 4 8 52 56 64 |
632 | VeryLargeStruct* children; // 4 8 56 60 72 |
633 | int8_t smallLastField; // 1 60 64 80 |
634 | // sizeof 64 72 88 |
635 | }; |
636 | |
637 | // Sums the fields of a very large struct, including the first field (a) from |
638 | // the parent and children. |
639 | // Used for testing alignment and padding in structs. |
640 | DART_EXPORT int64_t SumVeryLargeStruct(VeryLargeStruct* vls) { |
641 | std::cout << "SumVeryLargeStruct(" << vls << ")\n" ; |
642 | std::cout << "offsetof(a): " << offsetof(VeryLargeStruct, a) << "\n" ; |
643 | std::cout << "offsetof(b): " << offsetof(VeryLargeStruct, b) << "\n" ; |
644 | std::cout << "offsetof(c): " << offsetof(VeryLargeStruct, c) << "\n" ; |
645 | std::cout << "offsetof(d): " << offsetof(VeryLargeStruct, d) << "\n" ; |
646 | std::cout << "offsetof(e): " << offsetof(VeryLargeStruct, e) << "\n" ; |
647 | std::cout << "offsetof(f): " << offsetof(VeryLargeStruct, f) << "\n" ; |
648 | std::cout << "offsetof(g): " << offsetof(VeryLargeStruct, g) << "\n" ; |
649 | std::cout << "offsetof(h): " << offsetof(VeryLargeStruct, h) << "\n" ; |
650 | std::cout << "offsetof(i): " << offsetof(VeryLargeStruct, i) << "\n" ; |
651 | std::cout << "offsetof(j): " << offsetof(VeryLargeStruct, j) << "\n" ; |
652 | std::cout << "offsetof(k): " << offsetof(VeryLargeStruct, k) << "\n" ; |
653 | std::cout << "offsetof(parent): " << offsetof(VeryLargeStruct, parent) |
654 | << "\n" ; |
655 | std::cout << "offsetof(numChildren): " |
656 | << offsetof(VeryLargeStruct, numChildren) << "\n" ; |
657 | std::cout << "offsetof(children): " << offsetof(VeryLargeStruct, children) |
658 | << "\n" ; |
659 | std::cout << "offsetof(smallLastField): " |
660 | << offsetof(VeryLargeStruct, smallLastField) << "\n" ; |
661 | std::cout << "sizeof(VeryLargeStruct): " << sizeof(VeryLargeStruct) << "\n" ; |
662 | |
663 | std::cout << "vls->a: " << static_cast<int>(vls->a) << "\n" ; |
664 | std::cout << "vls->b: " << vls->b << "\n" ; |
665 | std::cout << "vls->c: " << vls->c << "\n" ; |
666 | std::cout << "vls->d: " << vls->d << "\n" ; |
667 | std::cout << "vls->e: " << static_cast<int>(vls->e) << "\n" ; |
668 | std::cout << "vls->f: " << vls->f << "\n" ; |
669 | std::cout << "vls->g: " << vls->g << "\n" ; |
670 | std::cout << "vls->h: " << vls->h << "\n" ; |
671 | std::cout << "vls->i: " << vls->i << "\n" ; |
672 | std::cout << "vls->j: " << vls->j << "\n" ; |
673 | std::cout << "vls->k: " << vls->k << "\n" ; |
674 | std::cout << "vls->parent: " << vls->parent << "\n" ; |
675 | std::cout << "vls->numChildren: " << vls->numChildren << "\n" ; |
676 | std::cout << "vls->children: " << vls->children << "\n" ; |
677 | std::cout << "vls->smallLastField: " << static_cast<int>(vls->smallLastField) |
678 | << "\n" ; |
679 | |
680 | int64_t retval = 0; |
681 | retval += 0x0L + vls->a; |
682 | retval += vls->b; |
683 | retval += vls->c; |
684 | retval += vls->d; |
685 | retval += vls->e; |
686 | retval += vls->f; |
687 | retval += vls->g; |
688 | retval += vls->h; |
689 | retval += vls->i; |
690 | retval += vls->j; |
691 | retval += vls->k; |
692 | retval += vls->smallLastField; |
693 | std::cout << retval << "\n" ; |
694 | if (vls->parent != nullptr) { |
695 | std::cout << "has parent\n" ; |
696 | retval += vls->parent->a; |
697 | } |
698 | std::cout << "has " << vls->numChildren << " children\n" ; |
699 | for (intptr_t i = 0; i < vls->numChildren; i++) { |
700 | retval += vls->children[i].a; |
701 | } |
702 | std::cout << "returning " << retval << "\n" ; |
703 | return retval; |
704 | } |
705 | |
706 | // Sums numbers of various sizes. |
707 | // Used for testing truncation and sign extension of non 64 bit parameters. |
708 | DART_EXPORT int64_t SumSmallNumbers(int8_t a, |
709 | int16_t b, |
710 | int32_t c, |
711 | uint8_t d, |
712 | uint16_t e, |
713 | uint32_t f) { |
714 | std::cout << "SumSmallNumbers(" << static_cast<int>(a) << ", " << b << ", " |
715 | << c << ", " << static_cast<int>(d) << ", " << e << ", " << f |
716 | << ")\n" ; |
717 | int64_t retval = 0; |
718 | retval += a; |
719 | retval += b; |
720 | retval += c; |
721 | retval += d; |
722 | retval += e; |
723 | retval += f; |
724 | std::cout << "returning " << retval << "\n" ; |
725 | return retval; |
726 | } |
727 | |
728 | // Checks whether the float is between 1336.0f and 1338.0f. |
729 | // Used for testing rounding of Dart Doubles to floats in Pointer.store(). |
730 | DART_EXPORT uint8_t IsRoughly1337(float* a) { |
731 | std::cout << "IsRoughly1337(" << a[0] << ")\n" ; |
732 | uint8_t retval = (1336.0f < a[0] && a[0] < 1338.0f) ? 1 : 0; |
733 | std::cout << "returning " << static_cast<int>(retval) << "\n" ; |
734 | return retval; |
735 | } |
736 | |
737 | // Does nothing with input. |
738 | // Used for testing functions that return void |
739 | DART_EXPORT void DevNullFloat(float a) { |
740 | std::cout << "DevNullFloat(" << a << ")\n" ; |
741 | std::cout << "returning nothing\n" ; |
742 | } |
743 | |
744 | // Invents an elite floating pointptr_t number. |
745 | // Used for testing functions that do not take any arguments. |
746 | DART_EXPORT float InventFloatValue() { |
747 | std::cout << "InventFloatValue()\n" ; |
748 | const float retval = 1337.0f; |
749 | std::cout << "returning " << retval << "\n" ; |
750 | return retval; |
751 | } |
752 | |
753 | //////////////////////////////////////////////////////////////////////////////// |
754 | // Tests for callbacks. |
755 | |
756 | // Sanity test. |
757 | DART_EXPORT intptr_t TestSimpleAddition(intptr_t (*add)(int, int)) { |
758 | CHECK_EQ(add(10, 20), 30); |
759 | return 0; |
760 | } |
761 | |
762 | //// Following tests are copied from above, with the role of Dart and C++ code |
763 | //// reversed. |
764 | |
765 | DART_EXPORT intptr_t |
766 | TestIntComputation(int64_t (*fn)(int8_t, int16_t, int32_t, int64_t)) { |
767 | CHECK_EQ(fn(125, 250, 500, 1000), 625); |
768 | CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL)); |
769 | CHECK_EQ(((int64_t)-0x8000000000000000LL), |
770 | fn(0, 0, 0, -0x8000000000000000LL)); |
771 | return 0; |
772 | } |
773 | |
774 | DART_EXPORT intptr_t |
775 | TestUintComputation(uint64_t (*fn)(uint8_t, uint16_t, uint32_t, uint64_t)) { |
776 | CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL)); |
777 | CHECK_EQ(-0x8000000000000000LL, fn(0, 0, 0, -0x8000000000000000LL)); |
778 | CHECK_EQ(-1, (int64_t)fn(0, 0, 0, -1)); |
779 | return 0; |
780 | } |
781 | |
782 | DART_EXPORT intptr_t TestSimpleMultiply(double (*fn)(double)) { |
783 | CHECK_EQ(fn(2.0), 2.0 * 1.337); |
784 | return 0; |
785 | } |
786 | |
787 | DART_EXPORT intptr_t TestSimpleMultiplyFloat(float (*fn)(float)) { |
788 | CHECK(::std::abs(fn(2.0) - 2.0 * 1.337) < 0.001); |
789 | return 0; |
790 | } |
791 | |
792 | DART_EXPORT intptr_t TestManyInts(intptr_t (*fn)(intptr_t, |
793 | intptr_t, |
794 | intptr_t, |
795 | intptr_t, |
796 | intptr_t, |
797 | intptr_t, |
798 | intptr_t, |
799 | intptr_t, |
800 | intptr_t, |
801 | intptr_t)) { |
802 | CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); |
803 | return 0; |
804 | } |
805 | |
806 | DART_EXPORT intptr_t TestManyDoubles(double (*fn)(double, |
807 | double, |
808 | double, |
809 | double, |
810 | double, |
811 | double, |
812 | double, |
813 | double, |
814 | double, |
815 | double)) { |
816 | CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); |
817 | return 0; |
818 | } |
819 | |
820 | DART_EXPORT intptr_t TestManyArgs(double (*fn)(intptr_t a, |
821 | float b, |
822 | intptr_t c, |
823 | double d, |
824 | intptr_t e, |
825 | float f, |
826 | intptr_t g, |
827 | double h, |
828 | intptr_t i, |
829 | float j, |
830 | intptr_t k, |
831 | double l, |
832 | intptr_t m, |
833 | float n, |
834 | intptr_t o, |
835 | double p, |
836 | intptr_t q, |
837 | float r, |
838 | intptr_t s, |
839 | double t)) { |
840 | CHECK(210.0 == fn(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, |
841 | 15, 16.0, 17, 18.0, 19, 20.0)); |
842 | return 0; |
843 | } |
844 | |
845 | // Used for testing floating point argument backfilling on Arm32 in hardfp. |
846 | DART_EXPORT intptr_t TestSumFloatsAndDoubles(double (*fn)(float, |
847 | double, |
848 | float)) { |
849 | CHECK_EQ(6.0, fn(1.0, 2.0, 3.0)); |
850 | return 0; |
851 | } |
852 | |
853 | // Very many small integers, tests alignment on stack. |
854 | DART_EXPORT intptr_t TestSumVeryManySmallInts(int16_t (*fn)(int8_t, |
855 | int16_t, |
856 | int8_t, |
857 | int16_t, |
858 | int8_t, |
859 | int16_t, |
860 | int8_t, |
861 | int16_t, |
862 | int8_t, |
863 | int16_t, |
864 | int8_t, |
865 | int16_t, |
866 | int8_t, |
867 | int16_t, |
868 | int8_t, |
869 | int16_t, |
870 | int8_t, |
871 | int16_t, |
872 | int8_t, |
873 | int16_t, |
874 | int8_t, |
875 | int16_t, |
876 | int8_t, |
877 | int16_t, |
878 | int8_t, |
879 | int16_t, |
880 | int8_t, |
881 | int16_t, |
882 | int8_t, |
883 | int16_t, |
884 | int8_t, |
885 | int16_t, |
886 | int8_t, |
887 | int16_t, |
888 | int8_t, |
889 | int16_t, |
890 | int8_t, |
891 | int16_t, |
892 | int8_t, |
893 | int16_t)) { |
894 | CHECK_EQ(40 * 41 / 2, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
895 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, |
896 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40)); |
897 | return 0; |
898 | } |
899 | |
900 | // Very many floating points, tests alignment on stack, and packing in |
901 | // floating point registers in hardfp. |
902 | DART_EXPORT intptr_t TestSumVeryManyFloatsDoubles(double (*fn)(float, |
903 | double, |
904 | float, |
905 | double, |
906 | float, |
907 | double, |
908 | float, |
909 | double, |
910 | float, |
911 | double, |
912 | float, |
913 | double, |
914 | float, |
915 | double, |
916 | float, |
917 | double, |
918 | float, |
919 | double, |
920 | float, |
921 | double, |
922 | float, |
923 | double, |
924 | float, |
925 | double, |
926 | float, |
927 | double, |
928 | float, |
929 | double, |
930 | float, |
931 | double, |
932 | float, |
933 | double, |
934 | float, |
935 | double, |
936 | float, |
937 | double, |
938 | float, |
939 | double, |
940 | float, |
941 | double)) { |
942 | CHECK_EQ(40 * 41 / 2, |
943 | fn(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, |
944 | 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, |
945 | 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, |
946 | 35.0, 36.0, 37.0, 38.0, 39.0, 40.0)); |
947 | return 0; |
948 | } |
949 | |
950 | DART_EXPORT intptr_t TestStore(int64_t* (*fn)(int64_t* a)) { |
951 | int64_t p[2] = {42, 1000}; |
952 | int64_t* result = fn(p); |
953 | CHECK_EQ(*result, 1337); |
954 | CHECK_EQ(p[1], 1337); |
955 | CHECK_EQ(result, p + 1); |
956 | return 0; |
957 | } |
958 | |
959 | DART_EXPORT intptr_t TestReturnNull(int32_t (*fn)()) { |
960 | CHECK_EQ(fn(), 42); |
961 | return 0; |
962 | } |
963 | |
964 | DART_EXPORT intptr_t TestNullPointers(int64_t* (*fn)(int64_t* ptr)) { |
965 | CHECK_EQ(fn(nullptr), reinterpret_cast<void*>(sizeof(int64_t))); |
966 | int64_t p[2] = {0}; |
967 | CHECK_EQ(fn(p), p + 1); |
968 | return 0; |
969 | } |
970 | |
971 | DART_EXPORT intptr_t TestReturnVoid(intptr_t (*return_void)()) { |
972 | CHECK_EQ(return_void(), 0); |
973 | return 0; |
974 | } |
975 | |
976 | DART_EXPORT intptr_t TestThrowExceptionDouble(double (*fn)()) { |
977 | CHECK_EQ(fn(), 42.0); |
978 | return 0; |
979 | } |
980 | |
981 | DART_EXPORT intptr_t TestThrowExceptionPointer(void* (*fn)()) { |
982 | CHECK_EQ(fn(), nullptr); |
983 | return 0; |
984 | } |
985 | |
986 | DART_EXPORT intptr_t TestThrowException(intptr_t (*fn)()) { |
987 | CHECK_EQ(fn(), 42); |
988 | return 0; |
989 | } |
990 | |
991 | DART_EXPORT intptr_t TestTakeMaxUint8x10(intptr_t (*fn)(uint8_t, |
992 | uint8_t, |
993 | uint8_t, |
994 | uint8_t, |
995 | uint8_t, |
996 | uint8_t, |
997 | uint8_t, |
998 | uint8_t, |
999 | uint8_t, |
1000 | uint8_t)) { |
1001 | CHECK_EQ(1, fn(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)); |
1002 | // Check the argument values are properly truncated. |
1003 | uint64_t v = 0xabcFF; |
1004 | CHECK_EQ(1, fn(v, v, v, v, v, v, v, v, v, v)); |
1005 | return 0; |
1006 | } |
1007 | |
1008 | DART_EXPORT intptr_t TestReturnMaxUint8(uint8_t (*fn)()) { |
1009 | std::cout << "TestReturnMaxUint8(fn): " << static_cast<int>(fn()) << "\n" ; |
1010 | CHECK_EQ(0xFF, fn()); |
1011 | return 0; |
1012 | } |
1013 | |
1014 | // Receives some pointer (Pointer<NativeType> in Dart) and writes some bits. |
1015 | DART_EXPORT void NativeTypePointerParam(void* p) { |
1016 | uint8_t* p2 = reinterpret_cast<uint8_t*>(p); |
1017 | p2[0] = 42; |
1018 | } |
1019 | |
1020 | // Manufactures some pointer (Pointer<NativeType> in Dart) with a bogus address. |
1021 | DART_EXPORT void* NativeTypePointerReturn() { |
1022 | uint64_t bogus_address = 0x13370000; |
1023 | return reinterpret_cast<void*>(bogus_address); |
1024 | } |
1025 | |
1026 | // Passes some pointer (Pointer<NativeType> in Dart) to Dart as argument. |
1027 | DART_EXPORT void CallbackNativeTypePointerParam(void (*f)(void*)) { |
1028 | void* pointer = malloc(sizeof(int64_t)); |
1029 | f(pointer); |
1030 | free(pointer); |
1031 | } |
1032 | |
1033 | // Receives some pointer (Pointer<NativeType> in Dart) from Dart as return |
1034 | // value. |
1035 | DART_EXPORT void CallbackNativeTypePointerReturn(void* (*f)()) { |
1036 | void* p = f(); |
1037 | uint8_t* p2 = reinterpret_cast<uint8_t*>(p); |
1038 | p2[0] = 42; |
1039 | } |
1040 | |
1041 | } // namespace dart |
1042 | |