Version 2.14.0-138.0.dev
Merge commit '35223586a3cedf11dc60212e90bfc3571100c7da' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b818c8..e74f84b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -138,6 +138,16 @@
}
```
+## 2.13.1 - 2021-05-25
+
+This is a patch release that fixes:
+
+* incorrect behavior in CastMap (issue [#45473][]).
+* missing nullability from recursive type hierarchies in DDC (issue [#45767][]).
+
+[#45473]: https://github.com/dart-lang/sdk/issues/45473
+[#45767]: https://github.com/dart-lang/sdk/issues/45767
+
## 2.13.0 - 2021-05-18
### Language
diff --git a/benchmarks/FfiCall/dart/FfiCall.dart b/benchmarks/FfiCall/dart/FfiCall.dart
index 7886ecf..e6c922e 100644
--- a/benchmarks/FfiCall/dart/FfiCall.dart
+++ b/benchmarks/FfiCall/dart/FfiCall.dart
@@ -283,7 +283,10 @@
//
abstract class FfiBenchmarkBase extends BenchmarkBase {
- FfiBenchmarkBase(String name) : super(name);
+ final bool isLeaf;
+
+ FfiBenchmarkBase(String name, {this.isLeaf: false})
+ : super('$name${isLeaf ? 'Leaf' : ''}');
void expectEquals(actual, expected) {
if (actual != expected) {
@@ -307,10 +310,13 @@
class Uint8x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint8x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint8, Function1int>(
- 'Function1Uint8'),
- super('FfiCall.Uint8x01');
+ Uint8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
+ Function1int>('Function1Uint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
+ Function1int>('Function1Uint8', isLeaf: false),
+ super('FfiCall.Uint8x01', isLeaf: isLeaf);
@override
void run() {
@@ -325,10 +331,13 @@
class Uint16x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint16x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
- Function1int>('Function1Uint16'),
- super('FfiCall.Uint16x01');
+ Uint16x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
+ Function1int>('Function1Uint16', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
+ Function1int>('Function1Uint16', isLeaf: false),
+ super('FfiCall.Uint16x01', isLeaf: isLeaf);
@override
void run() {
@@ -343,10 +352,13 @@
class Uint32x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint32x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
- Function1int>('Function1Uint32'),
- super('FfiCall.Uint32x01');
+ Uint32x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
+ Function1int>('Function1Uint32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
+ Function1int>('Function1Uint32', isLeaf: false),
+ super('FfiCall.Uint32x01', isLeaf: isLeaf);
@override
void run() {
@@ -361,10 +373,13 @@
class Uint64x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint64x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
- Function1int>('Function1Uint64'),
- super('FfiCall.Uint64x01');
+ Uint64x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
+ Function1int>('Function1Uint64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
+ Function1int>('Function1Uint64', isLeaf: false),
+ super('FfiCall.Uint64x01', isLeaf: isLeaf);
@override
void run() {
@@ -379,10 +394,13 @@
class Int8x01 extends FfiBenchmarkBase {
final Function1int f;
- Int8x01()
- : f = ffiTestFunctions
- .lookupFunction<NativeFunction1Int8, Function1int>('Function1Int8'),
- super('FfiCall.Int8x01');
+ Int8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int8,
+ Function1int>('Function1Int8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int8,
+ Function1int>('Function1Int8', isLeaf: false),
+ super('FfiCall.Int8x01', isLeaf: isLeaf);
@override
void run() {
@@ -397,10 +415,13 @@
class Int16x01 extends FfiBenchmarkBase {
final Function1int f;
- Int16x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int16, Function1int>(
- 'Function1Int16'),
- super('FfiCall.Int16x01');
+ Int16x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int16,
+ Function1int>('Function1Int16', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int16,
+ Function1int>('Function1Int16', isLeaf: false),
+ super('FfiCall.Int16x01', isLeaf: isLeaf);
@override
void run() {
@@ -415,10 +436,13 @@
class Int32x01 extends FfiBenchmarkBase {
final Function1int f;
- Int32x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int32, Function1int>(
- 'Function1Int32'),
- super('FfiCall.Int32x01');
+ Int32x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int32,
+ Function1int>('Function1Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int32,
+ Function1int>('Function1Int32', isLeaf: false),
+ super('FfiCall.Int32x01', isLeaf: isLeaf);
@override
void run() {
@@ -433,10 +457,13 @@
class Int32x02 extends FfiBenchmarkBase {
final Function2int f;
- Int32x02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Int32, Function2int>(
- 'Function2Int32'),
- super('FfiCall.Int32x02');
+ Int32x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Int32,
+ Function2int>('Function2Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Int32,
+ Function2int>('Function2Int32', isLeaf: false),
+ super('FfiCall.Int32x02', isLeaf: isLeaf);
@override
void run() {
@@ -451,10 +478,13 @@
class Int32x04 extends FfiBenchmarkBase {
final Function4int f;
- Int32x04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Int32, Function4int>(
- 'Function4Int32'),
- super('FfiCall.Int32x04');
+ Int32x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Int32,
+ Function4int>('Function4Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Int32,
+ Function4int>('Function4Int32', isLeaf: false),
+ super('FfiCall.Int32x04', isLeaf: isLeaf);
@override
void run() {
@@ -469,10 +499,13 @@
class Int32x10 extends FfiBenchmarkBase {
final Function10int f;
- Int32x10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Int32,
- Function10int>('Function10Int32'),
- super('FfiCall.Int32x10');
+ Int32x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Int32,
+ Function10int>('Function10Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Int32,
+ Function10int>('Function10Int32', isLeaf: false),
+ super('FfiCall.Int32x10', isLeaf: isLeaf);
@override
void run() {
@@ -487,10 +520,13 @@
class Int32x20 extends FfiBenchmarkBase {
final Function20int f;
- Int32x20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Int32,
- Function20int>('Function20Int32'),
- super('FfiCall.Int32x20');
+ Int32x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Int32,
+ Function20int>('Function20Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Int32,
+ Function20int>('Function20Int32', isLeaf: false),
+ super('FfiCall.Int32x20', isLeaf: isLeaf);
@override
void run() {
@@ -505,10 +541,13 @@
class Int64x01 extends FfiBenchmarkBase {
final Function1int f;
- Int64x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int64, Function1int>(
- 'Function1Int64'),
- super('FfiCall.Int64x01');
+ Int64x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: false),
+ super('FfiCall.Int64x01', isLeaf: isLeaf);
@override
void run() {
@@ -523,10 +562,13 @@
class Int64x02 extends FfiBenchmarkBase {
final Function2int f;
- Int64x02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Int64, Function2int>(
- 'Function2Int64'),
- super('FfiCall.Int64x02');
+ Int64x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Int64,
+ Function2int>('Function2Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Int64,
+ Function2int>('Function2Int64', isLeaf: false),
+ super('FfiCall.Int64x02', isLeaf: isLeaf);
@override
void run() {
@@ -541,10 +583,13 @@
class Int64x04 extends FfiBenchmarkBase {
final Function4int f;
- Int64x04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Int64, Function4int>(
- 'Function4Int64'),
- super('FfiCall.Int64x04');
+ Int64x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Int64,
+ Function4int>('Function4Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Int64,
+ Function4int>('Function4Int64', isLeaf: false),
+ super('FfiCall.Int64x04', isLeaf: isLeaf);
@override
void run() {
@@ -559,10 +604,13 @@
class Int64x10 extends FfiBenchmarkBase {
final Function10int f;
- Int64x10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Int64,
- Function10int>('Function10Int64'),
- super('FfiCall.Int64x10');
+ Int64x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Int64,
+ Function10int>('Function10Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Int64,
+ Function10int>('Function10Int64', isLeaf: false),
+ super('FfiCall.Int64x10', isLeaf: isLeaf);
@override
void run() {
@@ -577,10 +625,13 @@
class Int64x20 extends FfiBenchmarkBase {
final Function20int f;
- Int64x20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Int64,
- Function20int>('Function20Int64'),
- super('FfiCall.Int64x20');
+ Int64x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Int64,
+ Function20int>('Function20Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Int64,
+ Function20int>('Function20Int64', isLeaf: false),
+ super('FfiCall.Int64x20', isLeaf: isLeaf);
@override
void run() {
@@ -595,10 +646,13 @@
class Int64Mintx01 extends FfiBenchmarkBase {
final Function1int f;
- Int64Mintx01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int64, Function1int>(
- 'Function1Int64'),
- super('FfiCall.Int64Mintx01');
+ Int64Mintx01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: false),
+ super('FfiCall.Int64Mintx01', isLeaf: isLeaf);
@override
void run() {
@@ -613,10 +667,13 @@
class Floatx01 extends FfiBenchmarkBase {
final Function1double f;
- Floatx01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Float,
- Function1double>('Function1Float'),
- super('FfiCall.Floatx01');
+ Floatx01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Float,
+ Function1double>('Function1Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Float,
+ Function1double>('Function1Float', isLeaf: false),
+ super('FfiCall.Floatx01', isLeaf: isLeaf);
@override
void run() {
@@ -631,10 +688,13 @@
class Floatx02 extends FfiBenchmarkBase {
final Function2double f;
- Floatx02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Float,
- Function2double>('Function2Float'),
- super('FfiCall.Floatx02');
+ Floatx02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Float,
+ Function2double>('Function2Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Float,
+ Function2double>('Function2Float', isLeaf: false),
+ super('FfiCall.Floatx02', isLeaf: isLeaf);
@override
void run() {
@@ -649,10 +709,13 @@
class Floatx04 extends FfiBenchmarkBase {
final Function4double f;
- Floatx04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Float,
- Function4double>('Function4Float'),
- super('FfiCall.Floatx04');
+ Floatx04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Float,
+ Function4double>('Function4Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Float,
+ Function4double>('Function4Float', isLeaf: false),
+ super('FfiCall.Floatx04', isLeaf: isLeaf);
@override
void run() {
@@ -668,10 +731,13 @@
class Floatx10 extends FfiBenchmarkBase {
final Function10double f;
- Floatx10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Float,
- Function10double>('Function10Float'),
- super('FfiCall.Floatx10');
+ Floatx10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Float,
+ Function10double>('Function10Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Float,
+ Function10double>('Function10Float', isLeaf: false),
+ super('FfiCall.Floatx10', isLeaf: isLeaf);
@override
void run() {
@@ -688,10 +754,13 @@
class Floatx20 extends FfiBenchmarkBase {
final Function20double f;
- Floatx20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Float,
- Function20double>('Function20Float'),
- super('FfiCall.Floatx20');
+ Floatx20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Float,
+ Function20double>('Function20Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Float,
+ Function20double>('Function20Float', isLeaf: false),
+ super('FfiCall.Floatx20', isLeaf: isLeaf);
@override
void run() {
@@ -728,10 +797,13 @@
class Doublex01 extends FfiBenchmarkBase {
final Function1double f;
- Doublex01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Double,
- Function1double>('Function1Double'),
- super('FfiCall.Doublex01');
+ Doublex01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Double,
+ Function1double>('Function1Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Double,
+ Function1double>('Function1Double', isLeaf: false),
+ super('FfiCall.Doublex01', isLeaf: isLeaf);
@override
void run() {
@@ -747,10 +819,13 @@
class Doublex02 extends FfiBenchmarkBase {
final Function2double f;
- Doublex02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Double,
- Function2double>('Function2Double'),
- super('FfiCall.Doublex02');
+ Doublex02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Double,
+ Function2double>('Function2Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Double,
+ Function2double>('Function2Double', isLeaf: false),
+ super('FfiCall.Doublex02', isLeaf: isLeaf);
@override
void run() {
@@ -766,10 +841,13 @@
class Doublex04 extends FfiBenchmarkBase {
final Function4double f;
- Doublex04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Double,
- Function4double>('Function4Double'),
- super('FfiCall.Doublex04');
+ Doublex04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Double,
+ Function4double>('Function4Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Double,
+ Function4double>('Function4Double', isLeaf: false),
+ super('FfiCall.Doublex04', isLeaf: isLeaf);
@override
void run() {
@@ -785,10 +863,13 @@
class Doublex10 extends FfiBenchmarkBase {
final Function10double f;
- Doublex10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Double,
- Function10double>('Function10Double'),
- super('FfiCall.Doublex10');
+ Doublex10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Double,
+ Function10double>('Function10Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Double,
+ Function10double>('Function10Double', isLeaf: false),
+ super('FfiCall.Doublex10', isLeaf: isLeaf);
@override
void run() {
@@ -805,10 +886,13 @@
class Doublex20 extends FfiBenchmarkBase {
final Function20double f;
- Doublex20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Double,
- Function20double>('Function20Double'),
- super('FfiCall.Doublex20');
+ Doublex20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Double,
+ Function20double>('Function20Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Double,
+ Function20double>('Function20Double', isLeaf: false),
+ super('FfiCall.Doublex20', isLeaf: isLeaf);
@override
void run() {
@@ -845,10 +929,13 @@
class PointerUint8x01 extends FfiBenchmarkBase {
final Function1PointerUint8 f;
- PointerUint8x01()
- : f = ffiTestFunctions.lookupFunction<Function1PointerUint8,
- Function1PointerUint8>('Function1PointerUint8'),
- super('FfiCall.PointerUint8x01');
+ PointerUint8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function1PointerUint8,
+ Function1PointerUint8>('Function1PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function1PointerUint8,
+ Function1PointerUint8>('Function1PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x01', isLeaf: isLeaf);
Pointer<Uint8> p1 = nullptr;
@override
@@ -869,10 +956,13 @@
class PointerUint8x02 extends FfiBenchmarkBase {
final Function2PointerUint8 f;
- PointerUint8x02()
- : f = ffiTestFunctions.lookupFunction<Function2PointerUint8,
- Function2PointerUint8>('Function2PointerUint8'),
- super('FfiCall.PointerUint8x02');
+ PointerUint8x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function2PointerUint8,
+ Function2PointerUint8>('Function2PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function2PointerUint8,
+ Function2PointerUint8>('Function2PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x02', isLeaf: isLeaf);
Pointer<Uint8> p1 = nullptr;
Pointer<Uint8> p2 = nullptr;
@@ -901,10 +991,13 @@
class PointerUint8x04 extends FfiBenchmarkBase {
final Function4PointerUint8 f;
- PointerUint8x04()
- : f = ffiTestFunctions.lookupFunction<Function4PointerUint8,
- Function4PointerUint8>('Function4PointerUint8'),
- super('FfiCall.PointerUint8x04');
+ PointerUint8x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function4PointerUint8,
+ Function4PointerUint8>('Function4PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function4PointerUint8,
+ Function4PointerUint8>('Function4PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x04', isLeaf: isLeaf);
Pointer<Uint8> p1 = nullptr;
Pointer<Uint8> p2 = nullptr;
@@ -937,10 +1030,15 @@
class PointerUint8x10 extends FfiBenchmarkBase {
final Function10PointerUint8 f;
- PointerUint8x10()
- : f = ffiTestFunctions.lookupFunction<Function10PointerUint8,
- Function10PointerUint8>('Function10PointerUint8'),
- super('FfiCall.PointerUint8x10');
+ PointerUint8x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function10PointerUint8,
+ Function10PointerUint8>('Function10PointerUint8', isLeaf: true)
+ : ffiTestFunctions
+ .lookupFunction<Function10PointerUint8, Function10PointerUint8>(
+ 'Function10PointerUint8',
+ isLeaf: false),
+ super('FfiCall.PointerUint8x10', isLeaf: isLeaf);
Pointer<Uint8> p1 = nullptr;
Pointer<Uint8> p2 = nullptr;
@@ -985,10 +1083,15 @@
class PointerUint8x20 extends FfiBenchmarkBase {
final Function20PointerUint8 f;
- PointerUint8x20()
- : f = ffiTestFunctions.lookupFunction<Function20PointerUint8,
- Function20PointerUint8>('Function20PointerUint8'),
- super('FfiCall.PointerUint8x20');
+ PointerUint8x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function20PointerUint8,
+ Function20PointerUint8>('Function20PointerUint8', isLeaf: true)
+ : ffiTestFunctions
+ .lookupFunction<Function20PointerUint8, Function20PointerUint8>(
+ 'Function20PointerUint8',
+ isLeaf: false),
+ super('FfiCall.PointerUint8x20', isLeaf: isLeaf);
Pointer<Uint8> p1 = nullptr;
Pointer<Uint8> p2 = nullptr;
@@ -1061,8 +1164,8 @@
Handlex01()
: f = ffiTestFunctions.lookupFunction<NativeFunction1Handle,
- Function1Object>('Function1Handle'),
- super('FfiCall.Handlex01');
+ Function1Object>('Function1Handle', isLeaf: false),
+ super('FfiCall.Handlex01', isLeaf: false);
@override
void run() {
@@ -1080,8 +1183,8 @@
Handlex02()
: f = ffiTestFunctions.lookupFunction<NativeFunction2Handle,
- Function2Object>('Function2Handle'),
- super('FfiCall.Handlex02');
+ Function2Object>('Function2Handle', isLeaf: false),
+ super('FfiCall.Handlex02', isLeaf: false);
@override
void run() {
@@ -1100,8 +1203,8 @@
Handlex04()
: f = ffiTestFunctions.lookupFunction<NativeFunction4Handle,
- Function4Object>('Function4Handle'),
- super('FfiCall.Handlex04');
+ Function4Object>('Function4Handle', isLeaf: false),
+ super('FfiCall.Handlex04', isLeaf: false);
@override
void run() {
@@ -1122,8 +1225,8 @@
Handlex10()
: f = ffiTestFunctions.lookupFunction<NativeFunction10Handle,
- Function10Object>('Function10Handle'),
- super('FfiCall.Handlex10');
+ Function10Object>('Function10Handle', isLeaf: false),
+ super('FfiCall.Handlex10', isLeaf: false);
@override
void run() {
@@ -1150,8 +1253,8 @@
Handlex20()
: f = ffiTestFunctions.lookupFunction<NativeFunction20Handle,
- Function20Object>('Function20Handle'),
- super('FfiCall.Handlex20');
+ Function20Object>('Function20Handle', isLeaf: false),
+ super('FfiCall.Handlex20', isLeaf: false);
@override
void run() {
@@ -1191,10 +1294,12 @@
void main() {
final benchmarks = [
() => Uint8x01(),
+ () => Uint8x01(isLeaf: true),
() => Uint16x01(),
() => Uint32x01(),
() => Uint64x01(),
() => Int8x01(),
+ () => Int8x01(isLeaf: true),
() => Int16x01(),
() => Int32x01(),
() => Int32x02(),
@@ -1206,22 +1311,27 @@
() => Int64x04(),
() => Int64x10(),
() => Int64x20(),
+ () => Int64x20(isLeaf: true),
() => Int64Mintx01(),
+ () => Int64Mintx01(isLeaf: true),
() => Floatx01(),
() => Floatx02(),
() => Floatx04(),
() => Floatx10(),
() => Floatx20(),
+ () => Floatx20(isLeaf: true),
() => Doublex01(),
() => Doublex02(),
() => Doublex04(),
() => Doublex10(),
() => Doublex20(),
+ () => Doublex20(isLeaf: true),
() => PointerUint8x01(),
() => PointerUint8x02(),
() => PointerUint8x04(),
() => PointerUint8x10(),
() => PointerUint8x20(),
+ () => PointerUint8x20(isLeaf: true),
() => Handlex01(),
() => Handlex02(),
() => Handlex04(),
diff --git a/benchmarks/FfiCall/dart2/FfiCall.dart b/benchmarks/FfiCall/dart2/FfiCall.dart
index 4f0e465..1fd1b02 100644
--- a/benchmarks/FfiCall/dart2/FfiCall.dart
+++ b/benchmarks/FfiCall/dart2/FfiCall.dart
@@ -285,7 +285,10 @@
//
abstract class FfiBenchmarkBase extends BenchmarkBase {
- FfiBenchmarkBase(String name) : super(name);
+ final bool isLeaf;
+
+ FfiBenchmarkBase(String name, {this.isLeaf: false})
+ : super('$name${isLeaf ? 'Leaf' : ''}');
void expectEquals(actual, expected) {
if (actual != expected) {
@@ -309,10 +312,13 @@
class Uint8x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint8x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint8, Function1int>(
- 'Function1Uint8'),
- super('FfiCall.Uint8x01');
+ Uint8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
+ Function1int>('Function1Uint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
+ Function1int>('Function1Uint8', isLeaf: false),
+ super('FfiCall.Uint8x01', isLeaf: isLeaf);
@override
void run() {
@@ -327,10 +333,13 @@
class Uint16x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint16x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
- Function1int>('Function1Uint16'),
- super('FfiCall.Uint16x01');
+ Uint16x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
+ Function1int>('Function1Uint16', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
+ Function1int>('Function1Uint16', isLeaf: false),
+ super('FfiCall.Uint16x01', isLeaf: isLeaf);
@override
void run() {
@@ -345,10 +354,13 @@
class Uint32x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint32x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
- Function1int>('Function1Uint32'),
- super('FfiCall.Uint32x01');
+ Uint32x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
+ Function1int>('Function1Uint32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
+ Function1int>('Function1Uint32', isLeaf: false),
+ super('FfiCall.Uint32x01', isLeaf: isLeaf);
@override
void run() {
@@ -363,10 +375,13 @@
class Uint64x01 extends FfiBenchmarkBase {
final Function1int f;
- Uint64x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
- Function1int>('Function1Uint64'),
- super('FfiCall.Uint64x01');
+ Uint64x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
+ Function1int>('Function1Uint64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
+ Function1int>('Function1Uint64', isLeaf: false),
+ super('FfiCall.Uint64x01', isLeaf: isLeaf);
@override
void run() {
@@ -381,10 +396,13 @@
class Int8x01 extends FfiBenchmarkBase {
final Function1int f;
- Int8x01()
- : f = ffiTestFunctions
- .lookupFunction<NativeFunction1Int8, Function1int>('Function1Int8'),
- super('FfiCall.Int8x01');
+ Int8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int8,
+ Function1int>('Function1Int8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int8,
+ Function1int>('Function1Int8', isLeaf: false),
+ super('FfiCall.Int8x01', isLeaf: isLeaf);
@override
void run() {
@@ -399,10 +417,13 @@
class Int16x01 extends FfiBenchmarkBase {
final Function1int f;
- Int16x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int16, Function1int>(
- 'Function1Int16'),
- super('FfiCall.Int16x01');
+ Int16x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int16,
+ Function1int>('Function1Int16', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int16,
+ Function1int>('Function1Int16', isLeaf: false),
+ super('FfiCall.Int16x01', isLeaf: isLeaf);
@override
void run() {
@@ -417,10 +438,13 @@
class Int32x01 extends FfiBenchmarkBase {
final Function1int f;
- Int32x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int32, Function1int>(
- 'Function1Int32'),
- super('FfiCall.Int32x01');
+ Int32x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int32,
+ Function1int>('Function1Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int32,
+ Function1int>('Function1Int32', isLeaf: false),
+ super('FfiCall.Int32x01', isLeaf: isLeaf);
@override
void run() {
@@ -435,10 +459,13 @@
class Int32x02 extends FfiBenchmarkBase {
final Function2int f;
- Int32x02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Int32, Function2int>(
- 'Function2Int32'),
- super('FfiCall.Int32x02');
+ Int32x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Int32,
+ Function2int>('Function2Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Int32,
+ Function2int>('Function2Int32', isLeaf: false),
+ super('FfiCall.Int32x02', isLeaf: isLeaf);
@override
void run() {
@@ -453,10 +480,13 @@
class Int32x04 extends FfiBenchmarkBase {
final Function4int f;
- Int32x04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Int32, Function4int>(
- 'Function4Int32'),
- super('FfiCall.Int32x04');
+ Int32x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Int32,
+ Function4int>('Function4Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Int32,
+ Function4int>('Function4Int32', isLeaf: false),
+ super('FfiCall.Int32x04', isLeaf: isLeaf);
@override
void run() {
@@ -471,10 +501,13 @@
class Int32x10 extends FfiBenchmarkBase {
final Function10int f;
- Int32x10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Int32,
- Function10int>('Function10Int32'),
- super('FfiCall.Int32x10');
+ Int32x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Int32,
+ Function10int>('Function10Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Int32,
+ Function10int>('Function10Int32', isLeaf: false),
+ super('FfiCall.Int32x10', isLeaf: isLeaf);
@override
void run() {
@@ -489,10 +522,13 @@
class Int32x20 extends FfiBenchmarkBase {
final Function20int f;
- Int32x20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Int32,
- Function20int>('Function20Int32'),
- super('FfiCall.Int32x20');
+ Int32x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Int32,
+ Function20int>('Function20Int32', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Int32,
+ Function20int>('Function20Int32', isLeaf: false),
+ super('FfiCall.Int32x20', isLeaf: isLeaf);
@override
void run() {
@@ -507,10 +543,13 @@
class Int64x01 extends FfiBenchmarkBase {
final Function1int f;
- Int64x01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int64, Function1int>(
- 'Function1Int64'),
- super('FfiCall.Int64x01');
+ Int64x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: false),
+ super('FfiCall.Int64x01', isLeaf: isLeaf);
@override
void run() {
@@ -525,10 +564,13 @@
class Int64x02 extends FfiBenchmarkBase {
final Function2int f;
- Int64x02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Int64, Function2int>(
- 'Function2Int64'),
- super('FfiCall.Int64x02');
+ Int64x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Int64,
+ Function2int>('Function2Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Int64,
+ Function2int>('Function2Int64', isLeaf: false),
+ super('FfiCall.Int64x02', isLeaf: isLeaf);
@override
void run() {
@@ -543,10 +585,13 @@
class Int64x04 extends FfiBenchmarkBase {
final Function4int f;
- Int64x04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Int64, Function4int>(
- 'Function4Int64'),
- super('FfiCall.Int64x04');
+ Int64x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Int64,
+ Function4int>('Function4Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Int64,
+ Function4int>('Function4Int64', isLeaf: false),
+ super('FfiCall.Int64x04', isLeaf: isLeaf);
@override
void run() {
@@ -561,10 +606,13 @@
class Int64x10 extends FfiBenchmarkBase {
final Function10int f;
- Int64x10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Int64,
- Function10int>('Function10Int64'),
- super('FfiCall.Int64x10');
+ Int64x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Int64,
+ Function10int>('Function10Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Int64,
+ Function10int>('Function10Int64', isLeaf: false),
+ super('FfiCall.Int64x10', isLeaf: isLeaf);
@override
void run() {
@@ -579,10 +627,13 @@
class Int64x20 extends FfiBenchmarkBase {
final Function20int f;
- Int64x20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Int64,
- Function20int>('Function20Int64'),
- super('FfiCall.Int64x20');
+ Int64x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Int64,
+ Function20int>('Function20Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Int64,
+ Function20int>('Function20Int64', isLeaf: false),
+ super('FfiCall.Int64x20', isLeaf: isLeaf);
@override
void run() {
@@ -597,10 +648,13 @@
class Int64Mintx01 extends FfiBenchmarkBase {
final Function1int f;
- Int64Mintx01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Int64, Function1int>(
- 'Function1Int64'),
- super('FfiCall.Int64Mintx01');
+ Int64Mintx01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Int64,
+ Function1int>('Function1Int64', isLeaf: false),
+ super('FfiCall.Int64Mintx01', isLeaf: isLeaf);
@override
void run() {
@@ -615,10 +669,13 @@
class Floatx01 extends FfiBenchmarkBase {
final Function1double f;
- Floatx01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Float,
- Function1double>('Function1Float'),
- super('FfiCall.Floatx01');
+ Floatx01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Float,
+ Function1double>('Function1Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Float,
+ Function1double>('Function1Float', isLeaf: false),
+ super('FfiCall.Floatx01', isLeaf: isLeaf);
@override
void run() {
@@ -633,10 +690,13 @@
class Floatx02 extends FfiBenchmarkBase {
final Function2double f;
- Floatx02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Float,
- Function2double>('Function2Float'),
- super('FfiCall.Floatx02');
+ Floatx02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Float,
+ Function2double>('Function2Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Float,
+ Function2double>('Function2Float', isLeaf: false),
+ super('FfiCall.Floatx02', isLeaf: isLeaf);
@override
void run() {
@@ -651,10 +711,13 @@
class Floatx04 extends FfiBenchmarkBase {
final Function4double f;
- Floatx04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Float,
- Function4double>('Function4Float'),
- super('FfiCall.Floatx04');
+ Floatx04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Float,
+ Function4double>('Function4Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Float,
+ Function4double>('Function4Float', isLeaf: false),
+ super('FfiCall.Floatx04', isLeaf: isLeaf);
@override
void run() {
@@ -670,10 +733,13 @@
class Floatx10 extends FfiBenchmarkBase {
final Function10double f;
- Floatx10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Float,
- Function10double>('Function10Float'),
- super('FfiCall.Floatx10');
+ Floatx10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Float,
+ Function10double>('Function10Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Float,
+ Function10double>('Function10Float', isLeaf: false),
+ super('FfiCall.Floatx10', isLeaf: isLeaf);
@override
void run() {
@@ -690,10 +756,13 @@
class Floatx20 extends FfiBenchmarkBase {
final Function20double f;
- Floatx20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Float,
- Function20double>('Function20Float'),
- super('FfiCall.Floatx20');
+ Floatx20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Float,
+ Function20double>('Function20Float', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Float,
+ Function20double>('Function20Float', isLeaf: false),
+ super('FfiCall.Floatx20', isLeaf: isLeaf);
@override
void run() {
@@ -730,10 +799,13 @@
class Doublex01 extends FfiBenchmarkBase {
final Function1double f;
- Doublex01()
- : f = ffiTestFunctions.lookupFunction<NativeFunction1Double,
- Function1double>('Function1Double'),
- super('FfiCall.Doublex01');
+ Doublex01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction1Double,
+ Function1double>('Function1Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction1Double,
+ Function1double>('Function1Double', isLeaf: false),
+ super('FfiCall.Doublex01', isLeaf: isLeaf);
@override
void run() {
@@ -749,10 +821,13 @@
class Doublex02 extends FfiBenchmarkBase {
final Function2double f;
- Doublex02()
- : f = ffiTestFunctions.lookupFunction<NativeFunction2Double,
- Function2double>('Function2Double'),
- super('FfiCall.Doublex02');
+ Doublex02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction2Double,
+ Function2double>('Function2Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction2Double,
+ Function2double>('Function2Double', isLeaf: false),
+ super('FfiCall.Doublex02', isLeaf: isLeaf);
@override
void run() {
@@ -768,10 +843,13 @@
class Doublex04 extends FfiBenchmarkBase {
final Function4double f;
- Doublex04()
- : f = ffiTestFunctions.lookupFunction<NativeFunction4Double,
- Function4double>('Function4Double'),
- super('FfiCall.Doublex04');
+ Doublex04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction4Double,
+ Function4double>('Function4Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction4Double,
+ Function4double>('Function4Double', isLeaf: false),
+ super('FfiCall.Doublex04', isLeaf: isLeaf);
@override
void run() {
@@ -787,10 +865,13 @@
class Doublex10 extends FfiBenchmarkBase {
final Function10double f;
- Doublex10()
- : f = ffiTestFunctions.lookupFunction<NativeFunction10Double,
- Function10double>('Function10Double'),
- super('FfiCall.Doublex10');
+ Doublex10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction10Double,
+ Function10double>('Function10Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction10Double,
+ Function10double>('Function10Double', isLeaf: false),
+ super('FfiCall.Doublex10', isLeaf: isLeaf);
@override
void run() {
@@ -807,10 +888,13 @@
class Doublex20 extends FfiBenchmarkBase {
final Function20double f;
- Doublex20()
- : f = ffiTestFunctions.lookupFunction<NativeFunction20Double,
- Function20double>('Function20Double'),
- super('FfiCall.Doublex20');
+ Doublex20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeFunction20Double,
+ Function20double>('Function20Double', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeFunction20Double,
+ Function20double>('Function20Double', isLeaf: false),
+ super('FfiCall.Doublex20', isLeaf: isLeaf);
@override
void run() {
@@ -847,10 +931,13 @@
class PointerUint8x01 extends FfiBenchmarkBase {
final Function1PointerUint8 f;
- PointerUint8x01()
- : f = ffiTestFunctions.lookupFunction<Function1PointerUint8,
- Function1PointerUint8>('Function1PointerUint8'),
- super('FfiCall.PointerUint8x01');
+ PointerUint8x01({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function1PointerUint8,
+ Function1PointerUint8>('Function1PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function1PointerUint8,
+ Function1PointerUint8>('Function1PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x01', isLeaf: isLeaf);
Pointer<Uint8> p1;
@override
@@ -871,10 +958,13 @@
class PointerUint8x02 extends FfiBenchmarkBase {
final Function2PointerUint8 f;
- PointerUint8x02()
- : f = ffiTestFunctions.lookupFunction<Function2PointerUint8,
- Function2PointerUint8>('Function2PointerUint8'),
- super('FfiCall.PointerUint8x02');
+ PointerUint8x02({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function2PointerUint8,
+ Function2PointerUint8>('Function2PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function2PointerUint8,
+ Function2PointerUint8>('Function2PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x02', isLeaf: isLeaf);
Pointer<Uint8> p1, p2;
@@ -902,10 +992,13 @@
class PointerUint8x04 extends FfiBenchmarkBase {
final Function4PointerUint8 f;
- PointerUint8x04()
- : f = ffiTestFunctions.lookupFunction<Function4PointerUint8,
- Function4PointerUint8>('Function4PointerUint8'),
- super('FfiCall.PointerUint8x04');
+ PointerUint8x04({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function4PointerUint8,
+ Function4PointerUint8>('Function4PointerUint8', isLeaf: true)
+ : ffiTestFunctions.lookupFunction<Function4PointerUint8,
+ Function4PointerUint8>('Function4PointerUint8', isLeaf: false),
+ super('FfiCall.PointerUint8x04', isLeaf: isLeaf);
Pointer<Uint8> p1, p2, p3, p4;
@@ -935,10 +1028,15 @@
class PointerUint8x10 extends FfiBenchmarkBase {
final Function10PointerUint8 f;
- PointerUint8x10()
- : f = ffiTestFunctions.lookupFunction<Function10PointerUint8,
- Function10PointerUint8>('Function10PointerUint8'),
- super('FfiCall.PointerUint8x10');
+ PointerUint8x10({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function10PointerUint8,
+ Function10PointerUint8>('Function10PointerUint8', isLeaf: true)
+ : ffiTestFunctions
+ .lookupFunction<Function10PointerUint8, Function10PointerUint8>(
+ 'Function10PointerUint8',
+ isLeaf: false),
+ super('FfiCall.PointerUint8x10', isLeaf: isLeaf);
Pointer<Uint8> p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
@@ -974,10 +1072,15 @@
class PointerUint8x20 extends FfiBenchmarkBase {
final Function20PointerUint8 f;
- PointerUint8x20()
- : f = ffiTestFunctions.lookupFunction<Function20PointerUint8,
- Function20PointerUint8>('Function20PointerUint8'),
- super('FfiCall.PointerUint8x20');
+ PointerUint8x20({isLeaf: false})
+ : f = isLeaf
+ ? ffiTestFunctions.lookupFunction<Function20PointerUint8,
+ Function20PointerUint8>('Function20PointerUint8', isLeaf: true)
+ : ffiTestFunctions
+ .lookupFunction<Function20PointerUint8, Function20PointerUint8>(
+ 'Function20PointerUint8',
+ isLeaf: false),
+ super('FfiCall.PointerUint8x20', isLeaf: isLeaf);
Pointer<Uint8> p1,
p2,
@@ -1050,8 +1153,8 @@
Handlex01()
: f = ffiTestFunctions.lookupFunction<NativeFunction1Handle,
- Function1Object>('Function1Handle'),
- super('FfiCall.Handlex01');
+ Function1Object>('Function1Handle', isLeaf: false),
+ super('FfiCall.Handlex01', isLeaf: false);
@override
void run() {
@@ -1069,8 +1172,8 @@
Handlex02()
: f = ffiTestFunctions.lookupFunction<NativeFunction2Handle,
- Function2Object>('Function2Handle'),
- super('FfiCall.Handlex02');
+ Function2Object>('Function2Handle', isLeaf: false),
+ super('FfiCall.Handlex02', isLeaf: false);
@override
void run() {
@@ -1089,8 +1192,8 @@
Handlex04()
: f = ffiTestFunctions.lookupFunction<NativeFunction4Handle,
- Function4Object>('Function4Handle'),
- super('FfiCall.Handlex04');
+ Function4Object>('Function4Handle', isLeaf: false),
+ super('FfiCall.Handlex04', isLeaf: false);
@override
void run() {
@@ -1111,8 +1214,8 @@
Handlex10()
: f = ffiTestFunctions.lookupFunction<NativeFunction10Handle,
- Function10Object>('Function10Handle'),
- super('FfiCall.Handlex10');
+ Function10Object>('Function10Handle', isLeaf: false),
+ super('FfiCall.Handlex10', isLeaf: false);
@override
void run() {
@@ -1139,8 +1242,8 @@
Handlex20()
: f = ffiTestFunctions.lookupFunction<NativeFunction20Handle,
- Function20Object>('Function20Handle'),
- super('FfiCall.Handlex20');
+ Function20Object>('Function20Handle', isLeaf: false),
+ super('FfiCall.Handlex20', isLeaf: false);
@override
void run() {
@@ -1180,10 +1283,12 @@
void main() {
final benchmarks = [
() => Uint8x01(),
+ () => Uint8x01(isLeaf: true),
() => Uint16x01(),
() => Uint32x01(),
() => Uint64x01(),
() => Int8x01(),
+ () => Int8x01(isLeaf: true),
() => Int16x01(),
() => Int32x01(),
() => Int32x02(),
@@ -1195,22 +1300,27 @@
() => Int64x04(),
() => Int64x10(),
() => Int64x20(),
+ () => Int64x20(isLeaf: true),
() => Int64Mintx01(),
+ () => Int64Mintx01(isLeaf: true),
() => Floatx01(),
() => Floatx02(),
() => Floatx04(),
() => Floatx10(),
() => Floatx20(),
+ () => Floatx20(isLeaf: true),
() => Doublex01(),
() => Doublex02(),
() => Doublex04(),
() => Doublex10(),
() => Doublex20(),
+ () => Doublex20(isLeaf: true),
() => PointerUint8x01(),
() => PointerUint8x02(),
() => PointerUint8x04(),
() => PointerUint8x10(),
() => PointerUint8x20(),
+ () => PointerUint8x20(isLeaf: true),
() => Handlex01(),
() => Handlex02(),
() => Handlex04(),
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 6c9f2d3..5ac59ba 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -527,6 +527,9 @@
get_toolchain_args = [
# TODO(athom): use sys.executable (python3).
+ # Note: depot_tools contains python.bat not python.exe
+ # so for python to land on the first python in the PATH
+ # irrespective of its extension we pass shell=True below.
'python',
os.path.join(depot_tools_path, 'win_toolchain',
'get_toolchain_if_necessary.py'),
@@ -537,7 +540,7 @@
get_toolchain_args.append('--force')
if no_download:
get_toolchain_args.append('--no-download')
- subprocess.check_call(get_toolchain_args)
+ subprocess.check_call(get_toolchain_args, shell=True)
return 0
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 7600785..ed754b3 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3779,6 +3779,27 @@
message: r"""Exceptional return value must be a constant.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)> templateFfiExpectedConstantArg =
+ const Template<Message Function(String name)>(
+ messageTemplate: r"""Argument '#name' must be a constant.""",
+ withArguments: _withArgumentsFfiExpectedConstantArg);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFfiExpectedConstantArg =
+ const Code<Message Function(String name)>(
+ "FfiExpectedConstantArg",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiExpectedConstantArg(String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeFfiExpectedConstantArg,
+ message: """Argument '${name}' must be a constant.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
templateFfiExtendsOrImplementsSealedClass =
const Template<Message Function(String name)>(
@@ -3932,6 +3953,24 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiLeafCallMustNotReturnHandle =
+ messageFfiLeafCallMustNotReturnHandle;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiLeafCallMustNotReturnHandle = const MessageCode(
+ "FfiLeafCallMustNotReturnHandle",
+ message: r"""FFI leaf call must not have Handle return type.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiLeafCallMustNotTakeHandle =
+ messageFfiLeafCallMustNotTakeHandle;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiLeafCallMustNotTakeHandle = const MessageCode(
+ "FfiLeafCallMustNotTakeHandle",
+ message: r"""FFI leaf call must not have Handle argument types.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(String name)> templateFfiNotStatic = const Template<
Message Function(String name)>(
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index d02d937..37074c3 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -462,6 +462,7 @@
CompileTimeErrorCode.YIELD_IN_NON_GENERATOR,
CompileTimeErrorCode.YIELD_OF_INVALID_TYPE,
FfiCode.ANNOTATION_ON_POINTER_FIELD,
+ FfiCode.ARGUMENT_MUST_BE_A_CONSTANT,
FfiCode.EMPTY_STRUCT,
FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD,
FfiCode.EXTRA_SIZE_ANNOTATION_CARRAY,
@@ -470,6 +471,8 @@
FfiCode.GENERIC_STRUCT_SUBCLASS,
FfiCode.INVALID_EXCEPTION_VALUE,
FfiCode.INVALID_FIELD_TYPE_IN_STRUCT,
+ FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE,
+ FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE,
FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD,
FfiCode.MISSING_ANNOTATION_ON_STRUCT_FIELD,
FfiCode.MISSING_EXCEPTION_VALUE,
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
index a9b49b3..ef53b2c 100644
--- a/pkg/analyzer/lib/src/dart/error/ffi_code.dart
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
@@ -23,6 +23,15 @@
/**
* Parameters:
+ * 0: the name of the argument
+ */
+ static const FfiCode ARGUMENT_MUST_BE_A_CONSTANT = FfiCode(
+ name: 'ARGUMENT_MUST_BE_A_CONSTANT',
+ message: "Argument '{0}' must be a constant.",
+ correction: "Try replacing the value with a literal or const.");
+
+ /**
+ * Parameters:
* 0: the name of the struct class
*/
static const FfiCode EMPTY_STRUCT = FfiCode(
@@ -106,6 +115,22 @@
/**
* No parameters.
*/
+ static const FfiCode LEAF_CALL_MUST_NOT_RETURN_HANDLE = FfiCode(
+ name: 'LEAF_CALL_MUST_NOT_RETURN_HANDLE',
+ message: "FFI leaf call must not return a Handle.",
+ correction: "Try changing the return type to primitive or struct.");
+
+ /**
+ * No parameters.
+ */
+ static const FfiCode LEAF_CALL_MUST_NOT_TAKE_HANDLE = FfiCode(
+ name: 'LEAF_CALL_MUST_NOT_TAKE_HANDLE',
+ message: "FFI leaf call must not take arguments of type Handle.",
+ correction: "Try changing the argument type to primitive or struct.");
+
+ /**
+ * No parameters.
+ */
static const FfiCode MISMATCHED_ANNOTATION_ON_STRUCT_FIELD = FfiCode(
name: 'MISMATCHED_ANNOTATION_ON_STRUCT_FIELD',
message: "The annotation does not match the declared type of the field.",
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index caff222..d03a815 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/error/ffi_code.dart';
@@ -20,6 +21,7 @@
static const _allocatorExtensionName = 'AllocatorAlloc';
static const _arrayClassName = 'Array';
static const _dartFfiLibraryName = 'dart.ffi';
+ static const _isLeafParamName = 'isLeaf';
static const _opaqueClassName = 'Opaque';
static const List<String> _primitiveIntegerNativeTypes = [
@@ -341,6 +343,26 @@
return false;
}
+ // Get the const bool value of `expr` if it exists.
+ // Return null if it isn't a const bool.
+ bool? _maybeGetBoolConstValue(Expression expr) {
+ if (expr is BooleanLiteral) {
+ return expr.value;
+ } else if (expr is Identifier) {
+ final staticElm = expr.staticElement;
+ if (staticElm is ConstVariableElement) {
+ return staticElm.computeConstantValue()?.toBoolValue();
+ }
+ if (staticElm is PropertyAccessorElementImpl) {
+ final v = staticElm.variable;
+ if (v is ConstVariableElement) {
+ return v.computeConstantValue()?.toBoolValue();
+ }
+ }
+ }
+ return null;
+ }
+
_PrimitiveDartType _primitiveNativeType(DartType nativeType) {
if (nativeType is InterfaceType) {
final element = nativeType.element;
@@ -461,7 +483,9 @@
_errorReporter.reportErrorForNode(
FfiCode.MUST_BE_A_SUBTYPE, node, [TPrime, F, 'asFunction']);
}
+ _validateFfiLeafCallUsesNoHandles(node, TPrime, node);
}
+ _validateIsLeafIsConst(node);
}
/// Validates that the given [nativeType] is, when native types are converted
@@ -551,6 +575,37 @@
}
}
+ void _validateFfiLeafCallUsesNoHandles(
+ MethodInvocation node, DartType nativeType, AstNode errorNode) {
+ final args = node.argumentList.arguments;
+ if (args.isNotEmpty) {
+ for (final arg in args) {
+ if (arg is NamedExpression) {
+ if (arg.element?.name == _isLeafParamName) {
+ // Handles are ok for regular (non-leaf) calls. Check `isLeaf:true`.
+ final bool? isLeaf = _maybeGetBoolConstValue(arg.expression);
+ if (isLeaf != null && isLeaf) {
+ if (nativeType is FunctionType) {
+ if (_primitiveNativeType(nativeType.returnType) ==
+ _PrimitiveDartType.handle) {
+ _errorReporter.reportErrorForNode(
+ FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE, errorNode);
+ }
+ for (final param in nativeType.normalParameterTypes) {
+ if (_primitiveNativeType(param) ==
+ _PrimitiveDartType.handle) {
+ _errorReporter.reportErrorForNode(
+ FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE, errorNode);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/// Validate that the fields declared by the given [node] meet the
/// requirements for fields within a struct or union class.
void _validateFieldsInCompound(FieldDeclaration node) {
@@ -654,6 +709,27 @@
}
}
+ void _validateIsLeafIsConst(MethodInvocation node) {
+ // Ensure `isLeaf` is const as we need the value at compile time to know
+ // which trampoline to generate.
+ final args = node.argumentList.arguments;
+ if (args.isNotEmpty) {
+ for (final arg in args) {
+ if (arg is NamedExpression) {
+ if (arg.element?.name == _isLeafParamName) {
+ if (_maybeGetBoolConstValue(arg.expression) == null) {
+ final AstNode errorNode = node;
+ _errorReporter.reportErrorForNode(
+ FfiCode.ARGUMENT_MUST_BE_A_CONSTANT,
+ errorNode,
+ [_isLeafParamName]);
+ }
+ }
+ }
+ }
+ }
+ }
+
/// Validate the invocation of the instance method
/// `DynamicLibrary.lookupFunction<S, F>()`.
void _validateLookupFunction(MethodInvocation node) {
@@ -678,6 +754,8 @@
_errorReporter.reportErrorForNode(
FfiCode.MUST_BE_A_SUBTYPE, errorNode, [S, F, 'lookupFunction']);
}
+ _validateIsLeafIsConst(node);
+ _validateFfiLeafCallUsesNoHandles(node, S, typeArguments![0]);
}
/// Validate that none of the [annotations] are from `dart:ffi`.
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index d2def94..a7a7b27 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -620,6 +620,8 @@
const NativeType();
}
+class Handle extends NativeType {}
+
class Void extends NativeType {}
class Int8 extends NativeType {
@@ -674,7 +676,7 @@
extension NativeFunctionPointer<NF extends Function>
on Pointer<NativeFunction<NF>> {
- external DF asFunction<DF extends Function>();
+ external DF asFunction<DF extends Function>({bool isLeaf:false});
}
class _Compound extends NativeType {}
@@ -689,11 +691,13 @@
const Packed(this.memberAlignment);
}
-abstract class DynamicLibrary {}
+abstract class DynamicLibrary {
+ external factory DynamicLibrary.open(String name);
+}
extension DynamicLibraryExtension on DynamicLibrary {
external F lookupFunction<T extends Function, F extends Function>(
- String symbolName);
+ String symbolName, {bool isLeaf:false});
}
abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/pkg/analyzer/test/src/diagnostics/argument_must_be_a_constant_test.dart b/pkg/analyzer/test/src/diagnostics/argument_must_be_a_constant_test.dart
new file mode 100644
index 0000000..a60b375
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/argument_must_be_a_constant_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ArgumentMustBeAConstantTest);
+ });
+}
+
+@reflectiveTest
+class ArgumentMustBeAConstantTest extends PubPackageResolutionTest {
+ test_AsFunctionIsLeafGlobal() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef Int8UnOp = Int8 Function(Int8);
+typedef IntUnOp = int Function(int);
+bool isLeaf = false;
+doThings() {
+ Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+ IntUnOp f = p.asFunction(isLeaf:isLeaf);
+ f(8);
+}
+''', [
+ error(FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, 211, 27),
+ ]);
+ }
+
+ test_AsFunctionIsLeafLocal() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef Int8UnOp = Int8 Function(Int8);
+typedef IntUnOp = int Function(int);
+doThings() {
+ bool isLeaf = false;
+ Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+ IntUnOp f = p.asFunction(isLeaf:isLeaf);
+ f(8);
+}
+''', [
+ error(FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, 213, 27),
+ ]);
+ }
+
+ test_AsFunctionIsLeafParam() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef Int8UnOp = Int8 Function(Int8);
+typedef IntUnOp = int Function(int);
+doThings(bool isLeaf) {
+ Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+ IntUnOp f = p.asFunction(isLeaf:isLeaf);
+ f(8);
+}
+''', [
+ error(FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, 201, 27),
+ ]);
+ }
+
+ test_LookupFunctionIsLeaf() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef Int8UnOp = Int8 Function(Int8);
+typedef IntUnOp = int Function(int);
+doThings(bool isLeaf) {
+ DynamicLibrary l = DynamicLibrary.open("my_lib");
+ l.lookupFunction<Int8UnOp, IntUnOp>("timesFour", isLeaf:isLeaf);
+}
+''', [
+ error(FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, 174, 63),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/ffi_leaf_call_must_not_use_handle_test.dart b/pkg/analyzer/test/src/diagnostics/ffi_leaf_call_must_not_use_handle_test.dart
new file mode 100644
index 0000000..55320ad
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/ffi_leaf_call_must_not_use_handle_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(LeafCallMustNotUseHandle);
+ });
+}
+
+@reflectiveTest
+class LeafCallMustNotUseHandle extends PubPackageResolutionTest {
+ test_AsFunctionReturnsHandle() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef NativeReturnsHandle = Handle Function();
+typedef ReturnsHandle = Object Function();
+doThings() {
+ Pointer<NativeFunction<NativeReturnsHandle>> p = Pointer.fromAddress(1337);
+ ReturnsHandle f = p.asFunction(isLeaf:true);
+ f();
+}
+''', [
+ error(FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE, 222, 25),
+ ]);
+ }
+
+ test_AsFunctionTakesHandle() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef NativeTakesHandle = Void Function(Handle);
+typedef TakesHandle = void Function(Object);
+class MyClass {}
+doThings() {
+ Pointer<NativeFunction<NativeTakesHandle>> p = Pointer.fromAddress(1337);
+ TakesHandle f = p.asFunction(isLeaf:true);
+ f(MyClass());
+}
+''', [
+ error(FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE, 239, 25),
+ ]);
+ }
+
+ test_LookupFunctionReturnsHandle() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef NativeReturnsHandle = Handle Function();
+typedef ReturnsHandle = Object Function();
+doThings() {
+ DynamicLibrary l = DynamicLibrary.open("my_lib");
+ l.lookupFunction<NativeReturnsHandle, ReturnsHandle>("timesFour", isLeaf:true);
+}
+''', [
+ error(FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE, 195, 19),
+ ]);
+ }
+
+ test_LookupFunctionTakesHandle() async {
+ await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef NativeTakesHandle = Void Function(Handle);
+typedef TakesHandle = void Function(Object);
+class MyClass {}
+doThings() {
+ DynamicLibrary l = DynamicLibrary.open("my_lib");
+ l.lookupFunction<NativeTakesHandle, TakesHandle>("timesFour", isLeaf:true);
+}
+''', [
+ error(FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE, 216, 17),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index c6fcbe0..66018e3 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -17,6 +17,7 @@
import 'ambiguous_set_or_map_literal_test.dart' as ambiguous_set_or_map_literal;
import 'annotation_on_pointer_field_test.dart' as annotation_on_pointer_field;
import 'annotation_syntax_test.dart' as annotation_syntax;
+import 'argument_must_be_a_constant_test.dart' as argument_must_be_a_constant;
import 'argument_type_not_assignable_test.dart' as argument_type_not_assignable;
import 'argument_type_not_assignable_to_error_handler_test.dart'
as argument_type_not_assignable_to_error_handler;
@@ -188,6 +189,8 @@
import 'extra_size_annotation_carray_test.dart' as extra_size_annotation_carray;
import 'ffi_array_multi_non_positive_input_test.dart'
as ffi_array_multi_non_positive_input_test;
+import 'ffi_leaf_call_must_not_use_handle_test.dart'
+ as ffi_leaf_call_must_not_use_handle;
import 'field_in_struct_with_initializer_test.dart'
as field_in_struct_with_initializer;
import 'field_initialized_by_multiple_initializers_test.dart'
@@ -700,6 +703,7 @@
ambiguous_set_or_map_literal.main();
annotation_on_pointer_field.main();
annotation_syntax.main();
+ argument_must_be_a_constant.main();
argument_type_not_assignable.main();
argument_type_not_assignable_to_error_handler.main();
assert_in_redirecting_constructor.main();
@@ -816,6 +820,7 @@
extra_positional_arguments.main();
extra_size_annotation_carray.main();
ffi_array_multi_non_positive_input_test.main();
+ ffi_leaf_call_must_not_use_handle.main();
field_in_struct_with_initializer.main();
field_initialized_by_multiple_initializers.main();
final_initialized_in_declaration_and_constructor.main();
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index b2250cf..6506633 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -52,11 +52,14 @@
LocatedMessage,
messageFfiExceptionalReturnNull,
messageFfiExpectedConstant,
+ messageFfiLeafCallMustNotReturnHandle,
+ messageFfiLeafCallMustNotTakeHandle,
messageFfiPackedAnnotationAlignment,
messageNonPositiveArrayDimensions,
noLength,
templateFfiDartTypeMismatch,
templateFfiEmptyStruct,
+ templateFfiExpectedConstantArg,
templateFfiExpectedExceptionalReturn,
templateFfiExpectedNoExceptionalReturn,
templateFfiExtendsOrImplementsSealedClass,
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 9c7263d..c890c30 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -326,6 +326,7 @@
FfiEmptyStruct/analyzerCode: Fail
FfiExceptionalReturnNull/analyzerCode: Fail
FfiExpectedConstant/analyzerCode: Fail
+FfiExpectedConstantArg/analyzerCode: Fail
FfiExpectedExceptionalReturn/analyzerCode: Fail
FfiExpectedNoExceptionalReturn/analyzerCode: Fail
FfiExtendsOrImplementsSealedClass/analyzerCode: Fail
@@ -334,6 +335,8 @@
FfiFieldInitializer/analyzerCode: Fail
FfiFieldNoAnnotation/analyzerCode: Fail
FfiFieldNull/analyzerCode: Fail
+FfiLeafCallMustNotReturnHandle/analyzerCode: Fail
+FfiLeafCallMustNotTakeHandle/analyzerCode: Fail
FfiNotStatic/analyzerCode: Fail
FfiPackedAnnotation/analyzerCode: Fail
FfiPackedAnnotationAlignment/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 2afa94c..b00bab2 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4501,6 +4501,21 @@
template: "Exceptional return value must not be null."
external: test/ffi_test.dart
+FfiExpectedConstantArg:
+ # Used by dart:ffi
+ template: "Argument '#name' must be a constant."
+ external: test/ffi_test.dart
+
+FfiLeafCallMustNotTakeHandle:
+ # Used by dart:ffi
+ template: "FFI leaf call must not have Handle argument types."
+ external: test/ffi_test.dart
+
+FfiLeafCallMustNotReturnHandle:
+ # Used by dart:ffi
+ template: "FFI leaf call must not have Handle return type."
+ external: test/ffi_test.dart
+
SpreadTypeMismatch:
template: "Unexpected type '#type' of a spread. Expected 'dynamic' or an Iterable."
script:
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index a4c6fd4..5225286 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -221,6 +221,7 @@
final Library ffiLibrary;
final Class allocatorClass;
final Class nativeFunctionClass;
+ final Class handleClass;
final Class opaqueClass;
final Class arrayClass;
final Class arraySizeClass;
@@ -324,6 +325,7 @@
ffiLibrary = index.getLibrary('dart:ffi'),
allocatorClass = index.getClass('dart:ffi', 'Allocator'),
nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
+ handleClass = index.getClass('dart:ffi', 'Handle'),
opaqueClass = index.getClass('dart:ffi', 'Opaque'),
arrayClass = index.getClass('dart:ffi', 'Array'),
arraySizeClass = index.getClass('dart:ffi', '_ArraySize'),
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index d1640a2..6917fd1 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -8,7 +8,10 @@
show
messageFfiExceptionalReturnNull,
messageFfiExpectedConstant,
+ messageFfiLeafCallMustNotReturnHandle,
+ messageFfiLeafCallMustNotTakeHandle,
templateFfiDartTypeMismatch,
+ templateFfiExpectedConstantArg,
templateFfiExpectedExceptionalReturn,
templateFfiExpectedNoExceptionalReturn,
templateFfiExtendsOrImplementsSealedClass,
@@ -176,12 +179,14 @@
}
}
} else if (target == lookupFunctionMethod) {
- final DartType nativeType = InterfaceType(
+ final nativeType = InterfaceType(
nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
final DartType dartType = node.arguments.types[1];
_ensureNativeTypeValid(nativeType, node);
_ensureNativeTypeToDartType(nativeType, dartType, node);
+ _ensureIsLeafIsConst(node);
+ _ensureLeafCallDoesNotUseHandles(nativeType, node);
final replacement = _replaceLookupFunction(node);
@@ -197,20 +202,27 @@
}
return replacement;
} else if (target == asFunctionMethod) {
- final DartType dartType = node.arguments.types[1];
+ final dartType = node.arguments.types[1];
final DartType nativeType = InterfaceType(
nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
_ensureNativeTypeValid(nativeType, node);
_ensureNativeTypeToDartType(nativeType, dartType, node);
+ _ensureIsLeafIsConst(node);
+ _ensureLeafCallDoesNotUseHandles(nativeType, node);
final DartType nativeSignature =
(nativeType as InterfaceType).typeArguments[0];
+ bool isLeaf = _getIsLeafBoolean(node);
+ if (isLeaf == null) {
+ isLeaf = false;
+ }
+
// Inline function body to make all type arguments instatiated.
final replacement = StaticInvocation(
asFunctionInternal,
- Arguments([node.arguments.positional[0]],
+ Arguments([node.arguments.positional[0], BoolLiteral(isLeaf)],
types: [dartType, nativeSignature]));
if (dartType is FunctionType) {
@@ -411,12 +423,12 @@
Expression _replaceLookupFunction(StaticInvocation node) {
// The generated code looks like:
//
- // _asFunctionInternal<DS, NS>(lookup<NativeFunction<NS>>(symbolName))
-
+ // _asFunctionInternal<DS, NS>(lookup<NativeFunction<NS>>(symbolName),
+ // isLeaf)
final DartType nativeSignature = node.arguments.types[0];
final DartType dartSignature = node.arguments.types[1];
- final Arguments args = Arguments([
+ final Arguments lookupArgs = Arguments([
node.arguments.positional[1]
], types: [
InterfaceType(nativeFunctionClass, Nullability.legacy, [nativeSignature])
@@ -425,11 +437,18 @@
final Expression lookupResult = MethodInvocation(
node.arguments.positional[0],
Name("lookup"),
- args,
+ lookupArgs,
libraryLookupMethod);
- return StaticInvocation(asFunctionInternal,
- Arguments([lookupResult], types: [dartSignature, nativeSignature]));
+ bool isLeaf = _getIsLeafBoolean(node);
+ if (isLeaf == null) {
+ isLeaf = false;
+ }
+
+ return StaticInvocation(
+ asFunctionInternal,
+ Arguments([lookupResult, BoolLiteral(isLeaf)],
+ types: [dartSignature, nativeSignature]));
}
// We need to rewrite calls to 'fromFunction' into two calls, representing the
@@ -818,6 +837,72 @@
throw _FfiStaticTypeError();
}
}
+
+ // Returns
+ // - `true` if leaf
+ // - `false` if not leaf
+ // - `null` if the expression is not valid (e.g. non-const bool, null)
+ bool _getIsLeafBoolean(StaticInvocation node) {
+ for (final named in node.arguments.named) {
+ if (named.name == 'isLeaf') {
+ final expr = named.value;
+ if (expr is BoolLiteral) {
+ return expr.value;
+ } else if (expr is ConstantExpression) {
+ final constant = expr.constant;
+ if (constant is BoolConstant) {
+ return constant.value;
+ }
+ }
+ // isLeaf is passed some invalid value.
+ return null;
+ }
+ }
+ // isLeaf defaults to false.
+ return false;
+ }
+
+ void _ensureIsLeafIsConst(StaticInvocation node) {
+ final isLeaf = _getIsLeafBoolean(node);
+ if (isLeaf == null) {
+ diagnosticReporter.report(
+ templateFfiExpectedConstantArg.withArguments('isLeaf'),
+ node.fileOffset,
+ 1,
+ node.location.file);
+ // Throw so we don't get another error about not replacing
+ // `lookupFunction`, which will shadow the above error.
+ throw _FfiStaticTypeError();
+ }
+ }
+
+ void _ensureLeafCallDoesNotUseHandles(
+ InterfaceType nativeType, StaticInvocation node) {
+ // Handles are only disallowed for leaf calls.
+ final isLeaf = _getIsLeafBoolean(node);
+ if (isLeaf == null || isLeaf == false) {
+ return;
+ }
+
+ // Check if return type is Handle.
+ final functionType = nativeType.typeArguments[0];
+ if (functionType is FunctionType) {
+ final returnType = functionType.returnType;
+ if (returnType is InterfaceType) {
+ if (returnType.classNode == handleClass) {
+ diagnosticReporter.report(messageFfiLeafCallMustNotReturnHandle,
+ node.fileOffset, 1, node.location.file);
+ }
+ }
+ // Check if any of the argument types are Handle.
+ for (InterfaceType param in functionType.positionalParameters) {
+ if (param.classNode == handleClass) {
+ diagnosticReporter.report(messageFfiLeafCallMustNotTakeHandle,
+ node.fileOffset, 1, node.location.file);
+ }
+ }
+ }
+ }
}
/// Used internally for abnormal control flow to prevent cascading error
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
index 08c06bb..0e9d6a5 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
@@ -67,7 +67,7 @@
final ffi::DynamicLibrary* dylib = [@vm.inferred-type.metadata=dart.ffi::DynamicLibrary?] ffi::DynamicLibrary::executable();
final () →* self::Struct1* function1 = block {
_in::_nativeEffect(new self::Struct1::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)));
- } =>ffi::_asFunctionInternal<() →* self::Struct1*, () →* self::Struct1*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<() →* self::Struct1*>*>("function1"));
+ } =>ffi::_asFunctionInternal<() →* self::Struct1*, () →* self::Struct1*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<() →* self::Struct1*>*>("function1"), false);
final self::Struct1* struct1 = [@vm.call-site-attributes.metadata=receiverType:#lib::Struct1* Function()*] function1(){() →* self::Struct1*};
core::print(struct1);
}
@@ -75,7 +75,7 @@
final ffi::Pointer<ffi::NativeFunction<() →* self::Struct2*>*>* pointer = [@vm.inferred-type.metadata=dart.ffi::Pointer?] ffi::Pointer::fromAddress<ffi::NativeFunction<() →* self::Struct2*>*>(3735928559);
final () →* self::Struct2* function2 = block {
_in::_nativeEffect(new self::Struct2::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)));
- } =>ffi::_asFunctionInternal<() →* self::Struct2*, () →* self::Struct2*>(pointer);
+ } =>ffi::_asFunctionInternal<() →* self::Struct2*, () →* self::Struct2*>(pointer, false);
final self::Struct2* struct2 = [@vm.call-site-attributes.metadata=receiverType:#lib::Struct2* Function()*] function2(){() →* self::Struct2*};
core::print(struct2);
}
@@ -90,12 +90,12 @@
}
static method testLookupFunctionArgument() → void {
final ffi::DynamicLibrary* dylib = [@vm.inferred-type.metadata=dart.ffi::DynamicLibrary?] ffi::DynamicLibrary::executable();
- final (self::Struct5*) →* void function5 = [@vm.inferred-type.metadata=dart.core::_Closure?] ffi::_asFunctionInternal<(self::Struct5*) →* void, (self::Struct5*) →* ffi::Void*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<(self::Struct5*) →* ffi::Void*>*>("function5"));
+ final (self::Struct5*) →* void function5 = [@vm.inferred-type.metadata=dart.core::_Closure?] ffi::_asFunctionInternal<(self::Struct5*) →* void, (self::Struct5*) →* ffi::Void*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<(self::Struct5*) →* ffi::Void*>*>("function5"), false);
core::print(function5);
}
static method testAsFunctionArgument() → void {
final ffi::Pointer<ffi::NativeFunction<(self::Struct6*) →* ffi::Void*>*>* pointer = [@vm.inferred-type.metadata=dart.ffi::Pointer?] ffi::Pointer::fromAddress<ffi::NativeFunction<(self::Struct6*) →* ffi::Void*>*>(3735928559);
- final (self::Struct6*) →* void function6 = [@vm.inferred-type.metadata=dart.core::_Closure?] ffi::_asFunctionInternal<(self::Struct6*) →* void, (self::Struct6*) →* ffi::Void*>(pointer);
+ final (self::Struct6*) →* void function6 = [@vm.inferred-type.metadata=dart.core::_Closure?] ffi::_asFunctionInternal<(self::Struct6*) →* void, (self::Struct6*) →* ffi::Void*>(pointer, false);
core::print(function6);
}
static method returnStruct7() → self::Struct7* {
diff --git a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
index e642819..87e9d66 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
@@ -109,6 +109,13 @@
Dart_ExecuteInternalCommand("gc-now", nullptr);
}
+DART_EXPORT uint8_t IsThreadInGenerated() {
+ return Dart_ExecuteInternalCommand("is-thread-in-generated", nullptr) !=
+ nullptr
+ ? 1
+ : 0;
+}
+
#if !defined(HOST_OS_WINDOWS)
DART_EXPORT void* UnprotectCodeOtherThread(void* isolate,
std::condition_variable* var,
@@ -276,6 +283,35 @@
return ExpectAbort(fn);
}
+DART_EXPORT intptr_t TestCallbackLeaf(void (*fn)()) {
+#if defined(DEBUG)
+ // Calling a callback from a leaf call will crash on T->IsAtSafepoint().
+ return ExpectAbort(fn);
+#else
+ // The above will only crash in debug as ASSERTS are disabled in all other
+ // build modes.
+ return 0;
+#endif
+}
+
+void CallDebugName() {
+ Dart_DebugName();
+}
+
+DART_EXPORT intptr_t TestLeafCallApi(void (*fn)()) {
+ // This should be fine since it's a simple function that returns a const
+ // string. Though any API call should be considered unsafe from leaf calls.
+ Dart_VersionString();
+#if defined(DEBUG)
+ // This will fail because it requires running in DARTSCOPE.
+ return ExpectAbort(&CallDebugName);
+#else
+ // The above will only crash in debug as ASSERTS are disabled in all other
+ // build modes.
+ return 0;
+#endif
+}
+
#endif // defined(TARGET_OS_LINUX)
DART_EXPORT void IGH_MsanUnpoison(void* start, intptr_t length) {
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 95c7166..5b4601d 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -109,10 +109,10 @@
Options::depfile());
}
bool success = true;
- if (Options::snapshot_filename() != NULL) {
- success &= file->Print("%s: ", Options::snapshot_filename());
- } else {
+ if (Options::depfile_output_filename() != NULL) {
success &= file->Print("%s: ", Options::depfile_output_filename());
+ } else {
+ success &= file->Print("%s: ", Options::snapshot_filename());
}
if (kernel_isolate_is_running) {
Dart_KernelCompilationResult result = Dart_KernelListDependencies();
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 7b1ad66..f9217ed 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -62,7 +62,7 @@
}
// Static invocations to this method are translated directly in streaming FGB.
-DEFINE_NATIVE_ENTRY(Ffi_asFunctionInternal, 2, 1) {
+DEFINE_NATIVE_ENTRY(Ffi_asFunctionInternal, 2, 2) {
UNREACHABLE();
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index c17daf4..586c58a 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -406,7 +406,7 @@
V(Ffi_storePointer, 3) \
V(Ffi_address, 1) \
V(Ffi_fromAddress, 1) \
- V(Ffi_asFunctionInternal, 1) \
+ V(Ffi_asFunctionInternal, 2) \
V(Ffi_nativeCallbackFunction, 2) \
V(Ffi_pointerFromFunction, 1) \
V(Ffi_dl_open, 1) \
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 1011d8c..43a677c 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -6435,25 +6435,31 @@
#define Z zone_
-LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
- bool is_optimizing) const {
+LocationSummary* FfiCallInstr::MakeLocationSummaryInternal(
+ Zone* zone,
+ bool is_optimizing,
+ const Register temp) const {
// The temporary register needs to be callee-saved and not an argument
// register.
ASSERT(((1 << CallingConventions::kFfiAnyNonAbiRegister) &
CallingConventions::kArgumentRegisters) == 0);
- constexpr intptr_t kNumTemps = 2;
+ // TODO(dartbug.com/45468): Investigate whether we can avoid spilling
+ // registers across ffi leaf calls by not using `kCall` here.
+ LocationSummary* summary = new (zone) LocationSummary(
+ zone, /*num_inputs=*/InputCount(),
+ /*num_temps=*/temp == kNoRegister ? 2 : 3, LocationSummary::kCall);
- LocationSummary* summary = new (zone)
- LocationSummary(zone, /*num_inputs=*/InputCount(),
- /*num_temps=*/kNumTemps, LocationSummary::kCall);
-
- const Register temp0 = CallingConventions::kSecondNonArgumentRegister;
- const Register temp1 = CallingConventions::kFfiAnyNonAbiRegister;
+ const Register temp0 = CallingConventions::kFfiAnyNonAbiRegister;
+ const Register temp1 = CallingConventions::kSecondNonArgumentRegister;
ASSERT(temp0 != temp1);
summary->set_temp(0, Location::RegisterLocation(temp0));
summary->set_temp(1, Location::RegisterLocation(temp1));
+ if (temp != kNoRegister) {
+ summary->set_temp(2, Location::RegisterLocation(temp));
+ }
+
summary->set_in(TargetAddressIndex(),
Location::RegisterLocation(
CallingConventions::kFirstNonArgumentRegister));
@@ -6476,14 +6482,13 @@
return summary;
}
-void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler) {
+void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler,
+ const Register saved_fp,
+ const Register temp) {
if (compiler::Assembler::EmittingComments()) {
__ Comment("EmitParamMoves");
}
- const Register saved_fp = locs()->temp(0).reg();
- const Register temp = locs()->temp(1).reg();
-
// Moves for return pointer.
const auto& return_location =
marshaller_.Location(compiler::ffi::kResultIndex);
@@ -6591,7 +6596,9 @@
}
}
-void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
+void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler,
+ const Register temp0,
+ const Register temp1) {
__ Comment("EmitReturnMoves");
const auto& returnLocation =
@@ -6611,16 +6618,17 @@
ASSERT(returnLocation.payload_type().IsCompound());
ASSERT(marshaller_.PassTypedData());
- const Register temp0 = TMP != kNoRegister ? TMP : locs()->temp(0).reg();
- const Register temp1 = locs()->temp(1).reg();
- ASSERT(temp0 != temp1);
-
// Get the typed data pointer which we have pinned to a stack slot.
const Location typed_data_loc = locs()->in(TypedDataIndex());
ASSERT(typed_data_loc.IsStackSlot());
ASSERT(typed_data_loc.base_reg() == FPREG);
- __ LoadMemoryValue(temp0, FPREG, 0);
- __ LoadMemoryValue(temp0, temp0, typed_data_loc.ToStackSlotOffset());
+ // If this is a leaf call there is no extra call frame to step through.
+ if (is_leaf_) {
+ __ LoadMemoryValue(temp0, FPREG, typed_data_loc.ToStackSlotOffset());
+ } else {
+ __ LoadMemoryValue(temp0, FPREG, 0);
+ __ LoadMemoryValue(temp0, temp0, typed_data_loc.ToStackSlotOffset());
+ }
__ LoadField(
temp0,
compiler::FieldAddress(
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 12baaef..e5800c4 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5106,12 +5106,14 @@
public:
FfiCallInstr(Zone* zone,
intptr_t deopt_id,
- const compiler::ffi::CallMarshaller& marshaller)
+ const compiler::ffi::CallMarshaller& marshaller,
+ bool is_leaf)
: Definition(deopt_id),
zone_(zone),
marshaller_(marshaller),
inputs_(marshaller.NumDefinitions() + 1 +
- (marshaller.PassTypedData() ? 1 : 0)) {
+ (marshaller.PassTypedData() ? 1 : 0)),
+ is_leaf_(is_leaf) {
inputs_.FillWith(
nullptr, 0,
marshaller.NumDefinitions() + 1 + (marshaller.PassTypedData() ? 1 : 0));
@@ -5162,14 +5164,27 @@
private:
virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
- void EmitParamMoves(FlowGraphCompiler* compiler);
- void EmitReturnMoves(FlowGraphCompiler* compiler);
+ LocationSummary* MakeLocationSummaryInternal(Zone* zone,
+ bool is_optimizing,
+ const Register temp) const;
+
+ // Clobbers both given registers.
+ // `saved_fp` is used as the frame base to rebase off of.
+ void EmitParamMoves(FlowGraphCompiler* compiler,
+ const Register saved_fp,
+ const Register temp);
+ // Clobbers both given temp registers.
+ void EmitReturnMoves(FlowGraphCompiler* compiler,
+ const Register temp0,
+ const Register temp1);
Zone* const zone_;
const compiler::ffi::CallMarshaller& marshaller_;
GrowableArray<Value*> inputs_;
+ bool is_leaf_;
+
DISALLOW_COPY_AND_ASSIGN(FfiCallInstr);
};
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 6add21d..2358f4e 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1402,85 +1402,114 @@
__ Drop(ArgumentCount()); // Drop the arguments.
}
+LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
+ bool is_optimizing) const {
+ return MakeLocationSummaryInternal(zone, is_optimizing, R0);
+}
+
void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Register saved_fp = locs()->temp(0).reg();
- const Register temp = locs()->temp(1).reg();
+ // For regular calls, this holds the FP for rebasing the original locations
+ // during EmitParamMoves.
+ // For leaf calls, this holds the SP used to restore the pre-aligned SP after
+ // the call.
+ const Register saved_fp_or_sp = locs()->temp(0).reg();
+ RELEASE_ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
+ (1 << saved_fp_or_sp)) != 0);
+ const Register temp1 = locs()->temp(1).reg();
+ const Register temp2 = locs()->temp(2).reg();
const Register branch = locs()->in(TargetAddressIndex()).reg();
- // Save frame pointer because we're going to update it when we enter the exit
- // frame.
- __ mov(saved_fp, compiler::Operand(FPREG));
+ // Ensure these are callee-saved register and are preserved across the call.
+ ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
+ (1 << saved_fp_or_sp)) != 0);
+ // temp doesn't need to be preserved.
- // Make a space to put the return address.
- __ PushImmediate(0);
+ __ mov(saved_fp_or_sp,
+ is_leaf_ ? compiler::Operand(SPREG) : compiler::Operand(FPREG));
- // We need to create a dummy "exit frame". It will have a null code object.
- __ LoadObject(CODE_REG, Object::null_object());
- __ set_constant_pool_allowed(false);
- __ EnterDartFrame(0, /*load_pool_pointer=*/false);
+ if (!is_leaf_) {
+ // Make a space to put the return address.
+ __ PushImmediate(0);
- // Reserve space for arguments and align frame before entering C++ world.
+ // We need to create a dummy "exit frame". It will have a null code object.
+ __ LoadObject(CODE_REG, Object::null_object());
+ __ set_constant_pool_allowed(false);
+ __ EnterDartFrame(0, /*load_pool_pointer=*/false);
+ }
+
+ // Reserve space for the arguments that go on the stack (if any), then align.
__ ReserveAlignedFrameSpace(marshaller_.RequiredStackSpaceInBytes());
- EmitParamMoves(compiler);
+ EmitParamMoves(compiler, is_leaf_ ? FPREG : saved_fp_or_sp, temp1);
if (compiler::Assembler::EmittingComments()) {
- __ Comment("Call");
+ __ Comment(is_leaf_ ? "Leaf Call" : "Call");
}
- // We need to copy the return address up into the dummy stack frame so the
- // stack walker will know which safepoint to use.
- __ mov(TMP, compiler::Operand(PC));
- __ str(TMP, compiler::Address(FPREG, kSavedCallerPcSlotFromFp *
- compiler::target::kWordSize));
- // For historical reasons, the PC on ARM points 8 bytes past the current
- // instruction. Therefore we emit the metadata here, 8 bytes (2 instructions)
- // after the original mov.
- compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
- UntaggedPcDescriptors::Kind::kOther, locs(),
- env());
-
- // Update information in the thread object and enter a safepoint.
- if (CanExecuteGeneratedCodeInSafepoint()) {
- __ LoadImmediate(temp, compiler::target::Thread::exit_through_ffi());
- __ TransitionGeneratedToNative(branch, FPREG, temp, saved_fp,
- /*enter_safepoint=*/true);
-
+ if (is_leaf_) {
__ blx(branch);
-
- // Update information in the thread object and leave the safepoint.
- __ TransitionNativeToGenerated(saved_fp, temp, /*leave_safepoint=*/true);
} else {
- // We cannot trust that this code will be executable within a safepoint.
- // Therefore we delegate the responsibility of entering/exiting the
- // safepoint to a stub which in the VM isolate's heap, which will never lose
- // execute permission.
- __ ldr(TMP,
- compiler::Address(
- THR, compiler::target::Thread::
- call_native_through_safepoint_entry_point_offset()));
+ // We need to copy the return address up into the dummy stack frame so the
+ // stack walker will know which safepoint to use.
+ __ mov(temp1, compiler::Operand(PC));
+ __ str(temp1, compiler::Address(FPREG, kSavedCallerPcSlotFromFp *
+ compiler::target::kWordSize));
- // Calls R8 in a safepoint and clobbers R4 and NOTFP.
- ASSERT(branch == R8 && temp == R4);
- static_assert((kReservedCpuRegisters & (1 << NOTFP)) != 0,
- "NOTFP should be a reserved register");
- __ blx(TMP);
+ // For historical reasons, the PC on ARM points 8 bytes past the current
+ // instruction. Therefore we emit the metadata here, 8 bytes
+ // (2 instructions) after the original mov.
+ compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
+ UntaggedPcDescriptors::Kind::kOther, locs(),
+ env());
+
+ // Update information in the thread object and enter a safepoint.
+ if (CanExecuteGeneratedCodeInSafepoint()) {
+ __ LoadImmediate(temp1, compiler::target::Thread::exit_through_ffi());
+ __ TransitionGeneratedToNative(branch, FPREG, temp1, saved_fp_or_sp,
+ /*enter_safepoint=*/true);
+
+ __ blx(branch);
+
+ // Update information in the thread object and leave the safepoint.
+ __ TransitionNativeToGenerated(saved_fp_or_sp, temp1,
+ /*leave_safepoint=*/true);
+ } else {
+ // We cannot trust that this code will be executable within a safepoint.
+ // Therefore we delegate the responsibility of entering/exiting the
+ // safepoint to a stub which in the VM isolate's heap, which will never
+ // lose execute permission.
+ __ ldr(temp1,
+ compiler::Address(
+ THR, compiler::target::Thread::
+ call_native_through_safepoint_entry_point_offset()));
+
+ // Calls R8 in a safepoint and clobbers R4 and NOTFP.
+ ASSERT(branch == R8);
+ static_assert((kReservedCpuRegisters & (1 << NOTFP)) != 0,
+ "NOTFP should be a reserved register");
+ __ blx(temp1);
+ }
+
+ // Restore the global object pool after returning from runtime (old space is
+ // moving, so the GOP could have been relocated).
+ if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+ __ SetupGlobalPoolAndDispatchTable();
+ }
}
- // Restore the global object pool after returning from runtime (old space is
- // moving, so the GOP could have been relocated).
- if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
- __ SetupGlobalPoolAndDispatchTable();
+ EmitReturnMoves(compiler, temp1, temp2);
+
+ if (is_leaf_) {
+ // Restore the pre-aligned SP.
+ __ mov(SPREG, compiler::Operand(saved_fp_or_sp));
+ } else {
+ // Leave dummy exit frame.
+ __ LeaveDartFrame();
+ __ set_constant_pool_allowed(true);
+
+ // Instead of returning to the "fake" return address, we just pop it.
+ __ PopRegister(temp1);
}
-
- EmitReturnMoves(compiler);
-
- // Leave dummy exit frame.
- __ LeaveDartFrame();
- __ set_constant_pool_allowed(true);
-
- // Instead of returning to the "fake" return address, we just pop it.
- __ PopRegister(TMP);
}
// Keep in sync with NativeEntryInstr::EmitNativeCode.
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index c6e7064..9f3bfa7 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1228,46 +1228,48 @@
__ Drop(ArgumentCount()); // Drop the arguments.
}
+LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
+ bool is_optimizing) const {
+ return MakeLocationSummaryInternal(zone, is_optimizing, R11);
+}
+
void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Register saved_fp = locs()->temp(0).reg();
- const Register temp = locs()->temp(1).reg();
+ // For regular calls, this holds the FP for rebasing the original locations
+ // during EmitParamMoves.
+ // For leaf calls, this holds the SP used to restore the pre-aligned SP after
+ // the call.
+ const Register saved_fp_or_sp = locs()->temp(0).reg();
+ RELEASE_ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
+ (1 << saved_fp_or_sp)) != 0);
+ const Register temp1 = locs()->temp(1).reg();
+ const Register temp2 = locs()->temp(2).reg();
const Register branch = locs()->in(TargetAddressIndex()).reg();
- // Save frame pointer because we're going to update it when we enter the exit
- // frame.
- __ mov(saved_fp, FPREG);
+ // Ensure these are callee-saved register and are preserved across the call.
+ ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
+ (1 << saved_fp_or_sp)) != 0);
+ // temps don't need to be preserved.
- // We need to create a dummy "exit frame". It will share the same pool pointer
- // but have a null code object.
- __ LoadObject(CODE_REG, Object::null_object());
- __ set_constant_pool_allowed(false);
- __ EnterDartFrame(0, PP);
+ __ mov(saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
- // Make space for arguments and align the frame.
+ if (!is_leaf_) {
+ // We need to create a dummy "exit frame". It will share the same pool
+ // pointer but have a null code object.
+ __ LoadObject(CODE_REG, Object::null_object());
+ __ set_constant_pool_allowed(false);
+ __ EnterDartFrame(0, PP);
+ }
+
+ // Reserve space for the arguments that go on the stack (if any), then align.
__ ReserveAlignedFrameSpace(marshaller_.RequiredStackSpaceInBytes());
- EmitParamMoves(compiler);
+ EmitParamMoves(compiler, is_leaf_ ? FPREG : saved_fp_or_sp, temp1);
if (compiler::Assembler::EmittingComments()) {
- __ Comment("Call");
+ __ Comment(is_leaf_ ? "Leaf Call" : "Call");
}
- // We need to copy a dummy return address up into the dummy stack frame so the
- // stack walker will know which safepoint to use.
- //
- // ADR loads relative to itself, so add kInstrSize to point to the next
- // instruction.
- __ adr(temp, compiler::Immediate(Instr::kInstrSize));
- compiler->EmitCallsiteMetadata(
- source(), deopt_id(), UntaggedPcDescriptors::Kind::kOther, locs(), env());
- __ StoreToOffset(temp, FPREG, kSavedCallerPcSlotFromFp * kWordSize);
-
- if (CanExecuteGeneratedCodeInSafepoint()) {
- // Update information in the thread object and enter a safepoint.
- __ LoadImmediate(temp, compiler::target::Thread::exit_through_ffi());
- __ TransitionGeneratedToNative(branch, FPREG, temp,
- /*enter_safepoint=*/true);
-
+ if (is_leaf_) {
// We are entering runtime code, so the C stack pointer must be restored
// from the stack limit to the top of the stack.
__ mov(R25, CSP);
@@ -1278,39 +1280,75 @@
// Restore the Dart stack pointer.
__ mov(SP, CSP);
__ mov(CSP, R25);
-
- // Update information in the thread object and leave the safepoint.
- __ TransitionNativeToGenerated(temp, /*leave_safepoint=*/true);
} else {
- // We cannot trust that this code will be executable within a safepoint.
- // Therefore we delegate the responsibility of entering/exiting the
- // safepoint to a stub which in the VM isolate's heap, which will never lose
- // execute permission.
- __ ldr(TMP,
- compiler::Address(
- THR, compiler::target::Thread::
- call_native_through_safepoint_entry_point_offset()));
+ // We need to copy a dummy return address up into the dummy stack frame so
+ // the stack walker will know which safepoint to use.
+ //
+ // ADR loads relative to itself, so add kInstrSize to point to the next
+ // instruction.
+ __ adr(temp1, compiler::Immediate(Instr::kInstrSize));
+ compiler->EmitCallsiteMetadata(source(), deopt_id(),
+ UntaggedPcDescriptors::Kind::kOther, locs(),
+ env());
- // Calls R9 and clobbers R19 (along with volatile registers).
- ASSERT(branch == R9 && temp == R19);
- __ blr(TMP);
+ __ StoreToOffset(temp1, FPREG, kSavedCallerPcSlotFromFp * kWordSize);
+
+ if (CanExecuteGeneratedCodeInSafepoint()) {
+ // Update information in the thread object and enter a safepoint.
+ __ LoadImmediate(temp1, compiler::target::Thread::exit_through_ffi());
+ __ TransitionGeneratedToNative(branch, FPREG, temp1,
+ /*enter_safepoint=*/true);
+
+ // We are entering runtime code, so the C stack pointer must be restored
+ // from the stack limit to the top of the stack.
+ __ mov(R25, CSP);
+ __ mov(CSP, SP);
+
+ __ blr(branch);
+
+ // Restore the Dart stack pointer.
+ __ mov(SP, CSP);
+ __ mov(CSP, R25);
+
+ // Update information in the thread object and leave the safepoint.
+ __ TransitionNativeToGenerated(temp1, /*leave_safepoint=*/true);
+ } else {
+ // We cannot trust that this code will be executable within a safepoint.
+ // Therefore we delegate the responsibility of entering/exiting the
+ // safepoint to a stub which in the VM isolate's heap, which will never
+ // lose execute permission.
+ __ ldr(temp1,
+ compiler::Address(
+ THR, compiler::target::Thread::
+ call_native_through_safepoint_entry_point_offset()));
+
+ // Calls R9 and clobbers R19 (along with volatile registers).
+ ASSERT(branch == R9);
+ __ blr(temp1);
+ }
+
+ // Refresh pinned registers values (inc. write barrier mask and null
+ // object).
+ __ RestorePinnedRegisters();
}
- // Refresh pinned registers values (inc. write barrier mask and null object).
- __ RestorePinnedRegisters();
+ EmitReturnMoves(compiler, temp1, temp2);
- EmitReturnMoves(compiler);
+ if (is_leaf_) {
+ // Restore the pre-aligned SP.
+ __ mov(SPREG, saved_fp_or_sp);
+ } else {
+ // Although PP is a callee-saved register, it may have been moved by the GC.
+ __ LeaveDartFrame(compiler::kRestoreCallerPP);
- // Although PP is a callee-saved register, it may have been moved by the GC.
- __ LeaveDartFrame(compiler::kRestoreCallerPP);
+ // Restore the global object pool after returning from runtime (old space is
+ // moving, so the GOP could have been relocated).
+ if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+ __ SetupGlobalPoolAndDispatchTable();
+ }
- // Restore the global object pool after returning from runtime (old space is
- // moving, so the GOP could have been relocated).
- if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
- __ SetupGlobalPoolAndDispatchTable();
+ __ set_constant_pool_allowed(true);
}
-
- __ set_constant_pool_allowed(true);
}
// Keep in sync with NativeEntryInstr::EmitNativeCode.
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 045490a..f237309 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -999,57 +999,88 @@
__ Drop(ArgumentCount()); // Drop the arguments.
}
+LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
+ bool is_optimizing) const {
+ return MakeLocationSummaryInternal(zone, is_optimizing, kNoRegister);
+}
+
void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Register saved_fp = locs()->temp(0).reg();
+ // For regular calls, this holds the FP for rebasing the original locations
+ // during EmitParamMoves.
+ // For leaf calls, this holds the SP used to restore the pre-aligned SP after
+ // the call.
+ const Register saved_fp_or_sp = locs()->temp(0).reg();
const Register temp = locs()->temp(1).reg();
const Register branch = locs()->in(TargetAddressIndex()).reg();
- // Save frame pointer because we're going to update it when we enter the exit
- // frame.
- __ movl(saved_fp, FPREG);
+ // Ensure these are callee-saved register and are preserved across the call.
+ ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
+ (1 << saved_fp_or_sp)) != 0);
+ // temp doesn't need to be preserved.
- // Make a space to put the return address.
- __ pushl(compiler::Immediate(0));
+ __ movl(saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
- // We need to create a dummy "exit frame". It will have a null code object.
- __ LoadObject(CODE_REG, Object::null_object());
- __ EnterDartFrame(marshaller_.RequiredStackSpaceInBytes());
+ intptr_t stack_required = marshaller_.RequiredStackSpaceInBytes();
- // Align frame before entering C++ world.
- if (OS::ActivationFrameAlignment() > 1) {
- __ andl(SPREG, compiler::Immediate(~(OS::ActivationFrameAlignment() - 1)));
+ if (is_leaf_) {
+ // For leaf calls we need to leave space at the bottom for the pre-align SP.
+ stack_required += compiler::target::kWordSize;
+ } else {
+ // Make a space to put the return address.
+ __ pushl(compiler::Immediate(0));
+
+ // We need to create a dummy "exit frame". It will have a null code object.
+ __ LoadObject(CODE_REG, Object::null_object());
+ __ EnterDartFrame(0);
}
- EmitParamMoves(compiler);
+ // Reserve space for the arguments that go on the stack (if any), then align.
+ __ ReserveAlignedFrameSpace(stack_required);
+
+ EmitParamMoves(compiler, is_leaf_ ? FPREG : saved_fp_or_sp, temp);
+
+ if (is_leaf_) {
+ // We store the pre-align SP at a fixed offset from the final SP.
+ // Pushing before alignment would mean its placement would vary with how
+ // much the frame was unaligned.
+ __ movl(compiler::Address(SPREG, marshaller_.RequiredStackSpaceInBytes()),
+ saved_fp_or_sp);
+ }
if (compiler::Assembler::EmittingComments()) {
- __ Comment("Call");
+ __ Comment(is_leaf_ ? "Leaf Call" : "Call");
}
- // We need to copy a dummy return address up into the dummy stack frame so the
- // stack walker will know which safepoint to use. Unlike X64, there's no
- // PC-relative 'leaq' available, so we have do a trick with 'call'.
- compiler::Label get_pc;
- __ call(&get_pc);
- compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
- UntaggedPcDescriptors::Kind::kOther, locs(),
- env());
- __ Bind(&get_pc);
- __ popl(temp);
- __ movl(compiler::Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize), temp);
- ASSERT(!CanExecuteGeneratedCodeInSafepoint());
- // We cannot trust that this code will be executable within a safepoint.
- // Therefore we delegate the responsibility of entering/exiting the
- // safepoint to a stub which in the VM isolate's heap, which will never lose
- // execute permission.
- __ movl(temp,
- compiler::Address(
- THR, compiler::target::Thread::
- call_native_through_safepoint_entry_point_offset()));
+ if (is_leaf_) {
+ __ call(branch);
+ } else {
+ // We need to copy a dummy return address up into the dummy stack frame so
+ // the stack walker will know which safepoint to use. Unlike X64, there's no
+ // PC-relative 'leaq' available, so we have do a trick with 'call'.
+ compiler::Label get_pc;
+ __ call(&get_pc);
+ compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
+ UntaggedPcDescriptors::Kind::kOther, locs(),
+ env());
+ __ Bind(&get_pc);
+ __ popl(temp);
+ __ movl(compiler::Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize),
+ temp);
- // Calls EAX within a safepoint and clobbers EBX.
- ASSERT(temp == EBX && branch == EAX);
- __ call(temp);
+ ASSERT(!CanExecuteGeneratedCodeInSafepoint());
+ // We cannot trust that this code will be executable within a safepoint.
+ // Therefore we delegate the responsibility of entering/exiting the
+ // safepoint to a stub which in the VM isolate's heap, which will never lose
+ // execute permission.
+ __ movl(temp,
+ compiler::Address(
+ THR, compiler::target::Thread::
+ call_native_through_safepoint_entry_point_offset()));
+
+ // Calls EAX within a safepoint and clobbers EBX.
+ ASSERT(branch == EAX);
+ __ call(temp);
+ }
// Restore the stack when a struct by value is returned into memory pointed
// to by a pointer that is passed into the function.
@@ -1061,10 +1092,10 @@
__ subl(SPREG, compiler::Immediate(compiler::target::kWordSize));
}
- // The x86 calling convention requires floating point values to be returned on
- // the "floating-point stack" (aka. register ST0). We don't use the
- // floating-point stack in Dart, so we need to move the return value back into
- // an XMM register.
+ // The x86 calling convention requires floating point values to be returned
+ // on the "floating-point stack" (aka. register ST0). We don't use the
+ // floating-point stack in Dart, so we need to move the return value back
+ // into an XMM register.
if (representation() == kUnboxedDouble) {
__ fstpl(compiler::Address(SPREG, -kDoubleSize));
__ movsd(XMM0, compiler::Address(SPREG, -kDoubleSize));
@@ -1073,13 +1104,20 @@
__ movss(XMM0, compiler::Address(SPREG, -kFloatSize));
}
- EmitReturnMoves(compiler);
+ // Pass both registers for use as clobbered temp registers.
+ EmitReturnMoves(compiler, saved_fp_or_sp, temp);
- // Leave dummy exit frame.
- __ LeaveFrame();
+ if (is_leaf_) {
+ // Restore pre-align SP. Was stored right before the first stack argument.
+ __ movl(SPREG,
+ compiler::Address(SPREG, marshaller_.RequiredStackSpaceInBytes()));
+ } else {
+ // Leave dummy exit frame.
+ __ LeaveFrame();
- // Instead of returning to the "fake" return address, we just pop it.
- __ popl(temp);
+ // Instead of returning to the "fake" return address, we just pop it.
+ __ popl(temp);
+ }
}
// Keep in sync with NativeReturnInstr::EmitNativeCode.
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 8e6d3e9..43930b0 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1188,82 +1188,118 @@
__ Drop(ArgumentCount()); // Drop the arguments.
}
+LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
+ bool is_optimizing) const {
+ // Use R10 as a temp register. We can't use RDI, RSI, RDX, R8, R9 as they are
+ // arg registers, and R11 is TMP.
+ return MakeLocationSummaryInternal(zone, is_optimizing, R10);
+}
+
void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Register saved_fp = locs()->temp(0).reg();
+ // For leaf calls, this holds the SP used to restore the pre-aligned SP after
+ // the call.
+ // Note: R12 doubles as CODE_REG, which gets clobbered during frame setup in
+ // regular calls.
+ const Register saved_sp = locs()->temp(0).reg();
+ // For regular calls, this holds the FP for rebasing the original locations
+ // during EmitParamMoves.
+ const Register saved_fp = locs()->temp(1).reg();
+ const Register temp = locs()->temp(2).reg();
const Register target_address = locs()->in(TargetAddressIndex()).reg();
- // Save frame pointer because we're going to update it when we enter the exit
- // frame.
- __ movq(saved_fp, FPREG);
+ // Ensure these are callee-saved register and are preserved across the call.
+ ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << saved_sp)) != 0);
+ ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << saved_fp)) != 0);
+ // temp doesn't need to be preserved.
- // Make a space to put the return address.
- __ pushq(compiler::Immediate(0));
-
- // We need to create a dummy "exit frame". It will share the same pool pointer
- // but have a null code object.
- __ LoadObject(CODE_REG, Object::null_object());
- __ set_constant_pool_allowed(false);
- __ EnterDartFrame(marshaller_.RequiredStackSpaceInBytes(), PP);
-
- // Align frame before entering C++ world.
- if (OS::ActivationFrameAlignment() > 1) {
- __ andq(SPREG, compiler::Immediate(~(OS::ActivationFrameAlignment() - 1)));
- }
-
- EmitParamMoves(compiler);
-
- // We need to copy a dummy return address up into the dummy stack frame so the
- // stack walker will know which safepoint to use. RIP points to the *next*
- // instruction, so 'AddressRIPRelative' loads the address of the following
- // 'movq'.
- __ leaq(TMP, compiler::Address::AddressRIPRelative(0));
- compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
- UntaggedPcDescriptors::Kind::kOther, locs(),
- env());
- __ movq(compiler::Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize), TMP);
-
- if (CanExecuteGeneratedCodeInSafepoint()) {
- // Update information in the thread object and enter a safepoint.
- __ movq(TMP,
- compiler::Immediate(compiler::target::Thread::exit_through_ffi()));
- __ TransitionGeneratedToNative(target_address, FPREG, TMP,
- /*enter_safepoint=*/true);
-
- __ CallCFunction(target_address, /*restore_rsp=*/true);
-
- // Update information in the thread object and leave the safepoint.
- __ TransitionNativeToGenerated(/*leave_safepoint=*/true);
+ if (is_leaf_) {
+ __ movq(saved_sp, SPREG);
} else {
- // We cannot trust that this code will be executable within a safepoint.
- // Therefore we delegate the responsibility of entering/exiting the
- // safepoint to a stub which in the VM isolate's heap, which will never lose
- // execute permission.
- __ movq(TMP,
- compiler::Address(
- THR, compiler::target::Thread::
- call_native_through_safepoint_entry_point_offset()));
+ __ movq(saved_fp, FPREG);
+ // Make a space to put the return address.
+ __ pushq(compiler::Immediate(0));
- // Calls RBX within a safepoint.
- ASSERT(saved_fp == RBX);
- __ movq(RBX, target_address);
- __ call(TMP);
+ // We need to create a dummy "exit frame". It will share the same pool
+ // pointer but have a null code object.
+ __ LoadObject(CODE_REG, Code::null_object());
+ __ set_constant_pool_allowed(false);
+ __ EnterDartFrame(0, PP);
}
- EmitReturnMoves(compiler);
+ // Reserve space for the arguments that go on the stack (if any), then align.
+ __ ReserveAlignedFrameSpace(marshaller_.RequiredStackSpaceInBytes());
- // Although PP is a callee-saved register, it may have been moved by the GC.
- __ LeaveDartFrame(compiler::kRestoreCallerPP);
-
- // Restore the global object pool after returning from runtime (old space is
- // moving, so the GOP could have been relocated).
- if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
- __ movq(PP, compiler::Address(THR, Thread::global_object_pool_offset()));
+ if (is_leaf_) {
+ EmitParamMoves(compiler, FPREG, saved_fp);
+ } else {
+ EmitParamMoves(compiler, saved_fp, saved_sp);
}
- __ set_constant_pool_allowed(true);
+ if (compiler::Assembler::EmittingComments()) {
+ __ Comment(is_leaf_ ? "Leaf Call" : "Call");
+ }
- // Instead of returning to the "fake" return address, we just pop it.
- __ popq(TMP);
+ if (is_leaf_) {
+ __ CallCFunction(target_address, /*restore_rsp=*/true);
+ } else {
+ // We need to copy a dummy return address up into the dummy stack frame so
+ // the stack walker will know which safepoint to use. RIP points to the
+ // *next* instruction, so 'AddressRIPRelative' loads the address of the
+ // following 'movq'.
+ __ leaq(temp, compiler::Address::AddressRIPRelative(0));
+ compiler->EmitCallsiteMetadata(InstructionSource(), deopt_id(),
+ UntaggedPcDescriptors::Kind::kOther, locs(),
+ env());
+ __ movq(compiler::Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize),
+ temp);
+
+ if (CanExecuteGeneratedCodeInSafepoint()) {
+ // Update information in the thread object and enter a safepoint.
+ __ movq(temp, compiler::Immediate(
+ compiler::target::Thread::exit_through_ffi()));
+
+ __ TransitionGeneratedToNative(target_address, FPREG, temp,
+ /*enter_safepoint=*/true);
+
+ __ CallCFunction(target_address, /*restore_rsp=*/true);
+
+ // Update information in the thread object and leave the safepoint.
+ __ TransitionNativeToGenerated(/*leave_safepoint=*/true);
+ } else {
+ // We cannot trust that this code will be executable within a safepoint.
+ // Therefore we delegate the responsibility of entering/exiting the
+ // safepoint to a stub which is in the VM isolate's heap, which will never
+ // lose execute permission.
+ __ movq(temp,
+ compiler::Address(
+ THR, compiler::target::Thread::
+ call_native_through_safepoint_entry_point_offset()));
+
+ // Calls RBX within a safepoint. RBX and R12 are clobbered.
+ __ movq(RBX, target_address);
+ __ call(temp);
+ }
+ }
+
+ // Pass the `saved_fp` reg. as a temp to clobber since we're done with it.
+ EmitReturnMoves(compiler, temp, saved_fp);
+
+ if (is_leaf_) {
+ // Restore the pre-aligned SP.
+ __ movq(SPREG, saved_sp);
+ } else {
+ // Although PP is a callee-saved register, it may have been moved by the GC.
+ __ LeaveDartFrame(compiler::kRestoreCallerPP);
+ // Restore the global object pool after returning from runtime (old space is
+ // moving, so the GOP could have been relocated).
+ if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+ __ movq(PP, compiler::Address(THR, Thread::global_object_pool_offset()));
+ }
+ __ set_constant_pool_allowed(true);
+
+ // Instead of returning to the "fake" return address, we just pop it.
+ __ popq(temp);
+ }
}
// Keep in sync with NativeReturnInstr::EmitNativeCode.
diff --git a/runtime/vm/compiler/ffi/call.cc b/runtime/vm/compiler/ffi/call.cc
index 1735a69..990e257 100644
--- a/runtime/vm/compiler/ffi/call.cc
+++ b/runtime/vm/compiler/ffi/call.cc
@@ -15,7 +15,8 @@
// TODO(dartbug.com/36607): Cache the trampolines.
FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
- const FunctionType& c_signature) {
+ const FunctionType& c_signature,
+ bool is_leaf) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
String& name = String::Handle(zone, Symbols::New(thread, "FfiTrampoline"));
@@ -54,6 +55,8 @@
signature ^= ClassFinalizer::FinalizeType(signature);
function.set_signature(signature);
+ function.SetFfiIsLeaf(is_leaf);
+
return function.ptr();
}
diff --git a/runtime/vm/compiler/ffi/call.h b/runtime/vm/compiler/ffi/call.h
index 5a4e5f0..06bccde 100644
--- a/runtime/vm/compiler/ffi/call.h
+++ b/runtime/vm/compiler/ffi/call.h
@@ -20,7 +20,8 @@
namespace ffi {
FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
- const FunctionType& c_signature);
+ const FunctionType& c_signature,
+ bool is_leaf);
} // namespace ffi
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 52416d7..9e3e05f 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -980,7 +980,8 @@
}
Fragment BaseFlowGraphBuilder::BuildFfiAsFunctionInternalCall(
- const TypeArguments& signatures) {
+ const TypeArguments& signatures,
+ bool is_leaf) {
ASSERT(signatures.IsInstantiated());
ASSERT(signatures.Length() == 2);
@@ -990,7 +991,8 @@
ASSERT(dart_type.IsFunctionType() && native_type.IsFunctionType());
const Function& target =
Function::ZoneHandle(compiler::ffi::TrampolineFunction(
- FunctionType::Cast(dart_type), FunctionType::Cast(native_type)));
+ FunctionType::Cast(dart_type), FunctionType::Cast(native_type),
+ is_leaf));
Fragment code;
// Store the pointer in the context, we cannot load the untagged address
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index b2d1cfe..6873a4f 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -362,7 +362,8 @@
// Builds the graph for an invocation of '_asFunctionInternal'.
//
// 'signatures' contains the pair [<dart signature>, <native signature>].
- Fragment BuildFfiAsFunctionInternalCall(const TypeArguments& signatures);
+ Fragment BuildFfiAsFunctionInternalCall(const TypeArguments& signatures,
+ bool is_leaf);
Fragment AllocateObject(TokenPosition position,
const Class& klass,
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 1ff1ed3..5c94964 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -5667,20 +5667,32 @@
Fragment StreamingFlowGraphBuilder::BuildFfiAsFunctionInternal() {
const intptr_t argc = ReadUInt(); // Read argument count.
- ASSERT(argc == 1); // Pointer.
+ ASSERT(argc == 2); // Pointer, isLeaf.
const intptr_t list_length = ReadListLength(); // Read types list length.
- ASSERT(list_length == 2); // Dart signature, then native signature.
- const TypeArguments& type_arguments =
- T.BuildTypeArguments(list_length); // Read types.
+ ASSERT(list_length == 2); // Dart signature, then native signature
+ // Read types.
+ const TypeArguments& type_arguments = T.BuildTypeArguments(list_length);
Fragment code;
- const intptr_t positional_count =
- ReadListLength(); // Read positional argument count.
- ASSERT(positional_count == 1);
+ // Read positional argument count.
+ const intptr_t positional_count = ReadListLength();
+ ASSERT(positional_count == 2);
code += BuildExpression(); // Build first positional argument (pointer).
- const intptr_t named_args_len =
- ReadListLength(); // Skip empty named arguments list.
+
+ // The second argument, `isLeaf`, is only used internally and dictates whether
+ // we can do a lightweight leaf function call.
+ bool is_leaf = false;
+ Fragment frag = BuildExpression();
+ ASSERT(frag.entry->IsConstant());
+ if (frag.entry->AsConstant()->value().ptr() == Object::bool_true().ptr()) {
+ is_leaf = true;
+ }
+ Pop();
+
+ // Skip (empty) named arguments list.
+ const intptr_t named_args_len = ReadListLength();
ASSERT(named_args_len == 0);
- code += B->BuildFfiAsFunctionInternalCall(type_arguments);
+
+ code += B->BuildFfiAsFunctionInternalCall(type_arguments, is_leaf);
return code;
}
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index a12040d..ff70644 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -384,7 +384,8 @@
Fragment body;
FfiCallInstr* const call =
- new (Z) FfiCallInstr(Z, GetNextDeoptId(), marshaller);
+ new (Z) FfiCallInstr(Z, GetNextDeoptId(), marshaller,
+ parsed_function_->function().FfiIsLeaf());
for (intptr_t i = call->InputCount() - 1; i >= 0; --i) {
call->SetInputAt(i, Pop());
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index a36b5d4..58d8c8b 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -164,7 +164,7 @@
V(_WeakProperty, set:value, WeakProperty_setValue, 0x8b2bafab) \
V(::, _classRangeCheck, ClassRangeCheck, 0x00269620) \
V(::, _abi, FfiAbi, 0x7c4ab775) \
- V(::, _asFunctionInternal, FfiAsFunctionInternal, 0xbbcb235a) \
+ V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x92ae104f) \
V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x3ff5ae9c) \
V(::, _nativeEffect, NativeEffect, 0x61e00b59) \
V(::, _loadInt8, FfiLoadInt8, 0x0f04dfd6) \
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 95c2e89..6862f50 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -489,7 +489,7 @@
static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize =
12;
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
- 24;
+ 28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
@@ -1569,7 +1569,7 @@
static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize =
12;
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
- 24;
+ 28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
@@ -3738,7 +3738,7 @@
static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize =
12;
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
- 24;
+ 28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
@@ -4806,7 +4806,7 @@
static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize =
12;
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
- 24;
+ 28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
@@ -7018,7 +7018,7 @@
static constexpr dart::compiler::target::word
AOT_ExternalTypedData_InstanceSize = 12;
static constexpr dart::compiler::target::word
- AOT_FfiTrampolineData_InstanceSize = 24;
+ AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
@@ -10049,7 +10049,7 @@
static constexpr dart::compiler::target::word
AOT_ExternalTypedData_InstanceSize = 12;
static constexpr dart::compiler::target::word
- AOT_FfiTrampolineData_InstanceSize = 24;
+ AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 8914904..20f7748 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -246,6 +246,12 @@
IsolateGroup::Current()->heap()->CollectAllGarbage();
return nullptr;
+ } else if (strcmp(command, "is-thread-in-generated") == 0) {
+ if (Thread::Current()->execution_state() == Thread::kThreadInGenerated) {
+ return reinterpret_cast<void*>(1);
+ }
+ return nullptr;
+
} else if (strcmp(command, "is-mutator-in-native") == 0) {
Isolate* const isolate = reinterpret_cast<Isolate*>(arg);
if (isolate->mutator_thread()->execution_state_cross_thread_for_testing() ==
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 7a61184..bdef06a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7535,6 +7535,20 @@
FfiTrampolineData::Cast(obj).set_callback_id(value);
}
+bool Function::FfiIsLeaf() const {
+ ASSERT(IsFfiTrampoline());
+ const Object& obj = Object::Handle(untag()->data());
+ ASSERT(!obj.IsNull());
+ return FfiTrampolineData::Cast(obj).is_leaf();
+}
+
+void Function::SetFfiIsLeaf(bool is_leaf) const {
+ ASSERT(IsFfiTrampoline());
+ const Object& obj = Object::Handle(untag()->data());
+ ASSERT(!obj.IsNull());
+ FfiTrampolineData::Cast(obj).set_is_leaf(is_leaf);
+}
+
FunctionPtr Function::FfiCallbackTarget() const {
ASSERT(IsFfiTrampoline());
const Object& obj = Object::Handle(data());
@@ -10295,6 +10309,10 @@
StoreNonPointer(&untag()->callback_id_, callback_id);
}
+void FfiTrampolineData::set_is_leaf(bool is_leaf) const {
+ StoreNonPointer(&untag()->is_leaf_, is_leaf);
+}
+
void FfiTrampolineData::set_callback_exceptional_return(
const Instance& value) const {
untag()->set_callback_exceptional_return(value.ptr());
@@ -10307,6 +10325,7 @@
Heap::kOld, FfiTrampolineData::ContainsCompressedPointers());
FfiTrampolineDataPtr data = static_cast<FfiTrampolineDataPtr>(raw);
data->untag()->callback_id_ = 0;
+ data->untag()->is_leaf_ = false;
return data;
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a04f9b1..8461552 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2555,6 +2555,12 @@
void SetFfiCallbackId(int32_t value) const;
// Can only be called on FFI trampolines.
+ bool FfiIsLeaf() const;
+
+ // Can only be called on FFI trampolines.
+ void SetFfiIsLeaf(bool is_leaf) const;
+
+ // Can only be called on FFI trampolines.
// Null for Dart -> native calls.
FunctionPtr FfiCallbackTarget() const;
@@ -3869,6 +3875,9 @@
int32_t callback_id() const { return untag()->callback_id_; }
void set_callback_id(int32_t value) const;
+ bool is_leaf() const { return untag()->is_leaf_; }
+ void set_is_leaf(bool value) const;
+
static FfiTrampolineDataPtr New();
FINAL_HEAP_OBJECT_IMPLEMENTATION(FfiTrampolineData, Object);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index acff79d..f567ae7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1463,6 +1463,9 @@
// Will be 0 for non-callbacks. Check 'callback_target_' to determine if this
// is a callback or not.
uint32_t callback_id_;
+
+ // Whether this is a leaf call - i.e. one that doesn't call back into Dart.
+ bool is_leaf_;
};
class UntaggedField : public UntaggedObject {
diff --git a/samples/ffi/sample_ffi_functions.dart b/samples/ffi/sample_ffi_functions.dart
index 4ab9b81..51376e1 100644
--- a/samples/ffi/sample_ffi_functions.dart
+++ b/samples/ffi/sample_ffi_functions.dart
@@ -91,6 +91,16 @@
}
{
+ // As a leaf call.
+ BinaryOp sumPlus42Leaf = ffiTestFunctions
+ .lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42", isLeaf: true);
+
+ final result = sumPlus42Leaf(3, 17);
+ print(result);
+ print(result.runtimeType);
+ }
+
+ {
// Various size arguments.
QuadOp intComputation = ffiTestFunctions
.lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
diff --git a/samples_2/ffi/sample_ffi_functions.dart b/samples_2/ffi/sample_ffi_functions.dart
index a0526fa..f999ed6 100644
--- a/samples_2/ffi/sample_ffi_functions.dart
+++ b/samples_2/ffi/sample_ffi_functions.dart
@@ -93,6 +93,16 @@
}
{
+ // As a leaf call.
+ BinaryOp sumPlus42Leaf = ffiTestFunctions
+ .lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42", isLeaf: true);
+
+ final result = sumPlus42Leaf(3, 17);
+ print(result);
+ print(result.runtimeType);
+ }
+
+ {
// Various size arguments.
QuadOp intComputation = ffiTestFunctions
.lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
diff --git a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
index 655006c..5482890 100644
--- a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
@@ -52,7 +52,7 @@
extension DynamicLibraryExtension on DynamicLibrary {
@patch
- DS lookupFunction<NS extends Function, DS extends Function>(
- String symbolName) =>
+ DS lookupFunction<NS extends Function, DS extends Function>(String symbolName,
+ {bool isLeaf: false}) =>
throw UnsupportedError("The body is inlined in the frontend.");
}
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 4290185..ac745e3 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -38,7 +38,8 @@
// this function.
@pragma("vm:recognized", "other")
DS _asFunctionInternal<DS extends Function, NS extends Function>(
- Pointer<NativeFunction<NS>> ptr) native "Ffi_asFunctionInternal";
+ Pointer<NativeFunction<NS>> ptr,
+ bool isLeaf) native "Ffi_asFunctionInternal";
dynamic _asExternalTypedData(Pointer ptr, int count)
native "Ffi_asExternalTypedData";
@@ -336,7 +337,7 @@
extension NativeFunctionPointer<NF extends Function>
on Pointer<NativeFunction<NF>> {
@patch
- DF asFunction<DF extends Function>() =>
+ DF asFunction<DF extends Function>({bool isLeaf: false}) =>
throw UnsupportedError("The body is inlined in the frontend.");
}
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index 16e1b0f..e39e53c 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.dart
@@ -76,5 +76,6 @@
/// int Function(int, int)>('add');
/// ```
external F lookupFunction<T extends Function, F extends Function>(
- String symbolName);
+ String symbolName,
+ {bool isLeaf: false});
}
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 369b389..26177e8 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -149,7 +149,8 @@
on Pointer<NativeFunction<NF>> {
/// Convert to Dart function, automatically marshalling the arguments
/// and return value.
- external DF asFunction<@DartRepresentationOf("NF") DF extends Function>();
+ external DF asFunction<@DartRepresentationOf("NF") DF extends Function>(
+ {bool isLeaf: false});
}
//
diff --git a/tests/ffi/callback_tests_utils.dart b/tests/ffi/callback_tests_utils.dart
index e34a52b..3f5fed8 100644
--- a/tests/ffi/callback_tests_utils.dart
+++ b/tests/ffi/callback_tests_utils.dart
@@ -17,13 +17,19 @@
final String name;
final Pointer callback;
final void Function() afterCallbackChecks;
+ final bool isLeaf;
- CallbackTest(this.name, this.callback) : afterCallbackChecks = noChecks {}
- CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks) {}
+ CallbackTest(this.name, this.callback, {this.isLeaf: false})
+ : afterCallbackChecks = noChecks {}
+ CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks,
+ {this.isLeaf: false}) {}
void run() {
- final NativeCallbackTestFn tester = ffiTestFunctions
- .lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
+ final NativeCallbackTestFn tester = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeCallbackTest,
+ NativeCallbackTestFn>("Test$name", isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeCallbackTest,
+ NativeCallbackTestFn>("Test$name", isLeaf: false);
final int testCode = tester(callback);
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index e830631..6c970e1 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -133,6 +133,119 @@
testReturnStructNestedIntStructAlignmentInt32();
testReturnStructNestedIntStructAlignmentInt64();
testReturnStructNestedIrregularEvenBigger();
+ testPassStruct1ByteIntx10Leaf();
+ testPassStruct3BytesHomogeneousUint8x10Leaf();
+ testPassStruct3BytesInt2ByteAlignedx10Leaf();
+ testPassStruct4BytesHomogeneousInt16x10Leaf();
+ testPassStruct7BytesHomogeneousUint8x10Leaf();
+ testPassStruct7BytesInt4ByteAlignedx10Leaf();
+ testPassStruct8BytesIntx10Leaf();
+ testPassStruct8BytesHomogeneousFloatx10Leaf();
+ testPassStruct8BytesMixedx10Leaf();
+ testPassStruct9BytesHomogeneousUint8x10Leaf();
+ testPassStruct9BytesInt4Or8ByteAlignedx10Leaf();
+ testPassStruct12BytesHomogeneousFloatx6Leaf();
+ testPassStruct16BytesHomogeneousFloatx5Leaf();
+ testPassStruct16BytesMixedx10Leaf();
+ testPassStruct16BytesMixed2x10Leaf();
+ testPassStruct17BytesIntx10Leaf();
+ testPassStruct19BytesHomogeneousUint8x10Leaf();
+ testPassStruct20BytesHomogeneousInt32x10Leaf();
+ testPassStruct20BytesHomogeneousFloatLeaf();
+ testPassStruct32BytesHomogeneousDoublex5Leaf();
+ testPassStruct40BytesHomogeneousDoubleLeaf();
+ testPassStruct1024BytesHomogeneousUint64Leaf();
+ testPassFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf();
+ testPassFloatStruct32BytesHomogeneousDoubleFloatStructLeaf();
+ testPassInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf();
+ testPassDoublex6Struct16BytesMixedx4Int32Leaf();
+ testPassInt32x4Struct16BytesMixedx4DoubleLeaf();
+ testPassStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf();
+ testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf();
+ testPassStructAlignmentInt16Leaf();
+ testPassStructAlignmentInt32Leaf();
+ testPassStructAlignmentInt64Leaf();
+ testPassStruct8BytesNestedIntx10Leaf();
+ testPassStruct8BytesNestedFloatx10Leaf();
+ testPassStruct8BytesNestedFloat2x10Leaf();
+ testPassStruct8BytesNestedMixedx10Leaf();
+ testPassStruct16BytesNestedIntx2Leaf();
+ testPassStruct32BytesNestedIntx2Leaf();
+ testPassStructNestedIntStructAlignmentInt16Leaf();
+ testPassStructNestedIntStructAlignmentInt32Leaf();
+ testPassStructNestedIntStructAlignmentInt64Leaf();
+ testPassStructNestedIrregularEvenBiggerx4Leaf();
+ testPassStruct8BytesInlineArrayIntx4Leaf();
+ testPassStructInlineArrayIrregularx4Leaf();
+ testPassStructInlineArray100BytesLeaf();
+ testPassStructStruct16BytesHomogeneousFloat2x5Leaf();
+ testPassStructStruct32BytesHomogeneousDouble2x5Leaf();
+ testPassStructStruct16BytesMixed3x10Leaf();
+ testPassUint8Struct32BytesInlineArrayMultiDimensionalILeaf();
+ testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf();
+ testPassStruct3BytesPackedIntx10Leaf();
+ testPassStruct8BytesPackedIntx10Leaf();
+ testPassStruct9BytesPackedMixedx10DoubleInt32Leaf();
+ testPassStruct5BytesPackedMixedLeaf();
+ testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf();
+ testPassStruct6BytesInlineArrayIntLeaf();
+ testPassStruct15BytesInlineArrayMixedLeaf();
+ testPassUnion4BytesMixedx10Leaf();
+ testPassUnion8BytesNestedFloatx10Leaf();
+ testPassUnion9BytesNestedIntx10Leaf();
+ testPassUnion16BytesNestedInlineArrayFloatx10Leaf();
+ testPassUnion16BytesNestedFloatx10Leaf();
+ testReturnStruct1ByteIntLeaf();
+ testReturnStruct3BytesHomogeneousUint8Leaf();
+ testReturnStruct3BytesInt2ByteAlignedLeaf();
+ testReturnStruct4BytesHomogeneousInt16Leaf();
+ testReturnStruct7BytesHomogeneousUint8Leaf();
+ testReturnStruct7BytesInt4ByteAlignedLeaf();
+ testReturnStruct8BytesIntLeaf();
+ testReturnStruct8BytesHomogeneousFloatLeaf();
+ testReturnStruct8BytesMixedLeaf();
+ testReturnStruct9BytesHomogeneousUint8Leaf();
+ testReturnStruct9BytesInt4Or8ByteAlignedLeaf();
+ testReturnStruct12BytesHomogeneousFloatLeaf();
+ testReturnStruct16BytesHomogeneousFloatLeaf();
+ testReturnStruct16BytesMixedLeaf();
+ testReturnStruct16BytesMixed2Leaf();
+ testReturnStruct17BytesIntLeaf();
+ testReturnStruct19BytesHomogeneousUint8Leaf();
+ testReturnStruct20BytesHomogeneousInt32Leaf();
+ testReturnStruct20BytesHomogeneousFloatLeaf();
+ testReturnStruct32BytesHomogeneousDoubleLeaf();
+ testReturnStruct40BytesHomogeneousDoubleLeaf();
+ testReturnStruct1024BytesHomogeneousUint64Leaf();
+ testReturnStruct3BytesPackedIntLeaf();
+ testReturnStruct8BytesPackedIntLeaf();
+ testReturnStruct9BytesPackedMixedLeaf();
+ testReturnUnion4BytesMixedLeaf();
+ testReturnUnion8BytesNestedFloatLeaf();
+ testReturnUnion9BytesNestedIntLeaf();
+ testReturnUnion16BytesNestedFloatLeaf();
+ testReturnStructArgumentStruct1ByteIntLeaf();
+ testReturnStructArgumentInt32x8Struct1ByteIntLeaf();
+ testReturnStructArgumentStruct8BytesHomogeneousFloatLeaf();
+ testReturnStructArgumentStruct20BytesHomogeneousInt32Leaf();
+ testReturnStructArgumentInt32x8Struct20BytesHomogeneouLeaf();
+ testReturnStructArgumentStruct8BytesInlineArrayIntLeaf();
+ testReturnStructArgumentStructStruct16BytesHomogeneousLeaf();
+ testReturnStructArgumentStructStruct32BytesHomogeneousLeaf();
+ testReturnStructArgumentStructStruct16BytesMixed3Leaf();
+ testReturnStructAlignmentInt16Leaf();
+ testReturnStructAlignmentInt32Leaf();
+ testReturnStructAlignmentInt64Leaf();
+ testReturnStruct8BytesNestedIntLeaf();
+ testReturnStruct8BytesNestedFloatLeaf();
+ testReturnStruct8BytesNestedFloat2Leaf();
+ testReturnStruct8BytesNestedMixedLeaf();
+ testReturnStruct16BytesNestedIntLeaf();
+ testReturnStruct32BytesNestedIntLeaf();
+ testReturnStructNestedIntStructAlignmentInt16Leaf();
+ testReturnStructNestedIntStructAlignmentInt32Leaf();
+ testReturnStructNestedIntStructAlignmentInt64Leaf();
+ testReturnStructNestedIrregularEvenBiggerLeaf();
}
}
@@ -8770,3 +8883,7541 @@
calloc.free(a1Pointer);
calloc.free(a2Pointer);
}
+
+final passStruct1ByteIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt),
+ int Function(
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt)>("PassStruct1ByteIntx10", isLeaf: true);
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct1ByteIntx10Leaf() {
+ final a0Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a1.a0 = 2;
+ a2.a0 = -3;
+ a3.a0 = 4;
+ a4.a0 = -5;
+ a5.a0 = 6;
+ a6.a0 = -7;
+ a7.a0 = 8;
+ a8.a0 = -9;
+ a9.a0 = 10;
+
+ final result =
+ passStruct1ByteIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(5, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct3BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8),
+ int Function(
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8)>(
+ "PassStruct3BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a1.a0 = 4;
+ a1.a1 = 5;
+ a1.a2 = 6;
+ a2.a0 = 7;
+ a2.a1 = 8;
+ a2.a2 = 9;
+ a3.a0 = 10;
+ a3.a1 = 11;
+ a3.a2 = 12;
+ a4.a0 = 13;
+ a4.a1 = 14;
+ a4.a2 = 15;
+ a5.a0 = 16;
+ a5.a1 = 17;
+ a5.a2 = 18;
+ a6.a0 = 19;
+ a6.a1 = 20;
+ a6.a2 = 21;
+ a7.a0 = 22;
+ a7.a1 = 23;
+ a7.a2 = 24;
+ a8.a0 = 25;
+ a8.a1 = 26;
+ a8.a2 = 27;
+ a9.a0 = 28;
+ a9.a1 = 29;
+ a9.a2 = 30;
+
+ final result = passStruct3BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(465, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct3BytesInt2ByteAlignedx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned),
+ int Function(
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned)>("PassStruct3BytesInt2ByteAlignedx10",
+ isLeaf: true);
+
+/// Not a multiple of word size, not a power of two.
+/// With alignment rules taken into account size is 4 bytes.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesInt2ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct3BytesInt2ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct4BytesHomogeneousInt16x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16),
+ int Function(
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16)>(
+ "PassStruct4BytesHomogeneousInt16x10",
+ isLeaf: true);
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct4BytesHomogeneousInt16x10Leaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct4BytesHomogeneousInt16x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct7BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8),
+ int Function(
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8)>(
+ "PassStruct7BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a1.a0 = 8;
+ a1.a1 = 9;
+ a1.a2 = 10;
+ a1.a3 = 11;
+ a1.a4 = 12;
+ a1.a5 = 13;
+ a1.a6 = 14;
+ a2.a0 = 15;
+ a2.a1 = 16;
+ a2.a2 = 17;
+ a2.a3 = 18;
+ a2.a4 = 19;
+ a2.a5 = 20;
+ a2.a6 = 21;
+ a3.a0 = 22;
+ a3.a1 = 23;
+ a3.a2 = 24;
+ a3.a3 = 25;
+ a3.a4 = 26;
+ a3.a5 = 27;
+ a3.a6 = 28;
+ a4.a0 = 29;
+ a4.a1 = 30;
+ a4.a2 = 31;
+ a4.a3 = 32;
+ a4.a4 = 33;
+ a4.a5 = 34;
+ a4.a6 = 35;
+ a5.a0 = 36;
+ a5.a1 = 37;
+ a5.a2 = 38;
+ a5.a3 = 39;
+ a5.a4 = 40;
+ a5.a5 = 41;
+ a5.a6 = 42;
+ a6.a0 = 43;
+ a6.a1 = 44;
+ a6.a2 = 45;
+ a6.a3 = 46;
+ a6.a4 = 47;
+ a6.a5 = 48;
+ a6.a6 = 49;
+ a7.a0 = 50;
+ a7.a1 = 51;
+ a7.a2 = 52;
+ a7.a3 = 53;
+ a7.a4 = 54;
+ a7.a5 = 55;
+ a7.a6 = 56;
+ a8.a0 = 57;
+ a8.a1 = 58;
+ a8.a2 = 59;
+ a8.a3 = 60;
+ a8.a4 = 61;
+ a8.a5 = 62;
+ a8.a6 = 63;
+ a9.a0 = 64;
+ a9.a1 = 65;
+ a9.a2 = 66;
+ a9.a3 = 67;
+ a9.a4 = 68;
+ a9.a5 = 69;
+ a9.a6 = 70;
+
+ final result = passStruct7BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(2485, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct7BytesInt4ByteAlignedx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned),
+ int Function(
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned)>("PassStruct7BytesInt4ByteAlignedx10",
+ isLeaf: true);
+
+/// Sub word size on 64 bit architectures.
+/// With alignment rules taken into account size is 8 bytes.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesInt4ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result = passStruct7BytesInt4ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt),
+ int Function(
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt)>("PassStruct8BytesIntx10", isLeaf: true);
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct8BytesIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesHomogeneousFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat),
+ double Function(
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat)>(
+ "PassStruct8BytesHomogeneousFloatx10",
+ isLeaf: true);
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesHomogeneousFloatx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a1.a0 = -3.0;
+ a1.a1 = 4.0;
+ a2.a0 = -5.0;
+ a2.a1 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a4.a0 = -9.0;
+ a4.a1 = 10.0;
+ a5.a0 = -11.0;
+ a5.a1 = 12.0;
+ a6.a0 = -13.0;
+ a6.a1 = 14.0;
+ a7.a0 = -15.0;
+ a7.a1 = 16.0;
+ a8.a0 = -17.0;
+ a8.a1 = 18.0;
+ a9.a0 = -19.0;
+ a9.a1 = 20.0;
+
+ final result = passStruct8BytesHomogeneousFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed),
+ double Function(
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed)>("PassStruct8BytesMixedx10", isLeaf: true);
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4.0;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7.0;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10.0;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13.0;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16.0;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19.0;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22.0;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25.0;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28.0;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct8BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8),
+ int Function(
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8)>(
+ "PassStruct9BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Struct only has 1-byte aligned fields to test struct alignment itself.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+void testPassStruct9BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a1.a0 = 10;
+ a1.a1 = 11;
+ a1.a2 = 12;
+ a1.a3 = 13;
+ a1.a4 = 14;
+ a1.a5 = 15;
+ a1.a6 = 16;
+ a1.a7 = 17;
+ a1.a8 = 18;
+ a2.a0 = 19;
+ a2.a1 = 20;
+ a2.a2 = 21;
+ a2.a3 = 22;
+ a2.a4 = 23;
+ a2.a5 = 24;
+ a2.a6 = 25;
+ a2.a7 = 26;
+ a2.a8 = 27;
+ a3.a0 = 28;
+ a3.a1 = 29;
+ a3.a2 = 30;
+ a3.a3 = 31;
+ a3.a4 = 32;
+ a3.a5 = 33;
+ a3.a6 = 34;
+ a3.a7 = 35;
+ a3.a8 = 36;
+ a4.a0 = 37;
+ a4.a1 = 38;
+ a4.a2 = 39;
+ a4.a3 = 40;
+ a4.a4 = 41;
+ a4.a5 = 42;
+ a4.a6 = 43;
+ a4.a7 = 44;
+ a4.a8 = 45;
+ a5.a0 = 46;
+ a5.a1 = 47;
+ a5.a2 = 48;
+ a5.a3 = 49;
+ a5.a4 = 50;
+ a5.a5 = 51;
+ a5.a6 = 52;
+ a5.a7 = 53;
+ a5.a8 = 54;
+ a6.a0 = 55;
+ a6.a1 = 56;
+ a6.a2 = 57;
+ a6.a3 = 58;
+ a6.a4 = 59;
+ a6.a5 = 60;
+ a6.a6 = 61;
+ a6.a7 = 62;
+ a6.a8 = 63;
+ a7.a0 = 64;
+ a7.a1 = 65;
+ a7.a2 = 66;
+ a7.a3 = 67;
+ a7.a4 = 68;
+ a7.a5 = 69;
+ a7.a6 = 70;
+ a7.a7 = 71;
+ a7.a8 = 72;
+ a8.a0 = 73;
+ a8.a1 = 74;
+ a8.a2 = 75;
+ a8.a3 = 76;
+ a8.a4 = 77;
+ a8.a5 = 78;
+ a8.a6 = 79;
+ a8.a7 = 80;
+ a8.a8 = 81;
+ a9.a0 = 82;
+ a9.a1 = 83;
+ a9.a2 = 84;
+ a9.a3 = 85;
+ a9.a4 = 86;
+ a9.a5 = 87;
+ a9.a6 = 88;
+ a9.a7 = 89;
+ a9.a8 = 90;
+
+ final result = passStruct9BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(4095, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesInt4Or8ByteAlignedx10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned),
+ int Function(
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned)>(
+ "PassStruct9BytesInt4Or8ByteAlignedx10",
+ isLeaf: true);
+
+/// Argument is a single byte over a multiple of word size.
+/// With alignment rules taken into account size is 12 or 16 bytes.
+/// 10 struct arguments will exhaust available registers.
+///
+void testPassStruct9BytesInt4Or8ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct9BytesInt4Or8ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct12BytesHomogeneousFloatx6Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat),
+ double Function(
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat)>(
+ "PassStruct12BytesHomogeneousFloatx6",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// Struct arguments will exhaust available registers, and leave some empty.
+/// The last argument is to test whether arguments are backfilled.
+void testPassStruct12BytesHomogeneousFloatx6Leaf() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a5 = a5Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a1.a0 = 4.0;
+ a1.a1 = -5.0;
+ a1.a2 = 6.0;
+ a2.a0 = -7.0;
+ a2.a1 = 8.0;
+ a2.a2 = -9.0;
+ a3.a0 = 10.0;
+ a3.a1 = -11.0;
+ a3.a2 = 12.0;
+ a4.a0 = -13.0;
+ a4.a1 = 14.0;
+ a4.a2 = -15.0;
+ a5.a0 = 16.0;
+ a5.a1 = -17.0;
+ a5.a2 = 18.0;
+
+ final result =
+ passStruct12BytesHomogeneousFloatx6Leaf(a0, a1, a2, a3, a4, a5);
+
+ print("result = $result");
+
+ Expect.approxEquals(9.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+}
+
+final passStruct16BytesHomogeneousFloatx5Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat),
+ double Function(
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat)>(
+ "PassStruct16BytesHomogeneousFloatx5",
+ isLeaf: true);
+
+/// On Linux x64 argument is transferred on stack because it is over 16 bytes.
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct16BytesHomogeneousFloatx5Leaf() {
+ final a0Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a4 = a4Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8.0;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12.0;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16.0;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20.0;
+
+ final result = passStruct16BytesHomogeneousFloatx5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStruct16BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed),
+ double Function(
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed)>("PassStruct16BytesMixedx10", isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 8 byte aligned.
+void testPassStruct16BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+ a1.a0 = -3.0;
+ a1.a1 = 4;
+ a2.a0 = -5.0;
+ a2.a1 = 6;
+ a3.a0 = -7.0;
+ a3.a1 = 8;
+ a4.a0 = -9.0;
+ a4.a1 = 10;
+ a5.a0 = -11.0;
+ a5.a1 = 12;
+ a6.a0 = -13.0;
+ a6.a1 = 14;
+ a7.a0 = -15.0;
+ a7.a1 = 16;
+ a8.a0 = -17.0;
+ a8.a1 = 18;
+ a9.a0 = -19.0;
+ a9.a1 = 20;
+
+ final result =
+ passStruct16BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct16BytesMixed2x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2),
+ double Function(
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2)>("PassStruct16BytesMixed2x10", isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 4 byte aligned.
+void testPassStruct16BytesMixed2x10Leaf() {
+ final a0Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20;
+ a5.a0 = -21.0;
+ a5.a1 = 22.0;
+ a5.a2 = -23.0;
+ a5.a3 = 24;
+ a6.a0 = -25.0;
+ a6.a1 = 26.0;
+ a6.a2 = -27.0;
+ a6.a3 = 28;
+ a7.a0 = -29.0;
+ a7.a1 = 30.0;
+ a7.a2 = -31.0;
+ a7.a3 = 32;
+ a8.a0 = -33.0;
+ a8.a1 = 34.0;
+ a8.a2 = -35.0;
+ a8.a3 = 36;
+ a9.a0 = -37.0;
+ a9.a1 = 38.0;
+ a9.a2 = -39.0;
+ a9.a3 = 40;
+
+ final result =
+ passStruct16BytesMixed2x10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct17BytesIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt),
+ int Function(
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt)>("PassStruct17BytesIntx10", isLeaf: true);
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+void testPassStruct17BytesIntx10Leaf() {
+ final a0Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct17BytesIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct19BytesHomogeneousUint8x10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8),
+ int Function(
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8)>(
+ "PassStruct19BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is extended to the right size.
+///
+void testPassStruct19BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a0.a9 = 10;
+ a0.a10 = 11;
+ a0.a11 = 12;
+ a0.a12 = 13;
+ a0.a13 = 14;
+ a0.a14 = 15;
+ a0.a15 = 16;
+ a0.a16 = 17;
+ a0.a17 = 18;
+ a0.a18 = 19;
+ a1.a0 = 20;
+ a1.a1 = 21;
+ a1.a2 = 22;
+ a1.a3 = 23;
+ a1.a4 = 24;
+ a1.a5 = 25;
+ a1.a6 = 26;
+ a1.a7 = 27;
+ a1.a8 = 28;
+ a1.a9 = 29;
+ a1.a10 = 30;
+ a1.a11 = 31;
+ a1.a12 = 32;
+ a1.a13 = 33;
+ a1.a14 = 34;
+ a1.a15 = 35;
+ a1.a16 = 36;
+ a1.a17 = 37;
+ a1.a18 = 38;
+ a2.a0 = 39;
+ a2.a1 = 40;
+ a2.a2 = 41;
+ a2.a3 = 42;
+ a2.a4 = 43;
+ a2.a5 = 44;
+ a2.a6 = 45;
+ a2.a7 = 46;
+ a2.a8 = 47;
+ a2.a9 = 48;
+ a2.a10 = 49;
+ a2.a11 = 50;
+ a2.a12 = 51;
+ a2.a13 = 52;
+ a2.a14 = 53;
+ a2.a15 = 54;
+ a2.a16 = 55;
+ a2.a17 = 56;
+ a2.a18 = 57;
+ a3.a0 = 58;
+ a3.a1 = 59;
+ a3.a2 = 60;
+ a3.a3 = 61;
+ a3.a4 = 62;
+ a3.a5 = 63;
+ a3.a6 = 64;
+ a3.a7 = 65;
+ a3.a8 = 66;
+ a3.a9 = 67;
+ a3.a10 = 68;
+ a3.a11 = 69;
+ a3.a12 = 70;
+ a3.a13 = 71;
+ a3.a14 = 72;
+ a3.a15 = 73;
+ a3.a16 = 74;
+ a3.a17 = 75;
+ a3.a18 = 76;
+ a4.a0 = 77;
+ a4.a1 = 78;
+ a4.a2 = 79;
+ a4.a3 = 80;
+ a4.a4 = 81;
+ a4.a5 = 82;
+ a4.a6 = 83;
+ a4.a7 = 84;
+ a4.a8 = 85;
+ a4.a9 = 86;
+ a4.a10 = 87;
+ a4.a11 = 88;
+ a4.a12 = 89;
+ a4.a13 = 90;
+ a4.a14 = 91;
+ a4.a15 = 92;
+ a4.a16 = 93;
+ a4.a17 = 94;
+ a4.a18 = 95;
+ a5.a0 = 96;
+ a5.a1 = 97;
+ a5.a2 = 98;
+ a5.a3 = 99;
+ a5.a4 = 100;
+ a5.a5 = 101;
+ a5.a6 = 102;
+ a5.a7 = 103;
+ a5.a8 = 104;
+ a5.a9 = 105;
+ a5.a10 = 106;
+ a5.a11 = 107;
+ a5.a12 = 108;
+ a5.a13 = 109;
+ a5.a14 = 110;
+ a5.a15 = 111;
+ a5.a16 = 112;
+ a5.a17 = 113;
+ a5.a18 = 114;
+ a6.a0 = 115;
+ a6.a1 = 116;
+ a6.a2 = 117;
+ a6.a3 = 118;
+ a6.a4 = 119;
+ a6.a5 = 120;
+ a6.a6 = 121;
+ a6.a7 = 122;
+ a6.a8 = 123;
+ a6.a9 = 124;
+ a6.a10 = 125;
+ a6.a11 = 126;
+ a6.a12 = 127;
+ a6.a13 = 128;
+ a6.a14 = 129;
+ a6.a15 = 130;
+ a6.a16 = 131;
+ a6.a17 = 132;
+ a6.a18 = 133;
+ a7.a0 = 134;
+ a7.a1 = 135;
+ a7.a2 = 136;
+ a7.a3 = 137;
+ a7.a4 = 138;
+ a7.a5 = 139;
+ a7.a6 = 140;
+ a7.a7 = 141;
+ a7.a8 = 142;
+ a7.a9 = 143;
+ a7.a10 = 144;
+ a7.a11 = 145;
+ a7.a12 = 146;
+ a7.a13 = 147;
+ a7.a14 = 148;
+ a7.a15 = 149;
+ a7.a16 = 150;
+ a7.a17 = 151;
+ a7.a18 = 152;
+ a8.a0 = 153;
+ a8.a1 = 154;
+ a8.a2 = 155;
+ a8.a3 = 156;
+ a8.a4 = 157;
+ a8.a5 = 158;
+ a8.a6 = 159;
+ a8.a7 = 160;
+ a8.a8 = 161;
+ a8.a9 = 162;
+ a8.a10 = 163;
+ a8.a11 = 164;
+ a8.a12 = 165;
+ a8.a13 = 166;
+ a8.a14 = 167;
+ a8.a15 = 168;
+ a8.a16 = 169;
+ a8.a17 = 170;
+ a8.a18 = 171;
+ a9.a0 = 172;
+ a9.a1 = 173;
+ a9.a2 = 174;
+ a9.a3 = 175;
+ a9.a4 = 176;
+ a9.a5 = 177;
+ a9.a6 = 178;
+ a9.a7 = 179;
+ a9.a8 = 180;
+ a9.a9 = 181;
+ a9.a10 = 182;
+ a9.a11 = 183;
+ a9.a12 = 184;
+ a9.a13 = 185;
+ a9.a14 = 186;
+ a9.a15 = 187;
+ a9.a16 = 188;
+ a9.a17 = 189;
+ a9.a18 = 190;
+
+ final result = passStruct19BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(18145, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct20BytesHomogeneousInt32x10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int32 Function(
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32),
+ int Function(
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32)>(
+ "PassStruct20BytesHomogeneousInt32x10",
+ isLeaf: true);
+
+/// Argument too big to go into integer registers on arm64.
+/// The arguments are passed as pointers to copies.
+/// The amount of arguments exhausts the number of integer registers, such that
+/// pointers to copies are also passed on the stack.
+void testPassStruct20BytesHomogeneousInt32x10Leaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a0.a3 = 4;
+ a0.a4 = -5;
+ a1.a0 = 6;
+ a1.a1 = -7;
+ a1.a2 = 8;
+ a1.a3 = -9;
+ a1.a4 = 10;
+ a2.a0 = -11;
+ a2.a1 = 12;
+ a2.a2 = -13;
+ a2.a3 = 14;
+ a2.a4 = -15;
+ a3.a0 = 16;
+ a3.a1 = -17;
+ a3.a2 = 18;
+ a3.a3 = -19;
+ a3.a4 = 20;
+ a4.a0 = -21;
+ a4.a1 = 22;
+ a4.a2 = -23;
+ a4.a3 = 24;
+ a4.a4 = -25;
+ a5.a0 = 26;
+ a5.a1 = -27;
+ a5.a2 = 28;
+ a5.a3 = -29;
+ a5.a4 = 30;
+ a6.a0 = -31;
+ a6.a1 = 32;
+ a6.a2 = -33;
+ a6.a3 = 34;
+ a6.a4 = -35;
+ a7.a0 = 36;
+ a7.a1 = -37;
+ a7.a2 = 38;
+ a7.a3 = -39;
+ a7.a4 = 40;
+ a8.a0 = -41;
+ a8.a1 = 42;
+ a8.a2 = -43;
+ a8.a3 = 44;
+ a8.a4 = -45;
+ a9.a0 = 46;
+ a9.a1 = -47;
+ a9.a2 = 48;
+ a9.a3 = -49;
+ a9.a4 = 50;
+
+ final result = passStruct20BytesHomogeneousInt32x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(25, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct20BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Float Function(Struct20BytesHomogeneousFloat),
+ double Function(Struct20BytesHomogeneousFloat)>(
+ "PassStruct20BytesHomogeneousFloat",
+ isLeaf: true);
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+void testPassStruct20BytesHomogeneousFloatLeaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousFloat>();
+ final Struct20BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+
+ final result = passStruct20BytesHomogeneousFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(-3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct32BytesHomogeneousDoublex5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble),
+ double Function(
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble)>(
+ "PassStruct32BytesHomogeneousDoublex5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct32BytesHomogeneousDoublex5Leaf() {
+ final a0Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a4 = a4Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8.0;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12.0;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16.0;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20.0;
+
+ final result = passStruct32BytesHomogeneousDoublex5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStruct40BytesHomogeneousDoubleLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct40BytesHomogeneousDouble),
+ double Function(Struct40BytesHomogeneousDouble)>(
+ "PassStruct40BytesHomogeneousDouble",
+ isLeaf: true);
+
+/// Argument too big to go into FPU registers in arm64.
+void testPassStruct40BytesHomogeneousDoubleLeaf() {
+ final a0Pointer = calloc<Struct40BytesHomogeneousDouble>();
+ final Struct40BytesHomogeneousDouble a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+
+ final result = passStruct40BytesHomogeneousDoubleLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(-3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct1024BytesHomogeneousUint64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Uint64 Function(Struct1024BytesHomogeneousUint64),
+ int Function(Struct1024BytesHomogeneousUint64)>(
+ "PassStruct1024BytesHomogeneousUint64",
+ isLeaf: true);
+
+/// Test 1kb struct.
+void testPassStruct1024BytesHomogeneousUint64Leaf() {
+ final a0Pointer = calloc<Struct1024BytesHomogeneousUint64>();
+ final Struct1024BytesHomogeneousUint64 a0 = a0Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a0.a9 = 10;
+ a0.a10 = 11;
+ a0.a11 = 12;
+ a0.a12 = 13;
+ a0.a13 = 14;
+ a0.a14 = 15;
+ a0.a15 = 16;
+ a0.a16 = 17;
+ a0.a17 = 18;
+ a0.a18 = 19;
+ a0.a19 = 20;
+ a0.a20 = 21;
+ a0.a21 = 22;
+ a0.a22 = 23;
+ a0.a23 = 24;
+ a0.a24 = 25;
+ a0.a25 = 26;
+ a0.a26 = 27;
+ a0.a27 = 28;
+ a0.a28 = 29;
+ a0.a29 = 30;
+ a0.a30 = 31;
+ a0.a31 = 32;
+ a0.a32 = 33;
+ a0.a33 = 34;
+ a0.a34 = 35;
+ a0.a35 = 36;
+ a0.a36 = 37;
+ a0.a37 = 38;
+ a0.a38 = 39;
+ a0.a39 = 40;
+ a0.a40 = 41;
+ a0.a41 = 42;
+ a0.a42 = 43;
+ a0.a43 = 44;
+ a0.a44 = 45;
+ a0.a45 = 46;
+ a0.a46 = 47;
+ a0.a47 = 48;
+ a0.a48 = 49;
+ a0.a49 = 50;
+ a0.a50 = 51;
+ a0.a51 = 52;
+ a0.a52 = 53;
+ a0.a53 = 54;
+ a0.a54 = 55;
+ a0.a55 = 56;
+ a0.a56 = 57;
+ a0.a57 = 58;
+ a0.a58 = 59;
+ a0.a59 = 60;
+ a0.a60 = 61;
+ a0.a61 = 62;
+ a0.a62 = 63;
+ a0.a63 = 64;
+ a0.a64 = 65;
+ a0.a65 = 66;
+ a0.a66 = 67;
+ a0.a67 = 68;
+ a0.a68 = 69;
+ a0.a69 = 70;
+ a0.a70 = 71;
+ a0.a71 = 72;
+ a0.a72 = 73;
+ a0.a73 = 74;
+ a0.a74 = 75;
+ a0.a75 = 76;
+ a0.a76 = 77;
+ a0.a77 = 78;
+ a0.a78 = 79;
+ a0.a79 = 80;
+ a0.a80 = 81;
+ a0.a81 = 82;
+ a0.a82 = 83;
+ a0.a83 = 84;
+ a0.a84 = 85;
+ a0.a85 = 86;
+ a0.a86 = 87;
+ a0.a87 = 88;
+ a0.a88 = 89;
+ a0.a89 = 90;
+ a0.a90 = 91;
+ a0.a91 = 92;
+ a0.a92 = 93;
+ a0.a93 = 94;
+ a0.a94 = 95;
+ a0.a95 = 96;
+ a0.a96 = 97;
+ a0.a97 = 98;
+ a0.a98 = 99;
+ a0.a99 = 100;
+ a0.a100 = 101;
+ a0.a101 = 102;
+ a0.a102 = 103;
+ a0.a103 = 104;
+ a0.a104 = 105;
+ a0.a105 = 106;
+ a0.a106 = 107;
+ a0.a107 = 108;
+ a0.a108 = 109;
+ a0.a109 = 110;
+ a0.a110 = 111;
+ a0.a111 = 112;
+ a0.a112 = 113;
+ a0.a113 = 114;
+ a0.a114 = 115;
+ a0.a115 = 116;
+ a0.a116 = 117;
+ a0.a117 = 118;
+ a0.a118 = 119;
+ a0.a119 = 120;
+ a0.a120 = 121;
+ a0.a121 = 122;
+ a0.a122 = 123;
+ a0.a123 = 124;
+ a0.a124 = 125;
+ a0.a125 = 126;
+ a0.a126 = 127;
+ a0.a127 = 128;
+
+ final result = passStruct1024BytesHomogeneousUint64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(8256, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf =
+ ffiTestFunctions.lookupFunction<
+ Float Function(
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float),
+ double Function(
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double)>("PassFloatStruct16BytesHomogeneousFloatFloatStruct1",
+ isLeaf: true);
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf() {
+ double a0;
+ final a1Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a1 = a1Pointer.ref;
+ double a2;
+ final a3Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a3 = a3Pointer.ref;
+ double a4;
+ final a5Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a5 = a5Pointer.ref;
+ double a6;
+ final a7Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1.0;
+ a1.a0 = 2.0;
+ a1.a1 = -3.0;
+ a1.a2 = 4.0;
+ a1.a3 = -5.0;
+ a2 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a3.a2 = -9.0;
+ a3.a3 = 10.0;
+ a4 = -11.0;
+ a5.a0 = 12.0;
+ a5.a1 = -13.0;
+ a5.a2 = 14.0;
+ a5.a3 = -15.0;
+ a6 = 16.0;
+ a7.a0 = -17.0;
+ a7.a1 = 18.0;
+ a7.a2 = -19.0;
+ a7.a3 = 20.0;
+ a8 = -21.0;
+
+ final result = passFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-11.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passFloatStruct32BytesHomogeneousDoubleFloatStructLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float),
+ double Function(
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double)>("PassFloatStruct32BytesHomogeneousDoubleFloatStruct",
+ isLeaf: true);
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct32BytesHomogeneousDoubleFloatStructLeaf() {
+ double a0;
+ final a1Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a1 = a1Pointer.ref;
+ double a2;
+ final a3Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a3 = a3Pointer.ref;
+ double a4;
+ final a5Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a5 = a5Pointer.ref;
+ double a6;
+ final a7Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1.0;
+ a1.a0 = 2.0;
+ a1.a1 = -3.0;
+ a1.a2 = 4.0;
+ a1.a3 = -5.0;
+ a2 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a3.a2 = -9.0;
+ a3.a3 = 10.0;
+ a4 = -11.0;
+ a5.a0 = 12.0;
+ a5.a1 = -13.0;
+ a5.a2 = 14.0;
+ a5.a3 = -15.0;
+ a6 = 16.0;
+ a7.a0 = -17.0;
+ a7.a1 = 18.0;
+ a7.a2 = -19.0;
+ a7.a3 = 20.0;
+ a8 = -21.0;
+
+ final result = passFloatStruct32BytesHomogeneousDoubleFloatStructLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-11.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Int8, Struct16BytesMixed, Int8, Struct16BytesMixed,
+ Int8, Struct16BytesMixed, Int8, Struct16BytesMixed, Int8),
+ double Function(
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int)>("PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn",
+ isLeaf: true);
+
+/// Tests the alignment of structs in integers registers and on the stack.
+/// Arm32 aligns this struct at 8.
+/// Also, arm32 allocates the second struct partially in registers, partially
+/// on stack.
+/// Test backfilling of integer registers.
+void testPassInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a1 = a1Pointer.ref;
+ int a2;
+ final a3Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a3 = a3Pointer.ref;
+ int a4;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ int a6;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ int a8;
+
+ a0 = -1;
+ a1.a0 = 2.0;
+ a1.a1 = -3;
+ a2 = 4;
+ a3.a0 = -5.0;
+ a3.a1 = 6;
+ a4 = -7;
+ a5.a0 = 8.0;
+ a5.a1 = -9;
+ a6 = 10;
+ a7.a0 = -11.0;
+ a7.a1 = 12;
+ a8 = -13;
+
+ final result = passInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-7.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passDoublex6Struct16BytesMixedx4Int32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Int32),
+ double Function(
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ int)>("PassDoublex6Struct16BytesMixedx4Int32", isLeaf: true);
+
+/// On Linux x64, it will exhaust xmm registers first, after 6 doubles and 2
+/// structs. The rest of the structs will go on the stack.
+/// The int will be backfilled into the int register.
+void testPassDoublex6Struct16BytesMixedx4Int32Leaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+ double a5;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a9 = a9Pointer.ref;
+ int a10;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+ a5 = 6.0;
+ a6.a0 = -7.0;
+ a6.a1 = 8;
+ a7.a0 = -9.0;
+ a7.a1 = 10;
+ a8.a0 = -11.0;
+ a8.a1 = 12;
+ a9.a0 = -13.0;
+ a9.a1 = 14;
+ a10 = -15;
+
+ final result = passDoublex6Struct16BytesMixedx4Int32Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+ print("result = $result");
+
+ Expect.approxEquals(-8.0, result);
+
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passInt32x4Struct16BytesMixedx4DoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Int32, Int32, Int32, Int32, Struct16BytesMixed,
+ Struct16BytesMixed, Struct16BytesMixed, Struct16BytesMixed, Double),
+ double Function(
+ int,
+ int,
+ int,
+ int,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ double)>("PassInt32x4Struct16BytesMixedx4Double", isLeaf: true);
+
+/// On Linux x64, it will exhaust int registers first.
+/// The rest of the structs will go on the stack.
+/// The double will be backfilled into the xmm register.
+void testPassInt32x4Struct16BytesMixedx4DoubleLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ final a4Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4.a0 = -5.0;
+ a4.a1 = 6;
+ a5.a0 = -7.0;
+ a5.a1 = 8;
+ a6.a0 = -9.0;
+ a6.a1 = 10;
+ a7.a0 = -11.0;
+ a7.a1 = 12;
+ a8 = -13.0;
+
+ final result = passInt32x4Struct16BytesMixedx4DoubleLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-7.0, result);
+
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Struct40BytesHomogeneousDouble,
+ Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat),
+ double Function(Struct40BytesHomogeneousDouble,
+ Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat)>(
+ "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo",
+ isLeaf: true);
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf() {
+ final a0Pointer = calloc<Struct40BytesHomogeneousDouble>();
+ final Struct40BytesHomogeneousDouble a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a2 = a2Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+ a1.a0 = 6;
+ a1.a1 = -7;
+ a2.a0 = 8.0;
+ a2.a1 = -9.0;
+
+ final result =
+ passStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(-5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+}
+
+final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Int64,
+ Int8,
+ Struct1ByteInt,
+ Int64,
+ Int8,
+ Struct4BytesHomogeneousInt16,
+ Int64,
+ Int8,
+ Struct8BytesInt,
+ Int64,
+ Int8,
+ Struct8BytesHomogeneousFloat,
+ Int64,
+ Int8,
+ Struct8BytesMixed,
+ Int64,
+ Int8,
+ StructAlignmentInt16,
+ Int64,
+ Int8,
+ StructAlignmentInt32,
+ Int64,
+ Int8,
+ StructAlignmentInt64),
+ double Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ int,
+ int,
+ Struct1ByteInt,
+ int,
+ int,
+ Struct4BytesHomogeneousInt16,
+ int,
+ int,
+ Struct8BytesInt,
+ int,
+ int,
+ Struct8BytesHomogeneousFloat,
+ int,
+ int,
+ Struct8BytesMixed,
+ int,
+ int,
+ StructAlignmentInt16,
+ int,
+ int,
+ StructAlignmentInt32,
+ int,
+ int,
+ StructAlignmentInt64)>("PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ double a8;
+ double a9;
+ double a10;
+ double a11;
+ double a12;
+ double a13;
+ double a14;
+ double a15;
+ int a16;
+ int a17;
+ final a18Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a18 = a18Pointer.ref;
+ int a19;
+ int a20;
+ final a21Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a21 = a21Pointer.ref;
+ int a22;
+ int a23;
+ final a24Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a24 = a24Pointer.ref;
+ int a25;
+ int a26;
+ final a27Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a27 = a27Pointer.ref;
+ int a28;
+ int a29;
+ final a30Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a30 = a30Pointer.ref;
+ int a31;
+ int a32;
+ final a33Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a33 = a33Pointer.ref;
+ int a34;
+ int a35;
+ final a36Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a36 = a36Pointer.ref;
+ int a37;
+ int a38;
+ final a39Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a39 = a39Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8 = -9.0;
+ a9 = 10.0;
+ a10 = -11.0;
+ a11 = 12.0;
+ a12 = -13.0;
+ a13 = 14.0;
+ a14 = -15.0;
+ a15 = 16.0;
+ a16 = -17;
+ a17 = 18;
+ a18.a0 = -19;
+ a19 = 20;
+ a20 = -21;
+ a21.a0 = 22;
+ a21.a1 = -23;
+ a22 = 24;
+ a23 = -25;
+ a24.a0 = 26;
+ a24.a1 = -27;
+ a24.a2 = 28;
+ a25 = -29;
+ a26 = 30;
+ a27.a0 = -31.0;
+ a27.a1 = 32.0;
+ a28 = -33;
+ a29 = 34;
+ a30.a0 = -35.0;
+ a30.a1 = 36;
+ a30.a2 = -37;
+ a31 = 38;
+ a32 = -39;
+ a33.a0 = 40;
+ a33.a1 = -41;
+ a33.a2 = 42;
+ a34 = -43;
+ a35 = 44;
+ a36.a0 = -45;
+ a36.a1 = 46;
+ a36.a2 = -47;
+ a37 = 48;
+ a38 = -49;
+ a39.a0 = 50;
+ a39.a1 = -51;
+ a39.a2 = 52;
+
+ final result = passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf(
+ a0,
+ a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6,
+ a7,
+ a8,
+ a9,
+ a10,
+ a11,
+ a12,
+ a13,
+ a14,
+ a15,
+ a16,
+ a17,
+ a18,
+ a19,
+ a20,
+ a21,
+ a22,
+ a23,
+ a24,
+ a25,
+ a26,
+ a27,
+ a28,
+ a29,
+ a30,
+ a31,
+ a32,
+ a33,
+ a34,
+ a35,
+ a36,
+ a37,
+ a38,
+ a39);
+
+ print("result = $result");
+
+ Expect.approxEquals(26.0, result);
+
+ calloc.free(a18Pointer);
+ calloc.free(a21Pointer);
+ calloc.free(a24Pointer);
+ calloc.free(a27Pointer);
+ calloc.free(a30Pointer);
+ calloc.free(a33Pointer);
+ calloc.free(a36Pointer);
+ calloc.free(a39Pointer);
+}
+
+final passStructAlignmentInt16Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt16),
+ int Function(
+ StructAlignmentInt16)>("PassStructAlignmentInt16", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt16Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructAlignmentInt32Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt32),
+ int Function(
+ StructAlignmentInt32)>("PassStructAlignmentInt32", isLeaf: true);
+
+/// Test alignment and padding of 32 byte int within struct.
+void testPassStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructAlignmentInt64Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt64),
+ int Function(
+ StructAlignmentInt64)>("PassStructAlignmentInt64", isLeaf: true);
+
+/// Test alignment and padding of 64 byte int within struct.
+void testPassStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct8BytesNestedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt),
+ int Function(
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt)>("PassStruct8BytesNestedIntx10", isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust registers on all platforms.
+void testPassStruct8BytesNestedIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3;
+ a0.a1.a1 = 4;
+ a1.a0.a0 = -5;
+ a1.a0.a1 = 6;
+ a1.a1.a0 = -7;
+ a1.a1.a1 = 8;
+ a2.a0.a0 = -9;
+ a2.a0.a1 = 10;
+ a2.a1.a0 = -11;
+ a2.a1.a1 = 12;
+ a3.a0.a0 = -13;
+ a3.a0.a1 = 14;
+ a3.a1.a0 = -15;
+ a3.a1.a1 = 16;
+ a4.a0.a0 = -17;
+ a4.a0.a1 = 18;
+ a4.a1.a0 = -19;
+ a4.a1.a1 = 20;
+ a5.a0.a0 = -21;
+ a5.a0.a1 = 22;
+ a5.a1.a0 = -23;
+ a5.a1.a1 = 24;
+ a6.a0.a0 = -25;
+ a6.a0.a1 = 26;
+ a6.a1.a0 = -27;
+ a6.a1.a1 = 28;
+ a7.a0.a0 = -29;
+ a7.a0.a1 = 30;
+ a7.a1.a0 = -31;
+ a7.a1.a1 = 32;
+ a8.a0.a0 = -33;
+ a8.a0.a1 = 34;
+ a8.a1.a0 = -35;
+ a8.a1.a1 = 36;
+ a9.a0.a0 = -37;
+ a9.a0.a1 = 38;
+ a9.a1.a0 = -39;
+ a9.a1.a1 = 40;
+
+ final result =
+ passStruct8BytesNestedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(20, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat),
+ double Function(
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat)>("PassStruct8BytesNestedFloatx10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust fpu registers on all platforms.
+void testPassStruct8BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1.a0 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a1.a0 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a1.a0 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a1.a0 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a1.a0 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a1.a0 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a1.a0 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a1.a0 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a1.a0 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a1.a0 = 20.0;
+
+ final result = passStruct8BytesNestedFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedFloat2x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2),
+ double Function(
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2)>("PassStruct8BytesNestedFloat2x10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust fpu registers on all platforms.
+/// The nesting is irregular, testing homogenous float rules on arm and arm64,
+/// and the fpu register usage on x64.
+void testPassStruct8BytesNestedFloat2x10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a1 = 20.0;
+
+ final result = passStruct8BytesNestedFloat2x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed),
+ double Function(
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed)>("PassStruct8BytesNestedMixedx10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust all registers on all platforms.
+void testPassStruct8BytesNestedMixedx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3.0;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a1.a0 = 6.0;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a1.a0 = -9.0;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a1.a0 = 12.0;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a1.a0 = -15.0;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a1.a0 = 18.0;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a1.a0 = -21.0;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a1.a0 = 24.0;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a1.a0 = -27.0;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a1.a0 = 30.0;
+
+ final result = passStruct8BytesNestedMixedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct16BytesNestedIntx2Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(Struct16BytesNestedInt, Struct16BytesNestedInt),
+ int Function(Struct16BytesNestedInt,
+ Struct16BytesNestedInt)>("PassStruct16BytesNestedIntx2", isLeaf: true);
+
+/// Deeper nested struct to test recursive member access.
+void testPassStruct16BytesNestedIntx2Leaf() {
+ final a0Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0 = -1;
+ a0.a0.a0.a1 = 2;
+ a0.a0.a1.a0 = -3;
+ a0.a0.a1.a1 = 4;
+ a0.a1.a0.a0 = -5;
+ a0.a1.a0.a1 = 6;
+ a0.a1.a1.a0 = -7;
+ a0.a1.a1.a1 = 8;
+ a1.a0.a0.a0 = -9;
+ a1.a0.a0.a1 = 10;
+ a1.a0.a1.a0 = -11;
+ a1.a0.a1.a1 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15;
+ a1.a1.a1.a1 = 16;
+
+ final result = passStruct16BytesNestedIntx2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(8, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final passStruct32BytesNestedIntx2Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(Struct32BytesNestedInt, Struct32BytesNestedInt),
+ int Function(Struct32BytesNestedInt,
+ Struct32BytesNestedInt)>("PassStruct32BytesNestedIntx2", isLeaf: true);
+
+/// Even deeper nested struct to test recursive member access.
+void testPassStruct32BytesNestedIntx2Leaf() {
+ final a0Pointer = calloc<Struct32BytesNestedInt>();
+ final Struct32BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct32BytesNestedInt>();
+ final Struct32BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0.a0 = -1;
+ a0.a0.a0.a0.a1 = 2;
+ a0.a0.a0.a1.a0 = -3;
+ a0.a0.a0.a1.a1 = 4;
+ a0.a0.a1.a0.a0 = -5;
+ a0.a0.a1.a0.a1 = 6;
+ a0.a0.a1.a1.a0 = -7;
+ a0.a0.a1.a1.a1 = 8;
+ a0.a1.a0.a0.a0 = -9;
+ a0.a1.a0.a0.a1 = 10;
+ a0.a1.a0.a1.a0 = -11;
+ a0.a1.a0.a1.a1 = 12;
+ a0.a1.a1.a0.a0 = -13;
+ a0.a1.a1.a0.a1 = 14;
+ a0.a1.a1.a1.a0 = -15;
+ a0.a1.a1.a1.a1 = 16;
+ a1.a0.a0.a0.a0 = -17;
+ a1.a0.a0.a0.a1 = 18;
+ a1.a0.a0.a1.a0 = -19;
+ a1.a0.a0.a1.a1 = 20;
+ a1.a0.a1.a0.a0 = -21;
+ a1.a0.a1.a0.a1 = 22;
+ a1.a0.a1.a1.a0 = -23;
+ a1.a0.a1.a1.a1 = 24;
+ a1.a1.a0.a0.a0 = -25;
+ a1.a1.a0.a0.a1 = 26;
+ a1.a1.a0.a1.a0 = -27;
+ a1.a1.a0.a1.a1 = 28;
+ a1.a1.a1.a0.a0 = -29;
+ a1.a1.a1.a0.a1 = 30;
+ a1.a1.a1.a1.a0 = -31;
+ a1.a1.a1.a1.a1 = 32;
+
+ final result = passStruct32BytesNestedIntx2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(16, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt16Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt16),
+ int Function(StructNestedIntStructAlignmentInt16)>(
+ "PassStructNestedIntStructAlignmentInt16",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 16 byte int.
+void testPassStructNestedIntStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt16>();
+ final StructNestedIntStructAlignmentInt16 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt16Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt32),
+ int Function(StructNestedIntStructAlignmentInt32)>(
+ "PassStructNestedIntStructAlignmentInt32",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 32 byte int.
+void testPassStructNestedIntStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt32>();
+ final StructNestedIntStructAlignmentInt32 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt64),
+ int Function(StructNestedIntStructAlignmentInt64)>(
+ "PassStructNestedIntStructAlignmentInt64",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 64 byte int.
+void testPassStructNestedIntStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt64>();
+ final StructNestedIntStructAlignmentInt64 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIrregularEvenBiggerx4Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger),
+ double Function(
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger)>(
+ "PassStructNestedIrregularEvenBiggerx4",
+ isLeaf: true);
+
+/// Return big irregular struct as smoke test.
+void testPassStructNestedIrregularEvenBiggerx4Leaf() {
+ final a0Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a3 = a3Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1.a0.a0 = 2;
+ a0.a1.a0.a1.a0.a0 = -3;
+ a0.a1.a0.a1.a0.a1 = 4;
+ a0.a1.a0.a1.a1.a0 = -5.0;
+ a0.a1.a0.a2 = 6;
+ a0.a1.a0.a3.a0.a0 = -7.0;
+ a0.a1.a0.a3.a1 = 8.0;
+ a0.a1.a0.a4 = 9;
+ a0.a1.a0.a5.a0.a0 = 10.0;
+ a0.a1.a0.a5.a1.a0 = -11.0;
+ a0.a1.a0.a6 = 12;
+ a0.a1.a1.a0.a0 = -13;
+ a0.a1.a1.a0.a1 = 14;
+ a0.a1.a1.a1.a0 = -15.0;
+ a0.a1.a2 = 16.0;
+ a0.a1.a3 = -17.0;
+ a0.a2.a0.a0 = 18;
+ a0.a2.a0.a1.a0.a0 = -19;
+ a0.a2.a0.a1.a0.a1 = 20;
+ a0.a2.a0.a1.a1.a0 = -21.0;
+ a0.a2.a0.a2 = 22;
+ a0.a2.a0.a3.a0.a0 = -23.0;
+ a0.a2.a0.a3.a1 = 24.0;
+ a0.a2.a0.a4 = 25;
+ a0.a2.a0.a5.a0.a0 = 26.0;
+ a0.a2.a0.a5.a1.a0 = -27.0;
+ a0.a2.a0.a6 = 28;
+ a0.a2.a1.a0.a0 = -29;
+ a0.a2.a1.a0.a1 = 30;
+ a0.a2.a1.a1.a0 = -31.0;
+ a0.a2.a2 = 32.0;
+ a0.a2.a3 = -33.0;
+ a0.a3 = 34.0;
+ a1.a0 = 35;
+ a1.a1.a0.a0 = 36;
+ a1.a1.a0.a1.a0.a0 = -37;
+ a1.a1.a0.a1.a0.a1 = 38;
+ a1.a1.a0.a1.a1.a0 = -39.0;
+ a1.a1.a0.a2 = 40;
+ a1.a1.a0.a3.a0.a0 = -41.0;
+ a1.a1.a0.a3.a1 = 42.0;
+ a1.a1.a0.a4 = 43;
+ a1.a1.a0.a5.a0.a0 = 44.0;
+ a1.a1.a0.a5.a1.a0 = -45.0;
+ a1.a1.a0.a6 = 46;
+ a1.a1.a1.a0.a0 = -47;
+ a1.a1.a1.a0.a1 = 48;
+ a1.a1.a1.a1.a0 = -49.0;
+ a1.a1.a2 = 50.0;
+ a1.a1.a3 = -51.0;
+ a1.a2.a0.a0 = 52;
+ a1.a2.a0.a1.a0.a0 = -53;
+ a1.a2.a0.a1.a0.a1 = 54;
+ a1.a2.a0.a1.a1.a0 = -55.0;
+ a1.a2.a0.a2 = 56;
+ a1.a2.a0.a3.a0.a0 = -57.0;
+ a1.a2.a0.a3.a1 = 58.0;
+ a1.a2.a0.a4 = 59;
+ a1.a2.a0.a5.a0.a0 = 60.0;
+ a1.a2.a0.a5.a1.a0 = -61.0;
+ a1.a2.a0.a6 = 62;
+ a1.a2.a1.a0.a0 = -63;
+ a1.a2.a1.a0.a1 = 64;
+ a1.a2.a1.a1.a0 = -65.0;
+ a1.a2.a2 = 66.0;
+ a1.a2.a3 = -67.0;
+ a1.a3 = 68.0;
+ a2.a0 = 69;
+ a2.a1.a0.a0 = 70;
+ a2.a1.a0.a1.a0.a0 = -71;
+ a2.a1.a0.a1.a0.a1 = 72;
+ a2.a1.a0.a1.a1.a0 = -73.0;
+ a2.a1.a0.a2 = 74;
+ a2.a1.a0.a3.a0.a0 = -75.0;
+ a2.a1.a0.a3.a1 = 76.0;
+ a2.a1.a0.a4 = 77;
+ a2.a1.a0.a5.a0.a0 = 78.0;
+ a2.a1.a0.a5.a1.a0 = -79.0;
+ a2.a1.a0.a6 = 80;
+ a2.a1.a1.a0.a0 = -81;
+ a2.a1.a1.a0.a1 = 82;
+ a2.a1.a1.a1.a0 = -83.0;
+ a2.a1.a2 = 84.0;
+ a2.a1.a3 = -85.0;
+ a2.a2.a0.a0 = 86;
+ a2.a2.a0.a1.a0.a0 = -87;
+ a2.a2.a0.a1.a0.a1 = 88;
+ a2.a2.a0.a1.a1.a0 = -89.0;
+ a2.a2.a0.a2 = 90;
+ a2.a2.a0.a3.a0.a0 = -91.0;
+ a2.a2.a0.a3.a1 = 92.0;
+ a2.a2.a0.a4 = 93;
+ a2.a2.a0.a5.a0.a0 = 94.0;
+ a2.a2.a0.a5.a1.a0 = -95.0;
+ a2.a2.a0.a6 = 96;
+ a2.a2.a1.a0.a0 = -97;
+ a2.a2.a1.a0.a1 = 98;
+ a2.a2.a1.a1.a0 = -99.0;
+ a2.a2.a2 = 100.0;
+ a2.a2.a3 = -101.0;
+ a2.a3 = 102.0;
+ a3.a0 = 103;
+ a3.a1.a0.a0 = 104;
+ a3.a1.a0.a1.a0.a0 = -105;
+ a3.a1.a0.a1.a0.a1 = 106;
+ a3.a1.a0.a1.a1.a0 = -107.0;
+ a3.a1.a0.a2 = 108;
+ a3.a1.a0.a3.a0.a0 = -109.0;
+ a3.a1.a0.a3.a1 = 110.0;
+ a3.a1.a0.a4 = 111;
+ a3.a1.a0.a5.a0.a0 = 112.0;
+ a3.a1.a0.a5.a1.a0 = -113.0;
+ a3.a1.a0.a6 = 114;
+ a3.a1.a1.a0.a0 = -115;
+ a3.a1.a1.a0.a1 = 116;
+ a3.a1.a1.a1.a0 = -117.0;
+ a3.a1.a2 = 118.0;
+ a3.a1.a3 = -119.0;
+ a3.a2.a0.a0 = 120;
+ a3.a2.a0.a1.a0.a0 = -121;
+ a3.a2.a0.a1.a0.a1 = 122;
+ a3.a2.a0.a1.a1.a0 = -123.0;
+ a3.a2.a0.a2 = 124;
+ a3.a2.a0.a3.a0.a0 = -125.0;
+ a3.a2.a0.a3.a1 = 126.0;
+ a3.a2.a0.a4 = 127;
+ a3.a2.a0.a5.a0.a0 = 128.0;
+ a3.a2.a0.a5.a1.a0 = -129.0;
+ a3.a2.a0.a6 = 130;
+ a3.a2.a1.a0.a0 = -131;
+ a3.a2.a1.a0.a1 = 132;
+ a3.a2.a1.a1.a0 = -133.0;
+ a3.a2.a2 = 134.0;
+ a3.a2.a3 = -135.0;
+ a3.a3 = 136.0;
+
+ final result = passStructNestedIrregularEvenBiggerx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(1572.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStruct8BytesInlineArrayIntx4Leaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(Struct8BytesInlineArrayInt, Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt, Struct8BytesInlineArrayInt),
+ int Function(
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt)>("PassStruct8BytesInlineArrayIntx4",
+ isLeaf: true);
+
+/// Simple struct with inline array.
+void testPassStruct8BytesInlineArrayIntx4Leaf() {
+ final a0Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a3 = a3Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+ a1.a0[0] = 9;
+ a1.a0[1] = 10;
+ a1.a0[2] = 11;
+ a1.a0[3] = 12;
+ a1.a0[4] = 13;
+ a1.a0[5] = 14;
+ a1.a0[6] = 15;
+ a1.a0[7] = 16;
+ a2.a0[0] = 17;
+ a2.a0[1] = 18;
+ a2.a0[2] = 19;
+ a2.a0[3] = 20;
+ a2.a0[4] = 21;
+ a2.a0[5] = 22;
+ a2.a0[6] = 23;
+ a2.a0[7] = 24;
+ a3.a0[0] = 25;
+ a3.a0[1] = 26;
+ a3.a0[2] = 27;
+ a3.a0[3] = 28;
+ a3.a0[4] = 29;
+ a3.a0[5] = 30;
+ a3.a0[6] = 31;
+ a3.a0[7] = 32;
+
+ final result = passStruct8BytesInlineArrayIntx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(528, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStructInlineArrayIrregularx4Leaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(StructInlineArrayIrregular, StructInlineArrayIrregular,
+ StructInlineArrayIrregular, StructInlineArrayIrregular),
+ int Function(
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular)>("PassStructInlineArrayIrregularx4",
+ isLeaf: true);
+
+/// Irregular struct with inline array.
+void testPassStructInlineArrayIrregularx4Leaf() {
+ final a0Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a3 = a3Pointer.ref;
+
+ a0.a0[0].a0 = -1;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3;
+ a0.a0[1].a1 = 4;
+ a0.a1 = 5;
+ a1.a0[0].a0 = 6;
+ a1.a0[0].a1 = -7;
+ a1.a0[1].a0 = 8;
+ a1.a0[1].a1 = -9;
+ a1.a1 = 10;
+ a2.a0[0].a0 = -11;
+ a2.a0[0].a1 = 12;
+ a2.a0[1].a0 = -13;
+ a2.a0[1].a1 = 14;
+ a2.a1 = 15;
+ a3.a0[0].a0 = 16;
+ a3.a0[0].a1 = -17;
+ a3.a0[1].a0 = 18;
+ a3.a0[1].a1 = -19;
+ a3.a1 = 20;
+
+ final result = passStructInlineArrayIrregularx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(50, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStructInlineArray100BytesLeaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(StructInlineArray100Bytes),
+ int Function(StructInlineArray100Bytes)>(
+ "PassStructInlineArray100Bytes",
+ isLeaf: true);
+
+/// Regular larger struct with inline array.
+void testPassStructInlineArray100BytesLeaf() {
+ final a0Pointer = calloc<StructInlineArray100Bytes>();
+ final StructInlineArray100Bytes a0 = a0Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+ a0.a0[8] = 9;
+ a0.a0[9] = 10;
+ a0.a0[10] = 11;
+ a0.a0[11] = 12;
+ a0.a0[12] = 13;
+ a0.a0[13] = 14;
+ a0.a0[14] = 15;
+ a0.a0[15] = 16;
+ a0.a0[16] = 17;
+ a0.a0[17] = 18;
+ a0.a0[18] = 19;
+ a0.a0[19] = 20;
+ a0.a0[20] = 21;
+ a0.a0[21] = 22;
+ a0.a0[22] = 23;
+ a0.a0[23] = 24;
+ a0.a0[24] = 25;
+ a0.a0[25] = 26;
+ a0.a0[26] = 27;
+ a0.a0[27] = 28;
+ a0.a0[28] = 29;
+ a0.a0[29] = 30;
+ a0.a0[30] = 31;
+ a0.a0[31] = 32;
+ a0.a0[32] = 33;
+ a0.a0[33] = 34;
+ a0.a0[34] = 35;
+ a0.a0[35] = 36;
+ a0.a0[36] = 37;
+ a0.a0[37] = 38;
+ a0.a0[38] = 39;
+ a0.a0[39] = 40;
+ a0.a0[40] = 41;
+ a0.a0[41] = 42;
+ a0.a0[42] = 43;
+ a0.a0[43] = 44;
+ a0.a0[44] = 45;
+ a0.a0[45] = 46;
+ a0.a0[46] = 47;
+ a0.a0[47] = 48;
+ a0.a0[48] = 49;
+ a0.a0[49] = 50;
+ a0.a0[50] = 51;
+ a0.a0[51] = 52;
+ a0.a0[52] = 53;
+ a0.a0[53] = 54;
+ a0.a0[54] = 55;
+ a0.a0[55] = 56;
+ a0.a0[56] = 57;
+ a0.a0[57] = 58;
+ a0.a0[58] = 59;
+ a0.a0[59] = 60;
+ a0.a0[60] = 61;
+ a0.a0[61] = 62;
+ a0.a0[62] = 63;
+ a0.a0[63] = 64;
+ a0.a0[64] = 65;
+ a0.a0[65] = 66;
+ a0.a0[66] = 67;
+ a0.a0[67] = 68;
+ a0.a0[68] = 69;
+ a0.a0[69] = 70;
+ a0.a0[70] = 71;
+ a0.a0[71] = 72;
+ a0.a0[72] = 73;
+ a0.a0[73] = 74;
+ a0.a0[74] = 75;
+ a0.a0[75] = 76;
+ a0.a0[76] = 77;
+ a0.a0[77] = 78;
+ a0.a0[78] = 79;
+ a0.a0[79] = 80;
+ a0.a0[80] = 81;
+ a0.a0[81] = 82;
+ a0.a0[82] = 83;
+ a0.a0[83] = 84;
+ a0.a0[84] = 85;
+ a0.a0[85] = 86;
+ a0.a0[86] = 87;
+ a0.a0[87] = 88;
+ a0.a0[88] = 89;
+ a0.a0[89] = 90;
+ a0.a0[90] = 91;
+ a0.a0[91] = 92;
+ a0.a0[92] = 93;
+ a0.a0[93] = 94;
+ a0.a0[94] = 95;
+ a0.a0[95] = 96;
+ a0.a0[96] = 97;
+ a0.a0[97] = 98;
+ a0.a0[98] = 99;
+ a0.a0[99] = 100;
+
+ final result = passStructInlineArray100BytesLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(5050, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructStruct16BytesHomogeneousFloat2x5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Float Function(
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2),
+ double Function(
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2)>(
+ "PassStructStruct16BytesHomogeneousFloat2x5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStructStruct16BytesHomogeneousFloat2x5Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a4 = a4Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+ a1.a0.a0 = -5.0;
+ a1.a1[0].a0 = 6.0;
+ a1.a1[1].a0 = -7.0;
+ a1.a2 = 8.0;
+ a2.a0.a0 = -9.0;
+ a2.a1[0].a0 = 10.0;
+ a2.a1[1].a0 = -11.0;
+ a2.a2 = 12.0;
+ a3.a0.a0 = -13.0;
+ a3.a1[0].a0 = 14.0;
+ a3.a1[1].a0 = -15.0;
+ a3.a2 = 16.0;
+ a4.a0.a0 = -17.0;
+ a4.a1[0].a0 = 18.0;
+ a4.a1[1].a0 = -19.0;
+ a4.a2 = 20.0;
+
+ final result =
+ passStructStruct16BytesHomogeneousFloat2x5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStructStruct32BytesHomogeneousDouble2x5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2),
+ double Function(
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2)>(
+ "PassStructStruct32BytesHomogeneousDouble2x5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStructStruct32BytesHomogeneousDouble2x5Leaf() {
+ final a0Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a4 = a4Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+ a1.a0.a0 = -5.0;
+ a1.a1[0].a0 = 6.0;
+ a1.a1[1].a0 = -7.0;
+ a1.a2 = 8.0;
+ a2.a0.a0 = -9.0;
+ a2.a1[0].a0 = 10.0;
+ a2.a1[1].a0 = -11.0;
+ a2.a2 = 12.0;
+ a3.a0.a0 = -13.0;
+ a3.a1[0].a0 = 14.0;
+ a3.a1[1].a0 = -15.0;
+ a3.a2 = 16.0;
+ a4.a0.a0 = -17.0;
+ a4.a1[0].a0 = 18.0;
+ a4.a1[1].a0 = -19.0;
+ a4.a2 = 20.0;
+
+ final result =
+ passStructStruct32BytesHomogeneousDouble2x5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStructStruct16BytesMixed3x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3),
+ double Function(
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3)>("PassStructStruct16BytesMixed3x10",
+ isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 4 byte aligned.
+void testPassStructStruct16BytesMixed3x10Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[0].a1 = -3;
+ a0.a1[0].a2 = 4;
+ a0.a2[0] = -5;
+ a0.a2[1] = 6;
+ a1.a0.a0 = -7.0;
+ a1.a1[0].a0 = 8.0;
+ a1.a1[0].a1 = -9;
+ a1.a1[0].a2 = 10;
+ a1.a2[0] = -11;
+ a1.a2[1] = 12;
+ a2.a0.a0 = -13.0;
+ a2.a1[0].a0 = 14.0;
+ a2.a1[0].a1 = -15;
+ a2.a1[0].a2 = 16;
+ a2.a2[0] = -17;
+ a2.a2[1] = 18;
+ a3.a0.a0 = -19.0;
+ a3.a1[0].a0 = 20.0;
+ a3.a1[0].a1 = -21;
+ a3.a1[0].a2 = 22;
+ a3.a2[0] = -23;
+ a3.a2[1] = 24;
+ a4.a0.a0 = -25.0;
+ a4.a1[0].a0 = 26.0;
+ a4.a1[0].a1 = -27;
+ a4.a1[0].a2 = 28;
+ a4.a2[0] = -29;
+ a4.a2[1] = 30;
+ a5.a0.a0 = -31.0;
+ a5.a1[0].a0 = 32.0;
+ a5.a1[0].a1 = -33;
+ a5.a1[0].a2 = 34;
+ a5.a2[0] = -35;
+ a5.a2[1] = 36;
+ a6.a0.a0 = -37.0;
+ a6.a1[0].a0 = 38.0;
+ a6.a1[0].a1 = -39;
+ a6.a1[0].a2 = 40;
+ a6.a2[0] = -41;
+ a6.a2[1] = 42;
+ a7.a0.a0 = -43.0;
+ a7.a1[0].a0 = 44.0;
+ a7.a1[0].a1 = -45;
+ a7.a1[0].a2 = 46;
+ a7.a2[0] = -47;
+ a7.a2[1] = 48;
+ a8.a0.a0 = -49.0;
+ a8.a1[0].a0 = 50.0;
+ a8.a1[0].a1 = -51;
+ a8.a1[0].a2 = 52;
+ a8.a2[0] = -53;
+ a8.a2[1] = 54;
+ a9.a0.a0 = -55.0;
+ a9.a1[0].a0 = 56.0;
+ a9.a1[0].a1 = -57;
+ a9.a1[0].a2 = 58;
+ a9.a2[0] = -59;
+ a9.a2[1] = 60;
+
+ final result = passStructStruct16BytesMixed3x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(30.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUint8Struct32BytesInlineArrayMultiDimensionalILeaf =
+ ffiTestFunctions.lookupFunction<
+ Uint32 Function(
+ Uint8,
+ Struct32BytesInlineArrayMultiDimensionalInt,
+ Uint8,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ Uint8,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ Uint8),
+ int Function(
+ int,
+ Struct32BytesInlineArrayMultiDimensionalInt,
+ int,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ int,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ int)>("PassUint8Struct32BytesInlineArrayMultiDimensionalI",
+ isLeaf: true);
+
+/// Test multi dimensional inline array struct as argument.
+void testPassUint8Struct32BytesInlineArrayMultiDimensionalILeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct32BytesInlineArrayMultiDimensionalInt>();
+ final Struct32BytesInlineArrayMultiDimensionalInt a1 = a1Pointer.ref;
+ int a2;
+ final a3Pointer = calloc<Struct8BytesInlineArrayMultiDimensionalInt>();
+ final Struct8BytesInlineArrayMultiDimensionalInt a3 = a3Pointer.ref;
+ int a4;
+ final a5Pointer = calloc<Struct8BytesInlineArrayMultiDimensionalInt>();
+ final Struct8BytesInlineArrayMultiDimensionalInt a5 = a5Pointer.ref;
+ int a6;
+
+ a0 = 1;
+ a1.a0[0][0][0][0][0] = 2;
+ a1.a0[0][0][0][0][1] = 3;
+ a1.a0[0][0][0][1][0] = 4;
+ a1.a0[0][0][0][1][1] = 5;
+ a1.a0[0][0][1][0][0] = 6;
+ a1.a0[0][0][1][0][1] = 7;
+ a1.a0[0][0][1][1][0] = 8;
+ a1.a0[0][0][1][1][1] = 9;
+ a1.a0[0][1][0][0][0] = 10;
+ a1.a0[0][1][0][0][1] = 11;
+ a1.a0[0][1][0][1][0] = 12;
+ a1.a0[0][1][0][1][1] = 13;
+ a1.a0[0][1][1][0][0] = 14;
+ a1.a0[0][1][1][0][1] = 15;
+ a1.a0[0][1][1][1][0] = 16;
+ a1.a0[0][1][1][1][1] = 17;
+ a1.a0[1][0][0][0][0] = 18;
+ a1.a0[1][0][0][0][1] = 19;
+ a1.a0[1][0][0][1][0] = 20;
+ a1.a0[1][0][0][1][1] = 21;
+ a1.a0[1][0][1][0][0] = 22;
+ a1.a0[1][0][1][0][1] = 23;
+ a1.a0[1][0][1][1][0] = 24;
+ a1.a0[1][0][1][1][1] = 25;
+ a1.a0[1][1][0][0][0] = 26;
+ a1.a0[1][1][0][0][1] = 27;
+ a1.a0[1][1][0][1][0] = 28;
+ a1.a0[1][1][0][1][1] = 29;
+ a1.a0[1][1][1][0][0] = 30;
+ a1.a0[1][1][1][0][1] = 31;
+ a1.a0[1][1][1][1][0] = 32;
+ a1.a0[1][1][1][1][1] = 33;
+ a2 = 34;
+ a3.a0[0][0][0] = 35;
+ a3.a0[0][0][1] = 36;
+ a3.a0[0][1][0] = 37;
+ a3.a0[0][1][1] = 38;
+ a3.a0[1][0][0] = 39;
+ a3.a0[1][0][1] = 40;
+ a3.a0[1][1][0] = 41;
+ a3.a0[1][1][1] = 42;
+ a4 = 43;
+ a5.a0[0][0][0] = 44;
+ a5.a0[0][0][1] = 45;
+ a5.a0[0][1][0] = 46;
+ a5.a0[0][1][1] = 47;
+ a5.a0[1][0][0] = 48;
+ a5.a0[1][0][1] = 49;
+ a5.a0[1][1][0] = 50;
+ a5.a0[1][1][1] = 51;
+ a6 = 52;
+
+ final result = passUint8Struct32BytesInlineArrayMultiDimensionalILeaf(
+ a0, a1, a2, a3, a4, a5, a6);
+
+ print("result = $result");
+
+ Expect.equals(1378, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+}
+
+final passUint8Struct4BytesInlineArrayMultiDimensionalInLeaf =
+ ffiTestFunctions.lookupFunction<
+ Uint32 Function(
+ Uint8, Struct4BytesInlineArrayMultiDimensionalInt, Uint8),
+ int Function(int, Struct4BytesInlineArrayMultiDimensionalInt, int)>(
+ "PassUint8Struct4BytesInlineArrayMultiDimensionalIn",
+ isLeaf: true);
+
+/// Test struct in multi dimensional inline array.
+void testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct4BytesInlineArrayMultiDimensionalInt>();
+ final Struct4BytesInlineArrayMultiDimensionalInt a1 = a1Pointer.ref;
+ int a2;
+
+ a0 = 1;
+ a1.a0[0][0].a0 = 2;
+ a1.a0[0][1].a0 = -3;
+ a1.a0[1][0].a0 = 4;
+ a1.a0[1][1].a0 = -5;
+ a2 = 6;
+
+ final result =
+ passUint8Struct4BytesInlineArrayMultiDimensionalInLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(5, result);
+
+ calloc.free(a1Pointer);
+}
+
+final passStruct3BytesPackedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt),
+ int Function(
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt)>("PassStruct3BytesPackedIntx10", isLeaf: true);
+
+/// Small struct with mis-aligned member.
+void testPassStruct3BytesPackedIntx10Leaf() {
+ final a0Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result =
+ passStruct3BytesPackedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesPackedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt),
+ int Function(
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt)>("PassStruct8BytesPackedIntx10", isLeaf: true);
+
+/// Struct with mis-aligned member.
+void testPassStruct8BytesPackedIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a1.a0 = 6;
+ a1.a1 = 7;
+ a1.a2 = 8;
+ a1.a3 = 9;
+ a1.a4 = 10;
+ a2.a0 = 11;
+ a2.a1 = 12;
+ a2.a2 = 13;
+ a2.a3 = 14;
+ a2.a4 = 15;
+ a3.a0 = 16;
+ a3.a1 = 17;
+ a3.a2 = 18;
+ a3.a3 = 19;
+ a3.a4 = 20;
+ a4.a0 = 21;
+ a4.a1 = 22;
+ a4.a2 = 23;
+ a4.a3 = 24;
+ a4.a4 = 25;
+ a5.a0 = 26;
+ a5.a1 = 27;
+ a5.a2 = 28;
+ a5.a3 = 29;
+ a5.a4 = 30;
+ a6.a0 = 31;
+ a6.a1 = 32;
+ a6.a2 = 33;
+ a6.a3 = 34;
+ a6.a4 = 35;
+ a7.a0 = 36;
+ a7.a1 = 37;
+ a7.a2 = 38;
+ a7.a3 = 39;
+ a7.a4 = 40;
+ a8.a0 = 41;
+ a8.a1 = 42;
+ a8.a2 = 43;
+ a8.a3 = 44;
+ a8.a4 = 45;
+ a9.a0 = 46;
+ a9.a1 = 47;
+ a9.a2 = 48;
+ a9.a3 = 49;
+ a9.a4 = 50;
+
+ final result =
+ passStruct8BytesPackedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(1275, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesPackedMixedx10DoubleInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Double,
+ Int32),
+ double Function(
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ double,
+ int)>("PassStruct9BytesPackedMixedx10DoubleInt32", isLeaf: true);
+
+/// Struct with mis-aligned member.
+/// Tests backfilling of CPU and FPU registers.
+void testPassStruct9BytesPackedMixedx10DoubleInt32Leaf() {
+ final a0Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a9 = a9Pointer.ref;
+ double a10;
+ int a11;
+
+ a0.a0 = 1;
+ a0.a1 = 2.0;
+ a1.a0 = 3;
+ a1.a1 = 4.0;
+ a2.a0 = 5;
+ a2.a1 = 6.0;
+ a3.a0 = 7;
+ a3.a1 = 8.0;
+ a4.a0 = 9;
+ a4.a1 = 10.0;
+ a5.a0 = 11;
+ a5.a1 = 12.0;
+ a6.a0 = 13;
+ a6.a1 = 14.0;
+ a7.a0 = 15;
+ a7.a1 = 16.0;
+ a8.a0 = 17;
+ a8.a1 = 18.0;
+ a9.a0 = 19;
+ a9.a1 = 20.0;
+ a10 = -21.0;
+ a11 = 22;
+
+ final result = passStruct9BytesPackedMixedx10DoubleInt32Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+
+ print("result = $result");
+
+ Expect.approxEquals(211.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct5BytesPackedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct5BytesPackedMixed),
+ double Function(
+ Struct5BytesPackedMixed)>("PassStruct5BytesPackedMixed", isLeaf: true);
+
+/// This packed struct happens to have only aligned members.
+void testPassStruct5BytesPackedMixedLeaf() {
+ final a0Pointer = calloc<Struct5BytesPackedMixed>();
+ final Struct5BytesPackedMixed a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+
+ final result = passStruct5BytesPackedMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(1.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedAlignmentStruct5BytesPackedMixedLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(StructNestedAlignmentStruct5BytesPackedMixed),
+ double Function(StructNestedAlignmentStruct5BytesPackedMixed)>(
+ "PassStructNestedAlignmentStruct5BytesPackedMixed",
+ isLeaf: true);
+
+/// Check alignment of packed struct in non-packed struct.
+void testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf() {
+ final a0Pointer = calloc<StructNestedAlignmentStruct5BytesPackedMixed>();
+ final StructNestedAlignmentStruct5BytesPackedMixed a0 = a0Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1.a0 = 2.0;
+ a0.a1.a1 = 3;
+
+ final result = passStructNestedAlignmentStruct5BytesPackedMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(6.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct6BytesInlineArrayIntLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct6BytesInlineArrayInt),
+ double Function(Struct6BytesInlineArrayInt)>(
+ "PassStruct6BytesInlineArrayInt",
+ isLeaf: true);
+
+/// Check alignment of packed struct array in non-packed struct.
+void testPassStruct6BytesInlineArrayIntLeaf() {
+ final a0Pointer = calloc<Struct6BytesInlineArrayInt>();
+ final Struct6BytesInlineArrayInt a0 = a0Pointer.ref;
+
+ a0.a0[0].a0 = -1;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3;
+ a0.a0[1].a1 = 4;
+
+ final result = passStruct6BytesInlineArrayIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(2.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct15BytesInlineArrayMixedLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct15BytesInlineArrayMixed),
+ double Function(Struct15BytesInlineArrayMixed)>(
+ "PassStruct15BytesInlineArrayMixed",
+ isLeaf: true);
+
+/// Check alignment of packed struct array in non-packed struct.
+void testPassStruct15BytesInlineArrayMixedLeaf() {
+ final a0Pointer = calloc<Struct15BytesInlineArrayMixed>();
+ final Struct15BytesInlineArrayMixed a0 = a0Pointer.ref;
+
+ a0.a0[0].a0 = -1.0;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3.0;
+ a0.a0[1].a1 = 4;
+ a0.a0[2].a0 = -5.0;
+ a0.a0[2].a1 = 6;
+
+ final result = passStruct15BytesInlineArrayMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passUnion4BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed),
+ double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed)>("PassUnion4BytesMixedx10", isLeaf: true);
+
+/// Check placement of mixed integer/float union.
+void testPassUnion4BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a1.a0 = 2;
+ a2.a0 = 3;
+ a3.a0 = 4;
+ a4.a0 = 5;
+ a5.a0 = 6;
+ a6.a0 = 7;
+ a7.a0 = 8;
+ a8.a0 = 9;
+ a9.a0 = 10;
+
+ final result =
+ passUnion4BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(55.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion8BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat),
+ double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat)>("PassUnion8BytesNestedFloatx10", isLeaf: true);
+
+/// Check placement of mixed floats union.
+void testPassUnion8BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+ a2.a0 = -3.0;
+ a3.a0 = 4.0;
+ a4.a0 = -5.0;
+ a5.a0 = 6.0;
+ a6.a0 = -7.0;
+ a7.a0 = 8.0;
+ a8.a0 = -9.0;
+ a9.a0 = 10.0;
+
+ final result =
+ passUnion8BytesNestedFloatx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion9BytesNestedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt),
+ double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt)>("PassUnion9BytesNestedIntx10", isLeaf: true);
+
+/// Mixed-size union argument.
+void testPassUnion9BytesNestedIntx10Leaf() {
+ final a0Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a0.a2 = 6;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a0.a2 = -9;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a0.a2 = 12;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a0.a2 = -15;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a0.a2 = 18;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a0.a2 = -21;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a0.a2 = 24;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a0.a2 = -27;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a0.a2 = 30;
+
+ final result =
+ passUnion9BytesNestedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedInlineArrayFloatx10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat),
+ double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat)>(
+ "PassUnion16BytesNestedInlineArrayFloatx10",
+ isLeaf: true);
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedInlineArrayFloatx10Leaf() {
+ final a0Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a9 = a9Pointer.ref;
+
+ a0.a0[0] = -1.0;
+ a0.a0[1] = 2.0;
+ a0.a0[2] = -3.0;
+ a0.a0[3] = 4.0;
+ a1.a0[0] = -5.0;
+ a1.a0[1] = 6.0;
+ a1.a0[2] = -7.0;
+ a1.a0[3] = 8.0;
+ a2.a0[0] = -9.0;
+ a2.a0[1] = 10.0;
+ a2.a0[2] = -11.0;
+ a2.a0[3] = 12.0;
+ a3.a0[0] = -13.0;
+ a3.a0[1] = 14.0;
+ a3.a0[2] = -15.0;
+ a3.a0[3] = 16.0;
+ a4.a0[0] = -17.0;
+ a4.a0[1] = 18.0;
+ a4.a0[2] = -19.0;
+ a4.a0[3] = 20.0;
+ a5.a0[0] = -21.0;
+ a5.a0[1] = 22.0;
+ a5.a0[2] = -23.0;
+ a5.a0[3] = 24.0;
+ a6.a0[0] = -25.0;
+ a6.a0[1] = 26.0;
+ a6.a0[2] = -27.0;
+ a6.a0[3] = 28.0;
+ a7.a0[0] = -29.0;
+ a7.a0[1] = 30.0;
+ a7.a0[2] = -31.0;
+ a7.a0[3] = 32.0;
+ a8.a0[0] = -33.0;
+ a8.a0[1] = 34.0;
+ a8.a0[2] = -35.0;
+ a8.a0[3] = 36.0;
+ a9.a0[0] = -37.0;
+ a9.a0[1] = 38.0;
+ a9.a0[2] = -39.0;
+ a9.a0[3] = 40.0;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat),
+ double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat)>("PassUnion16BytesNestedFloatx10",
+ isLeaf: true);
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a0.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a0.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a0.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a0.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a0.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a0.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a0.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a0.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a0.a1 = 20.0;
+
+ final result = passUnion16BytesNestedFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final returnStruct1ByteIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Int8),
+ Struct1ByteInt Function(int)>("ReturnStruct1ByteInt", isLeaf: true);
+
+/// Smallest struct with data.
+void testReturnStruct1ByteIntLeaf() {
+ int a0;
+
+ a0 = -1;
+
+ final result = returnStruct1ByteIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnStruct3BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesHomogeneousUint8 Function(Uint8, Uint8, Uint8),
+ Struct3BytesHomogeneousUint8 Function(
+ int, int, int)>("ReturnStruct3BytesHomogeneousUint8", isLeaf: true);
+
+/// Smaller than word size return value on all architectures.
+void testReturnStruct3BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+
+ final result = returnStruct3BytesHomogeneousUint8Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct3BytesInt2ByteAlignedLeaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesInt2ByteAligned Function(Int16, Int8),
+ Struct3BytesInt2ByteAligned Function(
+ int, int)>("ReturnStruct3BytesInt2ByteAligned", isLeaf: true);
+
+/// Smaller than word size return value on all architectures.
+/// With alignment rules taken into account size is 4 bytes.
+void testReturnStruct3BytesInt2ByteAlignedLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct3BytesInt2ByteAlignedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct4BytesHomogeneousInt16Leaf = ffiTestFunctions.lookupFunction<
+ Struct4BytesHomogeneousInt16 Function(Int16, Int16),
+ Struct4BytesHomogeneousInt16 Function(
+ int, int)>("ReturnStruct4BytesHomogeneousInt16", isLeaf: true);
+
+/// Word size return value on 32 bit architectures..
+void testReturnStruct4BytesHomogeneousInt16Leaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct4BytesHomogeneousInt16Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct7BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct7BytesHomogeneousUint8 Function(
+ Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+ Struct7BytesHomogeneousUint8 Function(int, int, int, int, int, int,
+ int)>("ReturnStruct7BytesHomogeneousUint8", isLeaf: true);
+
+/// Non-wordsize return value.
+void testReturnStruct7BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+
+ final result =
+ returnStruct7BytesHomogeneousUint8Leaf(a0, a1, a2, a3, a4, a5, a6);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+}
+
+final returnStruct7BytesInt4ByteAlignedLeaf = ffiTestFunctions.lookupFunction<
+ Struct7BytesInt4ByteAligned Function(Int32, Int16, Int8),
+ Struct7BytesInt4ByteAligned Function(
+ int, int, int)>("ReturnStruct7BytesInt4ByteAligned", isLeaf: true);
+
+/// Non-wordsize return value.
+/// With alignment rules taken into account size is 8 bytes.
+void testReturnStruct7BytesInt4ByteAlignedLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct7BytesInt4ByteAlignedLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesInt Function(Int16, Int16, Int32),
+ Struct8BytesInt Function(
+ int, int, int)>("ReturnStruct8BytesInt", isLeaf: true);
+
+/// Return value in integer registers on many architectures.
+void testReturnStruct8BytesIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct8BytesIntLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesHomogeneousFloat Function(Float, Float),
+ Struct8BytesHomogeneousFloat Function(
+ double, double)>("ReturnStruct8BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FP registers on many architectures.
+void testReturnStruct8BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+
+ a0 = -1.0;
+ a1 = 2.0;
+
+ final result = returnStruct8BytesHomogeneousFloatLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+}
+
+final returnStruct8BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesMixed Function(Float, Int16, Int16),
+ Struct8BytesMixed Function(
+ double, int, int)>("ReturnStruct8BytesMixed", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct8BytesMixedLeaf() {
+ double a0;
+ int a1;
+ int a2;
+
+ a0 = -1.0;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct8BytesMixedLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct9BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct9BytesHomogeneousUint8 Function(
+ Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+ Struct9BytesHomogeneousUint8 Function(int, int, int, int, int, int, int,
+ int, int)>("ReturnStruct9BytesHomogeneousUint8", isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is the right size and that
+/// dart:ffi trampolines do not write outside this size.
+void testReturnStruct9BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+
+ final result = returnStruct9BytesHomogeneousUint8Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+}
+
+final returnStruct9BytesInt4Or8ByteAlignedLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct9BytesInt4Or8ByteAligned Function(Int64, Int8),
+ Struct9BytesInt4Or8ByteAligned Function(
+ int, int)>("ReturnStruct9BytesInt4Or8ByteAligned", isLeaf: true);
+
+/// Return value in two integer registers on x64.
+/// With alignment rules taken into account size is 12 or 16 bytes.
+void testReturnStruct9BytesInt4Or8ByteAlignedLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct9BytesInt4Or8ByteAlignedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct12BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct12BytesHomogeneousFloat Function(Float, Float, Float),
+ Struct12BytesHomogeneousFloat Function(double, double,
+ double)>("ReturnStruct12BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+void testReturnStruct12BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+
+ final result = returnStruct12BytesHomogeneousFloatLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+}
+
+final returnStruct16BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesHomogeneousFloat Function(Float, Float, Float, Float),
+ Struct16BytesHomogeneousFloat Function(double, double, double,
+ double)>("ReturnStruct16BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStruct16BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+
+ final result = returnStruct16BytesHomogeneousFloatLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+}
+
+final returnStruct16BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesMixed Function(Double, Int64),
+ Struct16BytesMixed Function(
+ double, int)>("ReturnStruct16BytesMixed", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct16BytesMixedLeaf() {
+ double a0;
+ int a1;
+
+ a0 = -1.0;
+ a1 = 2;
+
+ final result = returnStruct16BytesMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct16BytesMixed2Leaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesMixed2 Function(Float, Float, Float, Int32),
+ Struct16BytesMixed2 Function(double, double, double,
+ int)>("ReturnStruct16BytesMixed2", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+void testReturnStruct16BytesMixed2Leaf() {
+ double a0;
+ double a1;
+ double a2;
+ int a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4;
+
+ final result = returnStruct16BytesMixed2Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+}
+
+final returnStruct17BytesIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct17BytesInt Function(Int64, Int64, Int8),
+ Struct17BytesInt Function(
+ int, int, int)>("ReturnStruct17BytesInt", isLeaf: true);
+
+/// Rerturn value returned in preallocated space passed by pointer on most ABIs.
+/// Is non word size on purpose, to test that structs are rounded up to word size
+/// on all ABIs.
+void testReturnStruct17BytesIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct17BytesIntLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct19BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct19BytesHomogeneousUint8 Function(
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8),
+ Struct19BytesHomogeneousUint8 Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int)>("ReturnStruct19BytesHomogeneousUint8", isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is the right size and that
+/// dart:ffi trampolines do not write outside this size.
+void testReturnStruct19BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+ int a9;
+ int a10;
+ int a11;
+ int a12;
+ int a13;
+ int a14;
+ int a15;
+ int a16;
+ int a17;
+ int a18;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+ a9 = 10;
+ a10 = 11;
+ a11 = 12;
+ a12 = 13;
+ a13 = 14;
+ a14 = 15;
+ a15 = 16;
+ a16 = 17;
+ a17 = 18;
+ a18 = 19;
+
+ final result = returnStruct19BytesHomogeneousUint8Leaf(a0, a1, a2, a3, a4, a5,
+ a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+ Expect.equals(a9, result.a9);
+ Expect.equals(a10, result.a10);
+ Expect.equals(a11, result.a11);
+ Expect.equals(a12, result.a12);
+ Expect.equals(a13, result.a13);
+ Expect.equals(a14, result.a14);
+ Expect.equals(a15, result.a15);
+ Expect.equals(a16, result.a16);
+ Expect.equals(a17, result.a17);
+ Expect.equals(a18, result.a18);
+}
+
+final returnStruct20BytesHomogeneousInt32Leaf = ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32),
+ Struct20BytesHomogeneousInt32 Function(int, int, int, int,
+ int)>("ReturnStruct20BytesHomogeneousInt32", isLeaf: true);
+
+/// Return value too big to go in cpu registers on arm64.
+void testReturnStruct20BytesHomogeneousInt32Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+
+ final result = returnStruct20BytesHomogeneousInt32Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+}
+
+final returnStruct20BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousFloat Function(Float, Float, Float, Float, Float),
+ Struct20BytesHomogeneousFloat Function(double, double, double, double,
+ double)>("ReturnStruct20BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+void testReturnStruct20BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+
+ final result = returnStruct20BytesHomogeneousFloatLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+ Expect.approxEquals(a4, result.a4);
+}
+
+final returnStruct32BytesHomogeneousDoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double),
+ Struct32BytesHomogeneousDouble Function(double, double, double,
+ double)>("ReturnStruct32BytesHomogeneousDouble", isLeaf: true);
+
+/// Return value in FPU registers on arm64.
+void testReturnStruct32BytesHomogeneousDoubleLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+
+ final result = returnStruct32BytesHomogeneousDoubleLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+}
+
+final returnStruct40BytesHomogeneousDoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct40BytesHomogeneousDouble Function(
+ Double, Double, Double, Double, Double),
+ Struct40BytesHomogeneousDouble Function(double, double, double, double,
+ double)>("ReturnStruct40BytesHomogeneousDouble", isLeaf: true);
+
+/// Return value too big to go in FPU registers on arm64.
+void testReturnStruct40BytesHomogeneousDoubleLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+
+ final result = returnStruct40BytesHomogeneousDoubleLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+ Expect.approxEquals(a4, result.a4);
+}
+
+final returnStruct1024BytesHomogeneousUint64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Struct1024BytesHomogeneousUint64 Function(
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64),
+ Struct1024BytesHomogeneousUint64 Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int)>("ReturnStruct1024BytesHomogeneousUint64", isLeaf: true);
+
+/// Test 1kb struct.
+void testReturnStruct1024BytesHomogeneousUint64Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+ int a9;
+ int a10;
+ int a11;
+ int a12;
+ int a13;
+ int a14;
+ int a15;
+ int a16;
+ int a17;
+ int a18;
+ int a19;
+ int a20;
+ int a21;
+ int a22;
+ int a23;
+ int a24;
+ int a25;
+ int a26;
+ int a27;
+ int a28;
+ int a29;
+ int a30;
+ int a31;
+ int a32;
+ int a33;
+ int a34;
+ int a35;
+ int a36;
+ int a37;
+ int a38;
+ int a39;
+ int a40;
+ int a41;
+ int a42;
+ int a43;
+ int a44;
+ int a45;
+ int a46;
+ int a47;
+ int a48;
+ int a49;
+ int a50;
+ int a51;
+ int a52;
+ int a53;
+ int a54;
+ int a55;
+ int a56;
+ int a57;
+ int a58;
+ int a59;
+ int a60;
+ int a61;
+ int a62;
+ int a63;
+ int a64;
+ int a65;
+ int a66;
+ int a67;
+ int a68;
+ int a69;
+ int a70;
+ int a71;
+ int a72;
+ int a73;
+ int a74;
+ int a75;
+ int a76;
+ int a77;
+ int a78;
+ int a79;
+ int a80;
+ int a81;
+ int a82;
+ int a83;
+ int a84;
+ int a85;
+ int a86;
+ int a87;
+ int a88;
+ int a89;
+ int a90;
+ int a91;
+ int a92;
+ int a93;
+ int a94;
+ int a95;
+ int a96;
+ int a97;
+ int a98;
+ int a99;
+ int a100;
+ int a101;
+ int a102;
+ int a103;
+ int a104;
+ int a105;
+ int a106;
+ int a107;
+ int a108;
+ int a109;
+ int a110;
+ int a111;
+ int a112;
+ int a113;
+ int a114;
+ int a115;
+ int a116;
+ int a117;
+ int a118;
+ int a119;
+ int a120;
+ int a121;
+ int a122;
+ int a123;
+ int a124;
+ int a125;
+ int a126;
+ int a127;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+ a9 = 10;
+ a10 = 11;
+ a11 = 12;
+ a12 = 13;
+ a13 = 14;
+ a14 = 15;
+ a15 = 16;
+ a16 = 17;
+ a17 = 18;
+ a18 = 19;
+ a19 = 20;
+ a20 = 21;
+ a21 = 22;
+ a22 = 23;
+ a23 = 24;
+ a24 = 25;
+ a25 = 26;
+ a26 = 27;
+ a27 = 28;
+ a28 = 29;
+ a29 = 30;
+ a30 = 31;
+ a31 = 32;
+ a32 = 33;
+ a33 = 34;
+ a34 = 35;
+ a35 = 36;
+ a36 = 37;
+ a37 = 38;
+ a38 = 39;
+ a39 = 40;
+ a40 = 41;
+ a41 = 42;
+ a42 = 43;
+ a43 = 44;
+ a44 = 45;
+ a45 = 46;
+ a46 = 47;
+ a47 = 48;
+ a48 = 49;
+ a49 = 50;
+ a50 = 51;
+ a51 = 52;
+ a52 = 53;
+ a53 = 54;
+ a54 = 55;
+ a55 = 56;
+ a56 = 57;
+ a57 = 58;
+ a58 = 59;
+ a59 = 60;
+ a60 = 61;
+ a61 = 62;
+ a62 = 63;
+ a63 = 64;
+ a64 = 65;
+ a65 = 66;
+ a66 = 67;
+ a67 = 68;
+ a68 = 69;
+ a69 = 70;
+ a70 = 71;
+ a71 = 72;
+ a72 = 73;
+ a73 = 74;
+ a74 = 75;
+ a75 = 76;
+ a76 = 77;
+ a77 = 78;
+ a78 = 79;
+ a79 = 80;
+ a80 = 81;
+ a81 = 82;
+ a82 = 83;
+ a83 = 84;
+ a84 = 85;
+ a85 = 86;
+ a86 = 87;
+ a87 = 88;
+ a88 = 89;
+ a89 = 90;
+ a90 = 91;
+ a91 = 92;
+ a92 = 93;
+ a93 = 94;
+ a94 = 95;
+ a95 = 96;
+ a96 = 97;
+ a97 = 98;
+ a98 = 99;
+ a99 = 100;
+ a100 = 101;
+ a101 = 102;
+ a102 = 103;
+ a103 = 104;
+ a104 = 105;
+ a105 = 106;
+ a106 = 107;
+ a107 = 108;
+ a108 = 109;
+ a109 = 110;
+ a110 = 111;
+ a111 = 112;
+ a112 = 113;
+ a113 = 114;
+ a114 = 115;
+ a115 = 116;
+ a116 = 117;
+ a117 = 118;
+ a118 = 119;
+ a119 = 120;
+ a120 = 121;
+ a121 = 122;
+ a122 = 123;
+ a123 = 124;
+ a124 = 125;
+ a125 = 126;
+ a126 = 127;
+ a127 = 128;
+
+ final result = returnStruct1024BytesHomogeneousUint64Leaf(
+ a0,
+ a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6,
+ a7,
+ a8,
+ a9,
+ a10,
+ a11,
+ a12,
+ a13,
+ a14,
+ a15,
+ a16,
+ a17,
+ a18,
+ a19,
+ a20,
+ a21,
+ a22,
+ a23,
+ a24,
+ a25,
+ a26,
+ a27,
+ a28,
+ a29,
+ a30,
+ a31,
+ a32,
+ a33,
+ a34,
+ a35,
+ a36,
+ a37,
+ a38,
+ a39,
+ a40,
+ a41,
+ a42,
+ a43,
+ a44,
+ a45,
+ a46,
+ a47,
+ a48,
+ a49,
+ a50,
+ a51,
+ a52,
+ a53,
+ a54,
+ a55,
+ a56,
+ a57,
+ a58,
+ a59,
+ a60,
+ a61,
+ a62,
+ a63,
+ a64,
+ a65,
+ a66,
+ a67,
+ a68,
+ a69,
+ a70,
+ a71,
+ a72,
+ a73,
+ a74,
+ a75,
+ a76,
+ a77,
+ a78,
+ a79,
+ a80,
+ a81,
+ a82,
+ a83,
+ a84,
+ a85,
+ a86,
+ a87,
+ a88,
+ a89,
+ a90,
+ a91,
+ a92,
+ a93,
+ a94,
+ a95,
+ a96,
+ a97,
+ a98,
+ a99,
+ a100,
+ a101,
+ a102,
+ a103,
+ a104,
+ a105,
+ a106,
+ a107,
+ a108,
+ a109,
+ a110,
+ a111,
+ a112,
+ a113,
+ a114,
+ a115,
+ a116,
+ a117,
+ a118,
+ a119,
+ a120,
+ a121,
+ a122,
+ a123,
+ a124,
+ a125,
+ a126,
+ a127);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+ Expect.equals(a9, result.a9);
+ Expect.equals(a10, result.a10);
+ Expect.equals(a11, result.a11);
+ Expect.equals(a12, result.a12);
+ Expect.equals(a13, result.a13);
+ Expect.equals(a14, result.a14);
+ Expect.equals(a15, result.a15);
+ Expect.equals(a16, result.a16);
+ Expect.equals(a17, result.a17);
+ Expect.equals(a18, result.a18);
+ Expect.equals(a19, result.a19);
+ Expect.equals(a20, result.a20);
+ Expect.equals(a21, result.a21);
+ Expect.equals(a22, result.a22);
+ Expect.equals(a23, result.a23);
+ Expect.equals(a24, result.a24);
+ Expect.equals(a25, result.a25);
+ Expect.equals(a26, result.a26);
+ Expect.equals(a27, result.a27);
+ Expect.equals(a28, result.a28);
+ Expect.equals(a29, result.a29);
+ Expect.equals(a30, result.a30);
+ Expect.equals(a31, result.a31);
+ Expect.equals(a32, result.a32);
+ Expect.equals(a33, result.a33);
+ Expect.equals(a34, result.a34);
+ Expect.equals(a35, result.a35);
+ Expect.equals(a36, result.a36);
+ Expect.equals(a37, result.a37);
+ Expect.equals(a38, result.a38);
+ Expect.equals(a39, result.a39);
+ Expect.equals(a40, result.a40);
+ Expect.equals(a41, result.a41);
+ Expect.equals(a42, result.a42);
+ Expect.equals(a43, result.a43);
+ Expect.equals(a44, result.a44);
+ Expect.equals(a45, result.a45);
+ Expect.equals(a46, result.a46);
+ Expect.equals(a47, result.a47);
+ Expect.equals(a48, result.a48);
+ Expect.equals(a49, result.a49);
+ Expect.equals(a50, result.a50);
+ Expect.equals(a51, result.a51);
+ Expect.equals(a52, result.a52);
+ Expect.equals(a53, result.a53);
+ Expect.equals(a54, result.a54);
+ Expect.equals(a55, result.a55);
+ Expect.equals(a56, result.a56);
+ Expect.equals(a57, result.a57);
+ Expect.equals(a58, result.a58);
+ Expect.equals(a59, result.a59);
+ Expect.equals(a60, result.a60);
+ Expect.equals(a61, result.a61);
+ Expect.equals(a62, result.a62);
+ Expect.equals(a63, result.a63);
+ Expect.equals(a64, result.a64);
+ Expect.equals(a65, result.a65);
+ Expect.equals(a66, result.a66);
+ Expect.equals(a67, result.a67);
+ Expect.equals(a68, result.a68);
+ Expect.equals(a69, result.a69);
+ Expect.equals(a70, result.a70);
+ Expect.equals(a71, result.a71);
+ Expect.equals(a72, result.a72);
+ Expect.equals(a73, result.a73);
+ Expect.equals(a74, result.a74);
+ Expect.equals(a75, result.a75);
+ Expect.equals(a76, result.a76);
+ Expect.equals(a77, result.a77);
+ Expect.equals(a78, result.a78);
+ Expect.equals(a79, result.a79);
+ Expect.equals(a80, result.a80);
+ Expect.equals(a81, result.a81);
+ Expect.equals(a82, result.a82);
+ Expect.equals(a83, result.a83);
+ Expect.equals(a84, result.a84);
+ Expect.equals(a85, result.a85);
+ Expect.equals(a86, result.a86);
+ Expect.equals(a87, result.a87);
+ Expect.equals(a88, result.a88);
+ Expect.equals(a89, result.a89);
+ Expect.equals(a90, result.a90);
+ Expect.equals(a91, result.a91);
+ Expect.equals(a92, result.a92);
+ Expect.equals(a93, result.a93);
+ Expect.equals(a94, result.a94);
+ Expect.equals(a95, result.a95);
+ Expect.equals(a96, result.a96);
+ Expect.equals(a97, result.a97);
+ Expect.equals(a98, result.a98);
+ Expect.equals(a99, result.a99);
+ Expect.equals(a100, result.a100);
+ Expect.equals(a101, result.a101);
+ Expect.equals(a102, result.a102);
+ Expect.equals(a103, result.a103);
+ Expect.equals(a104, result.a104);
+ Expect.equals(a105, result.a105);
+ Expect.equals(a106, result.a106);
+ Expect.equals(a107, result.a107);
+ Expect.equals(a108, result.a108);
+ Expect.equals(a109, result.a109);
+ Expect.equals(a110, result.a110);
+ Expect.equals(a111, result.a111);
+ Expect.equals(a112, result.a112);
+ Expect.equals(a113, result.a113);
+ Expect.equals(a114, result.a114);
+ Expect.equals(a115, result.a115);
+ Expect.equals(a116, result.a116);
+ Expect.equals(a117, result.a117);
+ Expect.equals(a118, result.a118);
+ Expect.equals(a119, result.a119);
+ Expect.equals(a120, result.a120);
+ Expect.equals(a121, result.a121);
+ Expect.equals(a122, result.a122);
+ Expect.equals(a123, result.a123);
+ Expect.equals(a124, result.a124);
+ Expect.equals(a125, result.a125);
+ Expect.equals(a126, result.a126);
+ Expect.equals(a127, result.a127);
+}
+
+final returnStruct3BytesPackedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesPackedInt Function(Int8, Int16),
+ Struct3BytesPackedInt Function(
+ int, int)>("ReturnStruct3BytesPackedInt", isLeaf: true);
+
+/// Small struct with mis-aligned member.
+void testReturnStruct3BytesPackedIntLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct3BytesPackedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct8BytesPackedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesPackedInt Function(Uint8, Uint32, Uint8, Uint8, Uint8),
+ Struct8BytesPackedInt Function(
+ int, int, int, int, int)>("ReturnStruct8BytesPackedInt", isLeaf: true);
+
+/// Struct with mis-aligned member.
+void testReturnStruct8BytesPackedIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+
+ final result = returnStruct8BytesPackedIntLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+}
+
+final returnStruct9BytesPackedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct9BytesPackedMixed Function(Uint8, Double),
+ Struct9BytesPackedMixed Function(
+ int, double)>("ReturnStruct9BytesPackedMixed", isLeaf: true);
+
+/// Struct with mis-aligned member.
+/// Tests backfilling of CPU and FPU registers.
+void testReturnStruct9BytesPackedMixedLeaf() {
+ int a0;
+ double a1;
+
+ a0 = 1;
+ a1 = 2.0;
+
+ final result = returnStruct9BytesPackedMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+}
+
+final returnUnion4BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Union4BytesMixed Function(Uint32),
+ Union4BytesMixed Function(int)>("ReturnUnion4BytesMixed", isLeaf: true);
+
+/// Returning a mixed integer/float union.
+void testReturnUnion4BytesMixedLeaf() {
+ int a0;
+
+ a0 = 1;
+
+ final result = returnUnion4BytesMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnUnion8BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Union8BytesNestedFloat Function(Double),
+ Union8BytesNestedFloat Function(
+ double)>("ReturnUnion8BytesNestedFloat", isLeaf: true);
+
+/// Returning a floating point only union.
+void testReturnUnion8BytesNestedFloatLeaf() {
+ double a0;
+
+ a0 = -1.0;
+
+ final result = returnUnion8BytesNestedFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+}
+
+final returnUnion9BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Union9BytesNestedInt Function(Struct8BytesInt),
+ Union9BytesNestedInt Function(
+ Struct8BytesInt)>("ReturnUnion9BytesNestedInt", isLeaf: true);
+
+/// Returning a mixed-size union.
+void testReturnUnion9BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = returnUnion9BytesNestedIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnUnion16BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat),
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat)>(
+ "ReturnUnion16BytesNestedFloat",
+ isLeaf: true);
+
+/// Returning union with homogenous floats.
+void testReturnUnion16BytesNestedFloatLeaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnUnion16BytesNestedFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a0.a1, result.a0.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStruct1ByteIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Struct1ByteInt),
+ Struct1ByteInt Function(
+ Struct1ByteInt)>("ReturnStructArgumentStruct1ByteInt", isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in int registers in most ABIs.
+void testReturnStructArgumentStruct1ByteIntLeaf() {
+ final a0Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+
+ final result = returnStructArgumentStruct1ByteIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentInt32x8Struct1ByteIntLeaf =
+ ffiTestFunctions
+ .lookupFunction<
+ Struct1ByteInt Function(Int32, Int32, Int32, Int32, Int32, Int32,
+ Int32, Int32, Struct1ByteInt),
+ Struct1ByteInt Function(
+ int, int, int, int, int, int, int, int, Struct1ByteInt)>(
+ "ReturnStructArgumentInt32x8Struct1ByteInt",
+ isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+void testReturnStructArgumentInt32x8Struct1ByteIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ final a8Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a8 = a8Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8.a0 = -9;
+
+ final result = returnStructArgumentInt32x8Struct1ByteIntLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a8.a0, result.a0);
+
+ calloc.free(a8Pointer);
+}
+
+final returnStructArgumentStruct8BytesHomogeneousFloatLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat),
+ Struct8BytesHomogeneousFloat Function(
+ Struct8BytesHomogeneousFloat)>(
+ "ReturnStructArgumentStruct8BytesHomogeneousFloat",
+ isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in float registers in most ABIs.
+void testReturnStructArgumentStruct8BytesHomogeneousFloatLeaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnStructArgumentStruct8BytesHomogeneousFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0);
+ Expect.approxEquals(a0.a1, result.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStruct20BytesHomogeneousInt32Leaf =
+ ffiTestFunctions
+ .lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(
+ Struct20BytesHomogeneousInt32),
+ Struct20BytesHomogeneousInt32 Function(
+ Struct20BytesHomogeneousInt32)>(
+ "ReturnStructArgumentStruct20BytesHomogeneousInt32",
+ isLeaf: true);
+
+/// On arm64, both argument and return value are passed in by pointer.
+void testReturnStructArgumentStruct20BytesHomogeneousInt32Leaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a0.a3 = 4;
+ a0.a4 = -5;
+
+ final result = returnStructArgumentStruct20BytesHomogeneousInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0);
+ Expect.equals(a0.a1, result.a1);
+ Expect.equals(a0.a2, result.a2);
+ Expect.equals(a0.a3, result.a3);
+ Expect.equals(a0.a4, result.a4);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentInt32x8Struct20BytesHomogeneouLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32,
+ Int32, Int32, Int32, Int32, Struct20BytesHomogeneousInt32),
+ Struct20BytesHomogeneousInt32 Function(int, int, int, int, int, int,
+ int, int, Struct20BytesHomogeneousInt32)>(
+ "ReturnStructArgumentInt32x8Struct20BytesHomogeneou",
+ isLeaf: true);
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+void testReturnStructArgumentInt32x8Struct20BytesHomogeneouLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ final a8Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a8 = a8Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8.a0 = -9;
+ a8.a1 = 10;
+ a8.a2 = -11;
+ a8.a3 = 12;
+ a8.a4 = -13;
+
+ final result = returnStructArgumentInt32x8Struct20BytesHomogeneouLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a8.a0, result.a0);
+ Expect.equals(a8.a1, result.a1);
+ Expect.equals(a8.a2, result.a2);
+ Expect.equals(a8.a3, result.a3);
+ Expect.equals(a8.a4, result.a4);
+
+ calloc.free(a8Pointer);
+}
+
+final returnStructArgumentStruct8BytesInlineArrayIntLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct8BytesInlineArrayInt Function(Struct8BytesInlineArrayInt),
+ Struct8BytesInlineArrayInt Function(Struct8BytesInlineArrayInt)>(
+ "ReturnStructArgumentStruct8BytesInlineArrayInt",
+ isLeaf: true);
+
+/// Test returning struct with inline array.
+void testReturnStructArgumentStruct8BytesInlineArrayIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a0 = a0Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+
+ final result = returnStructArgumentStruct8BytesInlineArrayIntLeaf(a0);
+
+ print("result = $result");
+
+ for (int i = 0; i < 8; i++) {
+ Expect.equals(a0.a0[i], result.a0[i]);
+ }
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct16BytesHomogeneousLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct16BytesHomogeneousFloat2 Function(
+ StructStruct16BytesHomogeneousFloat2),
+ StructStruct16BytesHomogeneousFloat2 Function(
+ StructStruct16BytesHomogeneousFloat2)>(
+ "ReturnStructArgumentStructStruct16BytesHomogeneous",
+ isLeaf: true);
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStructArgumentStructStruct16BytesHomogeneousLeaf() {
+ final a0Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+
+ final result = returnStructArgumentStructStruct16BytesHomogeneousLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 2; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ }
+ Expect.approxEquals(a0.a2, result.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct32BytesHomogeneousLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct32BytesHomogeneousDouble2 Function(
+ StructStruct32BytesHomogeneousDouble2),
+ StructStruct32BytesHomogeneousDouble2 Function(
+ StructStruct32BytesHomogeneousDouble2)>(
+ "ReturnStructArgumentStructStruct32BytesHomogeneous",
+ isLeaf: true);
+
+/// Return value in FPU registers on arm64.
+void testReturnStructArgumentStructStruct32BytesHomogeneousLeaf() {
+ final a0Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+
+ final result = returnStructArgumentStructStruct32BytesHomogeneousLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 2; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ }
+ Expect.approxEquals(a0.a2, result.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct16BytesMixed3Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct16BytesMixed3 Function(StructStruct16BytesMixed3),
+ StructStruct16BytesMixed3 Function(StructStruct16BytesMixed3)>(
+ "ReturnStructArgumentStructStruct16BytesMixed3",
+ isLeaf: true);
+
+/// On x64 Linux, return value is split over FP and int registers.
+void testReturnStructArgumentStructStruct16BytesMixed3Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[0].a1 = -3;
+ a0.a1[0].a2 = 4;
+ a0.a2[0] = -5;
+ a0.a2[1] = 6;
+
+ final result = returnStructArgumentStructStruct16BytesMixed3Leaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 1; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ Expect.equals(a0.a1[i].a1, result.a1[i].a1);
+ Expect.equals(a0.a1[i].a2, result.a1[i].a2);
+ }
+ for (int i = 0; i < 2; i++) {
+ Expect.equals(a0.a2[i], result.a2[i]);
+ }
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructAlignmentInt16Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt16 Function(Int8, Int16, Int8),
+ StructAlignmentInt16 Function(
+ int, int, int)>("ReturnStructAlignmentInt16", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testReturnStructAlignmentInt16Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt16Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt32Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt32 Function(Int8, Int32, Int8),
+ StructAlignmentInt32 Function(
+ int, int, int)>("ReturnStructAlignmentInt32", isLeaf: true);
+
+/// Test alignment and padding of 32 byte int within struct.
+void testReturnStructAlignmentInt32Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt32Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt64Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt64 Function(Int8, Int64, Int8),
+ StructAlignmentInt64 Function(
+ int, int, int)>("ReturnStructAlignmentInt64", isLeaf: true);
+
+/// Test alignment and padding of 64 byte int within struct.
+void testReturnStructAlignmentInt64Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt64Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedInt Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesHomogeneousInt16),
+ Struct8BytesNestedInt Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesHomogeneousInt16)>(
+ "ReturnStruct8BytesNestedInt",
+ isLeaf: true);
+
+/// Simple nested struct.
+void testReturnStruct8BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+
+ final result = returnStruct8BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct8BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedFloat Function(Struct4BytesFloat, Struct4BytesFloat),
+ Struct8BytesNestedFloat Function(Struct4BytesFloat,
+ Struct4BytesFloat)>("ReturnStruct8BytesNestedFloat", isLeaf: true);
+
+/// Simple nested struct with floats.
+void testReturnStruct8BytesNestedFloatLeaf() {
+ final a0Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a1 = a1Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+
+ final result = returnStruct8BytesNestedFloatLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a1.a0, result.a1.a0);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct8BytesNestedFloat2Leaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedFloat2 Function(Struct4BytesFloat, Float),
+ Struct8BytesNestedFloat2 Function(Struct4BytesFloat,
+ double)>("ReturnStruct8BytesNestedFloat2", isLeaf: true);
+
+/// The nesting is irregular, testing homogenous float rules on arm and arm64,
+/// and the fpu register usage on x64.
+void testReturnStruct8BytesNestedFloat2Leaf() {
+ final a0Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a0 = a0Pointer.ref;
+ double a1;
+
+ a0.a0 = -1.0;
+ a1 = 2.0;
+
+ final result = returnStruct8BytesNestedFloat2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a1, result.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStruct8BytesNestedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedMixed Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesFloat),
+ Struct8BytesNestedMixed Function(Struct4BytesHomogeneousInt16,
+ Struct4BytesFloat)>("ReturnStruct8BytesNestedMixed", isLeaf: true);
+
+/// Simple nested struct with mixed members.
+void testReturnStruct8BytesNestedMixedLeaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3.0;
+
+ final result = returnStruct8BytesNestedMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.approxEquals(a1.a0, result.a1.a0);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct16BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesNestedInt Function(
+ Struct8BytesNestedInt, Struct8BytesNestedInt),
+ Struct16BytesNestedInt Function(Struct8BytesNestedInt,
+ Struct8BytesNestedInt)>("ReturnStruct16BytesNestedInt", isLeaf: true);
+
+/// Deeper nested struct to test recursive member access.
+void testReturnStruct16BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3;
+ a0.a1.a1 = 4;
+ a1.a0.a0 = -5;
+ a1.a0.a1 = 6;
+ a1.a1.a0 = -7;
+ a1.a1.a1 = 8;
+
+ final result = returnStruct16BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0.a0, result.a0.a0.a0);
+ Expect.equals(a0.a0.a1, result.a0.a0.a1);
+ Expect.equals(a0.a1.a0, result.a0.a1.a0);
+ Expect.equals(a0.a1.a1, result.a0.a1.a1);
+ Expect.equals(a1.a0.a0, result.a1.a0.a0);
+ Expect.equals(a1.a0.a1, result.a1.a0.a1);
+ Expect.equals(a1.a1.a0, result.a1.a1.a0);
+ Expect.equals(a1.a1.a1, result.a1.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct32BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct32BytesNestedInt Function(
+ Struct16BytesNestedInt, Struct16BytesNestedInt),
+ Struct32BytesNestedInt Function(Struct16BytesNestedInt,
+ Struct16BytesNestedInt)>("ReturnStruct32BytesNestedInt", isLeaf: true);
+
+/// Even deeper nested struct to test recursive member access.
+void testReturnStruct32BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0 = -1;
+ a0.a0.a0.a1 = 2;
+ a0.a0.a1.a0 = -3;
+ a0.a0.a1.a1 = 4;
+ a0.a1.a0.a0 = -5;
+ a0.a1.a0.a1 = 6;
+ a0.a1.a1.a0 = -7;
+ a0.a1.a1.a1 = 8;
+ a1.a0.a0.a0 = -9;
+ a1.a0.a0.a1 = 10;
+ a1.a0.a1.a0 = -11;
+ a1.a0.a1.a1 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15;
+ a1.a1.a1.a1 = 16;
+
+ final result = returnStruct32BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0.a0.a0, result.a0.a0.a0.a0);
+ Expect.equals(a0.a0.a0.a1, result.a0.a0.a0.a1);
+ Expect.equals(a0.a0.a1.a0, result.a0.a0.a1.a0);
+ Expect.equals(a0.a0.a1.a1, result.a0.a0.a1.a1);
+ Expect.equals(a0.a1.a0.a0, result.a0.a1.a0.a0);
+ Expect.equals(a0.a1.a0.a1, result.a0.a1.a0.a1);
+ Expect.equals(a0.a1.a1.a0, result.a0.a1.a1.a0);
+ Expect.equals(a0.a1.a1.a1, result.a0.a1.a1.a1);
+ Expect.equals(a1.a0.a0.a0, result.a1.a0.a0.a0);
+ Expect.equals(a1.a0.a0.a1, result.a1.a0.a0.a1);
+ Expect.equals(a1.a0.a1.a0, result.a1.a0.a1.a0);
+ Expect.equals(a1.a0.a1.a1, result.a1.a0.a1.a1);
+ Expect.equals(a1.a1.a0.a0, result.a1.a1.a0.a0);
+ Expect.equals(a1.a1.a0.a1, result.a1.a1.a0.a1);
+ Expect.equals(a1.a1.a1.a0, result.a1.a1.a1.a0);
+ Expect.equals(a1.a1.a1.a1, result.a1.a1.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt16Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt16 Function(
+ StructAlignmentInt16, StructAlignmentInt16),
+ StructNestedIntStructAlignmentInt16 Function(
+ StructAlignmentInt16, StructAlignmentInt16)>(
+ "ReturnStructNestedIntStructAlignmentInt16",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 16 byte int.
+void testReturnStructNestedIntStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt16Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt32 Function(
+ StructAlignmentInt32, StructAlignmentInt32),
+ StructNestedIntStructAlignmentInt32 Function(
+ StructAlignmentInt32, StructAlignmentInt32)>(
+ "ReturnStructNestedIntStructAlignmentInt32",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 32 byte int.
+void testReturnStructNestedIntStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt32Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt64Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt64 Function(
+ StructAlignmentInt64, StructAlignmentInt64),
+ StructNestedIntStructAlignmentInt64 Function(
+ StructAlignmentInt64, StructAlignmentInt64)>(
+ "ReturnStructNestedIntStructAlignmentInt64",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 64 byte int.
+void testReturnStructNestedIntStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt64Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIrregularEvenBiggerLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIrregularEvenBigger Function(Uint64,
+ StructNestedIrregularBigger, StructNestedIrregularBigger, Double),
+ StructNestedIrregularEvenBigger Function(
+ int,
+ StructNestedIrregularBigger,
+ StructNestedIrregularBigger,
+ double)>("ReturnStructNestedIrregularEvenBigger", isLeaf: true);
+
+/// Return big irregular struct as smoke test.
+void testReturnStructNestedIrregularEvenBiggerLeaf() {
+ int a0;
+ final a1Pointer = calloc<StructNestedIrregularBigger>();
+ final StructNestedIrregularBigger a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructNestedIrregularBigger>();
+ final StructNestedIrregularBigger a2 = a2Pointer.ref;
+ double a3;
+
+ a0 = 1;
+ a1.a0.a0 = 2;
+ a1.a0.a1.a0.a0 = -3;
+ a1.a0.a1.a0.a1 = 4;
+ a1.a0.a1.a1.a0 = -5.0;
+ a1.a0.a2 = 6;
+ a1.a0.a3.a0.a0 = -7.0;
+ a1.a0.a3.a1 = 8.0;
+ a1.a0.a4 = 9;
+ a1.a0.a5.a0.a0 = 10.0;
+ a1.a0.a5.a1.a0 = -11.0;
+ a1.a0.a6 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15.0;
+ a1.a2 = 16.0;
+ a1.a3 = -17.0;
+ a2.a0.a0 = 18;
+ a2.a0.a1.a0.a0 = -19;
+ a2.a0.a1.a0.a1 = 20;
+ a2.a0.a1.a1.a0 = -21.0;
+ a2.a0.a2 = 22;
+ a2.a0.a3.a0.a0 = -23.0;
+ a2.a0.a3.a1 = 24.0;
+ a2.a0.a4 = 25;
+ a2.a0.a5.a0.a0 = 26.0;
+ a2.a0.a5.a1.a0 = -27.0;
+ a2.a0.a6 = 28;
+ a2.a1.a0.a0 = -29;
+ a2.a1.a0.a1 = 30;
+ a2.a1.a1.a0 = -31.0;
+ a2.a2 = 32.0;
+ a2.a3 = -33.0;
+ a3 = 34.0;
+
+ final result = returnStructNestedIrregularEvenBiggerLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1.a0.a0, result.a1.a0.a0);
+ Expect.equals(a1.a0.a1.a0.a0, result.a1.a0.a1.a0.a0);
+ Expect.equals(a1.a0.a1.a0.a1, result.a1.a0.a1.a0.a1);
+ Expect.approxEquals(a1.a0.a1.a1.a0, result.a1.a0.a1.a1.a0);
+ Expect.equals(a1.a0.a2, result.a1.a0.a2);
+ Expect.approxEquals(a1.a0.a3.a0.a0, result.a1.a0.a3.a0.a0);
+ Expect.approxEquals(a1.a0.a3.a1, result.a1.a0.a3.a1);
+ Expect.equals(a1.a0.a4, result.a1.a0.a4);
+ Expect.approxEquals(a1.a0.a5.a0.a0, result.a1.a0.a5.a0.a0);
+ Expect.approxEquals(a1.a0.a5.a1.a0, result.a1.a0.a5.a1.a0);
+ Expect.equals(a1.a0.a6, result.a1.a0.a6);
+ Expect.equals(a1.a1.a0.a0, result.a1.a1.a0.a0);
+ Expect.equals(a1.a1.a0.a1, result.a1.a1.a0.a1);
+ Expect.approxEquals(a1.a1.a1.a0, result.a1.a1.a1.a0);
+ Expect.approxEquals(a1.a2, result.a1.a2);
+ Expect.approxEquals(a1.a3, result.a1.a3);
+ Expect.equals(a2.a0.a0, result.a2.a0.a0);
+ Expect.equals(a2.a0.a1.a0.a0, result.a2.a0.a1.a0.a0);
+ Expect.equals(a2.a0.a1.a0.a1, result.a2.a0.a1.a0.a1);
+ Expect.approxEquals(a2.a0.a1.a1.a0, result.a2.a0.a1.a1.a0);
+ Expect.equals(a2.a0.a2, result.a2.a0.a2);
+ Expect.approxEquals(a2.a0.a3.a0.a0, result.a2.a0.a3.a0.a0);
+ Expect.approxEquals(a2.a0.a3.a1, result.a2.a0.a3.a1);
+ Expect.equals(a2.a0.a4, result.a2.a0.a4);
+ Expect.approxEquals(a2.a0.a5.a0.a0, result.a2.a0.a5.a0.a0);
+ Expect.approxEquals(a2.a0.a5.a1.a0, result.a2.a0.a5.a1.a0);
+ Expect.equals(a2.a0.a6, result.a2.a0.a6);
+ Expect.equals(a2.a1.a0.a0, result.a2.a1.a0.a0);
+ Expect.equals(a2.a1.a0.a1, result.a2.a1.a0.a1);
+ Expect.approxEquals(a2.a1.a1.a0, result.a2.a1.a1.a0);
+ Expect.approxEquals(a2.a2, result.a2.a2);
+ Expect.approxEquals(a2.a3, result.a2.a3);
+ Expect.approxEquals(a3, result.a3);
+
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+}
diff --git a/tests/ffi/function_structs_test.dart b/tests/ffi/function_structs_test.dart
index d813247..b0f2cdb 100644
--- a/tests/ffi/function_structs_test.dart
+++ b/tests/ffi/function_structs_test.dart
@@ -19,18 +19,22 @@
typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
void main() {
- testFunctionWithStruct();
- testFunctionWithStructArray();
- testFunctionWithVeryLargeStruct();
+ for (final isLeaf in [false, true]) {
+ testFunctionWithStruct(isLeaf: isLeaf);
+ testFunctionWithStructArray(isLeaf: isLeaf);
+ testFunctionWithVeryLargeStruct(isLeaf: isLeaf);
+ }
}
DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
/// pass a struct to a c function and get a struct as return value
-void testFunctionWithStruct() {
+void testFunctionWithStruct({bool isLeaf: false}) {
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("TransposeCoordinate");
- NativeCoordinateOp f1 = p1.asFunction();
+ NativeCoordinateOp f1 =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
+ ;
final c1 = calloc<Coordinate>()
..ref.x = 10.0
@@ -54,10 +58,12 @@
}
/// pass an array of structs to a c funtion
-void testFunctionWithStructArray() {
+void testFunctionWithStructArray({bool isLeaf: false}) {
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("CoordinateElemAt1");
- NativeCoordinateOp f1 = p1.asFunction();
+ NativeCoordinateOp f1 =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
+ ;
final coordinateArray = calloc<Coordinate>(3);
Coordinate c1 = coordinateArray[0];
@@ -83,10 +89,12 @@
typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
typedef NativeVeryLargeStructSum = Int64 Function(Pointer<VeryLargeStruct>);
-void testFunctionWithVeryLargeStruct() {
+void testFunctionWithVeryLargeStruct({bool isLeaf: false}) {
Pointer<NativeFunction<NativeVeryLargeStructSum>> p1 =
ffiTestFunctions.lookup("SumVeryLargeStruct");
- VeryLargeStructSum f = p1.asFunction();
+ VeryLargeStructSum f =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
+ ;
final vlsArray = calloc<VeryLargeStruct>(2);
VeryLargeStruct vls1 = vlsArray[0];
diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart
index 0ab7739..c624d58 100644
--- a/tests/ffi/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi/generator/structs_by_value_tests_generator.dart
@@ -537,7 +537,7 @@
}
extension on FunctionType {
- String get dartCallCode {
+ String dartCallCode({bool isLeaf: false}) {
final a = ArgumentValueAssigner();
final assignValues = arguments.assignValueStatements(a);
final argumentFrees = arguments.dartFreeStatements();
@@ -561,17 +561,19 @@
break;
}
+ final namePostfix = isLeaf ? "Leaf" : "";
return """
- final $dartName =
- ffiTestFunctions.lookupFunction<$dartCType, $dartType>("$cName");
+ final $dartName$namePostfix =
+ ffiTestFunctions.lookupFunction<$dartCType, $dartType>(
+ "$cName"${isLeaf ? ", isLeaf:true" : ""});
${reason.makeDartDocComment()}
- void $dartTestName() {
+ void $dartTestName$namePostfix() {
${arguments.dartAllocateStatements()}
${assignValues}
- final result = $dartName($argumentNames);
+ final result = $dartName$namePostfix($argumentNames);
print("result = \$result");
@@ -886,11 +888,13 @@
void main() {
for (int i = 0; i < 10; ++i) {
${functions.map((e) => "${e.dartTestName}();").join("\n")}
+ ${functions.map((e) => "${e.dartTestName}Leaf();").join("\n")}
}
}
""");
buffer.writeAll(compounds.map((e) => e.dartClass(nnbd)));
- buffer.writeAll(functions.map((e) => e.dartCallCode));
+ buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: false)));
+ buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: true)));
final path = callTestPath(nnbd);
File(path).writeAsStringSync(buffer.toString());
diff --git a/tests/ffi/vmspecific_leaf_call_test.dart b/tests/ffi/vmspecific_leaf_call_test.dart
new file mode 100644
index 0000000..3d05173
--- /dev/null
+++ b/tests/ffi/vmspecific_leaf_call_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+import 'dylib_utils.dart';
+import 'ffi_test_helpers.dart';
+import 'callback_tests_utils.dart';
+
+DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+testLeafCall() {
+ // Note: This test currently fails on Windows AOT: https://dartbug.com/40579
+ // Regular calls should transition generated -> native.
+ final isThreadInGenerated = ffiTestFunctions.lookupFunction<
+ Int8 Function(), int Function()>("IsThreadInGenerated");
+ Expect.equals(0, isThreadInGenerated());
+ // Leaf calls should remain in generated state.
+ final isThreadInGeneratedLeaf = ffiTestFunctions.lookupFunction<
+ Int8 Function(), int Function()>("IsThreadInGenerated", isLeaf: true);
+ Expect.equals(1, isThreadInGeneratedLeaf());
+}
+
+testLeafCallApi() {
+ // Note: This will only crash as expected in debug build mode. In other modes
+ // it's effectively skip.
+ final f = ffiTestFunctions.lookupFunction<
+ Void Function(), void Function()>("TestLeafCallApi", isLeaf: true);
+ // Calling Dart_.. API is unsafe from leaf calls since we explicitly haven't
+ // made the generated -> native transition.
+ f();
+}
+
+void nop() {}
+
+testCallbackLeaf() {
+ // This should crash with "expected: T->IsAtSafepoint()", since it's unsafe to
+ // do callbacks from leaf calls (otherwise they wouldn't be leaf calls).
+ // Note: This will only crash as expected in debug build mode. In other modes
+ // it's effectively skip.
+ CallbackTest("CallbackLeaf", Pointer.fromFunction<Void Function()>(nop),
+ isLeaf:true).run();
+}
+
+main() {
+ testLeafCall(); //# 01: ok
+ // These tests terminate the process after successful completion, so we have
+ // to run them separately.
+ //
+ // Since they use signal handlers they only run on Linux.
+ if (Platform.isLinux && !const bool.fromEnvironment("dart.vm.product")) {
+ testLeafCallApi(); //# 02: ok
+ testCallbackLeaf(); //# 03: ok
+ }
+}
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index a89638c..9dca0e7 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -61,6 +61,12 @@
testSizeOfHandle();
testElementAtGeneric();
testElementAtNativeType();
+ testLookupFunctionIsLeafMustBeConst();
+ testAsFunctionIsLeafMustBeConst();
+ testLookupFunctionTakesHandle();
+ testAsFunctionTakesHandle();
+ testLookupFunctionReturnsHandle();
+ testAsFunctionReturnsHandle();
}
typedef Int8UnOp = Int8 Function(Int8);
@@ -705,6 +711,44 @@
external Pointer<Uint8> notEmpty;
}
+void testLookupFunctionIsLeafMustBeConst() {
+ bool notAConst = false;
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeDoubleUnOp, DoubleUnOp>("timesFour", isLeaf:notAConst); //# 1500: compile-time error
+}
+
+void testAsFunctionIsLeafMustBeConst() {
+ bool notAConst = false;
+ Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+ IntUnOp f = p.asFunction(isLeaf:notAConst); //# 1501: compile-time error
+}
+
+typedef NativeTakesHandle = Void Function(Handle);
+typedef TakesHandle = void Function(Object);
+
+void testLookupFunctionTakesHandle() {
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeTakesHandle, TakesHandle>("takesHandle", isLeaf:true); //# 1502: compile-time error
+}
+
+void testAsFunctionTakesHandle() {
+ Pointer<NativeFunction<NativeTakesHandle>> p = Pointer.fromAddress(1337); //# 1503: compile-time error
+ TakesHandle f = p.asFunction(isLeaf:true); //# 1503: compile-time error
+}
+
+typedef NativeReturnsHandle = Handle Function();
+typedef ReturnsHandle = Object Function();
+
+void testLookupFunctionReturnsHandle() {
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeReturnsHandle, ReturnsHandle>("returnsHandle", isLeaf:true); //# 1504: compile-time error
+}
+
+void testAsFunctionReturnsHandle() {
+ Pointer<NativeFunction<NativeReturnsHandle>> p = Pointer.fromAddress(1337); //# 1505: compile-time error
+ ReturnsHandle f = p.asFunction(isLeaf:true); //# 1505: compile-time error
+}
+
@Packed(1)
class TestStruct1600 extends Struct {
external Pointer<Uint8> notEmpty;
diff --git a/tests/ffi_2/callback_tests_utils.dart b/tests/ffi_2/callback_tests_utils.dart
index 40a2995..68621c0 100644
--- a/tests/ffi_2/callback_tests_utils.dart
+++ b/tests/ffi_2/callback_tests_utils.dart
@@ -19,13 +19,19 @@
final String name;
final Pointer callback;
final void Function() afterCallbackChecks;
+ final bool isLeaf;
- CallbackTest(this.name, this.callback) : afterCallbackChecks = noChecks {}
- CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks) {}
+ CallbackTest(this.name, this.callback, {this.isLeaf: false})
+ : afterCallbackChecks = noChecks {}
+ CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks,
+ {this.isLeaf: false}) {}
void run() {
- final NativeCallbackTestFn tester = ffiTestFunctions
- .lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
+ final NativeCallbackTestFn tester = isLeaf
+ ? ffiTestFunctions.lookupFunction<NativeCallbackTest,
+ NativeCallbackTestFn>("Test$name", isLeaf: true)
+ : ffiTestFunctions.lookupFunction<NativeCallbackTest,
+ NativeCallbackTestFn>("Test$name", isLeaf: false);
final int testCode = tester(callback);
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
index 9bf0376..b1e3f27 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -135,6 +135,119 @@
testReturnStructNestedIntStructAlignmentInt32();
testReturnStructNestedIntStructAlignmentInt64();
testReturnStructNestedIrregularEvenBigger();
+ testPassStruct1ByteIntx10Leaf();
+ testPassStruct3BytesHomogeneousUint8x10Leaf();
+ testPassStruct3BytesInt2ByteAlignedx10Leaf();
+ testPassStruct4BytesHomogeneousInt16x10Leaf();
+ testPassStruct7BytesHomogeneousUint8x10Leaf();
+ testPassStruct7BytesInt4ByteAlignedx10Leaf();
+ testPassStruct8BytesIntx10Leaf();
+ testPassStruct8BytesHomogeneousFloatx10Leaf();
+ testPassStruct8BytesMixedx10Leaf();
+ testPassStruct9BytesHomogeneousUint8x10Leaf();
+ testPassStruct9BytesInt4Or8ByteAlignedx10Leaf();
+ testPassStruct12BytesHomogeneousFloatx6Leaf();
+ testPassStruct16BytesHomogeneousFloatx5Leaf();
+ testPassStruct16BytesMixedx10Leaf();
+ testPassStruct16BytesMixed2x10Leaf();
+ testPassStruct17BytesIntx10Leaf();
+ testPassStruct19BytesHomogeneousUint8x10Leaf();
+ testPassStruct20BytesHomogeneousInt32x10Leaf();
+ testPassStruct20BytesHomogeneousFloatLeaf();
+ testPassStruct32BytesHomogeneousDoublex5Leaf();
+ testPassStruct40BytesHomogeneousDoubleLeaf();
+ testPassStruct1024BytesHomogeneousUint64Leaf();
+ testPassFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf();
+ testPassFloatStruct32BytesHomogeneousDoubleFloatStructLeaf();
+ testPassInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf();
+ testPassDoublex6Struct16BytesMixedx4Int32Leaf();
+ testPassInt32x4Struct16BytesMixedx4DoubleLeaf();
+ testPassStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf();
+ testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf();
+ testPassStructAlignmentInt16Leaf();
+ testPassStructAlignmentInt32Leaf();
+ testPassStructAlignmentInt64Leaf();
+ testPassStruct8BytesNestedIntx10Leaf();
+ testPassStruct8BytesNestedFloatx10Leaf();
+ testPassStruct8BytesNestedFloat2x10Leaf();
+ testPassStruct8BytesNestedMixedx10Leaf();
+ testPassStruct16BytesNestedIntx2Leaf();
+ testPassStruct32BytesNestedIntx2Leaf();
+ testPassStructNestedIntStructAlignmentInt16Leaf();
+ testPassStructNestedIntStructAlignmentInt32Leaf();
+ testPassStructNestedIntStructAlignmentInt64Leaf();
+ testPassStructNestedIrregularEvenBiggerx4Leaf();
+ testPassStruct8BytesInlineArrayIntx4Leaf();
+ testPassStructInlineArrayIrregularx4Leaf();
+ testPassStructInlineArray100BytesLeaf();
+ testPassStructStruct16BytesHomogeneousFloat2x5Leaf();
+ testPassStructStruct32BytesHomogeneousDouble2x5Leaf();
+ testPassStructStruct16BytesMixed3x10Leaf();
+ testPassUint8Struct32BytesInlineArrayMultiDimensionalILeaf();
+ testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf();
+ testPassStruct3BytesPackedIntx10Leaf();
+ testPassStruct8BytesPackedIntx10Leaf();
+ testPassStruct9BytesPackedMixedx10DoubleInt32Leaf();
+ testPassStruct5BytesPackedMixedLeaf();
+ testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf();
+ testPassStruct6BytesInlineArrayIntLeaf();
+ testPassStruct15BytesInlineArrayMixedLeaf();
+ testPassUnion4BytesMixedx10Leaf();
+ testPassUnion8BytesNestedFloatx10Leaf();
+ testPassUnion9BytesNestedIntx10Leaf();
+ testPassUnion16BytesNestedInlineArrayFloatx10Leaf();
+ testPassUnion16BytesNestedFloatx10Leaf();
+ testReturnStruct1ByteIntLeaf();
+ testReturnStruct3BytesHomogeneousUint8Leaf();
+ testReturnStruct3BytesInt2ByteAlignedLeaf();
+ testReturnStruct4BytesHomogeneousInt16Leaf();
+ testReturnStruct7BytesHomogeneousUint8Leaf();
+ testReturnStruct7BytesInt4ByteAlignedLeaf();
+ testReturnStruct8BytesIntLeaf();
+ testReturnStruct8BytesHomogeneousFloatLeaf();
+ testReturnStruct8BytesMixedLeaf();
+ testReturnStruct9BytesHomogeneousUint8Leaf();
+ testReturnStruct9BytesInt4Or8ByteAlignedLeaf();
+ testReturnStruct12BytesHomogeneousFloatLeaf();
+ testReturnStruct16BytesHomogeneousFloatLeaf();
+ testReturnStruct16BytesMixedLeaf();
+ testReturnStruct16BytesMixed2Leaf();
+ testReturnStruct17BytesIntLeaf();
+ testReturnStruct19BytesHomogeneousUint8Leaf();
+ testReturnStruct20BytesHomogeneousInt32Leaf();
+ testReturnStruct20BytesHomogeneousFloatLeaf();
+ testReturnStruct32BytesHomogeneousDoubleLeaf();
+ testReturnStruct40BytesHomogeneousDoubleLeaf();
+ testReturnStruct1024BytesHomogeneousUint64Leaf();
+ testReturnStruct3BytesPackedIntLeaf();
+ testReturnStruct8BytesPackedIntLeaf();
+ testReturnStruct9BytesPackedMixedLeaf();
+ testReturnUnion4BytesMixedLeaf();
+ testReturnUnion8BytesNestedFloatLeaf();
+ testReturnUnion9BytesNestedIntLeaf();
+ testReturnUnion16BytesNestedFloatLeaf();
+ testReturnStructArgumentStruct1ByteIntLeaf();
+ testReturnStructArgumentInt32x8Struct1ByteIntLeaf();
+ testReturnStructArgumentStruct8BytesHomogeneousFloatLeaf();
+ testReturnStructArgumentStruct20BytesHomogeneousInt32Leaf();
+ testReturnStructArgumentInt32x8Struct20BytesHomogeneouLeaf();
+ testReturnStructArgumentStruct8BytesInlineArrayIntLeaf();
+ testReturnStructArgumentStructStruct16BytesHomogeneousLeaf();
+ testReturnStructArgumentStructStruct32BytesHomogeneousLeaf();
+ testReturnStructArgumentStructStruct16BytesMixed3Leaf();
+ testReturnStructAlignmentInt16Leaf();
+ testReturnStructAlignmentInt32Leaf();
+ testReturnStructAlignmentInt64Leaf();
+ testReturnStruct8BytesNestedIntLeaf();
+ testReturnStruct8BytesNestedFloatLeaf();
+ testReturnStruct8BytesNestedFloat2Leaf();
+ testReturnStruct8BytesNestedMixedLeaf();
+ testReturnStruct16BytesNestedIntLeaf();
+ testReturnStruct32BytesNestedIntLeaf();
+ testReturnStructNestedIntStructAlignmentInt16Leaf();
+ testReturnStructNestedIntStructAlignmentInt32Leaf();
+ testReturnStructNestedIntStructAlignmentInt64Leaf();
+ testReturnStructNestedIrregularEvenBiggerLeaf();
}
}
@@ -8772,3 +8885,7541 @@
calloc.free(a1Pointer);
calloc.free(a2Pointer);
}
+
+final passStruct1ByteIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt),
+ int Function(
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt,
+ Struct1ByteInt)>("PassStruct1ByteIntx10", isLeaf: true);
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct1ByteIntx10Leaf() {
+ final a0Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a1.a0 = 2;
+ a2.a0 = -3;
+ a3.a0 = 4;
+ a4.a0 = -5;
+ a5.a0 = 6;
+ a6.a0 = -7;
+ a7.a0 = 8;
+ a8.a0 = -9;
+ a9.a0 = 10;
+
+ final result =
+ passStruct1ByteIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(5, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct3BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8),
+ int Function(
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8,
+ Struct3BytesHomogeneousUint8)>(
+ "PassStruct3BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesHomogeneousUint8>();
+ final Struct3BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a1.a0 = 4;
+ a1.a1 = 5;
+ a1.a2 = 6;
+ a2.a0 = 7;
+ a2.a1 = 8;
+ a2.a2 = 9;
+ a3.a0 = 10;
+ a3.a1 = 11;
+ a3.a2 = 12;
+ a4.a0 = 13;
+ a4.a1 = 14;
+ a4.a2 = 15;
+ a5.a0 = 16;
+ a5.a1 = 17;
+ a5.a2 = 18;
+ a6.a0 = 19;
+ a6.a1 = 20;
+ a6.a2 = 21;
+ a7.a0 = 22;
+ a7.a1 = 23;
+ a7.a2 = 24;
+ a8.a0 = 25;
+ a8.a1 = 26;
+ a8.a2 = 27;
+ a9.a0 = 28;
+ a9.a1 = 29;
+ a9.a2 = 30;
+
+ final result = passStruct3BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(465, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct3BytesInt2ByteAlignedx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned),
+ int Function(
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned,
+ Struct3BytesInt2ByteAligned)>("PassStruct3BytesInt2ByteAlignedx10",
+ isLeaf: true);
+
+/// Not a multiple of word size, not a power of two.
+/// With alignment rules taken into account size is 4 bytes.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesInt2ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesInt2ByteAligned>();
+ final Struct3BytesInt2ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct3BytesInt2ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct4BytesHomogeneousInt16x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16),
+ int Function(
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16,
+ Struct4BytesHomogeneousInt16)>(
+ "PassStruct4BytesHomogeneousInt16x10",
+ isLeaf: true);
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct4BytesHomogeneousInt16x10Leaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct4BytesHomogeneousInt16x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct7BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8),
+ int Function(
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8,
+ Struct7BytesHomogeneousUint8)>(
+ "PassStruct7BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct7BytesHomogeneousUint8>();
+ final Struct7BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a1.a0 = 8;
+ a1.a1 = 9;
+ a1.a2 = 10;
+ a1.a3 = 11;
+ a1.a4 = 12;
+ a1.a5 = 13;
+ a1.a6 = 14;
+ a2.a0 = 15;
+ a2.a1 = 16;
+ a2.a2 = 17;
+ a2.a3 = 18;
+ a2.a4 = 19;
+ a2.a5 = 20;
+ a2.a6 = 21;
+ a3.a0 = 22;
+ a3.a1 = 23;
+ a3.a2 = 24;
+ a3.a3 = 25;
+ a3.a4 = 26;
+ a3.a5 = 27;
+ a3.a6 = 28;
+ a4.a0 = 29;
+ a4.a1 = 30;
+ a4.a2 = 31;
+ a4.a3 = 32;
+ a4.a4 = 33;
+ a4.a5 = 34;
+ a4.a6 = 35;
+ a5.a0 = 36;
+ a5.a1 = 37;
+ a5.a2 = 38;
+ a5.a3 = 39;
+ a5.a4 = 40;
+ a5.a5 = 41;
+ a5.a6 = 42;
+ a6.a0 = 43;
+ a6.a1 = 44;
+ a6.a2 = 45;
+ a6.a3 = 46;
+ a6.a4 = 47;
+ a6.a5 = 48;
+ a6.a6 = 49;
+ a7.a0 = 50;
+ a7.a1 = 51;
+ a7.a2 = 52;
+ a7.a3 = 53;
+ a7.a4 = 54;
+ a7.a5 = 55;
+ a7.a6 = 56;
+ a8.a0 = 57;
+ a8.a1 = 58;
+ a8.a2 = 59;
+ a8.a3 = 60;
+ a8.a4 = 61;
+ a8.a5 = 62;
+ a8.a6 = 63;
+ a9.a0 = 64;
+ a9.a1 = 65;
+ a9.a2 = 66;
+ a9.a3 = 67;
+ a9.a4 = 68;
+ a9.a5 = 69;
+ a9.a6 = 70;
+
+ final result = passStruct7BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(2485, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct7BytesInt4ByteAlignedx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned),
+ int Function(
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned,
+ Struct7BytesInt4ByteAligned)>("PassStruct7BytesInt4ByteAlignedx10",
+ isLeaf: true);
+
+/// Sub word size on 64 bit architectures.
+/// With alignment rules taken into account size is 8 bytes.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesInt4ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct7BytesInt4ByteAligned>();
+ final Struct7BytesInt4ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result = passStruct7BytesInt4ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt),
+ int Function(
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt,
+ Struct8BytesInt)>("PassStruct8BytesIntx10", isLeaf: true);
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct8BytesIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesHomogeneousFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat),
+ double Function(
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat,
+ Struct8BytesHomogeneousFloat)>(
+ "PassStruct8BytesHomogeneousFloatx10",
+ isLeaf: true);
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesHomogeneousFloatx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a1.a0 = -3.0;
+ a1.a1 = 4.0;
+ a2.a0 = -5.0;
+ a2.a1 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a4.a0 = -9.0;
+ a4.a1 = 10.0;
+ a5.a0 = -11.0;
+ a5.a1 = 12.0;
+ a6.a0 = -13.0;
+ a6.a1 = 14.0;
+ a7.a0 = -15.0;
+ a7.a1 = 16.0;
+ a8.a0 = -17.0;
+ a8.a1 = 18.0;
+ a9.a0 = -19.0;
+ a9.a1 = 20.0;
+
+ final result = passStruct8BytesHomogeneousFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed),
+ double Function(
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed,
+ Struct8BytesMixed)>("PassStruct8BytesMixedx10", isLeaf: true);
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4.0;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7.0;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10.0;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13.0;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16.0;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19.0;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22.0;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25.0;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28.0;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct8BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesHomogeneousUint8x10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8),
+ int Function(
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8,
+ Struct9BytesHomogeneousUint8)>(
+ "PassStruct9BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Struct only has 1-byte aligned fields to test struct alignment itself.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+void testPassStruct9BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesHomogeneousUint8>();
+ final Struct9BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a1.a0 = 10;
+ a1.a1 = 11;
+ a1.a2 = 12;
+ a1.a3 = 13;
+ a1.a4 = 14;
+ a1.a5 = 15;
+ a1.a6 = 16;
+ a1.a7 = 17;
+ a1.a8 = 18;
+ a2.a0 = 19;
+ a2.a1 = 20;
+ a2.a2 = 21;
+ a2.a3 = 22;
+ a2.a4 = 23;
+ a2.a5 = 24;
+ a2.a6 = 25;
+ a2.a7 = 26;
+ a2.a8 = 27;
+ a3.a0 = 28;
+ a3.a1 = 29;
+ a3.a2 = 30;
+ a3.a3 = 31;
+ a3.a4 = 32;
+ a3.a5 = 33;
+ a3.a6 = 34;
+ a3.a7 = 35;
+ a3.a8 = 36;
+ a4.a0 = 37;
+ a4.a1 = 38;
+ a4.a2 = 39;
+ a4.a3 = 40;
+ a4.a4 = 41;
+ a4.a5 = 42;
+ a4.a6 = 43;
+ a4.a7 = 44;
+ a4.a8 = 45;
+ a5.a0 = 46;
+ a5.a1 = 47;
+ a5.a2 = 48;
+ a5.a3 = 49;
+ a5.a4 = 50;
+ a5.a5 = 51;
+ a5.a6 = 52;
+ a5.a7 = 53;
+ a5.a8 = 54;
+ a6.a0 = 55;
+ a6.a1 = 56;
+ a6.a2 = 57;
+ a6.a3 = 58;
+ a6.a4 = 59;
+ a6.a5 = 60;
+ a6.a6 = 61;
+ a6.a7 = 62;
+ a6.a8 = 63;
+ a7.a0 = 64;
+ a7.a1 = 65;
+ a7.a2 = 66;
+ a7.a3 = 67;
+ a7.a4 = 68;
+ a7.a5 = 69;
+ a7.a6 = 70;
+ a7.a7 = 71;
+ a7.a8 = 72;
+ a8.a0 = 73;
+ a8.a1 = 74;
+ a8.a2 = 75;
+ a8.a3 = 76;
+ a8.a4 = 77;
+ a8.a5 = 78;
+ a8.a6 = 79;
+ a8.a7 = 80;
+ a8.a8 = 81;
+ a9.a0 = 82;
+ a9.a1 = 83;
+ a9.a2 = 84;
+ a9.a3 = 85;
+ a9.a4 = 86;
+ a9.a5 = 87;
+ a9.a6 = 88;
+ a9.a7 = 89;
+ a9.a8 = 90;
+
+ final result = passStruct9BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(4095, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesInt4Or8ByteAlignedx10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned),
+ int Function(
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned,
+ Struct9BytesInt4Or8ByteAligned)>(
+ "PassStruct9BytesInt4Or8ByteAlignedx10",
+ isLeaf: true);
+
+/// Argument is a single byte over a multiple of word size.
+/// With alignment rules taken into account size is 12 or 16 bytes.
+/// 10 struct arguments will exhaust available registers.
+///
+void testPassStruct9BytesInt4Or8ByteAlignedx10Leaf() {
+ final a0Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesInt4Or8ByteAligned>();
+ final Struct9BytesInt4Or8ByteAligned a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result = passStruct9BytesInt4Or8ByteAlignedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct12BytesHomogeneousFloatx6Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat),
+ double Function(
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat,
+ Struct12BytesHomogeneousFloat)>(
+ "PassStruct12BytesHomogeneousFloatx6",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// Struct arguments will exhaust available registers, and leave some empty.
+/// The last argument is to test whether arguments are backfilled.
+void testPassStruct12BytesHomogeneousFloatx6Leaf() {
+ final a0Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct12BytesHomogeneousFloat>();
+ final Struct12BytesHomogeneousFloat a5 = a5Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a1.a0 = 4.0;
+ a1.a1 = -5.0;
+ a1.a2 = 6.0;
+ a2.a0 = -7.0;
+ a2.a1 = 8.0;
+ a2.a2 = -9.0;
+ a3.a0 = 10.0;
+ a3.a1 = -11.0;
+ a3.a2 = 12.0;
+ a4.a0 = -13.0;
+ a4.a1 = 14.0;
+ a4.a2 = -15.0;
+ a5.a0 = 16.0;
+ a5.a1 = -17.0;
+ a5.a2 = 18.0;
+
+ final result =
+ passStruct12BytesHomogeneousFloatx6Leaf(a0, a1, a2, a3, a4, a5);
+
+ print("result = $result");
+
+ Expect.approxEquals(9.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+}
+
+final passStruct16BytesHomogeneousFloatx5Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat),
+ double Function(
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat,
+ Struct16BytesHomogeneousFloat)>(
+ "PassStruct16BytesHomogeneousFloatx5",
+ isLeaf: true);
+
+/// On Linux x64 argument is transferred on stack because it is over 16 bytes.
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct16BytesHomogeneousFloatx5Leaf() {
+ final a0Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a4 = a4Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8.0;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12.0;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16.0;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20.0;
+
+ final result = passStruct16BytesHomogeneousFloatx5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStruct16BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed),
+ double Function(
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed)>("PassStruct16BytesMixedx10", isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 8 byte aligned.
+void testPassStruct16BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+ a1.a0 = -3.0;
+ a1.a1 = 4;
+ a2.a0 = -5.0;
+ a2.a1 = 6;
+ a3.a0 = -7.0;
+ a3.a1 = 8;
+ a4.a0 = -9.0;
+ a4.a1 = 10;
+ a5.a0 = -11.0;
+ a5.a1 = 12;
+ a6.a0 = -13.0;
+ a6.a1 = 14;
+ a7.a0 = -15.0;
+ a7.a1 = 16;
+ a8.a0 = -17.0;
+ a8.a1 = 18;
+ a9.a0 = -19.0;
+ a9.a1 = 20;
+
+ final result =
+ passStruct16BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct16BytesMixed2x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2),
+ double Function(
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2,
+ Struct16BytesMixed2)>("PassStruct16BytesMixed2x10", isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 4 byte aligned.
+void testPassStruct16BytesMixed2x10Leaf() {
+ final a0Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed2>();
+ final Struct16BytesMixed2 a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20;
+ a5.a0 = -21.0;
+ a5.a1 = 22.0;
+ a5.a2 = -23.0;
+ a5.a3 = 24;
+ a6.a0 = -25.0;
+ a6.a1 = 26.0;
+ a6.a2 = -27.0;
+ a6.a3 = 28;
+ a7.a0 = -29.0;
+ a7.a1 = 30.0;
+ a7.a2 = -31.0;
+ a7.a3 = 32;
+ a8.a0 = -33.0;
+ a8.a1 = 34.0;
+ a8.a2 = -35.0;
+ a8.a3 = 36;
+ a9.a0 = -37.0;
+ a9.a1 = 38.0;
+ a9.a2 = -39.0;
+ a9.a3 = 40;
+
+ final result =
+ passStruct16BytesMixed2x10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct17BytesIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt),
+ int Function(
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt,
+ Struct17BytesInt)>("PassStruct17BytesIntx10", isLeaf: true);
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+void testPassStruct17BytesIntx10Leaf() {
+ final a0Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct17BytesInt>();
+ final Struct17BytesInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+ a2.a0 = -7;
+ a2.a1 = 8;
+ a2.a2 = -9;
+ a3.a0 = 10;
+ a3.a1 = -11;
+ a3.a2 = 12;
+ a4.a0 = -13;
+ a4.a1 = 14;
+ a4.a2 = -15;
+ a5.a0 = 16;
+ a5.a1 = -17;
+ a5.a2 = 18;
+ a6.a0 = -19;
+ a6.a1 = 20;
+ a6.a2 = -21;
+ a7.a0 = 22;
+ a7.a1 = -23;
+ a7.a2 = 24;
+ a8.a0 = -25;
+ a8.a1 = 26;
+ a8.a2 = -27;
+ a9.a0 = 28;
+ a9.a1 = -29;
+ a9.a2 = 30;
+
+ final result =
+ passStruct17BytesIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(15, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct19BytesHomogeneousUint8x10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8),
+ int Function(
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8,
+ Struct19BytesHomogeneousUint8)>(
+ "PassStruct19BytesHomogeneousUint8x10",
+ isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is extended to the right size.
+///
+void testPassStruct19BytesHomogeneousUint8x10Leaf() {
+ final a0Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct19BytesHomogeneousUint8>();
+ final Struct19BytesHomogeneousUint8 a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a0.a9 = 10;
+ a0.a10 = 11;
+ a0.a11 = 12;
+ a0.a12 = 13;
+ a0.a13 = 14;
+ a0.a14 = 15;
+ a0.a15 = 16;
+ a0.a16 = 17;
+ a0.a17 = 18;
+ a0.a18 = 19;
+ a1.a0 = 20;
+ a1.a1 = 21;
+ a1.a2 = 22;
+ a1.a3 = 23;
+ a1.a4 = 24;
+ a1.a5 = 25;
+ a1.a6 = 26;
+ a1.a7 = 27;
+ a1.a8 = 28;
+ a1.a9 = 29;
+ a1.a10 = 30;
+ a1.a11 = 31;
+ a1.a12 = 32;
+ a1.a13 = 33;
+ a1.a14 = 34;
+ a1.a15 = 35;
+ a1.a16 = 36;
+ a1.a17 = 37;
+ a1.a18 = 38;
+ a2.a0 = 39;
+ a2.a1 = 40;
+ a2.a2 = 41;
+ a2.a3 = 42;
+ a2.a4 = 43;
+ a2.a5 = 44;
+ a2.a6 = 45;
+ a2.a7 = 46;
+ a2.a8 = 47;
+ a2.a9 = 48;
+ a2.a10 = 49;
+ a2.a11 = 50;
+ a2.a12 = 51;
+ a2.a13 = 52;
+ a2.a14 = 53;
+ a2.a15 = 54;
+ a2.a16 = 55;
+ a2.a17 = 56;
+ a2.a18 = 57;
+ a3.a0 = 58;
+ a3.a1 = 59;
+ a3.a2 = 60;
+ a3.a3 = 61;
+ a3.a4 = 62;
+ a3.a5 = 63;
+ a3.a6 = 64;
+ a3.a7 = 65;
+ a3.a8 = 66;
+ a3.a9 = 67;
+ a3.a10 = 68;
+ a3.a11 = 69;
+ a3.a12 = 70;
+ a3.a13 = 71;
+ a3.a14 = 72;
+ a3.a15 = 73;
+ a3.a16 = 74;
+ a3.a17 = 75;
+ a3.a18 = 76;
+ a4.a0 = 77;
+ a4.a1 = 78;
+ a4.a2 = 79;
+ a4.a3 = 80;
+ a4.a4 = 81;
+ a4.a5 = 82;
+ a4.a6 = 83;
+ a4.a7 = 84;
+ a4.a8 = 85;
+ a4.a9 = 86;
+ a4.a10 = 87;
+ a4.a11 = 88;
+ a4.a12 = 89;
+ a4.a13 = 90;
+ a4.a14 = 91;
+ a4.a15 = 92;
+ a4.a16 = 93;
+ a4.a17 = 94;
+ a4.a18 = 95;
+ a5.a0 = 96;
+ a5.a1 = 97;
+ a5.a2 = 98;
+ a5.a3 = 99;
+ a5.a4 = 100;
+ a5.a5 = 101;
+ a5.a6 = 102;
+ a5.a7 = 103;
+ a5.a8 = 104;
+ a5.a9 = 105;
+ a5.a10 = 106;
+ a5.a11 = 107;
+ a5.a12 = 108;
+ a5.a13 = 109;
+ a5.a14 = 110;
+ a5.a15 = 111;
+ a5.a16 = 112;
+ a5.a17 = 113;
+ a5.a18 = 114;
+ a6.a0 = 115;
+ a6.a1 = 116;
+ a6.a2 = 117;
+ a6.a3 = 118;
+ a6.a4 = 119;
+ a6.a5 = 120;
+ a6.a6 = 121;
+ a6.a7 = 122;
+ a6.a8 = 123;
+ a6.a9 = 124;
+ a6.a10 = 125;
+ a6.a11 = 126;
+ a6.a12 = 127;
+ a6.a13 = 128;
+ a6.a14 = 129;
+ a6.a15 = 130;
+ a6.a16 = 131;
+ a6.a17 = 132;
+ a6.a18 = 133;
+ a7.a0 = 134;
+ a7.a1 = 135;
+ a7.a2 = 136;
+ a7.a3 = 137;
+ a7.a4 = 138;
+ a7.a5 = 139;
+ a7.a6 = 140;
+ a7.a7 = 141;
+ a7.a8 = 142;
+ a7.a9 = 143;
+ a7.a10 = 144;
+ a7.a11 = 145;
+ a7.a12 = 146;
+ a7.a13 = 147;
+ a7.a14 = 148;
+ a7.a15 = 149;
+ a7.a16 = 150;
+ a7.a17 = 151;
+ a7.a18 = 152;
+ a8.a0 = 153;
+ a8.a1 = 154;
+ a8.a2 = 155;
+ a8.a3 = 156;
+ a8.a4 = 157;
+ a8.a5 = 158;
+ a8.a6 = 159;
+ a8.a7 = 160;
+ a8.a8 = 161;
+ a8.a9 = 162;
+ a8.a10 = 163;
+ a8.a11 = 164;
+ a8.a12 = 165;
+ a8.a13 = 166;
+ a8.a14 = 167;
+ a8.a15 = 168;
+ a8.a16 = 169;
+ a8.a17 = 170;
+ a8.a18 = 171;
+ a9.a0 = 172;
+ a9.a1 = 173;
+ a9.a2 = 174;
+ a9.a3 = 175;
+ a9.a4 = 176;
+ a9.a5 = 177;
+ a9.a6 = 178;
+ a9.a7 = 179;
+ a9.a8 = 180;
+ a9.a9 = 181;
+ a9.a10 = 182;
+ a9.a11 = 183;
+ a9.a12 = 184;
+ a9.a13 = 185;
+ a9.a14 = 186;
+ a9.a15 = 187;
+ a9.a16 = 188;
+ a9.a17 = 189;
+ a9.a18 = 190;
+
+ final result = passStruct19BytesHomogeneousUint8x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(18145, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct20BytesHomogeneousInt32x10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int32 Function(
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32),
+ int Function(
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32,
+ Struct20BytesHomogeneousInt32)>(
+ "PassStruct20BytesHomogeneousInt32x10",
+ isLeaf: true);
+
+/// Argument too big to go into integer registers on arm64.
+/// The arguments are passed as pointers to copies.
+/// The amount of arguments exhausts the number of integer registers, such that
+/// pointers to copies are also passed on the stack.
+void testPassStruct20BytesHomogeneousInt32x10Leaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a0.a3 = 4;
+ a0.a4 = -5;
+ a1.a0 = 6;
+ a1.a1 = -7;
+ a1.a2 = 8;
+ a1.a3 = -9;
+ a1.a4 = 10;
+ a2.a0 = -11;
+ a2.a1 = 12;
+ a2.a2 = -13;
+ a2.a3 = 14;
+ a2.a4 = -15;
+ a3.a0 = 16;
+ a3.a1 = -17;
+ a3.a2 = 18;
+ a3.a3 = -19;
+ a3.a4 = 20;
+ a4.a0 = -21;
+ a4.a1 = 22;
+ a4.a2 = -23;
+ a4.a3 = 24;
+ a4.a4 = -25;
+ a5.a0 = 26;
+ a5.a1 = -27;
+ a5.a2 = 28;
+ a5.a3 = -29;
+ a5.a4 = 30;
+ a6.a0 = -31;
+ a6.a1 = 32;
+ a6.a2 = -33;
+ a6.a3 = 34;
+ a6.a4 = -35;
+ a7.a0 = 36;
+ a7.a1 = -37;
+ a7.a2 = 38;
+ a7.a3 = -39;
+ a7.a4 = 40;
+ a8.a0 = -41;
+ a8.a1 = 42;
+ a8.a2 = -43;
+ a8.a3 = 44;
+ a8.a4 = -45;
+ a9.a0 = 46;
+ a9.a1 = -47;
+ a9.a2 = 48;
+ a9.a3 = -49;
+ a9.a4 = 50;
+
+ final result = passStruct20BytesHomogeneousInt32x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(25, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct20BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Float Function(Struct20BytesHomogeneousFloat),
+ double Function(Struct20BytesHomogeneousFloat)>(
+ "PassStruct20BytesHomogeneousFloat",
+ isLeaf: true);
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+void testPassStruct20BytesHomogeneousFloatLeaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousFloat>();
+ final Struct20BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+
+ final result = passStruct20BytesHomogeneousFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(-3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct32BytesHomogeneousDoublex5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble),
+ double Function(
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble,
+ Struct32BytesHomogeneousDouble)>(
+ "PassStruct32BytesHomogeneousDoublex5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct32BytesHomogeneousDoublex5Leaf() {
+ final a0Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a4 = a4Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a1.a0 = -5.0;
+ a1.a1 = 6.0;
+ a1.a2 = -7.0;
+ a1.a3 = 8.0;
+ a2.a0 = -9.0;
+ a2.a1 = 10.0;
+ a2.a2 = -11.0;
+ a2.a3 = 12.0;
+ a3.a0 = -13.0;
+ a3.a1 = 14.0;
+ a3.a2 = -15.0;
+ a3.a3 = 16.0;
+ a4.a0 = -17.0;
+ a4.a1 = 18.0;
+ a4.a2 = -19.0;
+ a4.a3 = 20.0;
+
+ final result = passStruct32BytesHomogeneousDoublex5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStruct40BytesHomogeneousDoubleLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct40BytesHomogeneousDouble),
+ double Function(Struct40BytesHomogeneousDouble)>(
+ "PassStruct40BytesHomogeneousDouble",
+ isLeaf: true);
+
+/// Argument too big to go into FPU registers in arm64.
+void testPassStruct40BytesHomogeneousDoubleLeaf() {
+ final a0Pointer = calloc<Struct40BytesHomogeneousDouble>();
+ final Struct40BytesHomogeneousDouble a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+
+ final result = passStruct40BytesHomogeneousDoubleLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(-3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct1024BytesHomogeneousUint64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Uint64 Function(Struct1024BytesHomogeneousUint64),
+ int Function(Struct1024BytesHomogeneousUint64)>(
+ "PassStruct1024BytesHomogeneousUint64",
+ isLeaf: true);
+
+/// Test 1kb struct.
+void testPassStruct1024BytesHomogeneousUint64Leaf() {
+ final a0Pointer = calloc<Struct1024BytesHomogeneousUint64>();
+ final Struct1024BytesHomogeneousUint64 a0 = a0Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a0.a5 = 6;
+ a0.a6 = 7;
+ a0.a7 = 8;
+ a0.a8 = 9;
+ a0.a9 = 10;
+ a0.a10 = 11;
+ a0.a11 = 12;
+ a0.a12 = 13;
+ a0.a13 = 14;
+ a0.a14 = 15;
+ a0.a15 = 16;
+ a0.a16 = 17;
+ a0.a17 = 18;
+ a0.a18 = 19;
+ a0.a19 = 20;
+ a0.a20 = 21;
+ a0.a21 = 22;
+ a0.a22 = 23;
+ a0.a23 = 24;
+ a0.a24 = 25;
+ a0.a25 = 26;
+ a0.a26 = 27;
+ a0.a27 = 28;
+ a0.a28 = 29;
+ a0.a29 = 30;
+ a0.a30 = 31;
+ a0.a31 = 32;
+ a0.a32 = 33;
+ a0.a33 = 34;
+ a0.a34 = 35;
+ a0.a35 = 36;
+ a0.a36 = 37;
+ a0.a37 = 38;
+ a0.a38 = 39;
+ a0.a39 = 40;
+ a0.a40 = 41;
+ a0.a41 = 42;
+ a0.a42 = 43;
+ a0.a43 = 44;
+ a0.a44 = 45;
+ a0.a45 = 46;
+ a0.a46 = 47;
+ a0.a47 = 48;
+ a0.a48 = 49;
+ a0.a49 = 50;
+ a0.a50 = 51;
+ a0.a51 = 52;
+ a0.a52 = 53;
+ a0.a53 = 54;
+ a0.a54 = 55;
+ a0.a55 = 56;
+ a0.a56 = 57;
+ a0.a57 = 58;
+ a0.a58 = 59;
+ a0.a59 = 60;
+ a0.a60 = 61;
+ a0.a61 = 62;
+ a0.a62 = 63;
+ a0.a63 = 64;
+ a0.a64 = 65;
+ a0.a65 = 66;
+ a0.a66 = 67;
+ a0.a67 = 68;
+ a0.a68 = 69;
+ a0.a69 = 70;
+ a0.a70 = 71;
+ a0.a71 = 72;
+ a0.a72 = 73;
+ a0.a73 = 74;
+ a0.a74 = 75;
+ a0.a75 = 76;
+ a0.a76 = 77;
+ a0.a77 = 78;
+ a0.a78 = 79;
+ a0.a79 = 80;
+ a0.a80 = 81;
+ a0.a81 = 82;
+ a0.a82 = 83;
+ a0.a83 = 84;
+ a0.a84 = 85;
+ a0.a85 = 86;
+ a0.a86 = 87;
+ a0.a87 = 88;
+ a0.a88 = 89;
+ a0.a89 = 90;
+ a0.a90 = 91;
+ a0.a91 = 92;
+ a0.a92 = 93;
+ a0.a93 = 94;
+ a0.a94 = 95;
+ a0.a95 = 96;
+ a0.a96 = 97;
+ a0.a97 = 98;
+ a0.a98 = 99;
+ a0.a99 = 100;
+ a0.a100 = 101;
+ a0.a101 = 102;
+ a0.a102 = 103;
+ a0.a103 = 104;
+ a0.a104 = 105;
+ a0.a105 = 106;
+ a0.a106 = 107;
+ a0.a107 = 108;
+ a0.a108 = 109;
+ a0.a109 = 110;
+ a0.a110 = 111;
+ a0.a111 = 112;
+ a0.a112 = 113;
+ a0.a113 = 114;
+ a0.a114 = 115;
+ a0.a115 = 116;
+ a0.a116 = 117;
+ a0.a117 = 118;
+ a0.a118 = 119;
+ a0.a119 = 120;
+ a0.a120 = 121;
+ a0.a121 = 122;
+ a0.a122 = 123;
+ a0.a123 = 124;
+ a0.a124 = 125;
+ a0.a125 = 126;
+ a0.a126 = 127;
+ a0.a127 = 128;
+
+ final result = passStruct1024BytesHomogeneousUint64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(8256, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf =
+ ffiTestFunctions.lookupFunction<
+ Float Function(
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float,
+ Struct16BytesHomogeneousFloat,
+ Float),
+ double Function(
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double,
+ Struct16BytesHomogeneousFloat,
+ double)>("PassFloatStruct16BytesHomogeneousFloatFloatStruct1",
+ isLeaf: true);
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf() {
+ double a0;
+ final a1Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a1 = a1Pointer.ref;
+ double a2;
+ final a3Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a3 = a3Pointer.ref;
+ double a4;
+ final a5Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a5 = a5Pointer.ref;
+ double a6;
+ final a7Pointer = calloc<Struct16BytesHomogeneousFloat>();
+ final Struct16BytesHomogeneousFloat a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1.0;
+ a1.a0 = 2.0;
+ a1.a1 = -3.0;
+ a1.a2 = 4.0;
+ a1.a3 = -5.0;
+ a2 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a3.a2 = -9.0;
+ a3.a3 = 10.0;
+ a4 = -11.0;
+ a5.a0 = 12.0;
+ a5.a1 = -13.0;
+ a5.a2 = 14.0;
+ a5.a3 = -15.0;
+ a6 = 16.0;
+ a7.a0 = -17.0;
+ a7.a1 = 18.0;
+ a7.a2 = -19.0;
+ a7.a3 = 20.0;
+ a8 = -21.0;
+
+ final result = passFloatStruct16BytesHomogeneousFloatFloatStruct1Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-11.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passFloatStruct32BytesHomogeneousDoubleFloatStructLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float,
+ Struct32BytesHomogeneousDouble,
+ Float),
+ double Function(
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double,
+ Struct32BytesHomogeneousDouble,
+ double)>("PassFloatStruct32BytesHomogeneousDoubleFloatStruct",
+ isLeaf: true);
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct32BytesHomogeneousDoubleFloatStructLeaf() {
+ double a0;
+ final a1Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a1 = a1Pointer.ref;
+ double a2;
+ final a3Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a3 = a3Pointer.ref;
+ double a4;
+ final a5Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a5 = a5Pointer.ref;
+ double a6;
+ final a7Pointer = calloc<Struct32BytesHomogeneousDouble>();
+ final Struct32BytesHomogeneousDouble a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1.0;
+ a1.a0 = 2.0;
+ a1.a1 = -3.0;
+ a1.a2 = 4.0;
+ a1.a3 = -5.0;
+ a2 = 6.0;
+ a3.a0 = -7.0;
+ a3.a1 = 8.0;
+ a3.a2 = -9.0;
+ a3.a3 = 10.0;
+ a4 = -11.0;
+ a5.a0 = 12.0;
+ a5.a1 = -13.0;
+ a5.a2 = 14.0;
+ a5.a3 = -15.0;
+ a6 = 16.0;
+ a7.a0 = -17.0;
+ a7.a1 = 18.0;
+ a7.a2 = -19.0;
+ a7.a3 = 20.0;
+ a8 = -21.0;
+
+ final result = passFloatStruct32BytesHomogeneousDoubleFloatStructLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-11.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Int8, Struct16BytesMixed, Int8, Struct16BytesMixed,
+ Int8, Struct16BytesMixed, Int8, Struct16BytesMixed, Int8),
+ double Function(
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int,
+ Struct16BytesMixed,
+ int)>("PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn",
+ isLeaf: true);
+
+/// Tests the alignment of structs in integers registers and on the stack.
+/// Arm32 aligns this struct at 8.
+/// Also, arm32 allocates the second struct partially in registers, partially
+/// on stack.
+/// Test backfilling of integer registers.
+void testPassInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a1 = a1Pointer.ref;
+ int a2;
+ final a3Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a3 = a3Pointer.ref;
+ int a4;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ int a6;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ int a8;
+
+ a0 = -1;
+ a1.a0 = 2.0;
+ a1.a1 = -3;
+ a2 = 4;
+ a3.a0 = -5.0;
+ a3.a1 = 6;
+ a4 = -7;
+ a5.a0 = 8.0;
+ a5.a1 = -9;
+ a6 = 10;
+ a7.a0 = -11.0;
+ a7.a1 = 12;
+ a8 = -13;
+
+ final result = passInt8Struct16BytesMixedInt8Struct16BytesMixedInLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-7.0, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passDoublex6Struct16BytesMixedx4Int32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Int32),
+ double Function(
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ int)>("PassDoublex6Struct16BytesMixedx4Int32", isLeaf: true);
+
+/// On Linux x64, it will exhaust xmm registers first, after 6 doubles and 2
+/// structs. The rest of the structs will go on the stack.
+/// The int will be backfilled into the int register.
+void testPassDoublex6Struct16BytesMixedx4Int32Leaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+ double a5;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a9 = a9Pointer.ref;
+ int a10;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+ a5 = 6.0;
+ a6.a0 = -7.0;
+ a6.a1 = 8;
+ a7.a0 = -9.0;
+ a7.a1 = 10;
+ a8.a0 = -11.0;
+ a8.a1 = 12;
+ a9.a0 = -13.0;
+ a9.a1 = 14;
+ a10 = -15;
+
+ final result = passDoublex6Struct16BytesMixedx4Int32Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+ print("result = $result");
+
+ Expect.approxEquals(-8.0, result);
+
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passInt32x4Struct16BytesMixedx4DoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Int32, Int32, Int32, Int32, Struct16BytesMixed,
+ Struct16BytesMixed, Struct16BytesMixed, Struct16BytesMixed, Double),
+ double Function(
+ int,
+ int,
+ int,
+ int,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ Struct16BytesMixed,
+ double)>("PassInt32x4Struct16BytesMixedx4Double", isLeaf: true);
+
+/// On Linux x64, it will exhaust int registers first.
+/// The rest of the structs will go on the stack.
+/// The double will be backfilled into the xmm register.
+void testPassInt32x4Struct16BytesMixedx4DoubleLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ final a4Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct16BytesMixed>();
+ final Struct16BytesMixed a7 = a7Pointer.ref;
+ double a8;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4.a0 = -5.0;
+ a4.a1 = 6;
+ a5.a0 = -7.0;
+ a5.a1 = 8;
+ a6.a0 = -9.0;
+ a6.a1 = 10;
+ a7.a0 = -11.0;
+ a7.a1 = 12;
+ a8 = -13.0;
+
+ final result = passInt32x4Struct16BytesMixedx4DoubleLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.approxEquals(-7.0, result);
+
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+}
+
+final passStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(Struct40BytesHomogeneousDouble,
+ Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat),
+ double Function(Struct40BytesHomogeneousDouble,
+ Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat)>(
+ "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo",
+ isLeaf: true);
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf() {
+ final a0Pointer = calloc<Struct40BytesHomogeneousDouble>();
+ final Struct40BytesHomogeneousDouble a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a2 = a2Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a0.a2 = -3.0;
+ a0.a3 = 4.0;
+ a0.a4 = -5.0;
+ a1.a0 = 6;
+ a1.a1 = -7;
+ a2.a0 = 8.0;
+ a2.a1 = -9.0;
+
+ final result =
+ passStruct40BytesHomogeneousDoubleStruct4BytesHomoLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(-5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+}
+
+final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Int32,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Double,
+ Int64,
+ Int8,
+ Struct1ByteInt,
+ Int64,
+ Int8,
+ Struct4BytesHomogeneousInt16,
+ Int64,
+ Int8,
+ Struct8BytesInt,
+ Int64,
+ Int8,
+ Struct8BytesHomogeneousFloat,
+ Int64,
+ Int8,
+ Struct8BytesMixed,
+ Int64,
+ Int8,
+ StructAlignmentInt16,
+ Int64,
+ Int8,
+ StructAlignmentInt32,
+ Int64,
+ Int8,
+ StructAlignmentInt64),
+ double Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ double,
+ int,
+ int,
+ Struct1ByteInt,
+ int,
+ int,
+ Struct4BytesHomogeneousInt16,
+ int,
+ int,
+ Struct8BytesInt,
+ int,
+ int,
+ Struct8BytesHomogeneousFloat,
+ int,
+ int,
+ Struct8BytesMixed,
+ int,
+ int,
+ StructAlignmentInt16,
+ int,
+ int,
+ StructAlignmentInt32,
+ int,
+ int,
+ StructAlignmentInt64)>("PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ double a8;
+ double a9;
+ double a10;
+ double a11;
+ double a12;
+ double a13;
+ double a14;
+ double a15;
+ int a16;
+ int a17;
+ final a18Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a18 = a18Pointer.ref;
+ int a19;
+ int a20;
+ final a21Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a21 = a21Pointer.ref;
+ int a22;
+ int a23;
+ final a24Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a24 = a24Pointer.ref;
+ int a25;
+ int a26;
+ final a27Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a27 = a27Pointer.ref;
+ int a28;
+ int a29;
+ final a30Pointer = calloc<Struct8BytesMixed>();
+ final Struct8BytesMixed a30 = a30Pointer.ref;
+ int a31;
+ int a32;
+ final a33Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a33 = a33Pointer.ref;
+ int a34;
+ int a35;
+ final a36Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a36 = a36Pointer.ref;
+ int a37;
+ int a38;
+ final a39Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a39 = a39Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8 = -9.0;
+ a9 = 10.0;
+ a10 = -11.0;
+ a11 = 12.0;
+ a12 = -13.0;
+ a13 = 14.0;
+ a14 = -15.0;
+ a15 = 16.0;
+ a16 = -17;
+ a17 = 18;
+ a18.a0 = -19;
+ a19 = 20;
+ a20 = -21;
+ a21.a0 = 22;
+ a21.a1 = -23;
+ a22 = 24;
+ a23 = -25;
+ a24.a0 = 26;
+ a24.a1 = -27;
+ a24.a2 = 28;
+ a25 = -29;
+ a26 = 30;
+ a27.a0 = -31.0;
+ a27.a1 = 32.0;
+ a28 = -33;
+ a29 = 34;
+ a30.a0 = -35.0;
+ a30.a1 = 36;
+ a30.a2 = -37;
+ a31 = 38;
+ a32 = -39;
+ a33.a0 = 40;
+ a33.a1 = -41;
+ a33.a2 = 42;
+ a34 = -43;
+ a35 = 44;
+ a36.a0 = -45;
+ a36.a1 = 46;
+ a36.a2 = -47;
+ a37 = 48;
+ a38 = -49;
+ a39.a0 = 50;
+ a39.a1 = -51;
+ a39.a2 = 52;
+
+ final result = passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntLeaf(
+ a0,
+ a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6,
+ a7,
+ a8,
+ a9,
+ a10,
+ a11,
+ a12,
+ a13,
+ a14,
+ a15,
+ a16,
+ a17,
+ a18,
+ a19,
+ a20,
+ a21,
+ a22,
+ a23,
+ a24,
+ a25,
+ a26,
+ a27,
+ a28,
+ a29,
+ a30,
+ a31,
+ a32,
+ a33,
+ a34,
+ a35,
+ a36,
+ a37,
+ a38,
+ a39);
+
+ print("result = $result");
+
+ Expect.approxEquals(26.0, result);
+
+ calloc.free(a18Pointer);
+ calloc.free(a21Pointer);
+ calloc.free(a24Pointer);
+ calloc.free(a27Pointer);
+ calloc.free(a30Pointer);
+ calloc.free(a33Pointer);
+ calloc.free(a36Pointer);
+ calloc.free(a39Pointer);
+}
+
+final passStructAlignmentInt16Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt16),
+ int Function(
+ StructAlignmentInt16)>("PassStructAlignmentInt16", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt16Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructAlignmentInt32Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt32),
+ int Function(
+ StructAlignmentInt32)>("PassStructAlignmentInt32", isLeaf: true);
+
+/// Test alignment and padding of 32 byte int within struct.
+void testPassStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructAlignmentInt64Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(StructAlignmentInt64),
+ int Function(
+ StructAlignmentInt64)>("PassStructAlignmentInt64", isLeaf: true);
+
+/// Test alignment and padding of 64 byte int within struct.
+void testPassStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = passStructAlignmentInt64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(-2, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct8BytesNestedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt),
+ int Function(
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt,
+ Struct8BytesNestedInt)>("PassStruct8BytesNestedIntx10", isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust registers on all platforms.
+void testPassStruct8BytesNestedIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3;
+ a0.a1.a1 = 4;
+ a1.a0.a0 = -5;
+ a1.a0.a1 = 6;
+ a1.a1.a0 = -7;
+ a1.a1.a1 = 8;
+ a2.a0.a0 = -9;
+ a2.a0.a1 = 10;
+ a2.a1.a0 = -11;
+ a2.a1.a1 = 12;
+ a3.a0.a0 = -13;
+ a3.a0.a1 = 14;
+ a3.a1.a0 = -15;
+ a3.a1.a1 = 16;
+ a4.a0.a0 = -17;
+ a4.a0.a1 = 18;
+ a4.a1.a0 = -19;
+ a4.a1.a1 = 20;
+ a5.a0.a0 = -21;
+ a5.a0.a1 = 22;
+ a5.a1.a0 = -23;
+ a5.a1.a1 = 24;
+ a6.a0.a0 = -25;
+ a6.a0.a1 = 26;
+ a6.a1.a0 = -27;
+ a6.a1.a1 = 28;
+ a7.a0.a0 = -29;
+ a7.a0.a1 = 30;
+ a7.a1.a0 = -31;
+ a7.a1.a1 = 32;
+ a8.a0.a0 = -33;
+ a8.a0.a1 = 34;
+ a8.a1.a0 = -35;
+ a8.a1.a1 = 36;
+ a9.a0.a0 = -37;
+ a9.a0.a1 = 38;
+ a9.a1.a0 = -39;
+ a9.a1.a1 = 40;
+
+ final result =
+ passStruct8BytesNestedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(20, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat),
+ double Function(
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat,
+ Struct8BytesNestedFloat)>("PassStruct8BytesNestedFloatx10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust fpu registers on all platforms.
+void testPassStruct8BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedFloat>();
+ final Struct8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1.a0 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a1.a0 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a1.a0 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a1.a0 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a1.a0 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a1.a0 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a1.a0 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a1.a0 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a1.a0 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a1.a0 = 20.0;
+
+ final result = passStruct8BytesNestedFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedFloat2x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2),
+ double Function(
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2,
+ Struct8BytesNestedFloat2)>("PassStruct8BytesNestedFloat2x10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust fpu registers on all platforms.
+/// The nesting is irregular, testing homogenous float rules on arm and arm64,
+/// and the fpu register usage on x64.
+void testPassStruct8BytesNestedFloat2x10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedFloat2>();
+ final Struct8BytesNestedFloat2 a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a1 = 20.0;
+
+ final result = passStruct8BytesNestedFloat2x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesNestedMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed),
+ double Function(
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed,
+ Struct8BytesNestedMixed)>("PassStruct8BytesNestedMixedx10",
+ isLeaf: true);
+
+/// Simple nested struct. No alignment gaps on any architectures.
+/// 10 arguments exhaust all registers on all platforms.
+void testPassStruct8BytesNestedMixedx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesNestedMixed>();
+ final Struct8BytesNestedMixed a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3.0;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a1.a0 = 6.0;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a1.a0 = -9.0;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a1.a0 = 12.0;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a1.a0 = -15.0;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a1.a0 = 18.0;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a1.a0 = -21.0;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a1.a0 = 24.0;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a1.a0 = -27.0;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a1.a0 = 30.0;
+
+ final result = passStruct8BytesNestedMixedx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct16BytesNestedIntx2Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(Struct16BytesNestedInt, Struct16BytesNestedInt),
+ int Function(Struct16BytesNestedInt,
+ Struct16BytesNestedInt)>("PassStruct16BytesNestedIntx2", isLeaf: true);
+
+/// Deeper nested struct to test recursive member access.
+void testPassStruct16BytesNestedIntx2Leaf() {
+ final a0Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0 = -1;
+ a0.a0.a0.a1 = 2;
+ a0.a0.a1.a0 = -3;
+ a0.a0.a1.a1 = 4;
+ a0.a1.a0.a0 = -5;
+ a0.a1.a0.a1 = 6;
+ a0.a1.a1.a0 = -7;
+ a0.a1.a1.a1 = 8;
+ a1.a0.a0.a0 = -9;
+ a1.a0.a0.a1 = 10;
+ a1.a0.a1.a0 = -11;
+ a1.a0.a1.a1 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15;
+ a1.a1.a1.a1 = 16;
+
+ final result = passStruct16BytesNestedIntx2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(8, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final passStruct32BytesNestedIntx2Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(Struct32BytesNestedInt, Struct32BytesNestedInt),
+ int Function(Struct32BytesNestedInt,
+ Struct32BytesNestedInt)>("PassStruct32BytesNestedIntx2", isLeaf: true);
+
+/// Even deeper nested struct to test recursive member access.
+void testPassStruct32BytesNestedIntx2Leaf() {
+ final a0Pointer = calloc<Struct32BytesNestedInt>();
+ final Struct32BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct32BytesNestedInt>();
+ final Struct32BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0.a0 = -1;
+ a0.a0.a0.a0.a1 = 2;
+ a0.a0.a0.a1.a0 = -3;
+ a0.a0.a0.a1.a1 = 4;
+ a0.a0.a1.a0.a0 = -5;
+ a0.a0.a1.a0.a1 = 6;
+ a0.a0.a1.a1.a0 = -7;
+ a0.a0.a1.a1.a1 = 8;
+ a0.a1.a0.a0.a0 = -9;
+ a0.a1.a0.a0.a1 = 10;
+ a0.a1.a0.a1.a0 = -11;
+ a0.a1.a0.a1.a1 = 12;
+ a0.a1.a1.a0.a0 = -13;
+ a0.a1.a1.a0.a1 = 14;
+ a0.a1.a1.a1.a0 = -15;
+ a0.a1.a1.a1.a1 = 16;
+ a1.a0.a0.a0.a0 = -17;
+ a1.a0.a0.a0.a1 = 18;
+ a1.a0.a0.a1.a0 = -19;
+ a1.a0.a0.a1.a1 = 20;
+ a1.a0.a1.a0.a0 = -21;
+ a1.a0.a1.a0.a1 = 22;
+ a1.a0.a1.a1.a0 = -23;
+ a1.a0.a1.a1.a1 = 24;
+ a1.a1.a0.a0.a0 = -25;
+ a1.a1.a0.a0.a1 = 26;
+ a1.a1.a0.a1.a0 = -27;
+ a1.a1.a0.a1.a1 = 28;
+ a1.a1.a1.a0.a0 = -29;
+ a1.a1.a1.a0.a1 = 30;
+ a1.a1.a1.a1.a0 = -31;
+ a1.a1.a1.a1.a1 = 32;
+
+ final result = passStruct32BytesNestedIntx2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(16, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt16Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt16),
+ int Function(StructNestedIntStructAlignmentInt16)>(
+ "PassStructNestedIntStructAlignmentInt16",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 16 byte int.
+void testPassStructNestedIntStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt16>();
+ final StructNestedIntStructAlignmentInt16 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt16Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt32),
+ int Function(StructNestedIntStructAlignmentInt32)>(
+ "PassStructNestedIntStructAlignmentInt32",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 32 byte int.
+void testPassStructNestedIntStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt32>();
+ final StructNestedIntStructAlignmentInt32 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIntStructAlignmentInt64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Int64 Function(StructNestedIntStructAlignmentInt64),
+ int Function(StructNestedIntStructAlignmentInt64)>(
+ "PassStructNestedIntStructAlignmentInt64",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 64 byte int.
+void testPassStructNestedIntStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructNestedIntStructAlignmentInt64>();
+ final StructNestedIntStructAlignmentInt64 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a0.a1.a0 = 4;
+ a0.a1.a1 = -5;
+ a0.a1.a2 = 6;
+
+ final result = passStructNestedIntStructAlignmentInt64Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(3, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedIrregularEvenBiggerx4Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger),
+ double Function(
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger,
+ StructNestedIrregularEvenBigger)>(
+ "PassStructNestedIrregularEvenBiggerx4",
+ isLeaf: true);
+
+/// Return big irregular struct as smoke test.
+void testPassStructNestedIrregularEvenBiggerx4Leaf() {
+ final a0Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructNestedIrregularEvenBigger>();
+ final StructNestedIrregularEvenBigger a3 = a3Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1.a0.a0 = 2;
+ a0.a1.a0.a1.a0.a0 = -3;
+ a0.a1.a0.a1.a0.a1 = 4;
+ a0.a1.a0.a1.a1.a0 = -5.0;
+ a0.a1.a0.a2 = 6;
+ a0.a1.a0.a3.a0.a0 = -7.0;
+ a0.a1.a0.a3.a1 = 8.0;
+ a0.a1.a0.a4 = 9;
+ a0.a1.a0.a5.a0.a0 = 10.0;
+ a0.a1.a0.a5.a1.a0 = -11.0;
+ a0.a1.a0.a6 = 12;
+ a0.a1.a1.a0.a0 = -13;
+ a0.a1.a1.a0.a1 = 14;
+ a0.a1.a1.a1.a0 = -15.0;
+ a0.a1.a2 = 16.0;
+ a0.a1.a3 = -17.0;
+ a0.a2.a0.a0 = 18;
+ a0.a2.a0.a1.a0.a0 = -19;
+ a0.a2.a0.a1.a0.a1 = 20;
+ a0.a2.a0.a1.a1.a0 = -21.0;
+ a0.a2.a0.a2 = 22;
+ a0.a2.a0.a3.a0.a0 = -23.0;
+ a0.a2.a0.a3.a1 = 24.0;
+ a0.a2.a0.a4 = 25;
+ a0.a2.a0.a5.a0.a0 = 26.0;
+ a0.a2.a0.a5.a1.a0 = -27.0;
+ a0.a2.a0.a6 = 28;
+ a0.a2.a1.a0.a0 = -29;
+ a0.a2.a1.a0.a1 = 30;
+ a0.a2.a1.a1.a0 = -31.0;
+ a0.a2.a2 = 32.0;
+ a0.a2.a3 = -33.0;
+ a0.a3 = 34.0;
+ a1.a0 = 35;
+ a1.a1.a0.a0 = 36;
+ a1.a1.a0.a1.a0.a0 = -37;
+ a1.a1.a0.a1.a0.a1 = 38;
+ a1.a1.a0.a1.a1.a0 = -39.0;
+ a1.a1.a0.a2 = 40;
+ a1.a1.a0.a3.a0.a0 = -41.0;
+ a1.a1.a0.a3.a1 = 42.0;
+ a1.a1.a0.a4 = 43;
+ a1.a1.a0.a5.a0.a0 = 44.0;
+ a1.a1.a0.a5.a1.a0 = -45.0;
+ a1.a1.a0.a6 = 46;
+ a1.a1.a1.a0.a0 = -47;
+ a1.a1.a1.a0.a1 = 48;
+ a1.a1.a1.a1.a0 = -49.0;
+ a1.a1.a2 = 50.0;
+ a1.a1.a3 = -51.0;
+ a1.a2.a0.a0 = 52;
+ a1.a2.a0.a1.a0.a0 = -53;
+ a1.a2.a0.a1.a0.a1 = 54;
+ a1.a2.a0.a1.a1.a0 = -55.0;
+ a1.a2.a0.a2 = 56;
+ a1.a2.a0.a3.a0.a0 = -57.0;
+ a1.a2.a0.a3.a1 = 58.0;
+ a1.a2.a0.a4 = 59;
+ a1.a2.a0.a5.a0.a0 = 60.0;
+ a1.a2.a0.a5.a1.a0 = -61.0;
+ a1.a2.a0.a6 = 62;
+ a1.a2.a1.a0.a0 = -63;
+ a1.a2.a1.a0.a1 = 64;
+ a1.a2.a1.a1.a0 = -65.0;
+ a1.a2.a2 = 66.0;
+ a1.a2.a3 = -67.0;
+ a1.a3 = 68.0;
+ a2.a0 = 69;
+ a2.a1.a0.a0 = 70;
+ a2.a1.a0.a1.a0.a0 = -71;
+ a2.a1.a0.a1.a0.a1 = 72;
+ a2.a1.a0.a1.a1.a0 = -73.0;
+ a2.a1.a0.a2 = 74;
+ a2.a1.a0.a3.a0.a0 = -75.0;
+ a2.a1.a0.a3.a1 = 76.0;
+ a2.a1.a0.a4 = 77;
+ a2.a1.a0.a5.a0.a0 = 78.0;
+ a2.a1.a0.a5.a1.a0 = -79.0;
+ a2.a1.a0.a6 = 80;
+ a2.a1.a1.a0.a0 = -81;
+ a2.a1.a1.a0.a1 = 82;
+ a2.a1.a1.a1.a0 = -83.0;
+ a2.a1.a2 = 84.0;
+ a2.a1.a3 = -85.0;
+ a2.a2.a0.a0 = 86;
+ a2.a2.a0.a1.a0.a0 = -87;
+ a2.a2.a0.a1.a0.a1 = 88;
+ a2.a2.a0.a1.a1.a0 = -89.0;
+ a2.a2.a0.a2 = 90;
+ a2.a2.a0.a3.a0.a0 = -91.0;
+ a2.a2.a0.a3.a1 = 92.0;
+ a2.a2.a0.a4 = 93;
+ a2.a2.a0.a5.a0.a0 = 94.0;
+ a2.a2.a0.a5.a1.a0 = -95.0;
+ a2.a2.a0.a6 = 96;
+ a2.a2.a1.a0.a0 = -97;
+ a2.a2.a1.a0.a1 = 98;
+ a2.a2.a1.a1.a0 = -99.0;
+ a2.a2.a2 = 100.0;
+ a2.a2.a3 = -101.0;
+ a2.a3 = 102.0;
+ a3.a0 = 103;
+ a3.a1.a0.a0 = 104;
+ a3.a1.a0.a1.a0.a0 = -105;
+ a3.a1.a0.a1.a0.a1 = 106;
+ a3.a1.a0.a1.a1.a0 = -107.0;
+ a3.a1.a0.a2 = 108;
+ a3.a1.a0.a3.a0.a0 = -109.0;
+ a3.a1.a0.a3.a1 = 110.0;
+ a3.a1.a0.a4 = 111;
+ a3.a1.a0.a5.a0.a0 = 112.0;
+ a3.a1.a0.a5.a1.a0 = -113.0;
+ a3.a1.a0.a6 = 114;
+ a3.a1.a1.a0.a0 = -115;
+ a3.a1.a1.a0.a1 = 116;
+ a3.a1.a1.a1.a0 = -117.0;
+ a3.a1.a2 = 118.0;
+ a3.a1.a3 = -119.0;
+ a3.a2.a0.a0 = 120;
+ a3.a2.a0.a1.a0.a0 = -121;
+ a3.a2.a0.a1.a0.a1 = 122;
+ a3.a2.a0.a1.a1.a0 = -123.0;
+ a3.a2.a0.a2 = 124;
+ a3.a2.a0.a3.a0.a0 = -125.0;
+ a3.a2.a0.a3.a1 = 126.0;
+ a3.a2.a0.a4 = 127;
+ a3.a2.a0.a5.a0.a0 = 128.0;
+ a3.a2.a0.a5.a1.a0 = -129.0;
+ a3.a2.a0.a6 = 130;
+ a3.a2.a1.a0.a0 = -131;
+ a3.a2.a1.a0.a1 = 132;
+ a3.a2.a1.a1.a0 = -133.0;
+ a3.a2.a2 = 134.0;
+ a3.a2.a3 = -135.0;
+ a3.a3 = 136.0;
+
+ final result = passStructNestedIrregularEvenBiggerx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(1572.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStruct8BytesInlineArrayIntx4Leaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(Struct8BytesInlineArrayInt, Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt, Struct8BytesInlineArrayInt),
+ int Function(
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt,
+ Struct8BytesInlineArrayInt)>("PassStruct8BytesInlineArrayIntx4",
+ isLeaf: true);
+
+/// Simple struct with inline array.
+void testPassStruct8BytesInlineArrayIntx4Leaf() {
+ final a0Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a3 = a3Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+ a1.a0[0] = 9;
+ a1.a0[1] = 10;
+ a1.a0[2] = 11;
+ a1.a0[3] = 12;
+ a1.a0[4] = 13;
+ a1.a0[5] = 14;
+ a1.a0[6] = 15;
+ a1.a0[7] = 16;
+ a2.a0[0] = 17;
+ a2.a0[1] = 18;
+ a2.a0[2] = 19;
+ a2.a0[3] = 20;
+ a2.a0[4] = 21;
+ a2.a0[5] = 22;
+ a2.a0[6] = 23;
+ a2.a0[7] = 24;
+ a3.a0[0] = 25;
+ a3.a0[1] = 26;
+ a3.a0[2] = 27;
+ a3.a0[3] = 28;
+ a3.a0[4] = 29;
+ a3.a0[5] = 30;
+ a3.a0[6] = 31;
+ a3.a0[7] = 32;
+
+ final result = passStruct8BytesInlineArrayIntx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(528, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStructInlineArrayIrregularx4Leaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(StructInlineArrayIrregular, StructInlineArrayIrregular,
+ StructInlineArrayIrregular, StructInlineArrayIrregular),
+ int Function(
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular,
+ StructInlineArrayIrregular)>("PassStructInlineArrayIrregularx4",
+ isLeaf: true);
+
+/// Irregular struct with inline array.
+void testPassStructInlineArrayIrregularx4Leaf() {
+ final a0Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructInlineArrayIrregular>();
+ final StructInlineArrayIrregular a3 = a3Pointer.ref;
+
+ a0.a0[0].a0 = -1;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3;
+ a0.a0[1].a1 = 4;
+ a0.a1 = 5;
+ a1.a0[0].a0 = 6;
+ a1.a0[0].a1 = -7;
+ a1.a0[1].a0 = 8;
+ a1.a0[1].a1 = -9;
+ a1.a1 = 10;
+ a2.a0[0].a0 = -11;
+ a2.a0[0].a1 = 12;
+ a2.a0[1].a0 = -13;
+ a2.a0[1].a1 = 14;
+ a2.a1 = 15;
+ a3.a0[0].a0 = 16;
+ a3.a0[0].a1 = -17;
+ a3.a0[1].a0 = 18;
+ a3.a0[1].a1 = -19;
+ a3.a1 = 20;
+
+ final result = passStructInlineArrayIrregularx4Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(50, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+}
+
+final passStructInlineArray100BytesLeaf = ffiTestFunctions.lookupFunction<
+ Int32 Function(StructInlineArray100Bytes),
+ int Function(StructInlineArray100Bytes)>(
+ "PassStructInlineArray100Bytes",
+ isLeaf: true);
+
+/// Regular larger struct with inline array.
+void testPassStructInlineArray100BytesLeaf() {
+ final a0Pointer = calloc<StructInlineArray100Bytes>();
+ final StructInlineArray100Bytes a0 = a0Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+ a0.a0[8] = 9;
+ a0.a0[9] = 10;
+ a0.a0[10] = 11;
+ a0.a0[11] = 12;
+ a0.a0[12] = 13;
+ a0.a0[13] = 14;
+ a0.a0[14] = 15;
+ a0.a0[15] = 16;
+ a0.a0[16] = 17;
+ a0.a0[17] = 18;
+ a0.a0[18] = 19;
+ a0.a0[19] = 20;
+ a0.a0[20] = 21;
+ a0.a0[21] = 22;
+ a0.a0[22] = 23;
+ a0.a0[23] = 24;
+ a0.a0[24] = 25;
+ a0.a0[25] = 26;
+ a0.a0[26] = 27;
+ a0.a0[27] = 28;
+ a0.a0[28] = 29;
+ a0.a0[29] = 30;
+ a0.a0[30] = 31;
+ a0.a0[31] = 32;
+ a0.a0[32] = 33;
+ a0.a0[33] = 34;
+ a0.a0[34] = 35;
+ a0.a0[35] = 36;
+ a0.a0[36] = 37;
+ a0.a0[37] = 38;
+ a0.a0[38] = 39;
+ a0.a0[39] = 40;
+ a0.a0[40] = 41;
+ a0.a0[41] = 42;
+ a0.a0[42] = 43;
+ a0.a0[43] = 44;
+ a0.a0[44] = 45;
+ a0.a0[45] = 46;
+ a0.a0[46] = 47;
+ a0.a0[47] = 48;
+ a0.a0[48] = 49;
+ a0.a0[49] = 50;
+ a0.a0[50] = 51;
+ a0.a0[51] = 52;
+ a0.a0[52] = 53;
+ a0.a0[53] = 54;
+ a0.a0[54] = 55;
+ a0.a0[55] = 56;
+ a0.a0[56] = 57;
+ a0.a0[57] = 58;
+ a0.a0[58] = 59;
+ a0.a0[59] = 60;
+ a0.a0[60] = 61;
+ a0.a0[61] = 62;
+ a0.a0[62] = 63;
+ a0.a0[63] = 64;
+ a0.a0[64] = 65;
+ a0.a0[65] = 66;
+ a0.a0[66] = 67;
+ a0.a0[67] = 68;
+ a0.a0[68] = 69;
+ a0.a0[69] = 70;
+ a0.a0[70] = 71;
+ a0.a0[71] = 72;
+ a0.a0[72] = 73;
+ a0.a0[73] = 74;
+ a0.a0[74] = 75;
+ a0.a0[75] = 76;
+ a0.a0[76] = 77;
+ a0.a0[77] = 78;
+ a0.a0[78] = 79;
+ a0.a0[79] = 80;
+ a0.a0[80] = 81;
+ a0.a0[81] = 82;
+ a0.a0[82] = 83;
+ a0.a0[83] = 84;
+ a0.a0[84] = 85;
+ a0.a0[85] = 86;
+ a0.a0[86] = 87;
+ a0.a0[87] = 88;
+ a0.a0[88] = 89;
+ a0.a0[89] = 90;
+ a0.a0[90] = 91;
+ a0.a0[91] = 92;
+ a0.a0[92] = 93;
+ a0.a0[93] = 94;
+ a0.a0[94] = 95;
+ a0.a0[95] = 96;
+ a0.a0[96] = 97;
+ a0.a0[97] = 98;
+ a0.a0[98] = 99;
+ a0.a0[99] = 100;
+
+ final result = passStructInlineArray100BytesLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(5050, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructStruct16BytesHomogeneousFloat2x5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Float Function(
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2),
+ double Function(
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2,
+ StructStruct16BytesHomogeneousFloat2)>(
+ "PassStructStruct16BytesHomogeneousFloat2x5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm hardfp and arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStructStruct16BytesHomogeneousFloat2x5Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a4 = a4Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+ a1.a0.a0 = -5.0;
+ a1.a1[0].a0 = 6.0;
+ a1.a1[1].a0 = -7.0;
+ a1.a2 = 8.0;
+ a2.a0.a0 = -9.0;
+ a2.a1[0].a0 = 10.0;
+ a2.a1[1].a0 = -11.0;
+ a2.a2 = 12.0;
+ a3.a0.a0 = -13.0;
+ a3.a1[0].a0 = 14.0;
+ a3.a1[1].a0 = -15.0;
+ a3.a2 = 16.0;
+ a4.a0.a0 = -17.0;
+ a4.a1[0].a0 = 18.0;
+ a4.a1[1].a0 = -19.0;
+ a4.a2 = 20.0;
+
+ final result =
+ passStructStruct16BytesHomogeneousFloat2x5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStructStruct32BytesHomogeneousDouble2x5Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2),
+ double Function(
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2,
+ StructStruct32BytesHomogeneousDouble2)>(
+ "PassStructStruct32BytesHomogeneousDouble2x5",
+ isLeaf: true);
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStructStruct32BytesHomogeneousDouble2x5Leaf() {
+ final a0Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a4 = a4Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+ a1.a0.a0 = -5.0;
+ a1.a1[0].a0 = 6.0;
+ a1.a1[1].a0 = -7.0;
+ a1.a2 = 8.0;
+ a2.a0.a0 = -9.0;
+ a2.a1[0].a0 = 10.0;
+ a2.a1[1].a0 = -11.0;
+ a2.a2 = 12.0;
+ a3.a0.a0 = -13.0;
+ a3.a1[0].a0 = 14.0;
+ a3.a1[1].a0 = -15.0;
+ a3.a2 = 16.0;
+ a4.a0.a0 = -17.0;
+ a4.a1[0].a0 = 18.0;
+ a4.a1[1].a0 = -19.0;
+ a4.a2 = 20.0;
+
+ final result =
+ passStructStruct32BytesHomogeneousDouble2x5Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+}
+
+final passStructStruct16BytesMixed3x10Leaf = ffiTestFunctions.lookupFunction<
+ Float Function(
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3),
+ double Function(
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3,
+ StructStruct16BytesMixed3)>("PassStructStruct16BytesMixed3x10",
+ isLeaf: true);
+
+/// On x64, arguments are split over FP and int registers.
+/// On x64, it will exhaust the integer registers with the 6th argument.
+/// The rest goes on the stack.
+/// On arm, arguments are 4 byte aligned.
+void testPassStructStruct16BytesMixed3x10Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a2 = a2Pointer.ref;
+ final a3Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a3 = a3Pointer.ref;
+ final a4Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a4 = a4Pointer.ref;
+ final a5Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a5 = a5Pointer.ref;
+ final a6Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a6 = a6Pointer.ref;
+ final a7Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a7 = a7Pointer.ref;
+ final a8Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a8 = a8Pointer.ref;
+ final a9Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[0].a1 = -3;
+ a0.a1[0].a2 = 4;
+ a0.a2[0] = -5;
+ a0.a2[1] = 6;
+ a1.a0.a0 = -7.0;
+ a1.a1[0].a0 = 8.0;
+ a1.a1[0].a1 = -9;
+ a1.a1[0].a2 = 10;
+ a1.a2[0] = -11;
+ a1.a2[1] = 12;
+ a2.a0.a0 = -13.0;
+ a2.a1[0].a0 = 14.0;
+ a2.a1[0].a1 = -15;
+ a2.a1[0].a2 = 16;
+ a2.a2[0] = -17;
+ a2.a2[1] = 18;
+ a3.a0.a0 = -19.0;
+ a3.a1[0].a0 = 20.0;
+ a3.a1[0].a1 = -21;
+ a3.a1[0].a2 = 22;
+ a3.a2[0] = -23;
+ a3.a2[1] = 24;
+ a4.a0.a0 = -25.0;
+ a4.a1[0].a0 = 26.0;
+ a4.a1[0].a1 = -27;
+ a4.a1[0].a2 = 28;
+ a4.a2[0] = -29;
+ a4.a2[1] = 30;
+ a5.a0.a0 = -31.0;
+ a5.a1[0].a0 = 32.0;
+ a5.a1[0].a1 = -33;
+ a5.a1[0].a2 = 34;
+ a5.a2[0] = -35;
+ a5.a2[1] = 36;
+ a6.a0.a0 = -37.0;
+ a6.a1[0].a0 = 38.0;
+ a6.a1[0].a1 = -39;
+ a6.a1[0].a2 = 40;
+ a6.a2[0] = -41;
+ a6.a2[1] = 42;
+ a7.a0.a0 = -43.0;
+ a7.a1[0].a0 = 44.0;
+ a7.a1[0].a1 = -45;
+ a7.a1[0].a2 = 46;
+ a7.a2[0] = -47;
+ a7.a2[1] = 48;
+ a8.a0.a0 = -49.0;
+ a8.a1[0].a0 = 50.0;
+ a8.a1[0].a1 = -51;
+ a8.a1[0].a2 = 52;
+ a8.a2[0] = -53;
+ a8.a2[1] = 54;
+ a9.a0.a0 = -55.0;
+ a9.a1[0].a0 = 56.0;
+ a9.a1[0].a1 = -57;
+ a9.a1[0].a2 = 58;
+ a9.a2[0] = -59;
+ a9.a2[1] = 60;
+
+ final result = passStructStruct16BytesMixed3x10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(30.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUint8Struct32BytesInlineArrayMultiDimensionalILeaf =
+ ffiTestFunctions.lookupFunction<
+ Uint32 Function(
+ Uint8,
+ Struct32BytesInlineArrayMultiDimensionalInt,
+ Uint8,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ Uint8,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ Uint8),
+ int Function(
+ int,
+ Struct32BytesInlineArrayMultiDimensionalInt,
+ int,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ int,
+ Struct8BytesInlineArrayMultiDimensionalInt,
+ int)>("PassUint8Struct32BytesInlineArrayMultiDimensionalI",
+ isLeaf: true);
+
+/// Test multi dimensional inline array struct as argument.
+void testPassUint8Struct32BytesInlineArrayMultiDimensionalILeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct32BytesInlineArrayMultiDimensionalInt>();
+ final Struct32BytesInlineArrayMultiDimensionalInt a1 = a1Pointer.ref;
+ int a2;
+ final a3Pointer = calloc<Struct8BytesInlineArrayMultiDimensionalInt>();
+ final Struct8BytesInlineArrayMultiDimensionalInt a3 = a3Pointer.ref;
+ int a4;
+ final a5Pointer = calloc<Struct8BytesInlineArrayMultiDimensionalInt>();
+ final Struct8BytesInlineArrayMultiDimensionalInt a5 = a5Pointer.ref;
+ int a6;
+
+ a0 = 1;
+ a1.a0[0][0][0][0][0] = 2;
+ a1.a0[0][0][0][0][1] = 3;
+ a1.a0[0][0][0][1][0] = 4;
+ a1.a0[0][0][0][1][1] = 5;
+ a1.a0[0][0][1][0][0] = 6;
+ a1.a0[0][0][1][0][1] = 7;
+ a1.a0[0][0][1][1][0] = 8;
+ a1.a0[0][0][1][1][1] = 9;
+ a1.a0[0][1][0][0][0] = 10;
+ a1.a0[0][1][0][0][1] = 11;
+ a1.a0[0][1][0][1][0] = 12;
+ a1.a0[0][1][0][1][1] = 13;
+ a1.a0[0][1][1][0][0] = 14;
+ a1.a0[0][1][1][0][1] = 15;
+ a1.a0[0][1][1][1][0] = 16;
+ a1.a0[0][1][1][1][1] = 17;
+ a1.a0[1][0][0][0][0] = 18;
+ a1.a0[1][0][0][0][1] = 19;
+ a1.a0[1][0][0][1][0] = 20;
+ a1.a0[1][0][0][1][1] = 21;
+ a1.a0[1][0][1][0][0] = 22;
+ a1.a0[1][0][1][0][1] = 23;
+ a1.a0[1][0][1][1][0] = 24;
+ a1.a0[1][0][1][1][1] = 25;
+ a1.a0[1][1][0][0][0] = 26;
+ a1.a0[1][1][0][0][1] = 27;
+ a1.a0[1][1][0][1][0] = 28;
+ a1.a0[1][1][0][1][1] = 29;
+ a1.a0[1][1][1][0][0] = 30;
+ a1.a0[1][1][1][0][1] = 31;
+ a1.a0[1][1][1][1][0] = 32;
+ a1.a0[1][1][1][1][1] = 33;
+ a2 = 34;
+ a3.a0[0][0][0] = 35;
+ a3.a0[0][0][1] = 36;
+ a3.a0[0][1][0] = 37;
+ a3.a0[0][1][1] = 38;
+ a3.a0[1][0][0] = 39;
+ a3.a0[1][0][1] = 40;
+ a3.a0[1][1][0] = 41;
+ a3.a0[1][1][1] = 42;
+ a4 = 43;
+ a5.a0[0][0][0] = 44;
+ a5.a0[0][0][1] = 45;
+ a5.a0[0][1][0] = 46;
+ a5.a0[0][1][1] = 47;
+ a5.a0[1][0][0] = 48;
+ a5.a0[1][0][1] = 49;
+ a5.a0[1][1][0] = 50;
+ a5.a0[1][1][1] = 51;
+ a6 = 52;
+
+ final result = passUint8Struct32BytesInlineArrayMultiDimensionalILeaf(
+ a0, a1, a2, a3, a4, a5, a6);
+
+ print("result = $result");
+
+ Expect.equals(1378, result);
+
+ calloc.free(a1Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a5Pointer);
+}
+
+final passUint8Struct4BytesInlineArrayMultiDimensionalInLeaf =
+ ffiTestFunctions.lookupFunction<
+ Uint32 Function(
+ Uint8, Struct4BytesInlineArrayMultiDimensionalInt, Uint8),
+ int Function(int, Struct4BytesInlineArrayMultiDimensionalInt, int)>(
+ "PassUint8Struct4BytesInlineArrayMultiDimensionalIn",
+ isLeaf: true);
+
+/// Test struct in multi dimensional inline array.
+void testPassUint8Struct4BytesInlineArrayMultiDimensionalInLeaf() {
+ int a0;
+ final a1Pointer = calloc<Struct4BytesInlineArrayMultiDimensionalInt>();
+ final Struct4BytesInlineArrayMultiDimensionalInt a1 = a1Pointer.ref;
+ int a2;
+
+ a0 = 1;
+ a1.a0[0][0].a0 = 2;
+ a1.a0[0][1].a0 = -3;
+ a1.a0[1][0].a0 = 4;
+ a1.a0[1][1].a0 = -5;
+ a2 = 6;
+
+ final result =
+ passUint8Struct4BytesInlineArrayMultiDimensionalInLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(5, result);
+
+ calloc.free(a1Pointer);
+}
+
+final passStruct3BytesPackedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt),
+ int Function(
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt,
+ Struct3BytesPackedInt)>("PassStruct3BytesPackedIntx10", isLeaf: true);
+
+/// Small struct with mis-aligned member.
+void testPassStruct3BytesPackedIntx10Leaf() {
+ final a0Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct3BytesPackedInt>();
+ final Struct3BytesPackedInt a9 = a9Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+ a2.a0 = -5;
+ a2.a1 = 6;
+ a3.a0 = -7;
+ a3.a1 = 8;
+ a4.a0 = -9;
+ a4.a1 = 10;
+ a5.a0 = -11;
+ a5.a1 = 12;
+ a6.a0 = -13;
+ a6.a1 = 14;
+ a7.a0 = -15;
+ a7.a1 = 16;
+ a8.a0 = -17;
+ a8.a1 = 18;
+ a9.a0 = -19;
+ a9.a1 = 20;
+
+ final result =
+ passStruct3BytesPackedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(10, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct8BytesPackedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Int64 Function(
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt),
+ int Function(
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt,
+ Struct8BytesPackedInt)>("PassStruct8BytesPackedIntx10", isLeaf: true);
+
+/// Struct with mis-aligned member.
+void testPassStruct8BytesPackedIntx10Leaf() {
+ final a0Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct8BytesPackedInt>();
+ final Struct8BytesPackedInt a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1 = 2;
+ a0.a2 = 3;
+ a0.a3 = 4;
+ a0.a4 = 5;
+ a1.a0 = 6;
+ a1.a1 = 7;
+ a1.a2 = 8;
+ a1.a3 = 9;
+ a1.a4 = 10;
+ a2.a0 = 11;
+ a2.a1 = 12;
+ a2.a2 = 13;
+ a2.a3 = 14;
+ a2.a4 = 15;
+ a3.a0 = 16;
+ a3.a1 = 17;
+ a3.a2 = 18;
+ a3.a3 = 19;
+ a3.a4 = 20;
+ a4.a0 = 21;
+ a4.a1 = 22;
+ a4.a2 = 23;
+ a4.a3 = 24;
+ a4.a4 = 25;
+ a5.a0 = 26;
+ a5.a1 = 27;
+ a5.a2 = 28;
+ a5.a3 = 29;
+ a5.a4 = 30;
+ a6.a0 = 31;
+ a6.a1 = 32;
+ a6.a2 = 33;
+ a6.a3 = 34;
+ a6.a4 = 35;
+ a7.a0 = 36;
+ a7.a1 = 37;
+ a7.a2 = 38;
+ a7.a3 = 39;
+ a7.a4 = 40;
+ a8.a0 = 41;
+ a8.a1 = 42;
+ a8.a2 = 43;
+ a8.a3 = 44;
+ a8.a4 = 45;
+ a9.a0 = 46;
+ a9.a1 = 47;
+ a9.a2 = 48;
+ a9.a3 = 49;
+ a9.a4 = 50;
+
+ final result =
+ passStruct8BytesPackedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.equals(1275, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct9BytesPackedMixedx10DoubleInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Double,
+ Int32),
+ double Function(
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ Struct9BytesPackedMixed,
+ double,
+ int)>("PassStruct9BytesPackedMixedx10DoubleInt32", isLeaf: true);
+
+/// Struct with mis-aligned member.
+/// Tests backfilling of CPU and FPU registers.
+void testPassStruct9BytesPackedMixedx10DoubleInt32Leaf() {
+ final a0Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Struct9BytesPackedMixed>();
+ final Struct9BytesPackedMixed a9 = a9Pointer.ref;
+ double a10;
+ int a11;
+
+ a0.a0 = 1;
+ a0.a1 = 2.0;
+ a1.a0 = 3;
+ a1.a1 = 4.0;
+ a2.a0 = 5;
+ a2.a1 = 6.0;
+ a3.a0 = 7;
+ a3.a1 = 8.0;
+ a4.a0 = 9;
+ a4.a1 = 10.0;
+ a5.a0 = 11;
+ a5.a1 = 12.0;
+ a6.a0 = 13;
+ a6.a1 = 14.0;
+ a7.a0 = 15;
+ a7.a1 = 16.0;
+ a8.a0 = 17;
+ a8.a1 = 18.0;
+ a9.a0 = 19;
+ a9.a1 = 20.0;
+ a10 = -21.0;
+ a11 = 22;
+
+ final result = passStruct9BytesPackedMixedx10DoubleInt32Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+
+ print("result = $result");
+
+ Expect.approxEquals(211.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passStruct5BytesPackedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct5BytesPackedMixed),
+ double Function(
+ Struct5BytesPackedMixed)>("PassStruct5BytesPackedMixed", isLeaf: true);
+
+/// This packed struct happens to have only aligned members.
+void testPassStruct5BytesPackedMixedLeaf() {
+ final a0Pointer = calloc<Struct5BytesPackedMixed>();
+ final Struct5BytesPackedMixed a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2;
+
+ final result = passStruct5BytesPackedMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(1.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStructNestedAlignmentStruct5BytesPackedMixedLeaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(StructNestedAlignmentStruct5BytesPackedMixed),
+ double Function(StructNestedAlignmentStruct5BytesPackedMixed)>(
+ "PassStructNestedAlignmentStruct5BytesPackedMixed",
+ isLeaf: true);
+
+/// Check alignment of packed struct in non-packed struct.
+void testPassStructNestedAlignmentStruct5BytesPackedMixedLeaf() {
+ final a0Pointer = calloc<StructNestedAlignmentStruct5BytesPackedMixed>();
+ final StructNestedAlignmentStruct5BytesPackedMixed a0 = a0Pointer.ref;
+
+ a0.a0 = 1;
+ a0.a1.a0 = 2.0;
+ a0.a1.a1 = 3;
+
+ final result = passStructNestedAlignmentStruct5BytesPackedMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(6.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct6BytesInlineArrayIntLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct6BytesInlineArrayInt),
+ double Function(Struct6BytesInlineArrayInt)>(
+ "PassStruct6BytesInlineArrayInt",
+ isLeaf: true);
+
+/// Check alignment of packed struct array in non-packed struct.
+void testPassStruct6BytesInlineArrayIntLeaf() {
+ final a0Pointer = calloc<Struct6BytesInlineArrayInt>();
+ final Struct6BytesInlineArrayInt a0 = a0Pointer.ref;
+
+ a0.a0[0].a0 = -1;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3;
+ a0.a0[1].a1 = 4;
+
+ final result = passStruct6BytesInlineArrayIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(2.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passStruct15BytesInlineArrayMixedLeaf = ffiTestFunctions.lookupFunction<
+ Double Function(Struct15BytesInlineArrayMixed),
+ double Function(Struct15BytesInlineArrayMixed)>(
+ "PassStruct15BytesInlineArrayMixed",
+ isLeaf: true);
+
+/// Check alignment of packed struct array in non-packed struct.
+void testPassStruct15BytesInlineArrayMixedLeaf() {
+ final a0Pointer = calloc<Struct15BytesInlineArrayMixed>();
+ final Struct15BytesInlineArrayMixed a0 = a0Pointer.ref;
+
+ a0.a0[0].a0 = -1.0;
+ a0.a0[0].a1 = 2;
+ a0.a0[1].a0 = -3.0;
+ a0.a0[1].a1 = 4;
+ a0.a0[2].a0 = -5.0;
+ a0.a0[2].a1 = 6;
+
+ final result = passStruct15BytesInlineArrayMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(3.0, result);
+
+ calloc.free(a0Pointer);
+}
+
+final passUnion4BytesMixedx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed),
+ double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed)>("PassUnion4BytesMixedx10", isLeaf: true);
+
+/// Check placement of mixed integer/float union.
+void testPassUnion4BytesMixedx10Leaf() {
+ final a0Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a1.a0 = 2;
+ a2.a0 = 3;
+ a3.a0 = 4;
+ a4.a0 = 5;
+ a5.a0 = 6;
+ a6.a0 = 7;
+ a7.a0 = 8;
+ a8.a0 = 9;
+ a9.a0 = 10;
+
+ final result =
+ passUnion4BytesMixedx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(55.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion8BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat),
+ double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat)>("PassUnion8BytesNestedFloatx10", isLeaf: true);
+
+/// Check placement of mixed floats union.
+void testPassUnion8BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+ a2.a0 = -3.0;
+ a3.a0 = 4.0;
+ a4.a0 = -5.0;
+ a5.a0 = 6.0;
+ a6.a0 = -7.0;
+ a7.a0 = 8.0;
+ a8.a0 = -9.0;
+ a9.a0 = 10.0;
+
+ final result =
+ passUnion8BytesNestedFloatx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion9BytesNestedIntx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt),
+ double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt)>("PassUnion9BytesNestedIntx10", isLeaf: true);
+
+/// Mixed-size union argument.
+void testPassUnion9BytesNestedIntx10Leaf() {
+ final a0Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a0.a2 = 6;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a0.a2 = -9;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a0.a2 = 12;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a0.a2 = -15;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a0.a2 = 18;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a0.a2 = -21;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a0.a2 = 24;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a0.a2 = -27;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a0.a2 = 30;
+
+ final result =
+ passUnion9BytesNestedIntx10Leaf(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedInlineArrayFloatx10Leaf =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat),
+ double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat)>(
+ "PassUnion16BytesNestedInlineArrayFloatx10",
+ isLeaf: true);
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedInlineArrayFloatx10Leaf() {
+ final a0Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a9 = a9Pointer.ref;
+
+ a0.a0[0] = -1.0;
+ a0.a0[1] = 2.0;
+ a0.a0[2] = -3.0;
+ a0.a0[3] = 4.0;
+ a1.a0[0] = -5.0;
+ a1.a0[1] = 6.0;
+ a1.a0[2] = -7.0;
+ a1.a0[3] = 8.0;
+ a2.a0[0] = -9.0;
+ a2.a0[1] = 10.0;
+ a2.a0[2] = -11.0;
+ a2.a0[3] = 12.0;
+ a3.a0[0] = -13.0;
+ a3.a0[1] = 14.0;
+ a3.a0[2] = -15.0;
+ a3.a0[3] = 16.0;
+ a4.a0[0] = -17.0;
+ a4.a0[1] = 18.0;
+ a4.a0[2] = -19.0;
+ a4.a0[3] = 20.0;
+ a5.a0[0] = -21.0;
+ a5.a0[1] = 22.0;
+ a5.a0[2] = -23.0;
+ a5.a0[3] = 24.0;
+ a6.a0[0] = -25.0;
+ a6.a0[1] = 26.0;
+ a6.a0[2] = -27.0;
+ a6.a0[3] = 28.0;
+ a7.a0[0] = -29.0;
+ a7.a0[1] = 30.0;
+ a7.a0[2] = -31.0;
+ a7.a0[3] = 32.0;
+ a8.a0[0] = -33.0;
+ a8.a0[1] = 34.0;
+ a8.a0[2] = -35.0;
+ a8.a0[3] = 36.0;
+ a9.a0[0] = -37.0;
+ a9.a0[1] = 38.0;
+ a9.a0[2] = -39.0;
+ a9.a0[3] = 40.0;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedFloatx10Leaf = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat),
+ double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat)>("PassUnion16BytesNestedFloatx10",
+ isLeaf: true);
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedFloatx10Leaf() {
+ final a0Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a0.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a0.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a0.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a0.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a0.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a0.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a0.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a0.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a0.a1 = 20.0;
+
+ final result = passUnion16BytesNestedFloatx10Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final returnStruct1ByteIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Int8),
+ Struct1ByteInt Function(int)>("ReturnStruct1ByteInt", isLeaf: true);
+
+/// Smallest struct with data.
+void testReturnStruct1ByteIntLeaf() {
+ int a0;
+
+ a0 = -1;
+
+ final result = returnStruct1ByteIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnStruct3BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesHomogeneousUint8 Function(Uint8, Uint8, Uint8),
+ Struct3BytesHomogeneousUint8 Function(
+ int, int, int)>("ReturnStruct3BytesHomogeneousUint8", isLeaf: true);
+
+/// Smaller than word size return value on all architectures.
+void testReturnStruct3BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+
+ final result = returnStruct3BytesHomogeneousUint8Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct3BytesInt2ByteAlignedLeaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesInt2ByteAligned Function(Int16, Int8),
+ Struct3BytesInt2ByteAligned Function(
+ int, int)>("ReturnStruct3BytesInt2ByteAligned", isLeaf: true);
+
+/// Smaller than word size return value on all architectures.
+/// With alignment rules taken into account size is 4 bytes.
+void testReturnStruct3BytesInt2ByteAlignedLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct3BytesInt2ByteAlignedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct4BytesHomogeneousInt16Leaf = ffiTestFunctions.lookupFunction<
+ Struct4BytesHomogeneousInt16 Function(Int16, Int16),
+ Struct4BytesHomogeneousInt16 Function(
+ int, int)>("ReturnStruct4BytesHomogeneousInt16", isLeaf: true);
+
+/// Word size return value on 32 bit architectures..
+void testReturnStruct4BytesHomogeneousInt16Leaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct4BytesHomogeneousInt16Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct7BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct7BytesHomogeneousUint8 Function(
+ Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+ Struct7BytesHomogeneousUint8 Function(int, int, int, int, int, int,
+ int)>("ReturnStruct7BytesHomogeneousUint8", isLeaf: true);
+
+/// Non-wordsize return value.
+void testReturnStruct7BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+
+ final result =
+ returnStruct7BytesHomogeneousUint8Leaf(a0, a1, a2, a3, a4, a5, a6);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+}
+
+final returnStruct7BytesInt4ByteAlignedLeaf = ffiTestFunctions.lookupFunction<
+ Struct7BytesInt4ByteAligned Function(Int32, Int16, Int8),
+ Struct7BytesInt4ByteAligned Function(
+ int, int, int)>("ReturnStruct7BytesInt4ByteAligned", isLeaf: true);
+
+/// Non-wordsize return value.
+/// With alignment rules taken into account size is 8 bytes.
+void testReturnStruct7BytesInt4ByteAlignedLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct7BytesInt4ByteAlignedLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesInt Function(Int16, Int16, Int32),
+ Struct8BytesInt Function(
+ int, int, int)>("ReturnStruct8BytesInt", isLeaf: true);
+
+/// Return value in integer registers on many architectures.
+void testReturnStruct8BytesIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct8BytesIntLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesHomogeneousFloat Function(Float, Float),
+ Struct8BytesHomogeneousFloat Function(
+ double, double)>("ReturnStruct8BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FP registers on many architectures.
+void testReturnStruct8BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+
+ a0 = -1.0;
+ a1 = 2.0;
+
+ final result = returnStruct8BytesHomogeneousFloatLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+}
+
+final returnStruct8BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesMixed Function(Float, Int16, Int16),
+ Struct8BytesMixed Function(
+ double, int, int)>("ReturnStruct8BytesMixed", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct8BytesMixedLeaf() {
+ double a0;
+ int a1;
+ int a2;
+
+ a0 = -1.0;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct8BytesMixedLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct9BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct9BytesHomogeneousUint8 Function(
+ Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+ Struct9BytesHomogeneousUint8 Function(int, int, int, int, int, int, int,
+ int, int)>("ReturnStruct9BytesHomogeneousUint8", isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is the right size and that
+/// dart:ffi trampolines do not write outside this size.
+void testReturnStruct9BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+
+ final result = returnStruct9BytesHomogeneousUint8Leaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+}
+
+final returnStruct9BytesInt4Or8ByteAlignedLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct9BytesInt4Or8ByteAligned Function(Int64, Int8),
+ Struct9BytesInt4Or8ByteAligned Function(
+ int, int)>("ReturnStruct9BytesInt4Or8ByteAligned", isLeaf: true);
+
+/// Return value in two integer registers on x64.
+/// With alignment rules taken into account size is 12 or 16 bytes.
+void testReturnStruct9BytesInt4Or8ByteAlignedLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct9BytesInt4Or8ByteAlignedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct12BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct12BytesHomogeneousFloat Function(Float, Float, Float),
+ Struct12BytesHomogeneousFloat Function(double, double,
+ double)>("ReturnStruct12BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+void testReturnStruct12BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+
+ final result = returnStruct12BytesHomogeneousFloatLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+}
+
+final returnStruct16BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesHomogeneousFloat Function(Float, Float, Float, Float),
+ Struct16BytesHomogeneousFloat Function(double, double, double,
+ double)>("ReturnStruct16BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStruct16BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+
+ final result = returnStruct16BytesHomogeneousFloatLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+}
+
+final returnStruct16BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesMixed Function(Double, Int64),
+ Struct16BytesMixed Function(
+ double, int)>("ReturnStruct16BytesMixed", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct16BytesMixedLeaf() {
+ double a0;
+ int a1;
+
+ a0 = -1.0;
+ a1 = 2;
+
+ final result = returnStruct16BytesMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct16BytesMixed2Leaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesMixed2 Function(Float, Float, Float, Int32),
+ Struct16BytesMixed2 Function(double, double, double,
+ int)>("ReturnStruct16BytesMixed2", isLeaf: true);
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+void testReturnStruct16BytesMixed2Leaf() {
+ double a0;
+ double a1;
+ double a2;
+ int a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4;
+
+ final result = returnStruct16BytesMixed2Leaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+}
+
+final returnStruct17BytesIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct17BytesInt Function(Int64, Int64, Int8),
+ Struct17BytesInt Function(
+ int, int, int)>("ReturnStruct17BytesInt", isLeaf: true);
+
+/// Rerturn value returned in preallocated space passed by pointer on most ABIs.
+/// Is non word size on purpose, to test that structs are rounded up to word size
+/// on all ABIs.
+void testReturnStruct17BytesIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStruct17BytesIntLeaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct19BytesHomogeneousUint8Leaf = ffiTestFunctions.lookupFunction<
+ Struct19BytesHomogeneousUint8 Function(
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8,
+ Uint8),
+ Struct19BytesHomogeneousUint8 Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int)>("ReturnStruct19BytesHomogeneousUint8", isLeaf: true);
+
+/// The minimum alignment of this struct is only 1 byte based on its fields.
+/// Test that the memory backing these structs is the right size and that
+/// dart:ffi trampolines do not write outside this size.
+void testReturnStruct19BytesHomogeneousUint8Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+ int a9;
+ int a10;
+ int a11;
+ int a12;
+ int a13;
+ int a14;
+ int a15;
+ int a16;
+ int a17;
+ int a18;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+ a9 = 10;
+ a10 = 11;
+ a11 = 12;
+ a12 = 13;
+ a13 = 14;
+ a14 = 15;
+ a15 = 16;
+ a16 = 17;
+ a17 = 18;
+ a18 = 19;
+
+ final result = returnStruct19BytesHomogeneousUint8Leaf(a0, a1, a2, a3, a4, a5,
+ a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+ Expect.equals(a9, result.a9);
+ Expect.equals(a10, result.a10);
+ Expect.equals(a11, result.a11);
+ Expect.equals(a12, result.a12);
+ Expect.equals(a13, result.a13);
+ Expect.equals(a14, result.a14);
+ Expect.equals(a15, result.a15);
+ Expect.equals(a16, result.a16);
+ Expect.equals(a17, result.a17);
+ Expect.equals(a18, result.a18);
+}
+
+final returnStruct20BytesHomogeneousInt32Leaf = ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32),
+ Struct20BytesHomogeneousInt32 Function(int, int, int, int,
+ int)>("ReturnStruct20BytesHomogeneousInt32", isLeaf: true);
+
+/// Return value too big to go in cpu registers on arm64.
+void testReturnStruct20BytesHomogeneousInt32Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+
+ final result = returnStruct20BytesHomogeneousInt32Leaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+}
+
+final returnStruct20BytesHomogeneousFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousFloat Function(Float, Float, Float, Float, Float),
+ Struct20BytesHomogeneousFloat Function(double, double, double, double,
+ double)>("ReturnStruct20BytesHomogeneousFloat", isLeaf: true);
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+void testReturnStruct20BytesHomogeneousFloatLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+
+ final result = returnStruct20BytesHomogeneousFloatLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+ Expect.approxEquals(a4, result.a4);
+}
+
+final returnStruct32BytesHomogeneousDoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double),
+ Struct32BytesHomogeneousDouble Function(double, double, double,
+ double)>("ReturnStruct32BytesHomogeneousDouble", isLeaf: true);
+
+/// Return value in FPU registers on arm64.
+void testReturnStruct32BytesHomogeneousDoubleLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+
+ final result = returnStruct32BytesHomogeneousDoubleLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+}
+
+final returnStruct40BytesHomogeneousDoubleLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct40BytesHomogeneousDouble Function(
+ Double, Double, Double, Double, Double),
+ Struct40BytesHomogeneousDouble Function(double, double, double, double,
+ double)>("ReturnStruct40BytesHomogeneousDouble", isLeaf: true);
+
+/// Return value too big to go in FPU registers on arm64.
+void testReturnStruct40BytesHomogeneousDoubleLeaf() {
+ double a0;
+ double a1;
+ double a2;
+ double a3;
+ double a4;
+
+ a0 = -1.0;
+ a1 = 2.0;
+ a2 = -3.0;
+ a3 = 4.0;
+ a4 = -5.0;
+
+ final result = returnStruct40BytesHomogeneousDoubleLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+ Expect.approxEquals(a2, result.a2);
+ Expect.approxEquals(a3, result.a3);
+ Expect.approxEquals(a4, result.a4);
+}
+
+final returnStruct1024BytesHomogeneousUint64Leaf =
+ ffiTestFunctions.lookupFunction<
+ Struct1024BytesHomogeneousUint64 Function(
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64,
+ Uint64),
+ Struct1024BytesHomogeneousUint64 Function(
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int,
+ int)>("ReturnStruct1024BytesHomogeneousUint64", isLeaf: true);
+
+/// Test 1kb struct.
+void testReturnStruct1024BytesHomogeneousUint64Leaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ int a8;
+ int a9;
+ int a10;
+ int a11;
+ int a12;
+ int a13;
+ int a14;
+ int a15;
+ int a16;
+ int a17;
+ int a18;
+ int a19;
+ int a20;
+ int a21;
+ int a22;
+ int a23;
+ int a24;
+ int a25;
+ int a26;
+ int a27;
+ int a28;
+ int a29;
+ int a30;
+ int a31;
+ int a32;
+ int a33;
+ int a34;
+ int a35;
+ int a36;
+ int a37;
+ int a38;
+ int a39;
+ int a40;
+ int a41;
+ int a42;
+ int a43;
+ int a44;
+ int a45;
+ int a46;
+ int a47;
+ int a48;
+ int a49;
+ int a50;
+ int a51;
+ int a52;
+ int a53;
+ int a54;
+ int a55;
+ int a56;
+ int a57;
+ int a58;
+ int a59;
+ int a60;
+ int a61;
+ int a62;
+ int a63;
+ int a64;
+ int a65;
+ int a66;
+ int a67;
+ int a68;
+ int a69;
+ int a70;
+ int a71;
+ int a72;
+ int a73;
+ int a74;
+ int a75;
+ int a76;
+ int a77;
+ int a78;
+ int a79;
+ int a80;
+ int a81;
+ int a82;
+ int a83;
+ int a84;
+ int a85;
+ int a86;
+ int a87;
+ int a88;
+ int a89;
+ int a90;
+ int a91;
+ int a92;
+ int a93;
+ int a94;
+ int a95;
+ int a96;
+ int a97;
+ int a98;
+ int a99;
+ int a100;
+ int a101;
+ int a102;
+ int a103;
+ int a104;
+ int a105;
+ int a106;
+ int a107;
+ int a108;
+ int a109;
+ int a110;
+ int a111;
+ int a112;
+ int a113;
+ int a114;
+ int a115;
+ int a116;
+ int a117;
+ int a118;
+ int a119;
+ int a120;
+ int a121;
+ int a122;
+ int a123;
+ int a124;
+ int a125;
+ int a126;
+ int a127;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+ a5 = 6;
+ a6 = 7;
+ a7 = 8;
+ a8 = 9;
+ a9 = 10;
+ a10 = 11;
+ a11 = 12;
+ a12 = 13;
+ a13 = 14;
+ a14 = 15;
+ a15 = 16;
+ a16 = 17;
+ a17 = 18;
+ a18 = 19;
+ a19 = 20;
+ a20 = 21;
+ a21 = 22;
+ a22 = 23;
+ a23 = 24;
+ a24 = 25;
+ a25 = 26;
+ a26 = 27;
+ a27 = 28;
+ a28 = 29;
+ a29 = 30;
+ a30 = 31;
+ a31 = 32;
+ a32 = 33;
+ a33 = 34;
+ a34 = 35;
+ a35 = 36;
+ a36 = 37;
+ a37 = 38;
+ a38 = 39;
+ a39 = 40;
+ a40 = 41;
+ a41 = 42;
+ a42 = 43;
+ a43 = 44;
+ a44 = 45;
+ a45 = 46;
+ a46 = 47;
+ a47 = 48;
+ a48 = 49;
+ a49 = 50;
+ a50 = 51;
+ a51 = 52;
+ a52 = 53;
+ a53 = 54;
+ a54 = 55;
+ a55 = 56;
+ a56 = 57;
+ a57 = 58;
+ a58 = 59;
+ a59 = 60;
+ a60 = 61;
+ a61 = 62;
+ a62 = 63;
+ a63 = 64;
+ a64 = 65;
+ a65 = 66;
+ a66 = 67;
+ a67 = 68;
+ a68 = 69;
+ a69 = 70;
+ a70 = 71;
+ a71 = 72;
+ a72 = 73;
+ a73 = 74;
+ a74 = 75;
+ a75 = 76;
+ a76 = 77;
+ a77 = 78;
+ a78 = 79;
+ a79 = 80;
+ a80 = 81;
+ a81 = 82;
+ a82 = 83;
+ a83 = 84;
+ a84 = 85;
+ a85 = 86;
+ a86 = 87;
+ a87 = 88;
+ a88 = 89;
+ a89 = 90;
+ a90 = 91;
+ a91 = 92;
+ a92 = 93;
+ a93 = 94;
+ a94 = 95;
+ a95 = 96;
+ a96 = 97;
+ a97 = 98;
+ a98 = 99;
+ a99 = 100;
+ a100 = 101;
+ a101 = 102;
+ a102 = 103;
+ a103 = 104;
+ a104 = 105;
+ a105 = 106;
+ a106 = 107;
+ a107 = 108;
+ a108 = 109;
+ a109 = 110;
+ a110 = 111;
+ a111 = 112;
+ a112 = 113;
+ a113 = 114;
+ a114 = 115;
+ a115 = 116;
+ a116 = 117;
+ a117 = 118;
+ a118 = 119;
+ a119 = 120;
+ a120 = 121;
+ a121 = 122;
+ a122 = 123;
+ a123 = 124;
+ a124 = 125;
+ a125 = 126;
+ a126 = 127;
+ a127 = 128;
+
+ final result = returnStruct1024BytesHomogeneousUint64Leaf(
+ a0,
+ a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6,
+ a7,
+ a8,
+ a9,
+ a10,
+ a11,
+ a12,
+ a13,
+ a14,
+ a15,
+ a16,
+ a17,
+ a18,
+ a19,
+ a20,
+ a21,
+ a22,
+ a23,
+ a24,
+ a25,
+ a26,
+ a27,
+ a28,
+ a29,
+ a30,
+ a31,
+ a32,
+ a33,
+ a34,
+ a35,
+ a36,
+ a37,
+ a38,
+ a39,
+ a40,
+ a41,
+ a42,
+ a43,
+ a44,
+ a45,
+ a46,
+ a47,
+ a48,
+ a49,
+ a50,
+ a51,
+ a52,
+ a53,
+ a54,
+ a55,
+ a56,
+ a57,
+ a58,
+ a59,
+ a60,
+ a61,
+ a62,
+ a63,
+ a64,
+ a65,
+ a66,
+ a67,
+ a68,
+ a69,
+ a70,
+ a71,
+ a72,
+ a73,
+ a74,
+ a75,
+ a76,
+ a77,
+ a78,
+ a79,
+ a80,
+ a81,
+ a82,
+ a83,
+ a84,
+ a85,
+ a86,
+ a87,
+ a88,
+ a89,
+ a90,
+ a91,
+ a92,
+ a93,
+ a94,
+ a95,
+ a96,
+ a97,
+ a98,
+ a99,
+ a100,
+ a101,
+ a102,
+ a103,
+ a104,
+ a105,
+ a106,
+ a107,
+ a108,
+ a109,
+ a110,
+ a111,
+ a112,
+ a113,
+ a114,
+ a115,
+ a116,
+ a117,
+ a118,
+ a119,
+ a120,
+ a121,
+ a122,
+ a123,
+ a124,
+ a125,
+ a126,
+ a127);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+ Expect.equals(a5, result.a5);
+ Expect.equals(a6, result.a6);
+ Expect.equals(a7, result.a7);
+ Expect.equals(a8, result.a8);
+ Expect.equals(a9, result.a9);
+ Expect.equals(a10, result.a10);
+ Expect.equals(a11, result.a11);
+ Expect.equals(a12, result.a12);
+ Expect.equals(a13, result.a13);
+ Expect.equals(a14, result.a14);
+ Expect.equals(a15, result.a15);
+ Expect.equals(a16, result.a16);
+ Expect.equals(a17, result.a17);
+ Expect.equals(a18, result.a18);
+ Expect.equals(a19, result.a19);
+ Expect.equals(a20, result.a20);
+ Expect.equals(a21, result.a21);
+ Expect.equals(a22, result.a22);
+ Expect.equals(a23, result.a23);
+ Expect.equals(a24, result.a24);
+ Expect.equals(a25, result.a25);
+ Expect.equals(a26, result.a26);
+ Expect.equals(a27, result.a27);
+ Expect.equals(a28, result.a28);
+ Expect.equals(a29, result.a29);
+ Expect.equals(a30, result.a30);
+ Expect.equals(a31, result.a31);
+ Expect.equals(a32, result.a32);
+ Expect.equals(a33, result.a33);
+ Expect.equals(a34, result.a34);
+ Expect.equals(a35, result.a35);
+ Expect.equals(a36, result.a36);
+ Expect.equals(a37, result.a37);
+ Expect.equals(a38, result.a38);
+ Expect.equals(a39, result.a39);
+ Expect.equals(a40, result.a40);
+ Expect.equals(a41, result.a41);
+ Expect.equals(a42, result.a42);
+ Expect.equals(a43, result.a43);
+ Expect.equals(a44, result.a44);
+ Expect.equals(a45, result.a45);
+ Expect.equals(a46, result.a46);
+ Expect.equals(a47, result.a47);
+ Expect.equals(a48, result.a48);
+ Expect.equals(a49, result.a49);
+ Expect.equals(a50, result.a50);
+ Expect.equals(a51, result.a51);
+ Expect.equals(a52, result.a52);
+ Expect.equals(a53, result.a53);
+ Expect.equals(a54, result.a54);
+ Expect.equals(a55, result.a55);
+ Expect.equals(a56, result.a56);
+ Expect.equals(a57, result.a57);
+ Expect.equals(a58, result.a58);
+ Expect.equals(a59, result.a59);
+ Expect.equals(a60, result.a60);
+ Expect.equals(a61, result.a61);
+ Expect.equals(a62, result.a62);
+ Expect.equals(a63, result.a63);
+ Expect.equals(a64, result.a64);
+ Expect.equals(a65, result.a65);
+ Expect.equals(a66, result.a66);
+ Expect.equals(a67, result.a67);
+ Expect.equals(a68, result.a68);
+ Expect.equals(a69, result.a69);
+ Expect.equals(a70, result.a70);
+ Expect.equals(a71, result.a71);
+ Expect.equals(a72, result.a72);
+ Expect.equals(a73, result.a73);
+ Expect.equals(a74, result.a74);
+ Expect.equals(a75, result.a75);
+ Expect.equals(a76, result.a76);
+ Expect.equals(a77, result.a77);
+ Expect.equals(a78, result.a78);
+ Expect.equals(a79, result.a79);
+ Expect.equals(a80, result.a80);
+ Expect.equals(a81, result.a81);
+ Expect.equals(a82, result.a82);
+ Expect.equals(a83, result.a83);
+ Expect.equals(a84, result.a84);
+ Expect.equals(a85, result.a85);
+ Expect.equals(a86, result.a86);
+ Expect.equals(a87, result.a87);
+ Expect.equals(a88, result.a88);
+ Expect.equals(a89, result.a89);
+ Expect.equals(a90, result.a90);
+ Expect.equals(a91, result.a91);
+ Expect.equals(a92, result.a92);
+ Expect.equals(a93, result.a93);
+ Expect.equals(a94, result.a94);
+ Expect.equals(a95, result.a95);
+ Expect.equals(a96, result.a96);
+ Expect.equals(a97, result.a97);
+ Expect.equals(a98, result.a98);
+ Expect.equals(a99, result.a99);
+ Expect.equals(a100, result.a100);
+ Expect.equals(a101, result.a101);
+ Expect.equals(a102, result.a102);
+ Expect.equals(a103, result.a103);
+ Expect.equals(a104, result.a104);
+ Expect.equals(a105, result.a105);
+ Expect.equals(a106, result.a106);
+ Expect.equals(a107, result.a107);
+ Expect.equals(a108, result.a108);
+ Expect.equals(a109, result.a109);
+ Expect.equals(a110, result.a110);
+ Expect.equals(a111, result.a111);
+ Expect.equals(a112, result.a112);
+ Expect.equals(a113, result.a113);
+ Expect.equals(a114, result.a114);
+ Expect.equals(a115, result.a115);
+ Expect.equals(a116, result.a116);
+ Expect.equals(a117, result.a117);
+ Expect.equals(a118, result.a118);
+ Expect.equals(a119, result.a119);
+ Expect.equals(a120, result.a120);
+ Expect.equals(a121, result.a121);
+ Expect.equals(a122, result.a122);
+ Expect.equals(a123, result.a123);
+ Expect.equals(a124, result.a124);
+ Expect.equals(a125, result.a125);
+ Expect.equals(a126, result.a126);
+ Expect.equals(a127, result.a127);
+}
+
+final returnStruct3BytesPackedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct3BytesPackedInt Function(Int8, Int16),
+ Struct3BytesPackedInt Function(
+ int, int)>("ReturnStruct3BytesPackedInt", isLeaf: true);
+
+/// Small struct with mis-aligned member.
+void testReturnStruct3BytesPackedIntLeaf() {
+ int a0;
+ int a1;
+
+ a0 = -1;
+ a1 = 2;
+
+ final result = returnStruct3BytesPackedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+}
+
+final returnStruct8BytesPackedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesPackedInt Function(Uint8, Uint32, Uint8, Uint8, Uint8),
+ Struct8BytesPackedInt Function(
+ int, int, int, int, int)>("ReturnStruct8BytesPackedInt", isLeaf: true);
+
+/// Struct with mis-aligned member.
+void testReturnStruct8BytesPackedIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+
+ a0 = 1;
+ a1 = 2;
+ a2 = 3;
+ a3 = 4;
+ a4 = 5;
+
+ final result = returnStruct8BytesPackedIntLeaf(a0, a1, a2, a3, a4);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+ Expect.equals(a3, result.a3);
+ Expect.equals(a4, result.a4);
+}
+
+final returnStruct9BytesPackedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct9BytesPackedMixed Function(Uint8, Double),
+ Struct9BytesPackedMixed Function(
+ int, double)>("ReturnStruct9BytesPackedMixed", isLeaf: true);
+
+/// Struct with mis-aligned member.
+/// Tests backfilling of CPU and FPU registers.
+void testReturnStruct9BytesPackedMixedLeaf() {
+ int a0;
+ double a1;
+
+ a0 = 1;
+ a1 = 2.0;
+
+ final result = returnStruct9BytesPackedMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.approxEquals(a1, result.a1);
+}
+
+final returnUnion4BytesMixedLeaf = ffiTestFunctions.lookupFunction<
+ Union4BytesMixed Function(Uint32),
+ Union4BytesMixed Function(int)>("ReturnUnion4BytesMixed", isLeaf: true);
+
+/// Returning a mixed integer/float union.
+void testReturnUnion4BytesMixedLeaf() {
+ int a0;
+
+ a0 = 1;
+
+ final result = returnUnion4BytesMixedLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnUnion8BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Union8BytesNestedFloat Function(Double),
+ Union8BytesNestedFloat Function(
+ double)>("ReturnUnion8BytesNestedFloat", isLeaf: true);
+
+/// Returning a floating point only union.
+void testReturnUnion8BytesNestedFloatLeaf() {
+ double a0;
+
+ a0 = -1.0;
+
+ final result = returnUnion8BytesNestedFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+}
+
+final returnUnion9BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Union9BytesNestedInt Function(Struct8BytesInt),
+ Union9BytesNestedInt Function(
+ Struct8BytesInt)>("ReturnUnion9BytesNestedInt", isLeaf: true);
+
+/// Returning a mixed-size union.
+void testReturnUnion9BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = returnUnion9BytesNestedIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnUnion16BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat),
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat)>(
+ "ReturnUnion16BytesNestedFloat",
+ isLeaf: true);
+
+/// Returning union with homogenous floats.
+void testReturnUnion16BytesNestedFloatLeaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnUnion16BytesNestedFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a0.a1, result.a0.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStruct1ByteIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Struct1ByteInt),
+ Struct1ByteInt Function(
+ Struct1ByteInt)>("ReturnStructArgumentStruct1ByteInt", isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in int registers in most ABIs.
+void testReturnStructArgumentStruct1ByteIntLeaf() {
+ final a0Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+
+ final result = returnStructArgumentStruct1ByteIntLeaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentInt32x8Struct1ByteIntLeaf =
+ ffiTestFunctions
+ .lookupFunction<
+ Struct1ByteInt Function(Int32, Int32, Int32, Int32, Int32, Int32,
+ Int32, Int32, Struct1ByteInt),
+ Struct1ByteInt Function(
+ int, int, int, int, int, int, int, int, Struct1ByteInt)>(
+ "ReturnStructArgumentInt32x8Struct1ByteInt",
+ isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+void testReturnStructArgumentInt32x8Struct1ByteIntLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ final a8Pointer = calloc<Struct1ByteInt>();
+ final Struct1ByteInt a8 = a8Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8.a0 = -9;
+
+ final result = returnStructArgumentInt32x8Struct1ByteIntLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a8.a0, result.a0);
+
+ calloc.free(a8Pointer);
+}
+
+final returnStructArgumentStruct8BytesHomogeneousFloatLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat),
+ Struct8BytesHomogeneousFloat Function(
+ Struct8BytesHomogeneousFloat)>(
+ "ReturnStructArgumentStruct8BytesHomogeneousFloat",
+ isLeaf: true);
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in float registers in most ABIs.
+void testReturnStructArgumentStruct8BytesHomogeneousFloatLeaf() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnStructArgumentStruct8BytesHomogeneousFloatLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0);
+ Expect.approxEquals(a0.a1, result.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStruct20BytesHomogeneousInt32Leaf =
+ ffiTestFunctions
+ .lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(
+ Struct20BytesHomogeneousInt32),
+ Struct20BytesHomogeneousInt32 Function(
+ Struct20BytesHomogeneousInt32)>(
+ "ReturnStructArgumentStruct20BytesHomogeneousInt32",
+ isLeaf: true);
+
+/// On arm64, both argument and return value are passed in by pointer.
+void testReturnStructArgumentStruct20BytesHomogeneousInt32Leaf() {
+ final a0Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a0.a3 = 4;
+ a0.a4 = -5;
+
+ final result = returnStructArgumentStruct20BytesHomogeneousInt32Leaf(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0);
+ Expect.equals(a0.a1, result.a1);
+ Expect.equals(a0.a2, result.a2);
+ Expect.equals(a0.a3, result.a3);
+ Expect.equals(a0.a4, result.a4);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentInt32x8Struct20BytesHomogeneouLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32,
+ Int32, Int32, Int32, Int32, Struct20BytesHomogeneousInt32),
+ Struct20BytesHomogeneousInt32 Function(int, int, int, int, int, int,
+ int, int, Struct20BytesHomogeneousInt32)>(
+ "ReturnStructArgumentInt32x8Struct20BytesHomogeneou",
+ isLeaf: true);
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+void testReturnStructArgumentInt32x8Struct20BytesHomogeneouLeaf() {
+ int a0;
+ int a1;
+ int a2;
+ int a3;
+ int a4;
+ int a5;
+ int a6;
+ int a7;
+ final a8Pointer = calloc<Struct20BytesHomogeneousInt32>();
+ final Struct20BytesHomogeneousInt32 a8 = a8Pointer.ref;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+ a3 = 4;
+ a4 = -5;
+ a5 = 6;
+ a6 = -7;
+ a7 = 8;
+ a8.a0 = -9;
+ a8.a1 = 10;
+ a8.a2 = -11;
+ a8.a3 = 12;
+ a8.a4 = -13;
+
+ final result = returnStructArgumentInt32x8Struct20BytesHomogeneouLeaf(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ print("result = $result");
+
+ Expect.equals(a8.a0, result.a0);
+ Expect.equals(a8.a1, result.a1);
+ Expect.equals(a8.a2, result.a2);
+ Expect.equals(a8.a3, result.a3);
+ Expect.equals(a8.a4, result.a4);
+
+ calloc.free(a8Pointer);
+}
+
+final returnStructArgumentStruct8BytesInlineArrayIntLeaf =
+ ffiTestFunctions.lookupFunction<
+ Struct8BytesInlineArrayInt Function(Struct8BytesInlineArrayInt),
+ Struct8BytesInlineArrayInt Function(Struct8BytesInlineArrayInt)>(
+ "ReturnStructArgumentStruct8BytesInlineArrayInt",
+ isLeaf: true);
+
+/// Test returning struct with inline array.
+void testReturnStructArgumentStruct8BytesInlineArrayIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesInlineArrayInt>();
+ final Struct8BytesInlineArrayInt a0 = a0Pointer.ref;
+
+ a0.a0[0] = 1;
+ a0.a0[1] = 2;
+ a0.a0[2] = 3;
+ a0.a0[3] = 4;
+ a0.a0[4] = 5;
+ a0.a0[5] = 6;
+ a0.a0[6] = 7;
+ a0.a0[7] = 8;
+
+ final result = returnStructArgumentStruct8BytesInlineArrayIntLeaf(a0);
+
+ print("result = $result");
+
+ for (int i = 0; i < 8; i++) {
+ Expect.equals(a0.a0[i], result.a0[i]);
+ }
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct16BytesHomogeneousLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct16BytesHomogeneousFloat2 Function(
+ StructStruct16BytesHomogeneousFloat2),
+ StructStruct16BytesHomogeneousFloat2 Function(
+ StructStruct16BytesHomogeneousFloat2)>(
+ "ReturnStructArgumentStructStruct16BytesHomogeneous",
+ isLeaf: true);
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStructArgumentStructStruct16BytesHomogeneousLeaf() {
+ final a0Pointer = calloc<StructStruct16BytesHomogeneousFloat2>();
+ final StructStruct16BytesHomogeneousFloat2 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+
+ final result = returnStructArgumentStructStruct16BytesHomogeneousLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 2; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ }
+ Expect.approxEquals(a0.a2, result.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct32BytesHomogeneousLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct32BytesHomogeneousDouble2 Function(
+ StructStruct32BytesHomogeneousDouble2),
+ StructStruct32BytesHomogeneousDouble2 Function(
+ StructStruct32BytesHomogeneousDouble2)>(
+ "ReturnStructArgumentStructStruct32BytesHomogeneous",
+ isLeaf: true);
+
+/// Return value in FPU registers on arm64.
+void testReturnStructArgumentStructStruct32BytesHomogeneousLeaf() {
+ final a0Pointer = calloc<StructStruct32BytesHomogeneousDouble2>();
+ final StructStruct32BytesHomogeneousDouble2 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[1].a0 = -3.0;
+ a0.a2 = 4.0;
+
+ final result = returnStructArgumentStructStruct32BytesHomogeneousLeaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 2; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ }
+ Expect.approxEquals(a0.a2, result.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructArgumentStructStruct16BytesMixed3Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructStruct16BytesMixed3 Function(StructStruct16BytesMixed3),
+ StructStruct16BytesMixed3 Function(StructStruct16BytesMixed3)>(
+ "ReturnStructArgumentStructStruct16BytesMixed3",
+ isLeaf: true);
+
+/// On x64 Linux, return value is split over FP and int registers.
+void testReturnStructArgumentStructStruct16BytesMixed3Leaf() {
+ final a0Pointer = calloc<StructStruct16BytesMixed3>();
+ final StructStruct16BytesMixed3 a0 = a0Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a1[0].a0 = 2.0;
+ a0.a1[0].a1 = -3;
+ a0.a1[0].a2 = 4;
+ a0.a2[0] = -5;
+ a0.a2[1] = 6;
+
+ final result = returnStructArgumentStructStruct16BytesMixed3Leaf(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0.a0, result.a0.a0);
+ for (int i = 0; i < 1; i++) {
+ Expect.approxEquals(a0.a1[i].a0, result.a1[i].a0);
+ Expect.equals(a0.a1[i].a1, result.a1[i].a1);
+ Expect.equals(a0.a1[i].a2, result.a1[i].a2);
+ }
+ for (int i = 0; i < 2; i++) {
+ Expect.equals(a0.a2[i], result.a2[i]);
+ }
+
+ calloc.free(a0Pointer);
+}
+
+final returnStructAlignmentInt16Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt16 Function(Int8, Int16, Int8),
+ StructAlignmentInt16 Function(
+ int, int, int)>("ReturnStructAlignmentInt16", isLeaf: true);
+
+/// Test alignment and padding of 16 byte int within struct.
+void testReturnStructAlignmentInt16Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt16Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt32Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt32 Function(Int8, Int32, Int8),
+ StructAlignmentInt32 Function(
+ int, int, int)>("ReturnStructAlignmentInt32", isLeaf: true);
+
+/// Test alignment and padding of 32 byte int within struct.
+void testReturnStructAlignmentInt32Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt32Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt64Leaf = ffiTestFunctions.lookupFunction<
+ StructAlignmentInt64 Function(Int8, Int64, Int8),
+ StructAlignmentInt64 Function(
+ int, int, int)>("ReturnStructAlignmentInt64", isLeaf: true);
+
+/// Test alignment and padding of 64 byte int within struct.
+void testReturnStructAlignmentInt64Leaf() {
+ int a0;
+ int a1;
+ int a2;
+
+ a0 = -1;
+ a1 = 2;
+ a2 = -3;
+
+ final result = returnStructAlignmentInt64Leaf(a0, a1, a2);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1, result.a1);
+ Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedInt Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesHomogeneousInt16),
+ Struct8BytesNestedInt Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesHomogeneousInt16)>(
+ "ReturnStruct8BytesNestedInt",
+ isLeaf: true);
+
+/// Simple nested struct.
+void testReturnStruct8BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3;
+ a1.a1 = 4;
+
+ final result = returnStruct8BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct8BytesNestedFloatLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedFloat Function(Struct4BytesFloat, Struct4BytesFloat),
+ Struct8BytesNestedFloat Function(Struct4BytesFloat,
+ Struct4BytesFloat)>("ReturnStruct8BytesNestedFloat", isLeaf: true);
+
+/// Simple nested struct with floats.
+void testReturnStruct8BytesNestedFloatLeaf() {
+ final a0Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a1 = a1Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+
+ final result = returnStruct8BytesNestedFloatLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a1.a0, result.a1.a0);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct8BytesNestedFloat2Leaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedFloat2 Function(Struct4BytesFloat, Float),
+ Struct8BytesNestedFloat2 Function(Struct4BytesFloat,
+ double)>("ReturnStruct8BytesNestedFloat2", isLeaf: true);
+
+/// The nesting is irregular, testing homogenous float rules on arm and arm64,
+/// and the fpu register usage on x64.
+void testReturnStruct8BytesNestedFloat2Leaf() {
+ final a0Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a0 = a0Pointer.ref;
+ double a1;
+
+ a0.a0 = -1.0;
+ a1 = 2.0;
+
+ final result = returnStruct8BytesNestedFloat2Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a1, result.a1);
+
+ calloc.free(a0Pointer);
+}
+
+final returnStruct8BytesNestedMixedLeaf = ffiTestFunctions.lookupFunction<
+ Struct8BytesNestedMixed Function(
+ Struct4BytesHomogeneousInt16, Struct4BytesFloat),
+ Struct8BytesNestedMixed Function(Struct4BytesHomogeneousInt16,
+ Struct4BytesFloat)>("ReturnStruct8BytesNestedMixed", isLeaf: true);
+
+/// Simple nested struct with mixed members.
+void testReturnStruct8BytesNestedMixedLeaf() {
+ final a0Pointer = calloc<Struct4BytesHomogeneousInt16>();
+ final Struct4BytesHomogeneousInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct4BytesFloat>();
+ final Struct4BytesFloat a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a1.a0 = -3.0;
+
+ final result = returnStruct8BytesNestedMixedLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.approxEquals(a1.a0, result.a1.a0);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct16BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct16BytesNestedInt Function(
+ Struct8BytesNestedInt, Struct8BytesNestedInt),
+ Struct16BytesNestedInt Function(Struct8BytesNestedInt,
+ Struct8BytesNestedInt)>("ReturnStruct16BytesNestedInt", isLeaf: true);
+
+/// Deeper nested struct to test recursive member access.
+void testReturnStruct16BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct8BytesNestedInt>();
+ final Struct8BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a1.a0 = -3;
+ a0.a1.a1 = 4;
+ a1.a0.a0 = -5;
+ a1.a0.a1 = 6;
+ a1.a1.a0 = -7;
+ a1.a1.a1 = 8;
+
+ final result = returnStruct16BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0.a0, result.a0.a0.a0);
+ Expect.equals(a0.a0.a1, result.a0.a0.a1);
+ Expect.equals(a0.a1.a0, result.a0.a1.a0);
+ Expect.equals(a0.a1.a1, result.a0.a1.a1);
+ Expect.equals(a1.a0.a0, result.a1.a0.a0);
+ Expect.equals(a1.a0.a1, result.a1.a0.a1);
+ Expect.equals(a1.a1.a0, result.a1.a1.a0);
+ Expect.equals(a1.a1.a1, result.a1.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStruct32BytesNestedIntLeaf = ffiTestFunctions.lookupFunction<
+ Struct32BytesNestedInt Function(
+ Struct16BytesNestedInt, Struct16BytesNestedInt),
+ Struct32BytesNestedInt Function(Struct16BytesNestedInt,
+ Struct16BytesNestedInt)>("ReturnStruct32BytesNestedInt", isLeaf: true);
+
+/// Even deeper nested struct to test recursive member access.
+void testReturnStruct32BytesNestedIntLeaf() {
+ final a0Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Struct16BytesNestedInt>();
+ final Struct16BytesNestedInt a1 = a1Pointer.ref;
+
+ a0.a0.a0.a0 = -1;
+ a0.a0.a0.a1 = 2;
+ a0.a0.a1.a0 = -3;
+ a0.a0.a1.a1 = 4;
+ a0.a1.a0.a0 = -5;
+ a0.a1.a0.a1 = 6;
+ a0.a1.a1.a0 = -7;
+ a0.a1.a1.a1 = 8;
+ a1.a0.a0.a0 = -9;
+ a1.a0.a0.a1 = 10;
+ a1.a0.a1.a0 = -11;
+ a1.a0.a1.a1 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15;
+ a1.a1.a1.a1 = 16;
+
+ final result = returnStruct32BytesNestedIntLeaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0.a0.a0, result.a0.a0.a0.a0);
+ Expect.equals(a0.a0.a0.a1, result.a0.a0.a0.a1);
+ Expect.equals(a0.a0.a1.a0, result.a0.a0.a1.a0);
+ Expect.equals(a0.a0.a1.a1, result.a0.a0.a1.a1);
+ Expect.equals(a0.a1.a0.a0, result.a0.a1.a0.a0);
+ Expect.equals(a0.a1.a0.a1, result.a0.a1.a0.a1);
+ Expect.equals(a0.a1.a1.a0, result.a0.a1.a1.a0);
+ Expect.equals(a0.a1.a1.a1, result.a0.a1.a1.a1);
+ Expect.equals(a1.a0.a0.a0, result.a1.a0.a0.a0);
+ Expect.equals(a1.a0.a0.a1, result.a1.a0.a0.a1);
+ Expect.equals(a1.a0.a1.a0, result.a1.a0.a1.a0);
+ Expect.equals(a1.a0.a1.a1, result.a1.a0.a1.a1);
+ Expect.equals(a1.a1.a0.a0, result.a1.a1.a0.a0);
+ Expect.equals(a1.a1.a0.a1, result.a1.a1.a0.a1);
+ Expect.equals(a1.a1.a1.a0, result.a1.a1.a1.a0);
+ Expect.equals(a1.a1.a1.a1, result.a1.a1.a1.a1);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt16Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt16 Function(
+ StructAlignmentInt16, StructAlignmentInt16),
+ StructNestedIntStructAlignmentInt16 Function(
+ StructAlignmentInt16, StructAlignmentInt16)>(
+ "ReturnStructNestedIntStructAlignmentInt16",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 16 byte int.
+void testReturnStructNestedIntStructAlignmentInt16Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt16>();
+ final StructAlignmentInt16 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt16Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt32Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt32 Function(
+ StructAlignmentInt32, StructAlignmentInt32),
+ StructNestedIntStructAlignmentInt32 Function(
+ StructAlignmentInt32, StructAlignmentInt32)>(
+ "ReturnStructNestedIntStructAlignmentInt32",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 32 byte int.
+void testReturnStructNestedIntStructAlignmentInt32Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt32>();
+ final StructAlignmentInt32 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt32Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIntStructAlignmentInt64Leaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIntStructAlignmentInt64 Function(
+ StructAlignmentInt64, StructAlignmentInt64),
+ StructNestedIntStructAlignmentInt64 Function(
+ StructAlignmentInt64, StructAlignmentInt64)>(
+ "ReturnStructNestedIntStructAlignmentInt64",
+ isLeaf: true);
+
+/// Test alignment and padding of nested struct with 64 byte int.
+void testReturnStructNestedIntStructAlignmentInt64Leaf() {
+ final a0Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a0 = a0Pointer.ref;
+ final a1Pointer = calloc<StructAlignmentInt64>();
+ final StructAlignmentInt64 a1 = a1Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+ a1.a0 = 4;
+ a1.a1 = -5;
+ a1.a2 = 6;
+
+ final result = returnStructNestedIntStructAlignmentInt64Leaf(a0, a1);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+ Expect.equals(a1.a0, result.a1.a0);
+ Expect.equals(a1.a1, result.a1.a1);
+ Expect.equals(a1.a2, result.a1.a2);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+}
+
+final returnStructNestedIrregularEvenBiggerLeaf =
+ ffiTestFunctions.lookupFunction<
+ StructNestedIrregularEvenBigger Function(Uint64,
+ StructNestedIrregularBigger, StructNestedIrregularBigger, Double),
+ StructNestedIrregularEvenBigger Function(
+ int,
+ StructNestedIrregularBigger,
+ StructNestedIrregularBigger,
+ double)>("ReturnStructNestedIrregularEvenBigger", isLeaf: true);
+
+/// Return big irregular struct as smoke test.
+void testReturnStructNestedIrregularEvenBiggerLeaf() {
+ int a0;
+ final a1Pointer = calloc<StructNestedIrregularBigger>();
+ final StructNestedIrregularBigger a1 = a1Pointer.ref;
+ final a2Pointer = calloc<StructNestedIrregularBigger>();
+ final StructNestedIrregularBigger a2 = a2Pointer.ref;
+ double a3;
+
+ a0 = 1;
+ a1.a0.a0 = 2;
+ a1.a0.a1.a0.a0 = -3;
+ a1.a0.a1.a0.a1 = 4;
+ a1.a0.a1.a1.a0 = -5.0;
+ a1.a0.a2 = 6;
+ a1.a0.a3.a0.a0 = -7.0;
+ a1.a0.a3.a1 = 8.0;
+ a1.a0.a4 = 9;
+ a1.a0.a5.a0.a0 = 10.0;
+ a1.a0.a5.a1.a0 = -11.0;
+ a1.a0.a6 = 12;
+ a1.a1.a0.a0 = -13;
+ a1.a1.a0.a1 = 14;
+ a1.a1.a1.a0 = -15.0;
+ a1.a2 = 16.0;
+ a1.a3 = -17.0;
+ a2.a0.a0 = 18;
+ a2.a0.a1.a0.a0 = -19;
+ a2.a0.a1.a0.a1 = 20;
+ a2.a0.a1.a1.a0 = -21.0;
+ a2.a0.a2 = 22;
+ a2.a0.a3.a0.a0 = -23.0;
+ a2.a0.a3.a1 = 24.0;
+ a2.a0.a4 = 25;
+ a2.a0.a5.a0.a0 = 26.0;
+ a2.a0.a5.a1.a0 = -27.0;
+ a2.a0.a6 = 28;
+ a2.a1.a0.a0 = -29;
+ a2.a1.a0.a1 = 30;
+ a2.a1.a1.a0 = -31.0;
+ a2.a2 = 32.0;
+ a2.a3 = -33.0;
+ a3 = 34.0;
+
+ final result = returnStructNestedIrregularEvenBiggerLeaf(a0, a1, a2, a3);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+ Expect.equals(a1.a0.a0, result.a1.a0.a0);
+ Expect.equals(a1.a0.a1.a0.a0, result.a1.a0.a1.a0.a0);
+ Expect.equals(a1.a0.a1.a0.a1, result.a1.a0.a1.a0.a1);
+ Expect.approxEquals(a1.a0.a1.a1.a0, result.a1.a0.a1.a1.a0);
+ Expect.equals(a1.a0.a2, result.a1.a0.a2);
+ Expect.approxEquals(a1.a0.a3.a0.a0, result.a1.a0.a3.a0.a0);
+ Expect.approxEquals(a1.a0.a3.a1, result.a1.a0.a3.a1);
+ Expect.equals(a1.a0.a4, result.a1.a0.a4);
+ Expect.approxEquals(a1.a0.a5.a0.a0, result.a1.a0.a5.a0.a0);
+ Expect.approxEquals(a1.a0.a5.a1.a0, result.a1.a0.a5.a1.a0);
+ Expect.equals(a1.a0.a6, result.a1.a0.a6);
+ Expect.equals(a1.a1.a0.a0, result.a1.a1.a0.a0);
+ Expect.equals(a1.a1.a0.a1, result.a1.a1.a0.a1);
+ Expect.approxEquals(a1.a1.a1.a0, result.a1.a1.a1.a0);
+ Expect.approxEquals(a1.a2, result.a1.a2);
+ Expect.approxEquals(a1.a3, result.a1.a3);
+ Expect.equals(a2.a0.a0, result.a2.a0.a0);
+ Expect.equals(a2.a0.a1.a0.a0, result.a2.a0.a1.a0.a0);
+ Expect.equals(a2.a0.a1.a0.a1, result.a2.a0.a1.a0.a1);
+ Expect.approxEquals(a2.a0.a1.a1.a0, result.a2.a0.a1.a1.a0);
+ Expect.equals(a2.a0.a2, result.a2.a0.a2);
+ Expect.approxEquals(a2.a0.a3.a0.a0, result.a2.a0.a3.a0.a0);
+ Expect.approxEquals(a2.a0.a3.a1, result.a2.a0.a3.a1);
+ Expect.equals(a2.a0.a4, result.a2.a0.a4);
+ Expect.approxEquals(a2.a0.a5.a0.a0, result.a2.a0.a5.a0.a0);
+ Expect.approxEquals(a2.a0.a5.a1.a0, result.a2.a0.a5.a1.a0);
+ Expect.equals(a2.a0.a6, result.a2.a0.a6);
+ Expect.equals(a2.a1.a0.a0, result.a2.a1.a0.a0);
+ Expect.equals(a2.a1.a0.a1, result.a2.a1.a0.a1);
+ Expect.approxEquals(a2.a1.a1.a0, result.a2.a1.a1.a0);
+ Expect.approxEquals(a2.a2, result.a2.a2);
+ Expect.approxEquals(a2.a3, result.a2.a3);
+ Expect.approxEquals(a3, result.a3);
+
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+}
diff --git a/tests/ffi_2/function_structs_test.dart b/tests/ffi_2/function_structs_test.dart
index c259435..86f49de 100644
--- a/tests/ffi_2/function_structs_test.dart
+++ b/tests/ffi_2/function_structs_test.dart
@@ -21,18 +21,21 @@
typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
void main() {
- testFunctionWithStruct();
- testFunctionWithStructArray();
- testFunctionWithVeryLargeStruct();
+ for (final isLeaf in [false, true]) {
+ testFunctionWithStruct(isLeaf: isLeaf);
+ testFunctionWithStructArray(isLeaf: isLeaf);
+ testFunctionWithVeryLargeStruct(isLeaf: isLeaf);
+ }
}
DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
/// pass a struct to a c function and get a struct as return value
-void testFunctionWithStruct() {
+void testFunctionWithStruct({bool isLeaf: false}) {
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("TransposeCoordinate");
- NativeCoordinateOp f1 = p1.asFunction();
+ NativeCoordinateOp f1 =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
final c1 = calloc<Coordinate>()
..ref.x = 10.0
@@ -56,10 +59,11 @@
}
/// pass an array of structs to a c funtion
-void testFunctionWithStructArray() {
+void testFunctionWithStructArray({bool isLeaf: false}) {
Pointer<NativeFunction<NativeCoordinateOp>> p1 =
ffiTestFunctions.lookup("CoordinateElemAt1");
- NativeCoordinateOp f1 = p1.asFunction();
+ NativeCoordinateOp f1 =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
final coordinateArray = calloc<Coordinate>(3);
Coordinate c1 = coordinateArray[0];
@@ -85,10 +89,11 @@
typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
typedef NativeVeryLargeStructSum = Int64 Function(Pointer<VeryLargeStruct>);
-void testFunctionWithVeryLargeStruct() {
+void testFunctionWithVeryLargeStruct({bool isLeaf: false}) {
Pointer<NativeFunction<NativeVeryLargeStructSum>> p1 =
ffiTestFunctions.lookup("SumVeryLargeStruct");
- VeryLargeStructSum f = p1.asFunction();
+ VeryLargeStructSum f =
+ (isLeaf ? p1.asFunction(isLeaf: true) : p1.asFunction(isLeaf: false));
final vlsArray = calloc<VeryLargeStruct>(2);
VeryLargeStruct vls1 = vlsArray[0];
diff --git a/tests/ffi_2/generator/structs_by_value_tests_generator.dart b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
index bbd3158..39d8f7f 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
@@ -539,7 +539,7 @@
}
extension on FunctionType {
- String get dartCallCode {
+ String dartCallCode({bool isLeaf: false}) {
final a = ArgumentValueAssigner();
final assignValues = arguments.assignValueStatements(a);
final argumentFrees = arguments.dartFreeStatements();
@@ -563,17 +563,19 @@
break;
}
+ final namePostfix = isLeaf ? "Leaf" : "";
return """
- final $dartName =
- ffiTestFunctions.lookupFunction<$dartCType, $dartType>("$cName");
+ final ${dartName}$namePostfix =
+ ffiTestFunctions.lookupFunction<$dartCType, $dartType>(
+ "$cName"${isLeaf ? ", isLeaf:true" : ""});
${reason.makeDartDocComment()}
- void $dartTestName() {
+ void ${dartTestName}$namePostfix() {
${arguments.dartAllocateStatements()}
${assignValues}
- final result = $dartName($argumentNames);
+ final result = ${dartName}$namePostfix($argumentNames);
print("result = \$result");
@@ -888,11 +890,13 @@
void main() {
for (int i = 0; i < 10; ++i) {
${functions.map((e) => "${e.dartTestName}();").join("\n")}
+ ${functions.map((e) => "${e.dartTestName}Leaf();").join("\n")}
}
}
""");
buffer.writeAll(compounds.map((e) => e.dartClass(nnbd)));
- buffer.writeAll(functions.map((e) => e.dartCallCode));
+ buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: false)));
+ buffer.writeAll(functions.map((e) => e.dartCallCode(isLeaf: true)));
final path = callTestPath(nnbd);
File(path).writeAsStringSync(buffer.toString());
diff --git a/tests/ffi_2/vmspecific_leaf_call_test.dart b/tests/ffi_2/vmspecific_leaf_call_test.dart
new file mode 100644
index 0000000..f4c0445
--- /dev/null
+++ b/tests/ffi_2/vmspecific_leaf_call_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+import 'dylib_utils.dart';
+import 'ffi_test_helpers.dart';
+import 'callback_tests_utils.dart';
+
+DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+testLeafCall() {
+ // Regular calls should transition generated -> native.
+ final isThreadInGenerated = ffiTestFunctions.lookupFunction<
+ Int8 Function(), int Function()>("IsThreadInGenerated");
+ Expect.equals(0, isThreadInGenerated());
+ // Leaf calls should remain in generated state.
+ final isThreadInGeneratedLeaf = ffiTestFunctions.lookupFunction<
+ Int8 Function(), int Function()>("IsThreadInGenerated", isLeaf: true);
+ Expect.equals(1, isThreadInGeneratedLeaf());
+}
+
+testLeafCallApi() {
+ // Note: This will only crash as expected in debug build mode. In other modes
+ // it's effectively skip.
+ final f = ffiTestFunctions.lookupFunction<
+ Void Function(), void Function()>("TestLeafCallApi", isLeaf: true);
+ // Calling Dart_.. API is unsafe from leaf calls since we explicitly haven't
+ // made the generated -> native transition.
+ f();
+}
+
+void nop() {}
+
+testCallbackLeaf() {
+ // This should crash with "expected: T->IsAtSafepoint()", since it's unsafe to
+ // do callbacks from leaf calls (otherwise they wouldn't be leaf calls).
+ // Note: This will only crash as expected in debug build mode. In other modes
+ // it's effectively skip.
+ CallbackTest("CallbackLeaf", Pointer.fromFunction<Void Function()>(nop),
+ isLeaf:true).run();
+}
+
+main() {
+ testLeafCall(); //# 01: ok
+ // These tests terminate the process after successful completion, so we have
+ // to run them separately.
+ //
+ // Since they use signal handlers they only run on Linux.
+ if (Platform.isLinux && !const bool.fromEnvironment("dart.vm.product")) {
+ testLeafCallApi(); //# 02: ok
+ testCallbackLeaf(); //# 03: ok
+ }
+}
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index ae19a0d..112455c 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -63,6 +63,12 @@
testSizeOfHandle();
testElementAtGeneric();
testElementAtNativeType();
+ testLookupFunctionIsLeafMustBeConst();
+ testAsFunctionIsLeafMustBeConst();
+ testLookupFunctionTakesHandle();
+ testAsFunctionTakesHandle();
+ testLookupFunctionReturnsHandle();
+ testAsFunctionReturnsHandle();
}
typedef Int8UnOp = Int8 Function(Int8);
@@ -705,6 +711,44 @@
Pointer<Uint8> notEmpty;
}
+void testLookupFunctionIsLeafMustBeConst() {
+ bool notAConst = false;
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeDoubleUnOp, DoubleUnOp>("timesFour", isLeaf:notAConst); //# 1500: compile-time error
+}
+
+void testAsFunctionIsLeafMustBeConst() {
+ bool notAConst = false;
+ Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+ IntUnOp f = p.asFunction(isLeaf:notAConst); //# 1501: compile-time error
+}
+
+typedef NativeTakesHandle = Void Function(Handle);
+typedef TakesHandle = void Function(Object);
+
+void testLookupFunctionTakesHandle() {
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeTakesHandle, TakesHandle>("takesHandle", isLeaf:true); //# 1502: compile-time error
+}
+
+void testAsFunctionTakesHandle() {
+ Pointer<NativeFunction<NativeTakesHandle>> p = Pointer.fromAddress(1337); //# 1503: compile-time error
+ TakesHandle f = p.asFunction(isLeaf:true); //# 1503: compile-time error
+}
+
+typedef NativeReturnsHandle = Handle Function();
+typedef ReturnsHandle = Object Function();
+
+void testLookupFunctionReturnsHandle() {
+ DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+ l.lookupFunction<NativeReturnsHandle, ReturnsHandle>("returnsHandle", isLeaf:true); //# 1504: compile-time error
+}
+
+void testAsFunctionReturnsHandle() {
+ Pointer<NativeFunction<NativeReturnsHandle>> p = Pointer.fromAddress(1337); //# 1505: compile-time error
+ ReturnsHandle f = p.asFunction(isLeaf:true); //# 1505: compile-time error
+}
+
@Packed(1)
class TestStruct1600 extends Struct {
Pointer<Uint8> notEmpty;
diff --git a/tools/VERSION b/tools/VERSION
index 1c363e3..89bbb25 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 137
+PRERELEASE 138
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/utils/application_snapshot.gni b/utils/application_snapshot.gni
index 7ecdf28..8df18fd 100644
--- a/utils/application_snapshot.gni
+++ b/utils/application_snapshot.gni
@@ -145,13 +145,15 @@
dfe = "$_dart_root/pkg/vm/bin/kernel_service.dart"
abs_depfile = rebase_path(depfile)
- abs_output = rebase_path(output, root_build_dir)
+ abs_output = rebase_path(output)
+ rel_output = rebase_path(output, root_build_dir)
vm_args = [
"--deterministic",
"--packages=$dot_packages",
"--snapshot=$abs_output",
"--snapshot-depfile=$abs_depfile",
+ "--depfile-output-filename=$rel_output",
] + snapshot_vm_args
if (dart_snapshot_kind == "kernel") {