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") {