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
25namespace 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
41int32_t globalVar;
42
43DART_EXPORT void SetGlobalVar(int32_t v) {
44 globalVar = v;
45}
46
47DART_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.
55DART_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.
63DART_EXPORT uint8_t ReturnMaxUint8() {
64 return 0xff;
65}
66
67DART_EXPORT uint16_t ReturnMaxUint16() {
68 return 0xffff;
69}
70
71DART_EXPORT uint32_t ReturnMaxUint32() {
72 return 0xffffffff;
73}
74
75DART_EXPORT int8_t ReturnMinInt8() {
76 return 0x80;
77}
78
79DART_EXPORT int16_t ReturnMinInt16() {
80 return 0x8000;
81}
82
83DART_EXPORT int32_t ReturnMinInt32() {
84 return 0x80000000;
85}
86
87// Test that return values are truncated by callee before passed to Dart.
88DART_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
95DART_EXPORT uint16_t ReturnMaxUint16v2() {
96 uint64_t v = 0xabcffff;
97 return v;
98}
99
100DART_EXPORT uint32_t ReturnMaxUint32v2() {
101 uint64_t v = 0xabcffffffff;
102 return v;
103}
104
105DART_EXPORT int8_t ReturnMinInt8v2() {
106 int64_t v = 0x8abc80;
107 return v;
108}
109
110DART_EXPORT int16_t ReturnMinInt16v2() {
111 int64_t v = 0x8abc8000;
112 return v;
113}
114
115DART_EXPORT int32_t ReturnMinInt32v2() {
116 int64_t v = 0x8abc80000000;
117 return v;
118}
119
120// Test that arguments are truncated correctly.
121DART_EXPORT intptr_t TakeMaxUint8(uint8_t x) {
122 std::cout << "TakeMaxUint8(" << static_cast<int>(x) << ")\n";
123 return x == 0xff ? 1 : 0;
124}
125
126DART_EXPORT intptr_t TakeMaxUint16(uint16_t x) {
127 std::cout << "TakeMaxUint16(" << x << ")\n";
128 return x == 0xffff ? 1 : 0;
129}
130
131DART_EXPORT intptr_t TakeMaxUint32(uint32_t x) {
132 std::cout << "TakeMaxUint32(" << x << ")\n";
133 return x == 0xffffffff ? 1 : 0;
134}
135
136DART_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
143DART_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
150DART_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
158DART_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.
183DART_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.
192DART_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
199DART_EXPORT intptr_t Regress40537(uint8_t x) {
200 std::cout << "Regress40537(" << static_cast<int>(x) << ")\n";
201 return x == 249 ? 1 : 0;
202}
203
204DART_EXPORT intptr_t Regress40537Variant2(uint8_t x) {
205 std::cout << "Regress40537Variant2(" << static_cast<int>(x) << ")\n";
206 return x;
207}
208
209DART_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.
216DART_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.
229DART_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.
240DART_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.
249DART_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.
259DART_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.
280DART_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.
300DART_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.
308DART_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.
379DART_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.
441DART_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.
463DART_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.
484DART_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.
517DART_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
528struct 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.
537DART_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.
549DART_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
561typedef 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.
566DART_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
573typedef 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?
579DART_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.
588DART_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.
598DART_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.
617struct 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.
640DART_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.
708DART_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().
730DART_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
739DART_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.
746DART_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.
757DART_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
765DART_EXPORT intptr_t
766TestIntComputation(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
774DART_EXPORT intptr_t
775TestUintComputation(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
782DART_EXPORT intptr_t TestSimpleMultiply(double (*fn)(double)) {
783 CHECK_EQ(fn(2.0), 2.0 * 1.337);
784 return 0;
785}
786
787DART_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
792DART_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
806DART_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
820DART_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.
846DART_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.
854DART_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.
902DART_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
950DART_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
959DART_EXPORT intptr_t TestReturnNull(int32_t (*fn)()) {
960 CHECK_EQ(fn(), 42);
961 return 0;
962}
963
964DART_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
971DART_EXPORT intptr_t TestReturnVoid(intptr_t (*return_void)()) {
972 CHECK_EQ(return_void(), 0);
973 return 0;
974}
975
976DART_EXPORT intptr_t TestThrowExceptionDouble(double (*fn)()) {
977 CHECK_EQ(fn(), 42.0);
978 return 0;
979}
980
981DART_EXPORT intptr_t TestThrowExceptionPointer(void* (*fn)()) {
982 CHECK_EQ(fn(), nullptr);
983 return 0;
984}
985
986DART_EXPORT intptr_t TestThrowException(intptr_t (*fn)()) {
987 CHECK_EQ(fn(), 42);
988 return 0;
989}
990
991DART_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
1008DART_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.
1015DART_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.
1021DART_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.
1027DART_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.
1035DART_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