[test/ffi] Passing structs by value test generator

Split off from https://dart-review.googlesource.com/c/sdk/+/140290/33
to make that CL smaller and review the test generator separately.

Because of the amount of corner cases in the calling conventions that
need to be covered, the tests are generated, rather than hand-written.

The tests are tested in the dependent CL. Tests are ignored in status
file and are un-ignored in dependent CL.

Change-Id: I5507f52229793fdf07da3066b49045fdb703a69d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168829
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 8f6992b..906eb34 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -1028,11 +1028,12 @@
     # This file must be compiled in for dynamic linking.
     "../include/dart_api_dl.c",
 
-    # The two files here do not depend on each other.
-    # flutter/flutter integration tests will only use `ffi_test_functions.cc` -
-    # any test functionality using `dart_api.h` has to go into
-    # `ffi_test_functions_vmspecific.cc`.
+    # The three files here do not depend on each other.
+    # flutter/flutter integration tests will only use
+    # `ffi_test_functions{,_generated}.cc` - any test functionality using
+    # `dart_api.h` has to go into `ffi_test_functions_vmspecific.cc`.
     "ffi_test/ffi_test_functions.cc",
+    "ffi_test/ffi_test_functions_generated.cc",
     "ffi_test/ffi_test_functions_vmspecific.cc",
   ]
   if (is_win && current_cpu == "x64") {
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index c9e39e9..3304154 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -750,12 +750,48 @@
   return retval;
 }
 
+// Can't easily share this with the generated file.
+struct Struct20BytesHomogeneousInt32Copy {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  int32_t a4;
+};
+
+DART_EXPORT Struct20BytesHomogeneousInt32Copy PassStructRecursive(
+    int64_t recursionCounter,
+    Struct20BytesHomogeneousInt32Copy a0,
+    Struct20BytesHomogeneousInt32Copy (*f)(int64_t,
+                                           Struct20BytesHomogeneousInt32Copy)) {
+  std::cout << "PassStruct20BytesHomogeneousInt32x10"
+            << "(" << recursionCounter << ", (" << a0.a0 << ", " << a0.a1
+            << ", " << a0.a2 << ", " << a0.a3 << ", " << a0.a4 << "), "
+            << reinterpret_cast<void*>(f) << ")\n";
+  a0.a0++;
+  const int32_t a0_a0_saved = a0.a0;
+
+  if (recursionCounter <= 0) {
+    return a0;
+  }
+
+  Struct20BytesHomogeneousInt32Copy result = f(recursionCounter - 1, a0);
+  result.a0++;
+  if (a0_a0_saved != a0.a0) {
+    result.a4 = 0;
+  }
+
+  return result;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Tests for callbacks.
 
 // Sanity test.
 DART_EXPORT intptr_t TestSimpleAddition(intptr_t (*add)(int, int)) {
-  CHECK_EQ(add(10, 20), 30);
+  const intptr_t result = add(10, 20);
+  std::cout << "result " << result << "\n";
+  CHECK_EQ(result, 30);
   return 0;
 }
 
@@ -764,7 +800,9 @@
 
 DART_EXPORT intptr_t
 TestIntComputation(int64_t (*fn)(int8_t, int16_t, int32_t, int64_t)) {
-  CHECK_EQ(fn(125, 250, 500, 1000), 625);
+  const int64_t result = fn(125, 250, 500, 1000);
+  std::cout << "result " << result << "\n";
+  CHECK_EQ(result, 625);
   CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL));
   CHECK_EQ(((int64_t)-0x8000000000000000LL),
            fn(0, 0, 0, -0x8000000000000000LL));
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
new file mode 100644
index 0000000..9c9789f
--- /dev/null
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -0,0 +1,8375 @@
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+#if defined(_WIN32)
+#define DART_EXPORT extern "C" __declspec(dllexport)
+#else
+#define DART_EXPORT                                                            \
+  extern "C" __attribute__((visibility("default"))) __attribute((used))
+#endif
+
+namespace dart {
+
+#define CHECK(X)                                                               \
+  if (!(X)) {                                                                  \
+    fprintf(stderr, "%s\n", "Check failed: " #X);                              \
+    return 1;                                                                  \
+  }
+
+#define CHECK_EQ(X, Y) CHECK((X) == (Y))
+
+// Works for positive, negative and zero.
+#define CHECK_APPROX(EXPECTED, ACTUAL)                                         \
+  CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \
+        ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
+
+struct Struct0Bytes {};
+
+struct Struct1ByteInt {
+  int8_t a0;
+};
+
+struct Struct3BytesInt {
+  int16_t a0;
+  int8_t a1;
+};
+
+struct Struct4BytesHomogeneousInt16 {
+  int16_t a0;
+  int16_t a1;
+};
+
+struct Struct7BytesInt {
+  int32_t a0;
+  int16_t a1;
+  int8_t a2;
+};
+
+struct Struct8BytesInt {
+  int16_t a0;
+  int16_t a1;
+  int32_t a2;
+};
+
+struct Struct8BytesHomogeneousFloat {
+  float a0;
+  float a1;
+};
+
+struct Struct8BytesMixed {
+  float a0;
+  int16_t a1;
+  int16_t a2;
+};
+
+struct Struct9BytesInt {
+  int64_t a0;
+  int8_t a1;
+};
+
+struct Struct9BytesHomogeneousUint82 {
+  uint8_t a0;
+  uint8_t a1;
+  uint8_t a2;
+  uint8_t a3;
+  uint8_t a4;
+  uint8_t a5;
+  uint8_t a6;
+  uint8_t a7;
+  uint8_t a8;
+};
+
+struct Struct12BytesHomogeneousFloat {
+  float a0;
+  float a1;
+  float a2;
+};
+
+struct Struct16BytesHomogeneousFloat {
+  float a0;
+  float a1;
+  float a2;
+  float a3;
+};
+
+struct Struct16BytesMixed {
+  double a0;
+  int64_t a1;
+};
+
+struct Struct16BytesMixed2 {
+  float a0;
+  float a1;
+  float a2;
+  int32_t a3;
+};
+
+struct Struct17BytesInt {
+  int64_t a0;
+  int64_t a1;
+  int8_t a2;
+};
+
+struct Struct19BytesHomogeneousUint8 {
+  uint8_t a0;
+  uint8_t a1;
+  uint8_t a2;
+  uint8_t a3;
+  uint8_t a4;
+  uint8_t a5;
+  uint8_t a6;
+  uint8_t a7;
+  uint8_t a8;
+  uint8_t a9;
+  uint8_t a10;
+  uint8_t a11;
+  uint8_t a12;
+  uint8_t a13;
+  uint8_t a14;
+  uint8_t a15;
+  uint8_t a16;
+  uint8_t a17;
+  uint8_t a18;
+};
+
+struct Struct20BytesHomogeneousInt32 {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  int32_t a4;
+};
+
+struct Struct20BytesHomogeneousFloat {
+  float a0;
+  float a1;
+  float a2;
+  float a3;
+  float a4;
+};
+
+struct Struct32BytesHomogeneousDouble {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+};
+
+struct Struct40BytesHomogeneousDouble {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+  double a4;
+};
+
+struct Struct1024BytesHomogeneousUint64 {
+  uint64_t a0;
+  uint64_t a1;
+  uint64_t a2;
+  uint64_t a3;
+  uint64_t a4;
+  uint64_t a5;
+  uint64_t a6;
+  uint64_t a7;
+  uint64_t a8;
+  uint64_t a9;
+  uint64_t a10;
+  uint64_t a11;
+  uint64_t a12;
+  uint64_t a13;
+  uint64_t a14;
+  uint64_t a15;
+  uint64_t a16;
+  uint64_t a17;
+  uint64_t a18;
+  uint64_t a19;
+  uint64_t a20;
+  uint64_t a21;
+  uint64_t a22;
+  uint64_t a23;
+  uint64_t a24;
+  uint64_t a25;
+  uint64_t a26;
+  uint64_t a27;
+  uint64_t a28;
+  uint64_t a29;
+  uint64_t a30;
+  uint64_t a31;
+  uint64_t a32;
+  uint64_t a33;
+  uint64_t a34;
+  uint64_t a35;
+  uint64_t a36;
+  uint64_t a37;
+  uint64_t a38;
+  uint64_t a39;
+  uint64_t a40;
+  uint64_t a41;
+  uint64_t a42;
+  uint64_t a43;
+  uint64_t a44;
+  uint64_t a45;
+  uint64_t a46;
+  uint64_t a47;
+  uint64_t a48;
+  uint64_t a49;
+  uint64_t a50;
+  uint64_t a51;
+  uint64_t a52;
+  uint64_t a53;
+  uint64_t a54;
+  uint64_t a55;
+  uint64_t a56;
+  uint64_t a57;
+  uint64_t a58;
+  uint64_t a59;
+  uint64_t a60;
+  uint64_t a61;
+  uint64_t a62;
+  uint64_t a63;
+  uint64_t a64;
+  uint64_t a65;
+  uint64_t a66;
+  uint64_t a67;
+  uint64_t a68;
+  uint64_t a69;
+  uint64_t a70;
+  uint64_t a71;
+  uint64_t a72;
+  uint64_t a73;
+  uint64_t a74;
+  uint64_t a75;
+  uint64_t a76;
+  uint64_t a77;
+  uint64_t a78;
+  uint64_t a79;
+  uint64_t a80;
+  uint64_t a81;
+  uint64_t a82;
+  uint64_t a83;
+  uint64_t a84;
+  uint64_t a85;
+  uint64_t a86;
+  uint64_t a87;
+  uint64_t a88;
+  uint64_t a89;
+  uint64_t a90;
+  uint64_t a91;
+  uint64_t a92;
+  uint64_t a93;
+  uint64_t a94;
+  uint64_t a95;
+  uint64_t a96;
+  uint64_t a97;
+  uint64_t a98;
+  uint64_t a99;
+  uint64_t a100;
+  uint64_t a101;
+  uint64_t a102;
+  uint64_t a103;
+  uint64_t a104;
+  uint64_t a105;
+  uint64_t a106;
+  uint64_t a107;
+  uint64_t a108;
+  uint64_t a109;
+  uint64_t a110;
+  uint64_t a111;
+  uint64_t a112;
+  uint64_t a113;
+  uint64_t a114;
+  uint64_t a115;
+  uint64_t a116;
+  uint64_t a117;
+  uint64_t a118;
+  uint64_t a119;
+  uint64_t a120;
+  uint64_t a121;
+  uint64_t a122;
+  uint64_t a123;
+  uint64_t a124;
+  uint64_t a125;
+  uint64_t a126;
+  uint64_t a127;
+};
+
+struct StructAlignmentInt16 {
+  int8_t a0;
+  int16_t a1;
+  int8_t a2;
+};
+
+struct StructAlignmentInt32 {
+  int8_t a0;
+  int32_t a1;
+  int8_t a2;
+};
+
+struct StructAlignmentInt64 {
+  int8_t a0;
+  int64_t a1;
+  int8_t a2;
+};
+
+// Used for testing structs by value.
+// Smallest struct with data.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT int64_t PassStruct1ByteIntx10(Struct1ByteInt a0,
+                                          Struct1ByteInt a1,
+                                          Struct1ByteInt a2,
+                                          Struct1ByteInt a3,
+                                          Struct1ByteInt a4,
+                                          Struct1ByteInt a5,
+                                          Struct1ByteInt a6,
+                                          Struct1ByteInt a7,
+                                          Struct1ByteInt a8,
+                                          Struct1ByteInt a9) {
+  std::cout << "PassStruct1ByteIntx10"
+            << "((" << static_cast<int>(a0.a0) << "), ("
+            << static_cast<int>(a1.a0) << "), (" << static_cast<int>(a2.a0)
+            << "), (" << static_cast<int>(a3.a0) << "), ("
+            << static_cast<int>(a4.a0) << "), (" << static_cast<int>(a5.a0)
+            << "), (" << static_cast<int>(a6.a0) << "), ("
+            << static_cast<int>(a7.a0) << "), (" << static_cast<int>(a8.a0)
+            << "), (" << static_cast<int>(a9.a0) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a1.a0;
+  result += a2.a0;
+  result += a3.a0;
+  result += a4.a0;
+  result += a5.a0;
+  result += a6.a0;
+  result += a7.a0;
+  result += a8.a0;
+  result += a9.a0;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Not a multiple of word size, not a power of two.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT int64_t PassStruct3BytesIntx10(Struct3BytesInt a0,
+                                           Struct3BytesInt a1,
+                                           Struct3BytesInt a2,
+                                           Struct3BytesInt a3,
+                                           Struct3BytesInt a4,
+                                           Struct3BytesInt a5,
+                                           Struct3BytesInt a6,
+                                           Struct3BytesInt a7,
+                                           Struct3BytesInt a8,
+                                           Struct3BytesInt a9) {
+  std::cout << "PassStruct3BytesIntx10"
+            << "((" << a0.a0 << ", " << static_cast<int>(a0.a1) << "), ("
+            << a1.a0 << ", " << static_cast<int>(a1.a1) << "), (" << a2.a0
+            << ", " << static_cast<int>(a2.a1) << "), (" << a3.a0 << ", "
+            << static_cast<int>(a3.a1) << "), (" << a4.a0 << ", "
+            << static_cast<int>(a4.a1) << "), (" << a5.a0 << ", "
+            << static_cast<int>(a5.a1) << "), (" << a6.a0 << ", "
+            << static_cast<int>(a6.a1) << "), (" << a7.a0 << ", "
+            << static_cast<int>(a7.a1) << "), (" << a8.a0 << ", "
+            << static_cast<int>(a8.a1) << "), (" << a9.a0 << ", "
+            << static_cast<int>(a9.a1) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Exactly word size on 32-bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT int64_t
+PassStruct4BytesHomogeneousInt16x10(Struct4BytesHomogeneousInt16 a0,
+                                    Struct4BytesHomogeneousInt16 a1,
+                                    Struct4BytesHomogeneousInt16 a2,
+                                    Struct4BytesHomogeneousInt16 a3,
+                                    Struct4BytesHomogeneousInt16 a4,
+                                    Struct4BytesHomogeneousInt16 a5,
+                                    Struct4BytesHomogeneousInt16 a6,
+                                    Struct4BytesHomogeneousInt16 a7,
+                                    Struct4BytesHomogeneousInt16 a8,
+                                    Struct4BytesHomogeneousInt16 a9) {
+  std::cout << "PassStruct4BytesHomogeneousInt16x10"
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Sub word size on 64 bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT int64_t PassStruct7BytesIntx10(Struct7BytesInt a0,
+                                           Struct7BytesInt a1,
+                                           Struct7BytesInt a2,
+                                           Struct7BytesInt a3,
+                                           Struct7BytesInt a4,
+                                           Struct7BytesInt a5,
+                                           Struct7BytesInt a6,
+                                           Struct7BytesInt a7,
+                                           Struct7BytesInt a8,
+                                           Struct7BytesInt a9) {
+  std::cout << "PassStruct7BytesIntx10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << static_cast<int>(a0.a2)
+            << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << static_cast<int>(a1.a2) << "), (" << a2.a0 << ", " << a2.a1
+            << ", " << static_cast<int>(a2.a2) << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << static_cast<int>(a3.a2) << "), (" << a4.a0
+            << ", " << a4.a1 << ", " << static_cast<int>(a4.a2) << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << static_cast<int>(a5.a2)
+            << "), (" << a6.a0 << ", " << a6.a1 << ", "
+            << static_cast<int>(a6.a2) << "), (" << a7.a0 << ", " << a7.a1
+            << ", " << static_cast<int>(a7.a2) << "), (" << a8.a0 << ", "
+            << a8.a1 << ", " << static_cast<int>(a8.a2) << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << static_cast<int>(a9.a2) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Exactly word size struct on 64bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT int64_t PassStruct8BytesIntx10(Struct8BytesInt a0,
+                                           Struct8BytesInt a1,
+                                           Struct8BytesInt a2,
+                                           Struct8BytesInt a3,
+                                           Struct8BytesInt a4,
+                                           Struct8BytesInt a5,
+                                           Struct8BytesInt a6,
+                                           Struct8BytesInt a7,
+                                           Struct8BytesInt a8,
+                                           Struct8BytesInt a9) {
+  std::cout << "PassStruct8BytesIntx10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << "), (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << "), ("
+            << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << a9.a2 << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Arguments passed in FP registers as long as they fit.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT float PassStruct8BytesHomogeneousFloatx10(
+    Struct8BytesHomogeneousFloat a0,
+    Struct8BytesHomogeneousFloat a1,
+    Struct8BytesHomogeneousFloat a2,
+    Struct8BytesHomogeneousFloat a3,
+    Struct8BytesHomogeneousFloat a4,
+    Struct8BytesHomogeneousFloat a5,
+    Struct8BytesHomogeneousFloat a6,
+    Struct8BytesHomogeneousFloat a7,
+    Struct8BytesHomogeneousFloat a8,
+    Struct8BytesHomogeneousFloat a9) {
+  std::cout << "PassStruct8BytesHomogeneousFloatx10"
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// On x64, arguments go in int registers because it is not only float.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT float PassStruct8BytesMixedx10(Struct8BytesMixed a0,
+                                           Struct8BytesMixed a1,
+                                           Struct8BytesMixed a2,
+                                           Struct8BytesMixed a3,
+                                           Struct8BytesMixed a4,
+                                           Struct8BytesMixed a5,
+                                           Struct8BytesMixed a6,
+                                           Struct8BytesMixed a7,
+                                           Struct8BytesMixed a8,
+                                           Struct8BytesMixed a9) {
+  std::cout << "PassStruct8BytesMixedx10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << "), (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << "), ("
+            << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << a9.a2 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Argument is a single byte over a multiple of word size.
+// 10 struct arguments will exhaust available registers.
+// Tests upper bytes in the integer registers that are partly filled.
+// Tests stack alignment of non word size stack arguments.
+DART_EXPORT int64_t PassStruct9BytesIntx10(Struct9BytesInt a0,
+                                           Struct9BytesInt a1,
+                                           Struct9BytesInt a2,
+                                           Struct9BytesInt a3,
+                                           Struct9BytesInt a4,
+                                           Struct9BytesInt a5,
+                                           Struct9BytesInt a6,
+                                           Struct9BytesInt a7,
+                                           Struct9BytesInt a8,
+                                           Struct9BytesInt a9) {
+  std::cout << "PassStruct9BytesIntx10"
+            << "((" << a0.a0 << ", " << static_cast<int>(a0.a1) << "), ("
+            << a1.a0 << ", " << static_cast<int>(a1.a1) << "), (" << a2.a0
+            << ", " << static_cast<int>(a2.a1) << "), (" << a3.a0 << ", "
+            << static_cast<int>(a3.a1) << "), (" << a4.a0 << ", "
+            << static_cast<int>(a4.a1) << "), (" << a5.a0 << ", "
+            << static_cast<int>(a5.a1) << "), (" << a6.a0 << ", "
+            << static_cast<int>(a6.a1) << "), (" << a7.a0 << ", "
+            << static_cast<int>(a7.a1) << "), (" << a8.a0 << ", "
+            << static_cast<int>(a8.a1) << "), (" << a9.a0 << ", "
+            << static_cast<int>(a9.a1) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+//
+DART_EXPORT int64_t
+PassStruct9BytesHomogeneousUint82x10(Struct9BytesHomogeneousUint82 a0,
+                                     Struct9BytesHomogeneousUint82 a1,
+                                     Struct9BytesHomogeneousUint82 a2,
+                                     Struct9BytesHomogeneousUint82 a3,
+                                     Struct9BytesHomogeneousUint82 a4,
+                                     Struct9BytesHomogeneousUint82 a5,
+                                     Struct9BytesHomogeneousUint82 a6,
+                                     Struct9BytesHomogeneousUint82 a7,
+                                     Struct9BytesHomogeneousUint82 a8,
+                                     Struct9BytesHomogeneousUint82 a9) {
+  std::cout
+      << "PassStruct9BytesHomogeneousUint82x10"
+      << "((" << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
+      << ", " << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
+      << ", " << static_cast<int>(a0.a4) << ", " << static_cast<int>(a0.a5)
+      << ", " << static_cast<int>(a0.a6) << ", " << static_cast<int>(a0.a7)
+      << ", " << static_cast<int>(a0.a8) << "), (" << static_cast<int>(a1.a0)
+      << ", " << static_cast<int>(a1.a1) << ", " << static_cast<int>(a1.a2)
+      << ", " << static_cast<int>(a1.a3) << ", " << static_cast<int>(a1.a4)
+      << ", " << static_cast<int>(a1.a5) << ", " << static_cast<int>(a1.a6)
+      << ", " << static_cast<int>(a1.a7) << ", " << static_cast<int>(a1.a8)
+      << "), (" << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
+      << ", " << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
+      << ", " << static_cast<int>(a2.a4) << ", " << static_cast<int>(a2.a5)
+      << ", " << static_cast<int>(a2.a6) << ", " << static_cast<int>(a2.a7)
+      << ", " << static_cast<int>(a2.a8) << "), (" << static_cast<int>(a3.a0)
+      << ", " << static_cast<int>(a3.a1) << ", " << static_cast<int>(a3.a2)
+      << ", " << static_cast<int>(a3.a3) << ", " << static_cast<int>(a3.a4)
+      << ", " << static_cast<int>(a3.a5) << ", " << static_cast<int>(a3.a6)
+      << ", " << static_cast<int>(a3.a7) << ", " << static_cast<int>(a3.a8)
+      << "), (" << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
+      << ", " << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
+      << ", " << static_cast<int>(a4.a4) << ", " << static_cast<int>(a4.a5)
+      << ", " << static_cast<int>(a4.a6) << ", " << static_cast<int>(a4.a7)
+      << ", " << static_cast<int>(a4.a8) << "), (" << static_cast<int>(a5.a0)
+      << ", " << static_cast<int>(a5.a1) << ", " << static_cast<int>(a5.a2)
+      << ", " << static_cast<int>(a5.a3) << ", " << static_cast<int>(a5.a4)
+      << ", " << static_cast<int>(a5.a5) << ", " << static_cast<int>(a5.a6)
+      << ", " << static_cast<int>(a5.a7) << ", " << static_cast<int>(a5.a8)
+      << "), (" << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
+      << ", " << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
+      << ", " << static_cast<int>(a6.a4) << ", " << static_cast<int>(a6.a5)
+      << ", " << static_cast<int>(a6.a6) << ", " << static_cast<int>(a6.a7)
+      << ", " << static_cast<int>(a6.a8) << "), (" << static_cast<int>(a7.a0)
+      << ", " << static_cast<int>(a7.a1) << ", " << static_cast<int>(a7.a2)
+      << ", " << static_cast<int>(a7.a3) << ", " << static_cast<int>(a7.a4)
+      << ", " << static_cast<int>(a7.a5) << ", " << static_cast<int>(a7.a6)
+      << ", " << static_cast<int>(a7.a7) << ", " << static_cast<int>(a7.a8)
+      << "), (" << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
+      << ", " << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
+      << ", " << static_cast<int>(a8.a4) << ", " << static_cast<int>(a8.a5)
+      << ", " << static_cast<int>(a8.a6) << ", " << static_cast<int>(a8.a7)
+      << ", " << static_cast<int>(a8.a8) << "), (" << static_cast<int>(a9.a0)
+      << ", " << static_cast<int>(a9.a1) << ", " << static_cast<int>(a9.a2)
+      << ", " << static_cast<int>(a9.a3) << ", " << static_cast<int>(a9.a4)
+      << ", " << static_cast<int>(a9.a5) << ", " << static_cast<int>(a9.a6)
+      << ", " << static_cast<int>(a9.a7) << ", " << static_cast<int>(a9.a8)
+      << "))"
+      << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+  result += a0.a5;
+  result += a0.a6;
+  result += a0.a7;
+  result += a0.a8;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a1.a4;
+  result += a1.a5;
+  result += a1.a6;
+  result += a1.a7;
+  result += a1.a8;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a2.a4;
+  result += a2.a5;
+  result += a2.a6;
+  result += a2.a7;
+  result += a2.a8;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a3.a4;
+  result += a3.a5;
+  result += a3.a6;
+  result += a3.a7;
+  result += a3.a8;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+  result += a4.a4;
+  result += a4.a5;
+  result += a4.a6;
+  result += a4.a7;
+  result += a4.a8;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a5.a4;
+  result += a5.a5;
+  result += a5.a6;
+  result += a5.a7;
+  result += a5.a8;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a6.a3;
+  result += a6.a4;
+  result += a6.a5;
+  result += a6.a6;
+  result += a6.a7;
+  result += a6.a8;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a7.a4;
+  result += a7.a5;
+  result += a7.a6;
+  result += a7.a7;
+  result += a7.a8;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a8.a3;
+  result += a8.a4;
+  result += a8.a5;
+  result += a8.a6;
+  result += a8.a7;
+  result += a8.a8;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+  result += a9.a3;
+  result += a9.a4;
+  result += a9.a5;
+  result += a9.a6;
+  result += a9.a7;
+  result += a9.a8;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT float PassStruct12BytesHomogeneousFloatx6(
+    Struct12BytesHomogeneousFloat a0,
+    Struct12BytesHomogeneousFloat a1,
+    Struct12BytesHomogeneousFloat a2,
+    Struct12BytesHomogeneousFloat a3,
+    Struct12BytesHomogeneousFloat a4,
+    Struct12BytesHomogeneousFloat a5) {
+  std::cout << "PassStruct12BytesHomogeneousFloatx6"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT float PassStruct16BytesHomogeneousFloatx5(
+    Struct16BytesHomogeneousFloat a0,
+    Struct16BytesHomogeneousFloat a1,
+    Struct16BytesHomogeneousFloat a2,
+    Struct16BytesHomogeneousFloat a3,
+    Struct16BytesHomogeneousFloat a4) {
+  std::cout << "PassStruct16BytesHomogeneousFloatx5"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT double PassStruct16BytesMixedx10(Struct16BytesMixed a0,
+                                             Struct16BytesMixed a1,
+                                             Struct16BytesMixed a2,
+                                             Struct16BytesMixed a3,
+                                             Struct16BytesMixed a4,
+                                             Struct16BytesMixed a5,
+                                             Struct16BytesMixed a6,
+                                             Struct16BytesMixed a7,
+                                             Struct16BytesMixed a8,
+                                             Struct16BytesMixed a9) {
+  std::cout << "PassStruct16BytesMixedx10"
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << "\n";
+
+  double result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT float PassStruct16BytesMixed2x10(Struct16BytesMixed2 a0,
+                                             Struct16BytesMixed2 a1,
+                                             Struct16BytesMixed2 a2,
+                                             Struct16BytesMixed2 a3,
+                                             Struct16BytesMixed2 a4,
+                                             Struct16BytesMixed2 a5,
+                                             Struct16BytesMixed2 a6,
+                                             Struct16BytesMixed2 a7,
+                                             Struct16BytesMixed2 a8,
+                                             Struct16BytesMixed2 a9) {
+  std::cout << "PassStruct16BytesMixed2x10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "), (" << a5.a0 << ", "
+            << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), (" << a6.a0
+            << ", " << a6.a1 << ", " << a6.a2 << ", " << a6.a3 << "), ("
+            << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), (" << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << ", "
+            << a8.a3 << "), (" << a9.a0 << ", " << a9.a1 << ", " << a9.a2
+            << ", " << a9.a3 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a6.a3;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a8.a3;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+  result += a9.a3;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Arguments are passed as pointer to copy on arm64.
+// Tests that the memory allocated for copies are rounded up to word size.
+DART_EXPORT int64_t PassStruct17BytesIntx10(Struct17BytesInt a0,
+                                            Struct17BytesInt a1,
+                                            Struct17BytesInt a2,
+                                            Struct17BytesInt a3,
+                                            Struct17BytesInt a4,
+                                            Struct17BytesInt a5,
+                                            Struct17BytesInt a6,
+                                            Struct17BytesInt a7,
+                                            Struct17BytesInt a8,
+                                            Struct17BytesInt a9) {
+  std::cout << "PassStruct17BytesIntx10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << static_cast<int>(a0.a2)
+            << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << static_cast<int>(a1.a2) << "), (" << a2.a0 << ", " << a2.a1
+            << ", " << static_cast<int>(a2.a2) << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << static_cast<int>(a3.a2) << "), (" << a4.a0
+            << ", " << a4.a1 << ", " << static_cast<int>(a4.a2) << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << static_cast<int>(a5.a2)
+            << "), (" << a6.a0 << ", " << a6.a1 << ", "
+            << static_cast<int>(a6.a2) << "), (" << a7.a0 << ", " << a7.a1
+            << ", " << static_cast<int>(a7.a2) << "), (" << a8.a0 << ", "
+            << a8.a1 << ", " << static_cast<int>(a8.a2) << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << static_cast<int>(a9.a2) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+//
+DART_EXPORT int64_t
+PassStruct19BytesHomogeneousUint8x10(Struct19BytesHomogeneousUint8 a0,
+                                     Struct19BytesHomogeneousUint8 a1,
+                                     Struct19BytesHomogeneousUint8 a2,
+                                     Struct19BytesHomogeneousUint8 a3,
+                                     Struct19BytesHomogeneousUint8 a4,
+                                     Struct19BytesHomogeneousUint8 a5,
+                                     Struct19BytesHomogeneousUint8 a6,
+                                     Struct19BytesHomogeneousUint8 a7,
+                                     Struct19BytesHomogeneousUint8 a8,
+                                     Struct19BytesHomogeneousUint8 a9) {
+  std::cout
+      << "PassStruct19BytesHomogeneousUint8x10"
+      << "((" << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
+      << ", " << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
+      << ", " << static_cast<int>(a0.a4) << ", " << static_cast<int>(a0.a5)
+      << ", " << static_cast<int>(a0.a6) << ", " << static_cast<int>(a0.a7)
+      << ", " << static_cast<int>(a0.a8) << ", " << static_cast<int>(a0.a9)
+      << ", " << static_cast<int>(a0.a10) << ", " << static_cast<int>(a0.a11)
+      << ", " << static_cast<int>(a0.a12) << ", " << static_cast<int>(a0.a13)
+      << ", " << static_cast<int>(a0.a14) << ", " << static_cast<int>(a0.a15)
+      << ", " << static_cast<int>(a0.a16) << ", " << static_cast<int>(a0.a17)
+      << ", " << static_cast<int>(a0.a18) << "), (" << static_cast<int>(a1.a0)
+      << ", " << static_cast<int>(a1.a1) << ", " << static_cast<int>(a1.a2)
+      << ", " << static_cast<int>(a1.a3) << ", " << static_cast<int>(a1.a4)
+      << ", " << static_cast<int>(a1.a5) << ", " << static_cast<int>(a1.a6)
+      << ", " << static_cast<int>(a1.a7) << ", " << static_cast<int>(a1.a8)
+      << ", " << static_cast<int>(a1.a9) << ", " << static_cast<int>(a1.a10)
+      << ", " << static_cast<int>(a1.a11) << ", " << static_cast<int>(a1.a12)
+      << ", " << static_cast<int>(a1.a13) << ", " << static_cast<int>(a1.a14)
+      << ", " << static_cast<int>(a1.a15) << ", " << static_cast<int>(a1.a16)
+      << ", " << static_cast<int>(a1.a17) << ", " << static_cast<int>(a1.a18)
+      << "), (" << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
+      << ", " << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
+      << ", " << static_cast<int>(a2.a4) << ", " << static_cast<int>(a2.a5)
+      << ", " << static_cast<int>(a2.a6) << ", " << static_cast<int>(a2.a7)
+      << ", " << static_cast<int>(a2.a8) << ", " << static_cast<int>(a2.a9)
+      << ", " << static_cast<int>(a2.a10) << ", " << static_cast<int>(a2.a11)
+      << ", " << static_cast<int>(a2.a12) << ", " << static_cast<int>(a2.a13)
+      << ", " << static_cast<int>(a2.a14) << ", " << static_cast<int>(a2.a15)
+      << ", " << static_cast<int>(a2.a16) << ", " << static_cast<int>(a2.a17)
+      << ", " << static_cast<int>(a2.a18) << "), (" << static_cast<int>(a3.a0)
+      << ", " << static_cast<int>(a3.a1) << ", " << static_cast<int>(a3.a2)
+      << ", " << static_cast<int>(a3.a3) << ", " << static_cast<int>(a3.a4)
+      << ", " << static_cast<int>(a3.a5) << ", " << static_cast<int>(a3.a6)
+      << ", " << static_cast<int>(a3.a7) << ", " << static_cast<int>(a3.a8)
+      << ", " << static_cast<int>(a3.a9) << ", " << static_cast<int>(a3.a10)
+      << ", " << static_cast<int>(a3.a11) << ", " << static_cast<int>(a3.a12)
+      << ", " << static_cast<int>(a3.a13) << ", " << static_cast<int>(a3.a14)
+      << ", " << static_cast<int>(a3.a15) << ", " << static_cast<int>(a3.a16)
+      << ", " << static_cast<int>(a3.a17) << ", " << static_cast<int>(a3.a18)
+      << "), (" << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
+      << ", " << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
+      << ", " << static_cast<int>(a4.a4) << ", " << static_cast<int>(a4.a5)
+      << ", " << static_cast<int>(a4.a6) << ", " << static_cast<int>(a4.a7)
+      << ", " << static_cast<int>(a4.a8) << ", " << static_cast<int>(a4.a9)
+      << ", " << static_cast<int>(a4.a10) << ", " << static_cast<int>(a4.a11)
+      << ", " << static_cast<int>(a4.a12) << ", " << static_cast<int>(a4.a13)
+      << ", " << static_cast<int>(a4.a14) << ", " << static_cast<int>(a4.a15)
+      << ", " << static_cast<int>(a4.a16) << ", " << static_cast<int>(a4.a17)
+      << ", " << static_cast<int>(a4.a18) << "), (" << static_cast<int>(a5.a0)
+      << ", " << static_cast<int>(a5.a1) << ", " << static_cast<int>(a5.a2)
+      << ", " << static_cast<int>(a5.a3) << ", " << static_cast<int>(a5.a4)
+      << ", " << static_cast<int>(a5.a5) << ", " << static_cast<int>(a5.a6)
+      << ", " << static_cast<int>(a5.a7) << ", " << static_cast<int>(a5.a8)
+      << ", " << static_cast<int>(a5.a9) << ", " << static_cast<int>(a5.a10)
+      << ", " << static_cast<int>(a5.a11) << ", " << static_cast<int>(a5.a12)
+      << ", " << static_cast<int>(a5.a13) << ", " << static_cast<int>(a5.a14)
+      << ", " << static_cast<int>(a5.a15) << ", " << static_cast<int>(a5.a16)
+      << ", " << static_cast<int>(a5.a17) << ", " << static_cast<int>(a5.a18)
+      << "), (" << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
+      << ", " << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
+      << ", " << static_cast<int>(a6.a4) << ", " << static_cast<int>(a6.a5)
+      << ", " << static_cast<int>(a6.a6) << ", " << static_cast<int>(a6.a7)
+      << ", " << static_cast<int>(a6.a8) << ", " << static_cast<int>(a6.a9)
+      << ", " << static_cast<int>(a6.a10) << ", " << static_cast<int>(a6.a11)
+      << ", " << static_cast<int>(a6.a12) << ", " << static_cast<int>(a6.a13)
+      << ", " << static_cast<int>(a6.a14) << ", " << static_cast<int>(a6.a15)
+      << ", " << static_cast<int>(a6.a16) << ", " << static_cast<int>(a6.a17)
+      << ", " << static_cast<int>(a6.a18) << "), (" << static_cast<int>(a7.a0)
+      << ", " << static_cast<int>(a7.a1) << ", " << static_cast<int>(a7.a2)
+      << ", " << static_cast<int>(a7.a3) << ", " << static_cast<int>(a7.a4)
+      << ", " << static_cast<int>(a7.a5) << ", " << static_cast<int>(a7.a6)
+      << ", " << static_cast<int>(a7.a7) << ", " << static_cast<int>(a7.a8)
+      << ", " << static_cast<int>(a7.a9) << ", " << static_cast<int>(a7.a10)
+      << ", " << static_cast<int>(a7.a11) << ", " << static_cast<int>(a7.a12)
+      << ", " << static_cast<int>(a7.a13) << ", " << static_cast<int>(a7.a14)
+      << ", " << static_cast<int>(a7.a15) << ", " << static_cast<int>(a7.a16)
+      << ", " << static_cast<int>(a7.a17) << ", " << static_cast<int>(a7.a18)
+      << "), (" << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
+      << ", " << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
+      << ", " << static_cast<int>(a8.a4) << ", " << static_cast<int>(a8.a5)
+      << ", " << static_cast<int>(a8.a6) << ", " << static_cast<int>(a8.a7)
+      << ", " << static_cast<int>(a8.a8) << ", " << static_cast<int>(a8.a9)
+      << ", " << static_cast<int>(a8.a10) << ", " << static_cast<int>(a8.a11)
+      << ", " << static_cast<int>(a8.a12) << ", " << static_cast<int>(a8.a13)
+      << ", " << static_cast<int>(a8.a14) << ", " << static_cast<int>(a8.a15)
+      << ", " << static_cast<int>(a8.a16) << ", " << static_cast<int>(a8.a17)
+      << ", " << static_cast<int>(a8.a18) << "), (" << static_cast<int>(a9.a0)
+      << ", " << static_cast<int>(a9.a1) << ", " << static_cast<int>(a9.a2)
+      << ", " << static_cast<int>(a9.a3) << ", " << static_cast<int>(a9.a4)
+      << ", " << static_cast<int>(a9.a5) << ", " << static_cast<int>(a9.a6)
+      << ", " << static_cast<int>(a9.a7) << ", " << static_cast<int>(a9.a8)
+      << ", " << static_cast<int>(a9.a9) << ", " << static_cast<int>(a9.a10)
+      << ", " << static_cast<int>(a9.a11) << ", " << static_cast<int>(a9.a12)
+      << ", " << static_cast<int>(a9.a13) << ", " << static_cast<int>(a9.a14)
+      << ", " << static_cast<int>(a9.a15) << ", " << static_cast<int>(a9.a16)
+      << ", " << static_cast<int>(a9.a17) << ", " << static_cast<int>(a9.a18)
+      << "))"
+      << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+  result += a0.a5;
+  result += a0.a6;
+  result += a0.a7;
+  result += a0.a8;
+  result += a0.a9;
+  result += a0.a10;
+  result += a0.a11;
+  result += a0.a12;
+  result += a0.a13;
+  result += a0.a14;
+  result += a0.a15;
+  result += a0.a16;
+  result += a0.a17;
+  result += a0.a18;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a1.a4;
+  result += a1.a5;
+  result += a1.a6;
+  result += a1.a7;
+  result += a1.a8;
+  result += a1.a9;
+  result += a1.a10;
+  result += a1.a11;
+  result += a1.a12;
+  result += a1.a13;
+  result += a1.a14;
+  result += a1.a15;
+  result += a1.a16;
+  result += a1.a17;
+  result += a1.a18;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a2.a4;
+  result += a2.a5;
+  result += a2.a6;
+  result += a2.a7;
+  result += a2.a8;
+  result += a2.a9;
+  result += a2.a10;
+  result += a2.a11;
+  result += a2.a12;
+  result += a2.a13;
+  result += a2.a14;
+  result += a2.a15;
+  result += a2.a16;
+  result += a2.a17;
+  result += a2.a18;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a3.a4;
+  result += a3.a5;
+  result += a3.a6;
+  result += a3.a7;
+  result += a3.a8;
+  result += a3.a9;
+  result += a3.a10;
+  result += a3.a11;
+  result += a3.a12;
+  result += a3.a13;
+  result += a3.a14;
+  result += a3.a15;
+  result += a3.a16;
+  result += a3.a17;
+  result += a3.a18;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+  result += a4.a4;
+  result += a4.a5;
+  result += a4.a6;
+  result += a4.a7;
+  result += a4.a8;
+  result += a4.a9;
+  result += a4.a10;
+  result += a4.a11;
+  result += a4.a12;
+  result += a4.a13;
+  result += a4.a14;
+  result += a4.a15;
+  result += a4.a16;
+  result += a4.a17;
+  result += a4.a18;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a5.a4;
+  result += a5.a5;
+  result += a5.a6;
+  result += a5.a7;
+  result += a5.a8;
+  result += a5.a9;
+  result += a5.a10;
+  result += a5.a11;
+  result += a5.a12;
+  result += a5.a13;
+  result += a5.a14;
+  result += a5.a15;
+  result += a5.a16;
+  result += a5.a17;
+  result += a5.a18;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a6.a3;
+  result += a6.a4;
+  result += a6.a5;
+  result += a6.a6;
+  result += a6.a7;
+  result += a6.a8;
+  result += a6.a9;
+  result += a6.a10;
+  result += a6.a11;
+  result += a6.a12;
+  result += a6.a13;
+  result += a6.a14;
+  result += a6.a15;
+  result += a6.a16;
+  result += a6.a17;
+  result += a6.a18;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a7.a4;
+  result += a7.a5;
+  result += a7.a6;
+  result += a7.a7;
+  result += a7.a8;
+  result += a7.a9;
+  result += a7.a10;
+  result += a7.a11;
+  result += a7.a12;
+  result += a7.a13;
+  result += a7.a14;
+  result += a7.a15;
+  result += a7.a16;
+  result += a7.a17;
+  result += a7.a18;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a8.a3;
+  result += a8.a4;
+  result += a8.a5;
+  result += a8.a6;
+  result += a8.a7;
+  result += a8.a8;
+  result += a8.a9;
+  result += a8.a10;
+  result += a8.a11;
+  result += a8.a12;
+  result += a8.a13;
+  result += a8.a14;
+  result += a8.a15;
+  result += a8.a16;
+  result += a8.a17;
+  result += a8.a18;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+  result += a9.a3;
+  result += a9.a4;
+  result += a9.a5;
+  result += a9.a6;
+  result += a9.a7;
+  result += a9.a8;
+  result += a9.a9;
+  result += a9.a10;
+  result += a9.a11;
+  result += a9.a12;
+  result += a9.a13;
+  result += a9.a14;
+  result += a9.a15;
+  result += a9.a16;
+  result += a9.a17;
+  result += a9.a18;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT int32_t
+PassStruct20BytesHomogeneousInt32x10(Struct20BytesHomogeneousInt32 a0,
+                                     Struct20BytesHomogeneousInt32 a1,
+                                     Struct20BytesHomogeneousInt32 a2,
+                                     Struct20BytesHomogeneousInt32 a3,
+                                     Struct20BytesHomogeneousInt32 a4,
+                                     Struct20BytesHomogeneousInt32 a5,
+                                     Struct20BytesHomogeneousInt32 a6,
+                                     Struct20BytesHomogeneousInt32 a7,
+                                     Struct20BytesHomogeneousInt32 a8,
+                                     Struct20BytesHomogeneousInt32 a9) {
+  std::cout << "PassStruct20BytesHomogeneousInt32x10"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << a1.a2 << ", " << a1.a3 << ", " << a1.a4 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << ", " << a2.a3 << ", " << a2.a4
+            << "), (" << a3.a0 << ", " << a3.a1 << ", " << a3.a2 << ", "
+            << a3.a3 << ", " << a3.a4 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << ", " << a4.a4 << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << ", "
+            << a5.a4 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << ", " << a6.a3 << ", " << a6.a4 << "), (" << a7.a0 << ", "
+            << a7.a1 << ", " << a7.a2 << ", " << a7.a3 << ", " << a7.a4
+            << "), (" << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << ", "
+            << a8.a3 << ", " << a8.a4 << "), (" << a9.a0 << ", " << a9.a1
+            << ", " << a9.a2 << ", " << a9.a3 << ", " << a9.a4 << "))"
+            << "\n";
+
+  int32_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a1.a4;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a2.a4;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a3.a4;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+  result += a4.a4;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a5.a4;
+  result += a6.a0;
+  result += a6.a1;
+  result += a6.a2;
+  result += a6.a3;
+  result += a6.a4;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a7.a4;
+  result += a8.a0;
+  result += a8.a1;
+  result += a8.a2;
+  result += a8.a3;
+  result += a8.a4;
+  result += a9.a0;
+  result += a9.a1;
+  result += a9.a2;
+  result += a9.a3;
+  result += a9.a4;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Argument too big to go into FPU registers in hardfp and arm64.
+DART_EXPORT float PassStruct20BytesHomogeneousFloat(
+    Struct20BytesHomogeneousFloat a0) {
+  std::cout << "PassStruct20BytesHomogeneousFloat"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << "\n";
+
+  float result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Arguments in FPU registers on arm64.
+// 5 struct arguments will exhaust available registers.
+DART_EXPORT double PassStruct32BytesHomogeneousDoublex5(
+    Struct32BytesHomogeneousDouble a0,
+    Struct32BytesHomogeneousDouble a1,
+    Struct32BytesHomogeneousDouble a2,
+    Struct32BytesHomogeneousDouble a3,
+    Struct32BytesHomogeneousDouble a4) {
+  std::cout << "PassStruct32BytesHomogeneousDoublex5"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "))"
+            << "\n";
+
+  double result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a2.a0;
+  result += a2.a1;
+  result += a2.a2;
+  result += a2.a3;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a4.a0;
+  result += a4.a1;
+  result += a4.a2;
+  result += a4.a3;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Argument too big to go into FPU registers in arm64.
+DART_EXPORT double PassStruct40BytesHomogeneousDouble(
+    Struct40BytesHomogeneousDouble a0) {
+  std::cout << "PassStruct40BytesHomogeneousDouble"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << "\n";
+
+  double result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test 1kb struct.
+DART_EXPORT uint64_t
+PassStruct1024BytesHomogeneousUint64(Struct1024BytesHomogeneousUint64 a0) {
+  std::cout << "PassStruct1024BytesHomogeneousUint64"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << ", " << a0.a5 << ", " << a0.a6 << ", " << a0.a7
+            << ", " << a0.a8 << ", " << a0.a9 << ", " << a0.a10 << ", "
+            << a0.a11 << ", " << a0.a12 << ", " << a0.a13 << ", " << a0.a14
+            << ", " << a0.a15 << ", " << a0.a16 << ", " << a0.a17 << ", "
+            << a0.a18 << ", " << a0.a19 << ", " << a0.a20 << ", " << a0.a21
+            << ", " << a0.a22 << ", " << a0.a23 << ", " << a0.a24 << ", "
+            << a0.a25 << ", " << a0.a26 << ", " << a0.a27 << ", " << a0.a28
+            << ", " << a0.a29 << ", " << a0.a30 << ", " << a0.a31 << ", "
+            << a0.a32 << ", " << a0.a33 << ", " << a0.a34 << ", " << a0.a35
+            << ", " << a0.a36 << ", " << a0.a37 << ", " << a0.a38 << ", "
+            << a0.a39 << ", " << a0.a40 << ", " << a0.a41 << ", " << a0.a42
+            << ", " << a0.a43 << ", " << a0.a44 << ", " << a0.a45 << ", "
+            << a0.a46 << ", " << a0.a47 << ", " << a0.a48 << ", " << a0.a49
+            << ", " << a0.a50 << ", " << a0.a51 << ", " << a0.a52 << ", "
+            << a0.a53 << ", " << a0.a54 << ", " << a0.a55 << ", " << a0.a56
+            << ", " << a0.a57 << ", " << a0.a58 << ", " << a0.a59 << ", "
+            << a0.a60 << ", " << a0.a61 << ", " << a0.a62 << ", " << a0.a63
+            << ", " << a0.a64 << ", " << a0.a65 << ", " << a0.a66 << ", "
+            << a0.a67 << ", " << a0.a68 << ", " << a0.a69 << ", " << a0.a70
+            << ", " << a0.a71 << ", " << a0.a72 << ", " << a0.a73 << ", "
+            << a0.a74 << ", " << a0.a75 << ", " << a0.a76 << ", " << a0.a77
+            << ", " << a0.a78 << ", " << a0.a79 << ", " << a0.a80 << ", "
+            << a0.a81 << ", " << a0.a82 << ", " << a0.a83 << ", " << a0.a84
+            << ", " << a0.a85 << ", " << a0.a86 << ", " << a0.a87 << ", "
+            << a0.a88 << ", " << a0.a89 << ", " << a0.a90 << ", " << a0.a91
+            << ", " << a0.a92 << ", " << a0.a93 << ", " << a0.a94 << ", "
+            << a0.a95 << ", " << a0.a96 << ", " << a0.a97 << ", " << a0.a98
+            << ", " << a0.a99 << ", " << a0.a100 << ", " << a0.a101 << ", "
+            << a0.a102 << ", " << a0.a103 << ", " << a0.a104 << ", " << a0.a105
+            << ", " << a0.a106 << ", " << a0.a107 << ", " << a0.a108 << ", "
+            << a0.a109 << ", " << a0.a110 << ", " << a0.a111 << ", " << a0.a112
+            << ", " << a0.a113 << ", " << a0.a114 << ", " << a0.a115 << ", "
+            << a0.a116 << ", " << a0.a117 << ", " << a0.a118 << ", " << a0.a119
+            << ", " << a0.a120 << ", " << a0.a121 << ", " << a0.a122 << ", "
+            << a0.a123 << ", " << a0.a124 << ", " << a0.a125 << ", " << a0.a126
+            << ", " << a0.a127 << "))"
+            << "\n";
+
+  uint64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+  result += a0.a5;
+  result += a0.a6;
+  result += a0.a7;
+  result += a0.a8;
+  result += a0.a9;
+  result += a0.a10;
+  result += a0.a11;
+  result += a0.a12;
+  result += a0.a13;
+  result += a0.a14;
+  result += a0.a15;
+  result += a0.a16;
+  result += a0.a17;
+  result += a0.a18;
+  result += a0.a19;
+  result += a0.a20;
+  result += a0.a21;
+  result += a0.a22;
+  result += a0.a23;
+  result += a0.a24;
+  result += a0.a25;
+  result += a0.a26;
+  result += a0.a27;
+  result += a0.a28;
+  result += a0.a29;
+  result += a0.a30;
+  result += a0.a31;
+  result += a0.a32;
+  result += a0.a33;
+  result += a0.a34;
+  result += a0.a35;
+  result += a0.a36;
+  result += a0.a37;
+  result += a0.a38;
+  result += a0.a39;
+  result += a0.a40;
+  result += a0.a41;
+  result += a0.a42;
+  result += a0.a43;
+  result += a0.a44;
+  result += a0.a45;
+  result += a0.a46;
+  result += a0.a47;
+  result += a0.a48;
+  result += a0.a49;
+  result += a0.a50;
+  result += a0.a51;
+  result += a0.a52;
+  result += a0.a53;
+  result += a0.a54;
+  result += a0.a55;
+  result += a0.a56;
+  result += a0.a57;
+  result += a0.a58;
+  result += a0.a59;
+  result += a0.a60;
+  result += a0.a61;
+  result += a0.a62;
+  result += a0.a63;
+  result += a0.a64;
+  result += a0.a65;
+  result += a0.a66;
+  result += a0.a67;
+  result += a0.a68;
+  result += a0.a69;
+  result += a0.a70;
+  result += a0.a71;
+  result += a0.a72;
+  result += a0.a73;
+  result += a0.a74;
+  result += a0.a75;
+  result += a0.a76;
+  result += a0.a77;
+  result += a0.a78;
+  result += a0.a79;
+  result += a0.a80;
+  result += a0.a81;
+  result += a0.a82;
+  result += a0.a83;
+  result += a0.a84;
+  result += a0.a85;
+  result += a0.a86;
+  result += a0.a87;
+  result += a0.a88;
+  result += a0.a89;
+  result += a0.a90;
+  result += a0.a91;
+  result += a0.a92;
+  result += a0.a93;
+  result += a0.a94;
+  result += a0.a95;
+  result += a0.a96;
+  result += a0.a97;
+  result += a0.a98;
+  result += a0.a99;
+  result += a0.a100;
+  result += a0.a101;
+  result += a0.a102;
+  result += a0.a103;
+  result += a0.a104;
+  result += a0.a105;
+  result += a0.a106;
+  result += a0.a107;
+  result += a0.a108;
+  result += a0.a109;
+  result += a0.a110;
+  result += a0.a111;
+  result += a0.a112;
+  result += a0.a113;
+  result += a0.a114;
+  result += a0.a115;
+  result += a0.a116;
+  result += a0.a117;
+  result += a0.a118;
+  result += a0.a119;
+  result += a0.a120;
+  result += a0.a121;
+  result += a0.a122;
+  result += a0.a123;
+  result += a0.a124;
+  result += a0.a125;
+  result += a0.a126;
+  result += a0.a127;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Tests the alignment of structs in FPU registers and backfilling.
+DART_EXPORT float PassFloatStruct16BytesHomogeneousFloatFloatStruct1(
+    float a0,
+    Struct16BytesHomogeneousFloat a1,
+    float a2,
+    Struct16BytesHomogeneousFloat a3,
+    float a4,
+    Struct16BytesHomogeneousFloat a5,
+    float a6,
+    Struct16BytesHomogeneousFloat a7,
+    float a8) {
+  std::cout << "PassFloatStruct16BytesHomogeneousFloatFloatStruct1"
+            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
+            << ", " << a1.a3 << "), " << a2 << ", (" << a3.a0 << ", " << a3.a1
+            << ", " << a3.a2 << ", " << a3.a3 << "), " << a4 << ", (" << a5.a0
+            << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), " << a6
+            << ", (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), " << a8 << ")"
+            << "\n";
+
+  float result = 0;
+
+  result += a0;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a4;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a6;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a8;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Tests the alignment of structs in FPU registers and backfilling.
+DART_EXPORT double PassFloatStruct32BytesHomogeneousDoubleFloatStruct(
+    float a0,
+    Struct32BytesHomogeneousDouble a1,
+    float a2,
+    Struct32BytesHomogeneousDouble a3,
+    float a4,
+    Struct32BytesHomogeneousDouble a5,
+    float a6,
+    Struct32BytesHomogeneousDouble a7,
+    float a8) {
+  std::cout << "PassFloatStruct32BytesHomogeneousDoubleFloatStruct"
+            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
+            << ", " << a1.a3 << "), " << a2 << ", (" << a3.a0 << ", " << a3.a1
+            << ", " << a3.a2 << ", " << a3.a3 << "), " << a4 << ", (" << a5.a0
+            << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), " << a6
+            << ", (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), " << a8 << ")"
+            << "\n";
+
+  double result = 0;
+
+  result += a0;
+  result += a1.a0;
+  result += a1.a1;
+  result += a1.a2;
+  result += a1.a3;
+  result += a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a3.a2;
+  result += a3.a3;
+  result += a4;
+  result += a5.a0;
+  result += a5.a1;
+  result += a5.a2;
+  result += a5.a3;
+  result += a6;
+  result += a7.a0;
+  result += a7.a1;
+  result += a7.a2;
+  result += a7.a3;
+  result += a8;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT double PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+    int8_t a0,
+    Struct16BytesMixed a1,
+    int8_t a2,
+    Struct16BytesMixed a3,
+    int8_t a4,
+    Struct16BytesMixed a5,
+    int8_t a6,
+    Struct16BytesMixed a7,
+    int8_t a8) {
+  std::cout << "PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn"
+            << "(" << static_cast<int>(a0) << ", (" << a1.a0 << ", " << a1.a1
+            << "), " << static_cast<int>(a2) << ", (" << a3.a0 << ", " << a3.a1
+            << "), " << static_cast<int>(a4) << ", (" << a5.a0 << ", " << a5.a1
+            << "), " << static_cast<int>(a6) << ", (" << a7.a0 << ", " << a7.a1
+            << "), " << static_cast<int>(a8) << ")"
+            << "\n";
+
+  double result = 0;
+
+  result += a0;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2;
+  result += a3.a0;
+  result += a3.a1;
+  result += a4;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT double PassDoublex6Struct16BytesMixedx4Int32(double a0,
+                                                         double a1,
+                                                         double a2,
+                                                         double a3,
+                                                         double a4,
+                                                         double a5,
+                                                         Struct16BytesMixed a6,
+                                                         Struct16BytesMixed a7,
+                                                         Struct16BytesMixed a8,
+                                                         Struct16BytesMixed a9,
+                                                         int32_t a10) {
+  std::cout << "PassDoublex6Struct16BytesMixedx4Int32"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", (" << a6.a0 << ", " << a6.a1 << "), (" << a7.a0
+            << ", " << a7.a1 << "), (" << a8.a0 << ", " << a8.a1 << "), ("
+            << a9.a0 << ", " << a9.a1 << "), " << a10 << ")"
+            << "\n";
+
+  double result = 0;
+
+  result += a0;
+  result += a1;
+  result += a2;
+  result += a3;
+  result += a4;
+  result += a5;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8.a0;
+  result += a8.a1;
+  result += a9.a0;
+  result += a9.a1;
+  result += a10;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT double PassInt32x4Struct16BytesMixedx4Double(int32_t a0,
+                                                         int32_t a1,
+                                                         int32_t a2,
+                                                         int32_t a3,
+                                                         Struct16BytesMixed a4,
+                                                         Struct16BytesMixed a5,
+                                                         Struct16BytesMixed a6,
+                                                         Struct16BytesMixed a7,
+                                                         double a8) {
+  std::cout << "PassInt32x4Struct16BytesMixedx4Double"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", ("
+            << a4.a0 << ", " << a4.a1 << "), (" << a5.a0 << ", " << a5.a1
+            << "), (" << a6.a0 << ", " << a6.a1 << "), (" << a7.a0 << ", "
+            << a7.a1 << "), " << a8 << ")"
+            << "\n";
+
+  double result = 0;
+
+  result += a0;
+  result += a1;
+  result += a2;
+  result += a3;
+  result += a4.a0;
+  result += a4.a1;
+  result += a5.a0;
+  result += a5.a1;
+  result += a6.a0;
+  result += a6.a1;
+  result += a7.a0;
+  result += a7.a1;
+  result += a8;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// On various architectures, first struct is allocated on stack.
+// Check that the other two arguments are allocated on registers.
+DART_EXPORT double PassStruct40BytesHomogeneousDoubleStruct4BytesHomo(
+    Struct40BytesHomogeneousDouble a0,
+    Struct4BytesHomogeneousInt16 a1,
+    Struct8BytesHomogeneousFloat a2) {
+  std::cout << "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "), (" << a1.a0 << ", " << a1.a1 << "), ("
+            << a2.a0 << ", " << a2.a1 << "))"
+            << "\n";
+
+  double result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+  result += a0.a3;
+  result += a0.a4;
+  result += a1.a0;
+  result += a1.a1;
+  result += a2.a0;
+  result += a2.a1;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 16 byte int within struct.
+DART_EXPORT int64_t PassStructAlignmentInt16(StructAlignmentInt16 a0) {
+  std::cout << "PassStructAlignmentInt16"
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 32 byte int within struct.
+DART_EXPORT int64_t PassStructAlignmentInt32(StructAlignmentInt32 a0) {
+  std::cout << "PassStructAlignmentInt32"
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 64 byte int within struct.
+DART_EXPORT int64_t PassStructAlignmentInt64(StructAlignmentInt64 a0) {
+  std::cout << "PassStructAlignmentInt64"
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << "\n";
+
+  int64_t result = 0;
+
+  result += a0.a0;
+  result += a0.a1;
+  result += a0.a2;
+
+  std::cout << "result = " << result << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Smallest struct with data.
+DART_EXPORT Struct1ByteInt ReturnStruct1ByteInt(int8_t a0) {
+  std::cout << "ReturnStruct1ByteInt"
+            << "(" << static_cast<int>(a0) << ")"
+            << "\n";
+
+  Struct1ByteInt result;
+
+  result.a0 = a0;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Smaller than word size return value on all architectures.
+DART_EXPORT Struct3BytesInt ReturnStruct3BytesInt(int16_t a0, int8_t a1) {
+  std::cout << "ReturnStruct3BytesInt"
+            << "(" << a0 << ", " << static_cast<int>(a1) << ")"
+            << "\n";
+
+  Struct3BytesInt result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << static_cast<int>(result.a1) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Word size return value on 32 bit architectures..
+DART_EXPORT Struct4BytesHomogeneousInt16
+ReturnStruct4BytesHomogeneousInt16(int16_t a0, int16_t a1) {
+  std::cout << "ReturnStruct4BytesHomogeneousInt16"
+            << "(" << a0 << ", " << a1 << ")"
+            << "\n";
+
+  Struct4BytesHomogeneousInt16 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Non-wordsize return value.
+DART_EXPORT Struct7BytesInt ReturnStruct7BytesInt(int32_t a0,
+                                                  int16_t a1,
+                                                  int8_t a2) {
+  std::cout << "ReturnStruct7BytesInt"
+            << "(" << a0 << ", " << a1 << ", " << static_cast<int>(a2) << ")"
+            << "\n";
+
+  Struct7BytesInt result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in integer registers on many architectures.
+DART_EXPORT Struct8BytesInt ReturnStruct8BytesInt(int16_t a0,
+                                                  int16_t a1,
+                                                  int32_t a2) {
+  std::cout << "ReturnStruct8BytesInt"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << "\n";
+
+  Struct8BytesInt result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in FP registers on many architectures.
+DART_EXPORT Struct8BytesHomogeneousFloat
+ReturnStruct8BytesHomogeneousFloat(float a0, float a1) {
+  std::cout << "ReturnStruct8BytesHomogeneousFloat"
+            << "(" << a0 << ", " << a1 << ")"
+            << "\n";
+
+  Struct8BytesHomogeneousFloat result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+DART_EXPORT Struct8BytesMixed ReturnStruct8BytesMixed(float a0,
+                                                      int16_t a1,
+                                                      int16_t a2) {
+  std::cout << "ReturnStruct8BytesMixed"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << "\n";
+
+  Struct8BytesMixed result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in two integer registers on x64.
+// The second register only contains a single byte.
+DART_EXPORT Struct9BytesInt ReturnStruct9BytesInt(int64_t a0, int8_t a1) {
+  std::cout << "ReturnStruct9BytesInt"
+            << "(" << a0 << ", " << static_cast<int>(a1) << ")"
+            << "\n";
+
+  Struct9BytesInt result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << static_cast<int>(result.a1) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT Struct9BytesHomogeneousUint82
+ReturnStruct9BytesHomogeneousUint82(uint8_t a0,
+                                    uint8_t a1,
+                                    uint8_t a2,
+                                    uint8_t a3,
+                                    uint8_t a4,
+                                    uint8_t a5,
+                                    uint8_t a6,
+                                    uint8_t a7,
+                                    uint8_t a8) {
+  std::cout << "ReturnStruct9BytesHomogeneousUint82"
+            << "(" << static_cast<int>(a0) << ", " << static_cast<int>(a1)
+            << ", " << static_cast<int>(a2) << ", " << static_cast<int>(a3)
+            << ", " << static_cast<int>(a4) << ", " << static_cast<int>(a5)
+            << ", " << static_cast<int>(a6) << ", " << static_cast<int>(a7)
+            << ", " << static_cast<int>(a8) << ")"
+            << "\n";
+
+  Struct9BytesHomogeneousUint82 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+  result.a5 = a5;
+  result.a6 = a6;
+  result.a7 = a7;
+  result.a8 = a8;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", "
+            << static_cast<int>(result.a1) << ", "
+            << static_cast<int>(result.a2) << ", "
+            << static_cast<int>(result.a3) << ", "
+            << static_cast<int>(result.a4) << ", "
+            << static_cast<int>(result.a5) << ", "
+            << static_cast<int>(result.a6) << ", "
+            << static_cast<int>(result.a7) << ", "
+            << static_cast<int>(result.a8) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers, but does not use all registers on arm hardfp
+// and arm64.
+DART_EXPORT Struct12BytesHomogeneousFloat
+ReturnStruct12BytesHomogeneousFloat(float a0, float a1, float a2) {
+  std::cout << "ReturnStruct12BytesHomogeneousFloat"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << "\n";
+
+  Struct12BytesHomogeneousFloat result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers on arm hardfp and arm64.
+DART_EXPORT Struct16BytesHomogeneousFloat
+ReturnStruct16BytesHomogeneousFloat(float a0, float a1, float a2, float a3) {
+  std::cout << "ReturnStruct16BytesHomogeneousFloat"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << "\n";
+
+  Struct16BytesHomogeneousFloat result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+DART_EXPORT Struct16BytesMixed ReturnStruct16BytesMixed(double a0, int64_t a1) {
+  std::cout << "ReturnStruct16BytesMixed"
+            << "(" << a0 << ", " << a1 << ")"
+            << "\n";
+
+  Struct16BytesMixed result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+// The integer register contains half float half int.
+DART_EXPORT Struct16BytesMixed2 ReturnStruct16BytesMixed2(float a0,
+                                                          float a1,
+                                                          float a2,
+                                                          int32_t a3) {
+  std::cout << "ReturnStruct16BytesMixed2"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << "\n";
+
+  Struct16BytesMixed2 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT Struct17BytesInt ReturnStruct17BytesInt(int64_t a0,
+                                                    int64_t a1,
+                                                    int8_t a2) {
+  std::cout << "ReturnStruct17BytesInt"
+            << "(" << a0 << ", " << a1 << ", " << static_cast<int>(a2) << ")"
+            << "\n";
+
+  Struct17BytesInt result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT Struct19BytesHomogeneousUint8
+ReturnStruct19BytesHomogeneousUint8(uint8_t a0,
+                                    uint8_t a1,
+                                    uint8_t a2,
+                                    uint8_t a3,
+                                    uint8_t a4,
+                                    uint8_t a5,
+                                    uint8_t a6,
+                                    uint8_t a7,
+                                    uint8_t a8,
+                                    uint8_t a9,
+                                    uint8_t a10,
+                                    uint8_t a11,
+                                    uint8_t a12,
+                                    uint8_t a13,
+                                    uint8_t a14,
+                                    uint8_t a15,
+                                    uint8_t a16,
+                                    uint8_t a17,
+                                    uint8_t a18) {
+  std::cout << "ReturnStruct19BytesHomogeneousUint8"
+            << "(" << static_cast<int>(a0) << ", " << static_cast<int>(a1)
+            << ", " << static_cast<int>(a2) << ", " << static_cast<int>(a3)
+            << ", " << static_cast<int>(a4) << ", " << static_cast<int>(a5)
+            << ", " << static_cast<int>(a6) << ", " << static_cast<int>(a7)
+            << ", " << static_cast<int>(a8) << ", " << static_cast<int>(a9)
+            << ", " << static_cast<int>(a10) << ", " << static_cast<int>(a11)
+            << ", " << static_cast<int>(a12) << ", " << static_cast<int>(a13)
+            << ", " << static_cast<int>(a14) << ", " << static_cast<int>(a15)
+            << ", " << static_cast<int>(a16) << ", " << static_cast<int>(a17)
+            << ", " << static_cast<int>(a18) << ")"
+            << "\n";
+
+  Struct19BytesHomogeneousUint8 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+  result.a5 = a5;
+  result.a6 = a6;
+  result.a7 = a7;
+  result.a8 = a8;
+  result.a9 = a9;
+  result.a10 = a10;
+  result.a11 = a11;
+  result.a12 = a12;
+  result.a13 = a13;
+  result.a14 = a14;
+  result.a15 = a15;
+  result.a16 = a16;
+  result.a17 = a17;
+  result.a18 = a18;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", "
+            << static_cast<int>(result.a1) << ", "
+            << static_cast<int>(result.a2) << ", "
+            << static_cast<int>(result.a3) << ", "
+            << static_cast<int>(result.a4) << ", "
+            << static_cast<int>(result.a5) << ", "
+            << static_cast<int>(result.a6) << ", "
+            << static_cast<int>(result.a7) << ", "
+            << static_cast<int>(result.a8) << ", "
+            << static_cast<int>(result.a9) << ", "
+            << static_cast<int>(result.a10) << ", "
+            << static_cast<int>(result.a11) << ", "
+            << static_cast<int>(result.a12) << ", "
+            << static_cast<int>(result.a13) << ", "
+            << static_cast<int>(result.a14) << ", "
+            << static_cast<int>(result.a15) << ", "
+            << static_cast<int>(result.a16) << ", "
+            << static_cast<int>(result.a17) << ", "
+            << static_cast<int>(result.a18) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in cpu registers on arm64.
+DART_EXPORT Struct20BytesHomogeneousInt32
+ReturnStruct20BytesHomogeneousInt32(int32_t a0,
+                                    int32_t a1,
+                                    int32_t a2,
+                                    int32_t a3,
+                                    int32_t a4) {
+  std::cout << "ReturnStruct20BytesHomogeneousInt32"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << "\n";
+
+  Struct20BytesHomogeneousInt32 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+DART_EXPORT Struct20BytesHomogeneousFloat
+ReturnStruct20BytesHomogeneousFloat(float a0,
+                                    float a1,
+                                    float a2,
+                                    float a3,
+                                    float a4) {
+  std::cout << "ReturnStruct20BytesHomogeneousFloat"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << "\n";
+
+  Struct20BytesHomogeneousFloat result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers on arm64.
+DART_EXPORT Struct32BytesHomogeneousDouble
+ReturnStruct32BytesHomogeneousDouble(double a0,
+                                     double a1,
+                                     double a2,
+                                     double a3) {
+  std::cout << "ReturnStruct32BytesHomogeneousDouble"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << "\n";
+
+  Struct32BytesHomogeneousDouble result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in FPU registers on arm64.
+DART_EXPORT Struct40BytesHomogeneousDouble
+ReturnStruct40BytesHomogeneousDouble(double a0,
+                                     double a1,
+                                     double a2,
+                                     double a3,
+                                     double a4) {
+  std::cout << "ReturnStruct40BytesHomogeneousDouble"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << "\n";
+
+  Struct40BytesHomogeneousDouble result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test 1kb struct.
+DART_EXPORT Struct1024BytesHomogeneousUint64
+ReturnStruct1024BytesHomogeneousUint64(uint64_t a0,
+                                       uint64_t a1,
+                                       uint64_t a2,
+                                       uint64_t a3,
+                                       uint64_t a4,
+                                       uint64_t a5,
+                                       uint64_t a6,
+                                       uint64_t a7,
+                                       uint64_t a8,
+                                       uint64_t a9,
+                                       uint64_t a10,
+                                       uint64_t a11,
+                                       uint64_t a12,
+                                       uint64_t a13,
+                                       uint64_t a14,
+                                       uint64_t a15,
+                                       uint64_t a16,
+                                       uint64_t a17,
+                                       uint64_t a18,
+                                       uint64_t a19,
+                                       uint64_t a20,
+                                       uint64_t a21,
+                                       uint64_t a22,
+                                       uint64_t a23,
+                                       uint64_t a24,
+                                       uint64_t a25,
+                                       uint64_t a26,
+                                       uint64_t a27,
+                                       uint64_t a28,
+                                       uint64_t a29,
+                                       uint64_t a30,
+                                       uint64_t a31,
+                                       uint64_t a32,
+                                       uint64_t a33,
+                                       uint64_t a34,
+                                       uint64_t a35,
+                                       uint64_t a36,
+                                       uint64_t a37,
+                                       uint64_t a38,
+                                       uint64_t a39,
+                                       uint64_t a40,
+                                       uint64_t a41,
+                                       uint64_t a42,
+                                       uint64_t a43,
+                                       uint64_t a44,
+                                       uint64_t a45,
+                                       uint64_t a46,
+                                       uint64_t a47,
+                                       uint64_t a48,
+                                       uint64_t a49,
+                                       uint64_t a50,
+                                       uint64_t a51,
+                                       uint64_t a52,
+                                       uint64_t a53,
+                                       uint64_t a54,
+                                       uint64_t a55,
+                                       uint64_t a56,
+                                       uint64_t a57,
+                                       uint64_t a58,
+                                       uint64_t a59,
+                                       uint64_t a60,
+                                       uint64_t a61,
+                                       uint64_t a62,
+                                       uint64_t a63,
+                                       uint64_t a64,
+                                       uint64_t a65,
+                                       uint64_t a66,
+                                       uint64_t a67,
+                                       uint64_t a68,
+                                       uint64_t a69,
+                                       uint64_t a70,
+                                       uint64_t a71,
+                                       uint64_t a72,
+                                       uint64_t a73,
+                                       uint64_t a74,
+                                       uint64_t a75,
+                                       uint64_t a76,
+                                       uint64_t a77,
+                                       uint64_t a78,
+                                       uint64_t a79,
+                                       uint64_t a80,
+                                       uint64_t a81,
+                                       uint64_t a82,
+                                       uint64_t a83,
+                                       uint64_t a84,
+                                       uint64_t a85,
+                                       uint64_t a86,
+                                       uint64_t a87,
+                                       uint64_t a88,
+                                       uint64_t a89,
+                                       uint64_t a90,
+                                       uint64_t a91,
+                                       uint64_t a92,
+                                       uint64_t a93,
+                                       uint64_t a94,
+                                       uint64_t a95,
+                                       uint64_t a96,
+                                       uint64_t a97,
+                                       uint64_t a98,
+                                       uint64_t a99,
+                                       uint64_t a100,
+                                       uint64_t a101,
+                                       uint64_t a102,
+                                       uint64_t a103,
+                                       uint64_t a104,
+                                       uint64_t a105,
+                                       uint64_t a106,
+                                       uint64_t a107,
+                                       uint64_t a108,
+                                       uint64_t a109,
+                                       uint64_t a110,
+                                       uint64_t a111,
+                                       uint64_t a112,
+                                       uint64_t a113,
+                                       uint64_t a114,
+                                       uint64_t a115,
+                                       uint64_t a116,
+                                       uint64_t a117,
+                                       uint64_t a118,
+                                       uint64_t a119,
+                                       uint64_t a120,
+                                       uint64_t a121,
+                                       uint64_t a122,
+                                       uint64_t a123,
+                                       uint64_t a124,
+                                       uint64_t a125,
+                                       uint64_t a126,
+                                       uint64_t a127) {
+  std::cout << "ReturnStruct1024BytesHomogeneousUint64"
+            << "(" << 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 << ")"
+            << "\n";
+
+  Struct1024BytesHomogeneousUint64 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+  result.a3 = a3;
+  result.a4 = a4;
+  result.a5 = a5;
+  result.a6 = a6;
+  result.a7 = a7;
+  result.a8 = a8;
+  result.a9 = a9;
+  result.a10 = a10;
+  result.a11 = a11;
+  result.a12 = a12;
+  result.a13 = a13;
+  result.a14 = a14;
+  result.a15 = a15;
+  result.a16 = a16;
+  result.a17 = a17;
+  result.a18 = a18;
+  result.a19 = a19;
+  result.a20 = a20;
+  result.a21 = a21;
+  result.a22 = a22;
+  result.a23 = a23;
+  result.a24 = a24;
+  result.a25 = a25;
+  result.a26 = a26;
+  result.a27 = a27;
+  result.a28 = a28;
+  result.a29 = a29;
+  result.a30 = a30;
+  result.a31 = a31;
+  result.a32 = a32;
+  result.a33 = a33;
+  result.a34 = a34;
+  result.a35 = a35;
+  result.a36 = a36;
+  result.a37 = a37;
+  result.a38 = a38;
+  result.a39 = a39;
+  result.a40 = a40;
+  result.a41 = a41;
+  result.a42 = a42;
+  result.a43 = a43;
+  result.a44 = a44;
+  result.a45 = a45;
+  result.a46 = a46;
+  result.a47 = a47;
+  result.a48 = a48;
+  result.a49 = a49;
+  result.a50 = a50;
+  result.a51 = a51;
+  result.a52 = a52;
+  result.a53 = a53;
+  result.a54 = a54;
+  result.a55 = a55;
+  result.a56 = a56;
+  result.a57 = a57;
+  result.a58 = a58;
+  result.a59 = a59;
+  result.a60 = a60;
+  result.a61 = a61;
+  result.a62 = a62;
+  result.a63 = a63;
+  result.a64 = a64;
+  result.a65 = a65;
+  result.a66 = a66;
+  result.a67 = a67;
+  result.a68 = a68;
+  result.a69 = a69;
+  result.a70 = a70;
+  result.a71 = a71;
+  result.a72 = a72;
+  result.a73 = a73;
+  result.a74 = a74;
+  result.a75 = a75;
+  result.a76 = a76;
+  result.a77 = a77;
+  result.a78 = a78;
+  result.a79 = a79;
+  result.a80 = a80;
+  result.a81 = a81;
+  result.a82 = a82;
+  result.a83 = a83;
+  result.a84 = a84;
+  result.a85 = a85;
+  result.a86 = a86;
+  result.a87 = a87;
+  result.a88 = a88;
+  result.a89 = a89;
+  result.a90 = a90;
+  result.a91 = a91;
+  result.a92 = a92;
+  result.a93 = a93;
+  result.a94 = a94;
+  result.a95 = a95;
+  result.a96 = a96;
+  result.a97 = a97;
+  result.a98 = a98;
+  result.a99 = a99;
+  result.a100 = a100;
+  result.a101 = a101;
+  result.a102 = a102;
+  result.a103 = a103;
+  result.a104 = a104;
+  result.a105 = a105;
+  result.a106 = a106;
+  result.a107 = a107;
+  result.a108 = a108;
+  result.a109 = a109;
+  result.a110 = a110;
+  result.a111 = a111;
+  result.a112 = a112;
+  result.a113 = a113;
+  result.a114 = a114;
+  result.a115 = a115;
+  result.a116 = a116;
+  result.a117 = a117;
+  result.a118 = a118;
+  result.a119 = a119;
+  result.a120 = a120;
+  result.a121 = a121;
+  result.a122 = a122;
+  result.a123 = a123;
+  result.a124 = a124;
+  result.a125 = a125;
+  result.a126 = a126;
+  result.a127 = a127;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ", " << result.a5
+            << ", " << result.a6 << ", " << result.a7 << ", " << result.a8
+            << ", " << result.a9 << ", " << result.a10 << ", " << result.a11
+            << ", " << result.a12 << ", " << result.a13 << ", " << result.a14
+            << ", " << result.a15 << ", " << result.a16 << ", " << result.a17
+            << ", " << result.a18 << ", " << result.a19 << ", " << result.a20
+            << ", " << result.a21 << ", " << result.a22 << ", " << result.a23
+            << ", " << result.a24 << ", " << result.a25 << ", " << result.a26
+            << ", " << result.a27 << ", " << result.a28 << ", " << result.a29
+            << ", " << result.a30 << ", " << result.a31 << ", " << result.a32
+            << ", " << result.a33 << ", " << result.a34 << ", " << result.a35
+            << ", " << result.a36 << ", " << result.a37 << ", " << result.a38
+            << ", " << result.a39 << ", " << result.a40 << ", " << result.a41
+            << ", " << result.a42 << ", " << result.a43 << ", " << result.a44
+            << ", " << result.a45 << ", " << result.a46 << ", " << result.a47
+            << ", " << result.a48 << ", " << result.a49 << ", " << result.a50
+            << ", " << result.a51 << ", " << result.a52 << ", " << result.a53
+            << ", " << result.a54 << ", " << result.a55 << ", " << result.a56
+            << ", " << result.a57 << ", " << result.a58 << ", " << result.a59
+            << ", " << result.a60 << ", " << result.a61 << ", " << result.a62
+            << ", " << result.a63 << ", " << result.a64 << ", " << result.a65
+            << ", " << result.a66 << ", " << result.a67 << ", " << result.a68
+            << ", " << result.a69 << ", " << result.a70 << ", " << result.a71
+            << ", " << result.a72 << ", " << result.a73 << ", " << result.a74
+            << ", " << result.a75 << ", " << result.a76 << ", " << result.a77
+            << ", " << result.a78 << ", " << result.a79 << ", " << result.a80
+            << ", " << result.a81 << ", " << result.a82 << ", " << result.a83
+            << ", " << result.a84 << ", " << result.a85 << ", " << result.a86
+            << ", " << result.a87 << ", " << result.a88 << ", " << result.a89
+            << ", " << result.a90 << ", " << result.a91 << ", " << result.a92
+            << ", " << result.a93 << ", " << result.a94 << ", " << result.a95
+            << ", " << result.a96 << ", " << result.a97 << ", " << result.a98
+            << ", " << result.a99 << ", " << result.a100 << ", " << result.a101
+            << ", " << result.a102 << ", " << result.a103 << ", " << result.a104
+            << ", " << result.a105 << ", " << result.a106 << ", " << result.a107
+            << ", " << result.a108 << ", " << result.a109 << ", " << result.a110
+            << ", " << result.a111 << ", " << result.a112 << ", " << result.a113
+            << ", " << result.a114 << ", " << result.a115 << ", " << result.a116
+            << ", " << result.a117 << ", " << result.a118 << ", " << result.a119
+            << ", " << result.a120 << ", " << result.a121 << ", " << result.a122
+            << ", " << result.a123 << ", " << result.a124 << ", " << result.a125
+            << ", " << result.a126 << ", " << result.a127 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed in int registers in most ABIs.
+DART_EXPORT Struct1ByteInt
+ReturnStructArgumentStruct1ByteInt(Struct1ByteInt a0) {
+  std::cout << "ReturnStructArgumentStruct1ByteInt"
+            << "((" << static_cast<int>(a0.a0) << "))"
+            << "\n";
+
+  Struct1ByteInt result = a0;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed on stack on all ABIs.
+DART_EXPORT Struct1ByteInt
+ReturnStructArgumentInt32x8Struct1ByteInt(int32_t a0,
+                                          int32_t a1,
+                                          int32_t a2,
+                                          int32_t a3,
+                                          int32_t a4,
+                                          int32_t a5,
+                                          int32_t a6,
+                                          int32_t a7,
+                                          Struct1ByteInt a8) {
+  std::cout << "ReturnStructArgumentInt32x8Struct1ByteInt"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", " << a6 << ", " << a7 << ", ("
+            << static_cast<int>(a8.a0) << "))"
+            << "\n";
+
+  Struct1ByteInt result = a8;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed in float registers in most ABIs.
+DART_EXPORT Struct8BytesHomogeneousFloat
+ReturnStructArgumentStruct8BytesHomogeneousFloat(
+    Struct8BytesHomogeneousFloat a0) {
+  std::cout << "ReturnStructArgumentStruct8BytesHomogeneousFloat"
+            << "((" << a0.a0 << ", " << a0.a1 << "))"
+            << "\n";
+
+  Struct8BytesHomogeneousFloat result = a0;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// On arm64, both argument and return value are passed in by pointer.
+DART_EXPORT Struct20BytesHomogeneousInt32
+ReturnStructArgumentStruct20BytesHomogeneousInt32(
+    Struct20BytesHomogeneousInt32 a0) {
+  std::cout << "ReturnStructArgumentStruct20BytesHomogeneousInt32"
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << "\n";
+
+  Struct20BytesHomogeneousInt32 result = a0;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// On arm64, both argument and return value are passed in by pointer.
+// Ints exhaust registers, so that pointer is passed on stack.
+DART_EXPORT Struct20BytesHomogeneousInt32
+ReturnStructArgumentInt32x8Struct20BytesHomogeneou(
+    int32_t a0,
+    int32_t a1,
+    int32_t a2,
+    int32_t a3,
+    int32_t a4,
+    int32_t a5,
+    int32_t a6,
+    int32_t a7,
+    Struct20BytesHomogeneousInt32 a8) {
+  std::cout << "ReturnStructArgumentInt32x8Struct20BytesHomogeneou"
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", " << a6 << ", " << a7 << ", (" << a8.a0 << ", "
+            << a8.a1 << ", " << a8.a2 << ", " << a8.a3 << ", " << a8.a4 << "))"
+            << "\n";
+
+  Struct20BytesHomogeneousInt32 result = a8;
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 16 byte int within struct.
+DART_EXPORT StructAlignmentInt16 ReturnStructAlignmentInt16(int8_t a0,
+                                                            int16_t a1,
+                                                            int8_t a2) {
+  std::cout << "ReturnStructAlignmentInt16"
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << "\n";
+
+  StructAlignmentInt16 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 32 byte int within struct.
+DART_EXPORT StructAlignmentInt32 ReturnStructAlignmentInt32(int8_t a0,
+                                                            int32_t a1,
+                                                            int8_t a2) {
+  std::cout << "ReturnStructAlignmentInt32"
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << "\n";
+
+  StructAlignmentInt32 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 64 byte int within struct.
+DART_EXPORT StructAlignmentInt64 ReturnStructAlignmentInt64(int8_t a0,
+                                                            int64_t a1,
+                                                            int8_t a2) {
+  std::cout << "ReturnStructAlignmentInt64"
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << "\n";
+
+  StructAlignmentInt64 result;
+
+  result.a0 = a0;
+  result.a1 = a1;
+  result.a2 = a2;
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  return result;
+}
+
+// Used for testing structs by value.
+// Smallest struct with data.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct1ByteIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct1ByteInt a0,
+                 Struct1ByteInt a1,
+                 Struct1ByteInt a2,
+                 Struct1ByteInt a3,
+                 Struct1ByteInt a4,
+                 Struct1ByteInt a5,
+                 Struct1ByteInt a6,
+                 Struct1ByteInt a7,
+                 Struct1ByteInt a8,
+                 Struct1ByteInt a9)) {
+  Struct1ByteInt a0;
+  Struct1ByteInt a1;
+  Struct1ByteInt a2;
+  Struct1ByteInt a3;
+  Struct1ByteInt a4;
+  Struct1ByteInt a5;
+  Struct1ByteInt a6;
+  Struct1ByteInt a7;
+  Struct1ByteInt a8;
+  Struct1ByteInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct1ByteIntx10("
+            << "((" << static_cast<int>(a0.a0) << "), ("
+            << static_cast<int>(a1.a0) << "), (" << static_cast<int>(a2.a0)
+            << "), (" << static_cast<int>(a3.a0) << "), ("
+            << static_cast<int>(a4.a0) << "), (" << static_cast<int>(a5.a0)
+            << "), (" << static_cast<int>(a6.a0) << "), ("
+            << static_cast<int>(a7.a0) << "), (" << static_cast<int>(a8.a0)
+            << "), (" << static_cast<int>(a9.a0) << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(5, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Not a multiple of word size, not a power of two.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct3BytesIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct3BytesInt a0,
+                 Struct3BytesInt a1,
+                 Struct3BytesInt a2,
+                 Struct3BytesInt a3,
+                 Struct3BytesInt a4,
+                 Struct3BytesInt a5,
+                 Struct3BytesInt a6,
+                 Struct3BytesInt a7,
+                 Struct3BytesInt a8,
+                 Struct3BytesInt a9)) {
+  Struct3BytesInt a0;
+  Struct3BytesInt a1;
+  Struct3BytesInt a2;
+  Struct3BytesInt a3;
+  Struct3BytesInt a4;
+  Struct3BytesInt a5;
+  Struct3BytesInt a6;
+  Struct3BytesInt a7;
+  Struct3BytesInt a8;
+  Struct3BytesInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct3BytesIntx10("
+            << "((" << a0.a0 << ", " << static_cast<int>(a0.a1) << "), ("
+            << a1.a0 << ", " << static_cast<int>(a1.a1) << "), (" << a2.a0
+            << ", " << static_cast<int>(a2.a1) << "), (" << a3.a0 << ", "
+            << static_cast<int>(a3.a1) << "), (" << a4.a0 << ", "
+            << static_cast<int>(a4.a1) << "), (" << a5.a0 << ", "
+            << static_cast<int>(a5.a1) << "), (" << a6.a0 << ", "
+            << static_cast<int>(a6.a1) << "), (" << a7.a0 << ", "
+            << static_cast<int>(a7.a1) << "), (" << a8.a0 << ", "
+            << static_cast<int>(a8.a1) << "), (" << a9.a0 << ", "
+            << static_cast<int>(a9.a1) << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(10, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Exactly word size on 32-bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct4BytesHomogeneousInt16x10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct4BytesHomogeneousInt16 a0,
+                 Struct4BytesHomogeneousInt16 a1,
+                 Struct4BytesHomogeneousInt16 a2,
+                 Struct4BytesHomogeneousInt16 a3,
+                 Struct4BytesHomogeneousInt16 a4,
+                 Struct4BytesHomogeneousInt16 a5,
+                 Struct4BytesHomogeneousInt16 a6,
+                 Struct4BytesHomogeneousInt16 a7,
+                 Struct4BytesHomogeneousInt16 a8,
+                 Struct4BytesHomogeneousInt16 a9)) {
+  Struct4BytesHomogeneousInt16 a0;
+  Struct4BytesHomogeneousInt16 a1;
+  Struct4BytesHomogeneousInt16 a2;
+  Struct4BytesHomogeneousInt16 a3;
+  Struct4BytesHomogeneousInt16 a4;
+  Struct4BytesHomogeneousInt16 a5;
+  Struct4BytesHomogeneousInt16 a6;
+  Struct4BytesHomogeneousInt16 a7;
+  Struct4BytesHomogeneousInt16 a8;
+  Struct4BytesHomogeneousInt16 a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct4BytesHomogeneousInt16x10("
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(10, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Sub word size on 64 bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct7BytesIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct7BytesInt a0,
+                 Struct7BytesInt a1,
+                 Struct7BytesInt a2,
+                 Struct7BytesInt a3,
+                 Struct7BytesInt a4,
+                 Struct7BytesInt a5,
+                 Struct7BytesInt a6,
+                 Struct7BytesInt a7,
+                 Struct7BytesInt a8,
+                 Struct7BytesInt a9)) {
+  Struct7BytesInt a0;
+  Struct7BytesInt a1;
+  Struct7BytesInt a2;
+  Struct7BytesInt a3;
+  Struct7BytesInt a4;
+  Struct7BytesInt a5;
+  Struct7BytesInt a6;
+  Struct7BytesInt a7;
+  Struct7BytesInt a8;
+  Struct7BytesInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct7BytesIntx10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << static_cast<int>(a0.a2)
+            << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << static_cast<int>(a1.a2) << "), (" << a2.a0 << ", " << a2.a1
+            << ", " << static_cast<int>(a2.a2) << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << static_cast<int>(a3.a2) << "), (" << a4.a0
+            << ", " << a4.a1 << ", " << static_cast<int>(a4.a2) << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << static_cast<int>(a5.a2)
+            << "), (" << a6.a0 << ", " << a6.a1 << ", "
+            << static_cast<int>(a6.a2) << "), (" << a7.a0 << ", " << a7.a1
+            << ", " << static_cast<int>(a7.a2) << "), (" << a8.a0 << ", "
+            << a8.a1 << ", " << static_cast<int>(a8.a2) << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << static_cast<int>(a9.a2) << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(15, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Exactly word size struct on 64bit architectures.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct8BytesIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct8BytesInt a0,
+                 Struct8BytesInt a1,
+                 Struct8BytesInt a2,
+                 Struct8BytesInt a3,
+                 Struct8BytesInt a4,
+                 Struct8BytesInt a5,
+                 Struct8BytesInt a6,
+                 Struct8BytesInt a7,
+                 Struct8BytesInt a8,
+                 Struct8BytesInt a9)) {
+  Struct8BytesInt a0;
+  Struct8BytesInt a1;
+  Struct8BytesInt a2;
+  Struct8BytesInt a3;
+  Struct8BytesInt a4;
+  Struct8BytesInt a5;
+  Struct8BytesInt a6;
+  Struct8BytesInt a7;
+  Struct8BytesInt a8;
+  Struct8BytesInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct8BytesIntx10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << "), (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << "), ("
+            << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << a9.a2 << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(15, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Arguments passed in FP registers as long as they fit.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct8BytesHomogeneousFloatx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct8BytesHomogeneousFloat a0,
+               Struct8BytesHomogeneousFloat a1,
+               Struct8BytesHomogeneousFloat a2,
+               Struct8BytesHomogeneousFloat a3,
+               Struct8BytesHomogeneousFloat a4,
+               Struct8BytesHomogeneousFloat a5,
+               Struct8BytesHomogeneousFloat a6,
+               Struct8BytesHomogeneousFloat a7,
+               Struct8BytesHomogeneousFloat a8,
+               Struct8BytesHomogeneousFloat a9)) {
+  Struct8BytesHomogeneousFloat a0;
+  Struct8BytesHomogeneousFloat a1;
+  Struct8BytesHomogeneousFloat a2;
+  Struct8BytesHomogeneousFloat a3;
+  Struct8BytesHomogeneousFloat a4;
+  Struct8BytesHomogeneousFloat a5;
+  Struct8BytesHomogeneousFloat a6;
+  Struct8BytesHomogeneousFloat a7;
+  Struct8BytesHomogeneousFloat a8;
+  Struct8BytesHomogeneousFloat a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct8BytesHomogeneousFloatx10("
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(10.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// On x64, arguments go in int registers because it is not only float.
+// 10 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct8BytesMixedx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct8BytesMixed a0,
+               Struct8BytesMixed a1,
+               Struct8BytesMixed a2,
+               Struct8BytesMixed a3,
+               Struct8BytesMixed a4,
+               Struct8BytesMixed a5,
+               Struct8BytesMixed a6,
+               Struct8BytesMixed a7,
+               Struct8BytesMixed a8,
+               Struct8BytesMixed a9)) {
+  Struct8BytesMixed a0;
+  Struct8BytesMixed a1;
+  Struct8BytesMixed a2;
+  Struct8BytesMixed a3;
+  Struct8BytesMixed a4;
+  Struct8BytesMixed a5;
+  Struct8BytesMixed a6;
+  Struct8BytesMixed a7;
+  Struct8BytesMixed a8;
+  Struct8BytesMixed a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct8BytesMixedx10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << "), (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << "), ("
+            << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << a9.a2 << "))"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(15.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Argument is a single byte over a multiple of word size.
+// 10 struct arguments will exhaust available registers.
+// Tests upper bytes in the integer registers that are partly filled.
+// Tests stack alignment of non word size stack arguments.
+DART_EXPORT intptr_t TestPassStruct9BytesIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct9BytesInt a0,
+                 Struct9BytesInt a1,
+                 Struct9BytesInt a2,
+                 Struct9BytesInt a3,
+                 Struct9BytesInt a4,
+                 Struct9BytesInt a5,
+                 Struct9BytesInt a6,
+                 Struct9BytesInt a7,
+                 Struct9BytesInt a8,
+                 Struct9BytesInt a9)) {
+  Struct9BytesInt a0;
+  Struct9BytesInt a1;
+  Struct9BytesInt a2;
+  Struct9BytesInt a3;
+  Struct9BytesInt a4;
+  Struct9BytesInt a5;
+  Struct9BytesInt a6;
+  Struct9BytesInt a7;
+  Struct9BytesInt a8;
+  Struct9BytesInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct9BytesIntx10("
+            << "((" << a0.a0 << ", " << static_cast<int>(a0.a1) << "), ("
+            << a1.a0 << ", " << static_cast<int>(a1.a1) << "), (" << a2.a0
+            << ", " << static_cast<int>(a2.a1) << "), (" << a3.a0 << ", "
+            << static_cast<int>(a3.a1) << "), (" << a4.a0 << ", "
+            << static_cast<int>(a4.a1) << "), (" << a5.a0 << ", "
+            << static_cast<int>(a5.a1) << "), (" << a6.a0 << ", "
+            << static_cast<int>(a6.a1) << "), (" << a7.a0 << ", "
+            << static_cast<int>(a7.a1) << "), (" << a8.a0 << ", "
+            << static_cast<int>(a8.a1) << "), (" << a9.a0 << ", "
+            << static_cast<int>(a9.a1) << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(10, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+//
+DART_EXPORT intptr_t TestPassStruct9BytesHomogeneousUint82x10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct9BytesHomogeneousUint82 a0,
+                 Struct9BytesHomogeneousUint82 a1,
+                 Struct9BytesHomogeneousUint82 a2,
+                 Struct9BytesHomogeneousUint82 a3,
+                 Struct9BytesHomogeneousUint82 a4,
+                 Struct9BytesHomogeneousUint82 a5,
+                 Struct9BytesHomogeneousUint82 a6,
+                 Struct9BytesHomogeneousUint82 a7,
+                 Struct9BytesHomogeneousUint82 a8,
+                 Struct9BytesHomogeneousUint82 a9)) {
+  Struct9BytesHomogeneousUint82 a0;
+  Struct9BytesHomogeneousUint82 a1;
+  Struct9BytesHomogeneousUint82 a2;
+  Struct9BytesHomogeneousUint82 a3;
+  Struct9BytesHomogeneousUint82 a4;
+  Struct9BytesHomogeneousUint82 a5;
+  Struct9BytesHomogeneousUint82 a6;
+  Struct9BytesHomogeneousUint82 a7;
+  Struct9BytesHomogeneousUint82 a8;
+  Struct9BytesHomogeneousUint82 a9;
+
+  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;
+
+  std::cout
+      << "Calling TestPassStruct9BytesHomogeneousUint82x10("
+      << "((" << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
+      << ", " << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
+      << ", " << static_cast<int>(a0.a4) << ", " << static_cast<int>(a0.a5)
+      << ", " << static_cast<int>(a0.a6) << ", " << static_cast<int>(a0.a7)
+      << ", " << static_cast<int>(a0.a8) << "), (" << static_cast<int>(a1.a0)
+      << ", " << static_cast<int>(a1.a1) << ", " << static_cast<int>(a1.a2)
+      << ", " << static_cast<int>(a1.a3) << ", " << static_cast<int>(a1.a4)
+      << ", " << static_cast<int>(a1.a5) << ", " << static_cast<int>(a1.a6)
+      << ", " << static_cast<int>(a1.a7) << ", " << static_cast<int>(a1.a8)
+      << "), (" << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
+      << ", " << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
+      << ", " << static_cast<int>(a2.a4) << ", " << static_cast<int>(a2.a5)
+      << ", " << static_cast<int>(a2.a6) << ", " << static_cast<int>(a2.a7)
+      << ", " << static_cast<int>(a2.a8) << "), (" << static_cast<int>(a3.a0)
+      << ", " << static_cast<int>(a3.a1) << ", " << static_cast<int>(a3.a2)
+      << ", " << static_cast<int>(a3.a3) << ", " << static_cast<int>(a3.a4)
+      << ", " << static_cast<int>(a3.a5) << ", " << static_cast<int>(a3.a6)
+      << ", " << static_cast<int>(a3.a7) << ", " << static_cast<int>(a3.a8)
+      << "), (" << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
+      << ", " << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
+      << ", " << static_cast<int>(a4.a4) << ", " << static_cast<int>(a4.a5)
+      << ", " << static_cast<int>(a4.a6) << ", " << static_cast<int>(a4.a7)
+      << ", " << static_cast<int>(a4.a8) << "), (" << static_cast<int>(a5.a0)
+      << ", " << static_cast<int>(a5.a1) << ", " << static_cast<int>(a5.a2)
+      << ", " << static_cast<int>(a5.a3) << ", " << static_cast<int>(a5.a4)
+      << ", " << static_cast<int>(a5.a5) << ", " << static_cast<int>(a5.a6)
+      << ", " << static_cast<int>(a5.a7) << ", " << static_cast<int>(a5.a8)
+      << "), (" << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
+      << ", " << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
+      << ", " << static_cast<int>(a6.a4) << ", " << static_cast<int>(a6.a5)
+      << ", " << static_cast<int>(a6.a6) << ", " << static_cast<int>(a6.a7)
+      << ", " << static_cast<int>(a6.a8) << "), (" << static_cast<int>(a7.a0)
+      << ", " << static_cast<int>(a7.a1) << ", " << static_cast<int>(a7.a2)
+      << ", " << static_cast<int>(a7.a3) << ", " << static_cast<int>(a7.a4)
+      << ", " << static_cast<int>(a7.a5) << ", " << static_cast<int>(a7.a6)
+      << ", " << static_cast<int>(a7.a7) << ", " << static_cast<int>(a7.a8)
+      << "), (" << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
+      << ", " << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
+      << ", " << static_cast<int>(a8.a4) << ", " << static_cast<int>(a8.a5)
+      << ", " << static_cast<int>(a8.a6) << ", " << static_cast<int>(a8.a7)
+      << ", " << static_cast<int>(a8.a8) << "), (" << static_cast<int>(a9.a0)
+      << ", " << static_cast<int>(a9.a1) << ", " << static_cast<int>(a9.a2)
+      << ", " << static_cast<int>(a9.a3) << ", " << static_cast<int>(a9.a4)
+      << ", " << static_cast<int>(a9.a5) << ", " << static_cast<int>(a9.a6)
+      << ", " << static_cast<int>(a9.a7) << ", " << static_cast<int>(a9.a8)
+      << "))"
+      << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(4095, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassStruct12BytesHomogeneousFloatx6(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct12BytesHomogeneousFloat a0,
+               Struct12BytesHomogeneousFloat a1,
+               Struct12BytesHomogeneousFloat a2,
+               Struct12BytesHomogeneousFloat a3,
+               Struct12BytesHomogeneousFloat a4,
+               Struct12BytesHomogeneousFloat a5)) {
+  Struct12BytesHomogeneousFloat a0;
+  Struct12BytesHomogeneousFloat a1;
+  Struct12BytesHomogeneousFloat a2;
+  Struct12BytesHomogeneousFloat a3;
+  Struct12BytesHomogeneousFloat a4;
+  Struct12BytesHomogeneousFloat a5;
+
+  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;
+
+  std::cout << "Calling TestPassStruct12BytesHomogeneousFloatx6("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), ("
+            << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << a3.a2 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << "), (" << a5.a0 << ", " << a5.a1 << ", "
+            << a5.a2 << "))"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4, a5);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(9.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassStruct16BytesHomogeneousFloatx5(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct16BytesHomogeneousFloat a0,
+               Struct16BytesHomogeneousFloat a1,
+               Struct16BytesHomogeneousFloat a2,
+               Struct16BytesHomogeneousFloat a3,
+               Struct16BytesHomogeneousFloat a4)) {
+  Struct16BytesHomogeneousFloat a0;
+  Struct16BytesHomogeneousFloat a1;
+  Struct16BytesHomogeneousFloat a2;
+  Struct16BytesHomogeneousFloat a3;
+  Struct16BytesHomogeneousFloat a4;
+
+  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;
+
+  std::cout << "Calling TestPassStruct16BytesHomogeneousFloatx5("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "))"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(10.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassStruct16BytesMixedx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(Struct16BytesMixed a0,
+                Struct16BytesMixed a1,
+                Struct16BytesMixed a2,
+                Struct16BytesMixed a3,
+                Struct16BytesMixed a4,
+                Struct16BytesMixed a5,
+                Struct16BytesMixed a6,
+                Struct16BytesMixed a7,
+                Struct16BytesMixed a8,
+                Struct16BytesMixed a9)) {
+  Struct16BytesMixed a0;
+  Struct16BytesMixed a1;
+  Struct16BytesMixed a2;
+  Struct16BytesMixed a3;
+  Struct16BytesMixed a4;
+  Struct16BytesMixed a5;
+  Struct16BytesMixed a6;
+  Struct16BytesMixed a7;
+  Struct16BytesMixed a8;
+  Struct16BytesMixed a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct16BytesMixedx10("
+            << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+            << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+            << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+            << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+            << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+            << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(10.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassStruct16BytesMixed2x10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct16BytesMixed2 a0,
+               Struct16BytesMixed2 a1,
+               Struct16BytesMixed2 a2,
+               Struct16BytesMixed2 a3,
+               Struct16BytesMixed2 a4,
+               Struct16BytesMixed2 a5,
+               Struct16BytesMixed2 a6,
+               Struct16BytesMixed2 a7,
+               Struct16BytesMixed2 a8,
+               Struct16BytesMixed2 a9)) {
+  Struct16BytesMixed2 a0;
+  Struct16BytesMixed2 a1;
+  Struct16BytesMixed2 a2;
+  Struct16BytesMixed2 a3;
+  Struct16BytesMixed2 a4;
+  Struct16BytesMixed2 a5;
+  Struct16BytesMixed2 a6;
+  Struct16BytesMixed2 a7;
+  Struct16BytesMixed2 a8;
+  Struct16BytesMixed2 a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct16BytesMixed2x10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "), (" << a5.a0 << ", "
+            << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), (" << a6.a0
+            << ", " << a6.a1 << ", " << a6.a2 << ", " << a6.a3 << "), ("
+            << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), (" << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << ", "
+            << a8.a3 << "), (" << a9.a0 << ", " << a9.a1 << ", " << a9.a2
+            << ", " << a9.a3 << "))"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(20.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Arguments are passed as pointer to copy on arm64.
+// Tests that the memory allocated for copies are rounded up to word size.
+DART_EXPORT intptr_t TestPassStruct17BytesIntx10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct17BytesInt a0,
+                 Struct17BytesInt a1,
+                 Struct17BytesInt a2,
+                 Struct17BytesInt a3,
+                 Struct17BytesInt a4,
+                 Struct17BytesInt a5,
+                 Struct17BytesInt a6,
+                 Struct17BytesInt a7,
+                 Struct17BytesInt a8,
+                 Struct17BytesInt a9)) {
+  Struct17BytesInt a0;
+  Struct17BytesInt a1;
+  Struct17BytesInt a2;
+  Struct17BytesInt a3;
+  Struct17BytesInt a4;
+  Struct17BytesInt a5;
+  Struct17BytesInt a6;
+  Struct17BytesInt a7;
+  Struct17BytesInt a8;
+  Struct17BytesInt a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct17BytesIntx10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << static_cast<int>(a0.a2)
+            << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << static_cast<int>(a1.a2) << "), (" << a2.a0 << ", " << a2.a1
+            << ", " << static_cast<int>(a2.a2) << "), (" << a3.a0 << ", "
+            << a3.a1 << ", " << static_cast<int>(a3.a2) << "), (" << a4.a0
+            << ", " << a4.a1 << ", " << static_cast<int>(a4.a2) << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << static_cast<int>(a5.a2)
+            << "), (" << a6.a0 << ", " << a6.a1 << ", "
+            << static_cast<int>(a6.a2) << "), (" << a7.a0 << ", " << a7.a1
+            << ", " << static_cast<int>(a7.a2) << "), (" << a8.a0 << ", "
+            << a8.a1 << ", " << static_cast<int>(a8.a2) << "), (" << a9.a0
+            << ", " << a9.a1 << ", " << static_cast<int>(a9.a2) << "))"
+            << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(15, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+//
+DART_EXPORT intptr_t TestPassStruct19BytesHomogeneousUint8x10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(Struct19BytesHomogeneousUint8 a0,
+                 Struct19BytesHomogeneousUint8 a1,
+                 Struct19BytesHomogeneousUint8 a2,
+                 Struct19BytesHomogeneousUint8 a3,
+                 Struct19BytesHomogeneousUint8 a4,
+                 Struct19BytesHomogeneousUint8 a5,
+                 Struct19BytesHomogeneousUint8 a6,
+                 Struct19BytesHomogeneousUint8 a7,
+                 Struct19BytesHomogeneousUint8 a8,
+                 Struct19BytesHomogeneousUint8 a9)) {
+  Struct19BytesHomogeneousUint8 a0;
+  Struct19BytesHomogeneousUint8 a1;
+  Struct19BytesHomogeneousUint8 a2;
+  Struct19BytesHomogeneousUint8 a3;
+  Struct19BytesHomogeneousUint8 a4;
+  Struct19BytesHomogeneousUint8 a5;
+  Struct19BytesHomogeneousUint8 a6;
+  Struct19BytesHomogeneousUint8 a7;
+  Struct19BytesHomogeneousUint8 a8;
+  Struct19BytesHomogeneousUint8 a9;
+
+  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;
+
+  std::cout
+      << "Calling TestPassStruct19BytesHomogeneousUint8x10("
+      << "((" << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
+      << ", " << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
+      << ", " << static_cast<int>(a0.a4) << ", " << static_cast<int>(a0.a5)
+      << ", " << static_cast<int>(a0.a6) << ", " << static_cast<int>(a0.a7)
+      << ", " << static_cast<int>(a0.a8) << ", " << static_cast<int>(a0.a9)
+      << ", " << static_cast<int>(a0.a10) << ", " << static_cast<int>(a0.a11)
+      << ", " << static_cast<int>(a0.a12) << ", " << static_cast<int>(a0.a13)
+      << ", " << static_cast<int>(a0.a14) << ", " << static_cast<int>(a0.a15)
+      << ", " << static_cast<int>(a0.a16) << ", " << static_cast<int>(a0.a17)
+      << ", " << static_cast<int>(a0.a18) << "), (" << static_cast<int>(a1.a0)
+      << ", " << static_cast<int>(a1.a1) << ", " << static_cast<int>(a1.a2)
+      << ", " << static_cast<int>(a1.a3) << ", " << static_cast<int>(a1.a4)
+      << ", " << static_cast<int>(a1.a5) << ", " << static_cast<int>(a1.a6)
+      << ", " << static_cast<int>(a1.a7) << ", " << static_cast<int>(a1.a8)
+      << ", " << static_cast<int>(a1.a9) << ", " << static_cast<int>(a1.a10)
+      << ", " << static_cast<int>(a1.a11) << ", " << static_cast<int>(a1.a12)
+      << ", " << static_cast<int>(a1.a13) << ", " << static_cast<int>(a1.a14)
+      << ", " << static_cast<int>(a1.a15) << ", " << static_cast<int>(a1.a16)
+      << ", " << static_cast<int>(a1.a17) << ", " << static_cast<int>(a1.a18)
+      << "), (" << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
+      << ", " << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
+      << ", " << static_cast<int>(a2.a4) << ", " << static_cast<int>(a2.a5)
+      << ", " << static_cast<int>(a2.a6) << ", " << static_cast<int>(a2.a7)
+      << ", " << static_cast<int>(a2.a8) << ", " << static_cast<int>(a2.a9)
+      << ", " << static_cast<int>(a2.a10) << ", " << static_cast<int>(a2.a11)
+      << ", " << static_cast<int>(a2.a12) << ", " << static_cast<int>(a2.a13)
+      << ", " << static_cast<int>(a2.a14) << ", " << static_cast<int>(a2.a15)
+      << ", " << static_cast<int>(a2.a16) << ", " << static_cast<int>(a2.a17)
+      << ", " << static_cast<int>(a2.a18) << "), (" << static_cast<int>(a3.a0)
+      << ", " << static_cast<int>(a3.a1) << ", " << static_cast<int>(a3.a2)
+      << ", " << static_cast<int>(a3.a3) << ", " << static_cast<int>(a3.a4)
+      << ", " << static_cast<int>(a3.a5) << ", " << static_cast<int>(a3.a6)
+      << ", " << static_cast<int>(a3.a7) << ", " << static_cast<int>(a3.a8)
+      << ", " << static_cast<int>(a3.a9) << ", " << static_cast<int>(a3.a10)
+      << ", " << static_cast<int>(a3.a11) << ", " << static_cast<int>(a3.a12)
+      << ", " << static_cast<int>(a3.a13) << ", " << static_cast<int>(a3.a14)
+      << ", " << static_cast<int>(a3.a15) << ", " << static_cast<int>(a3.a16)
+      << ", " << static_cast<int>(a3.a17) << ", " << static_cast<int>(a3.a18)
+      << "), (" << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
+      << ", " << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
+      << ", " << static_cast<int>(a4.a4) << ", " << static_cast<int>(a4.a5)
+      << ", " << static_cast<int>(a4.a6) << ", " << static_cast<int>(a4.a7)
+      << ", " << static_cast<int>(a4.a8) << ", " << static_cast<int>(a4.a9)
+      << ", " << static_cast<int>(a4.a10) << ", " << static_cast<int>(a4.a11)
+      << ", " << static_cast<int>(a4.a12) << ", " << static_cast<int>(a4.a13)
+      << ", " << static_cast<int>(a4.a14) << ", " << static_cast<int>(a4.a15)
+      << ", " << static_cast<int>(a4.a16) << ", " << static_cast<int>(a4.a17)
+      << ", " << static_cast<int>(a4.a18) << "), (" << static_cast<int>(a5.a0)
+      << ", " << static_cast<int>(a5.a1) << ", " << static_cast<int>(a5.a2)
+      << ", " << static_cast<int>(a5.a3) << ", " << static_cast<int>(a5.a4)
+      << ", " << static_cast<int>(a5.a5) << ", " << static_cast<int>(a5.a6)
+      << ", " << static_cast<int>(a5.a7) << ", " << static_cast<int>(a5.a8)
+      << ", " << static_cast<int>(a5.a9) << ", " << static_cast<int>(a5.a10)
+      << ", " << static_cast<int>(a5.a11) << ", " << static_cast<int>(a5.a12)
+      << ", " << static_cast<int>(a5.a13) << ", " << static_cast<int>(a5.a14)
+      << ", " << static_cast<int>(a5.a15) << ", " << static_cast<int>(a5.a16)
+      << ", " << static_cast<int>(a5.a17) << ", " << static_cast<int>(a5.a18)
+      << "), (" << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
+      << ", " << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
+      << ", " << static_cast<int>(a6.a4) << ", " << static_cast<int>(a6.a5)
+      << ", " << static_cast<int>(a6.a6) << ", " << static_cast<int>(a6.a7)
+      << ", " << static_cast<int>(a6.a8) << ", " << static_cast<int>(a6.a9)
+      << ", " << static_cast<int>(a6.a10) << ", " << static_cast<int>(a6.a11)
+      << ", " << static_cast<int>(a6.a12) << ", " << static_cast<int>(a6.a13)
+      << ", " << static_cast<int>(a6.a14) << ", " << static_cast<int>(a6.a15)
+      << ", " << static_cast<int>(a6.a16) << ", " << static_cast<int>(a6.a17)
+      << ", " << static_cast<int>(a6.a18) << "), (" << static_cast<int>(a7.a0)
+      << ", " << static_cast<int>(a7.a1) << ", " << static_cast<int>(a7.a2)
+      << ", " << static_cast<int>(a7.a3) << ", " << static_cast<int>(a7.a4)
+      << ", " << static_cast<int>(a7.a5) << ", " << static_cast<int>(a7.a6)
+      << ", " << static_cast<int>(a7.a7) << ", " << static_cast<int>(a7.a8)
+      << ", " << static_cast<int>(a7.a9) << ", " << static_cast<int>(a7.a10)
+      << ", " << static_cast<int>(a7.a11) << ", " << static_cast<int>(a7.a12)
+      << ", " << static_cast<int>(a7.a13) << ", " << static_cast<int>(a7.a14)
+      << ", " << static_cast<int>(a7.a15) << ", " << static_cast<int>(a7.a16)
+      << ", " << static_cast<int>(a7.a17) << ", " << static_cast<int>(a7.a18)
+      << "), (" << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
+      << ", " << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
+      << ", " << static_cast<int>(a8.a4) << ", " << static_cast<int>(a8.a5)
+      << ", " << static_cast<int>(a8.a6) << ", " << static_cast<int>(a8.a7)
+      << ", " << static_cast<int>(a8.a8) << ", " << static_cast<int>(a8.a9)
+      << ", " << static_cast<int>(a8.a10) << ", " << static_cast<int>(a8.a11)
+      << ", " << static_cast<int>(a8.a12) << ", " << static_cast<int>(a8.a13)
+      << ", " << static_cast<int>(a8.a14) << ", " << static_cast<int>(a8.a15)
+      << ", " << static_cast<int>(a8.a16) << ", " << static_cast<int>(a8.a17)
+      << ", " << static_cast<int>(a8.a18) << "), (" << static_cast<int>(a9.a0)
+      << ", " << static_cast<int>(a9.a1) << ", " << static_cast<int>(a9.a2)
+      << ", " << static_cast<int>(a9.a3) << ", " << static_cast<int>(a9.a4)
+      << ", " << static_cast<int>(a9.a5) << ", " << static_cast<int>(a9.a6)
+      << ", " << static_cast<int>(a9.a7) << ", " << static_cast<int>(a9.a8)
+      << ", " << static_cast<int>(a9.a9) << ", " << static_cast<int>(a9.a10)
+      << ", " << static_cast<int>(a9.a11) << ", " << static_cast<int>(a9.a12)
+      << ", " << static_cast<int>(a9.a13) << ", " << static_cast<int>(a9.a14)
+      << ", " << static_cast<int>(a9.a15) << ", " << static_cast<int>(a9.a16)
+      << ", " << static_cast<int>(a9.a17) << ", " << static_cast<int>(a9.a18)
+      << "))"
+      << ")\n";
+
+  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(18145, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassStruct20BytesHomogeneousInt32x10(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int32_t (*f)(Struct20BytesHomogeneousInt32 a0,
+                 Struct20BytesHomogeneousInt32 a1,
+                 Struct20BytesHomogeneousInt32 a2,
+                 Struct20BytesHomogeneousInt32 a3,
+                 Struct20BytesHomogeneousInt32 a4,
+                 Struct20BytesHomogeneousInt32 a5,
+                 Struct20BytesHomogeneousInt32 a6,
+                 Struct20BytesHomogeneousInt32 a7,
+                 Struct20BytesHomogeneousInt32 a8,
+                 Struct20BytesHomogeneousInt32 a9)) {
+  Struct20BytesHomogeneousInt32 a0;
+  Struct20BytesHomogeneousInt32 a1;
+  Struct20BytesHomogeneousInt32 a2;
+  Struct20BytesHomogeneousInt32 a3;
+  Struct20BytesHomogeneousInt32 a4;
+  Struct20BytesHomogeneousInt32 a5;
+  Struct20BytesHomogeneousInt32 a6;
+  Struct20BytesHomogeneousInt32 a7;
+  Struct20BytesHomogeneousInt32 a8;
+  Struct20BytesHomogeneousInt32 a9;
+
+  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;
+
+  std::cout << "Calling TestPassStruct20BytesHomogeneousInt32x10("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "), (" << a1.a0 << ", " << a1.a1 << ", "
+            << a1.a2 << ", " << a1.a3 << ", " << a1.a4 << "), (" << a2.a0
+            << ", " << a2.a1 << ", " << a2.a2 << ", " << a2.a3 << ", " << a2.a4
+            << "), (" << a3.a0 << ", " << a3.a1 << ", " << a3.a2 << ", "
+            << a3.a3 << ", " << a3.a4 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << ", " << a4.a4 << "), ("
+            << a5.a0 << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << ", "
+            << a5.a4 << "), (" << a6.a0 << ", " << a6.a1 << ", " << a6.a2
+            << ", " << a6.a3 << ", " << a6.a4 << "), (" << a7.a0 << ", "
+            << a7.a1 << ", " << a7.a2 << ", " << a7.a3 << ", " << a7.a4
+            << "), (" << a8.a0 << ", " << a8.a1 << ", " << a8.a2 << ", "
+            << a8.a3 << ", " << a8.a4 << "), (" << a9.a0 << ", " << a9.a1
+            << ", " << a9.a2 << ", " << a9.a3 << ", " << a9.a4 << "))"
+            << ")\n";
+
+  int32_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(25, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Argument too big to go into FPU registers in hardfp and arm64.
+DART_EXPORT intptr_t TestPassStruct20BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(Struct20BytesHomogeneousFloat a0)) {
+  Struct20BytesHomogeneousFloat a0;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  std::cout << "Calling TestPassStruct20BytesHomogeneousFloat("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << ")\n";
+
+  float result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-3.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Arguments in FPU registers on arm64.
+// 5 struct arguments will exhaust available registers.
+DART_EXPORT intptr_t TestPassStruct32BytesHomogeneousDoublex5(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(Struct32BytesHomogeneousDouble a0,
+                Struct32BytesHomogeneousDouble a1,
+                Struct32BytesHomogeneousDouble a2,
+                Struct32BytesHomogeneousDouble a3,
+                Struct32BytesHomogeneousDouble a4)) {
+  Struct32BytesHomogeneousDouble a0;
+  Struct32BytesHomogeneousDouble a1;
+  Struct32BytesHomogeneousDouble a2;
+  Struct32BytesHomogeneousDouble a3;
+  Struct32BytesHomogeneousDouble a4;
+
+  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;
+
+  std::cout << "Calling TestPassStruct32BytesHomogeneousDoublex5("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << "), (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", "
+            << a1.a3 << "), (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
+            << ", " << a2.a3 << "), (" << a3.a0 << ", " << a3.a1 << ", "
+            << a3.a2 << ", " << a3.a3 << "), (" << a4.a0 << ", " << a4.a1
+            << ", " << a4.a2 << ", " << a4.a3 << "))"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(10.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Argument too big to go into FPU registers in arm64.
+DART_EXPORT intptr_t TestPassStruct40BytesHomogeneousDouble(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(Struct40BytesHomogeneousDouble a0)) {
+  Struct40BytesHomogeneousDouble a0;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  std::cout << "Calling TestPassStruct40BytesHomogeneousDouble("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << ")\n";
+
+  double result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-3.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test 1kb struct.
+DART_EXPORT intptr_t TestPassStruct1024BytesHomogeneousUint64(
+    // NOLINTNEXTLINE(whitespace/parens)
+    uint64_t (*f)(Struct1024BytesHomogeneousUint64 a0)) {
+  Struct1024BytesHomogeneousUint64 a0;
+
+  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;
+
+  std::cout << "Calling TestPassStruct1024BytesHomogeneousUint64("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << ", " << a0.a5 << ", " << a0.a6 << ", " << a0.a7
+            << ", " << a0.a8 << ", " << a0.a9 << ", " << a0.a10 << ", "
+            << a0.a11 << ", " << a0.a12 << ", " << a0.a13 << ", " << a0.a14
+            << ", " << a0.a15 << ", " << a0.a16 << ", " << a0.a17 << ", "
+            << a0.a18 << ", " << a0.a19 << ", " << a0.a20 << ", " << a0.a21
+            << ", " << a0.a22 << ", " << a0.a23 << ", " << a0.a24 << ", "
+            << a0.a25 << ", " << a0.a26 << ", " << a0.a27 << ", " << a0.a28
+            << ", " << a0.a29 << ", " << a0.a30 << ", " << a0.a31 << ", "
+            << a0.a32 << ", " << a0.a33 << ", " << a0.a34 << ", " << a0.a35
+            << ", " << a0.a36 << ", " << a0.a37 << ", " << a0.a38 << ", "
+            << a0.a39 << ", " << a0.a40 << ", " << a0.a41 << ", " << a0.a42
+            << ", " << a0.a43 << ", " << a0.a44 << ", " << a0.a45 << ", "
+            << a0.a46 << ", " << a0.a47 << ", " << a0.a48 << ", " << a0.a49
+            << ", " << a0.a50 << ", " << a0.a51 << ", " << a0.a52 << ", "
+            << a0.a53 << ", " << a0.a54 << ", " << a0.a55 << ", " << a0.a56
+            << ", " << a0.a57 << ", " << a0.a58 << ", " << a0.a59 << ", "
+            << a0.a60 << ", " << a0.a61 << ", " << a0.a62 << ", " << a0.a63
+            << ", " << a0.a64 << ", " << a0.a65 << ", " << a0.a66 << ", "
+            << a0.a67 << ", " << a0.a68 << ", " << a0.a69 << ", " << a0.a70
+            << ", " << a0.a71 << ", " << a0.a72 << ", " << a0.a73 << ", "
+            << a0.a74 << ", " << a0.a75 << ", " << a0.a76 << ", " << a0.a77
+            << ", " << a0.a78 << ", " << a0.a79 << ", " << a0.a80 << ", "
+            << a0.a81 << ", " << a0.a82 << ", " << a0.a83 << ", " << a0.a84
+            << ", " << a0.a85 << ", " << a0.a86 << ", " << a0.a87 << ", "
+            << a0.a88 << ", " << a0.a89 << ", " << a0.a90 << ", " << a0.a91
+            << ", " << a0.a92 << ", " << a0.a93 << ", " << a0.a94 << ", "
+            << a0.a95 << ", " << a0.a96 << ", " << a0.a97 << ", " << a0.a98
+            << ", " << a0.a99 << ", " << a0.a100 << ", " << a0.a101 << ", "
+            << a0.a102 << ", " << a0.a103 << ", " << a0.a104 << ", " << a0.a105
+            << ", " << a0.a106 << ", " << a0.a107 << ", " << a0.a108 << ", "
+            << a0.a109 << ", " << a0.a110 << ", " << a0.a111 << ", " << a0.a112
+            << ", " << a0.a113 << ", " << a0.a114 << ", " << a0.a115 << ", "
+            << a0.a116 << ", " << a0.a117 << ", " << a0.a118 << ", " << a0.a119
+            << ", " << a0.a120 << ", " << a0.a121 << ", " << a0.a122 << ", "
+            << a0.a123 << ", " << a0.a124 << ", " << a0.a125 << ", " << a0.a126
+            << ", " << a0.a127 << "))"
+            << ")\n";
+
+  uint64_t result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(8256, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Tests the alignment of structs in FPU registers and backfilling.
+DART_EXPORT intptr_t TestPassFloatStruct16BytesHomogeneousFloatFloatStruct1(
+    // NOLINTNEXTLINE(whitespace/parens)
+    float (*f)(float a0,
+               Struct16BytesHomogeneousFloat a1,
+               float a2,
+               Struct16BytesHomogeneousFloat a3,
+               float a4,
+               Struct16BytesHomogeneousFloat a5,
+               float a6,
+               Struct16BytesHomogeneousFloat a7,
+               float a8)) {
+  float a0;
+  Struct16BytesHomogeneousFloat a1;
+  float a2;
+  Struct16BytesHomogeneousFloat a3;
+  float a4;
+  Struct16BytesHomogeneousFloat a5;
+  float a6;
+  Struct16BytesHomogeneousFloat a7;
+  float 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;
+
+  std::cout << "Calling TestPassFloatStruct16BytesHomogeneousFloatFloatStruct1("
+            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
+            << ", " << a1.a3 << "), " << a2 << ", (" << a3.a0 << ", " << a3.a1
+            << ", " << a3.a2 << ", " << a3.a3 << "), " << a4 << ", (" << a5.a0
+            << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), " << a6
+            << ", (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), " << a8 << ")"
+            << ")\n";
+
+  float result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-11.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Tests the alignment of structs in FPU registers and backfilling.
+DART_EXPORT intptr_t TestPassFloatStruct32BytesHomogeneousDoubleFloatStruct(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(float a0,
+                Struct32BytesHomogeneousDouble a1,
+                float a2,
+                Struct32BytesHomogeneousDouble a3,
+                float a4,
+                Struct32BytesHomogeneousDouble a5,
+                float a6,
+                Struct32BytesHomogeneousDouble a7,
+                float a8)) {
+  float a0;
+  Struct32BytesHomogeneousDouble a1;
+  float a2;
+  Struct32BytesHomogeneousDouble a3;
+  float a4;
+  Struct32BytesHomogeneousDouble a5;
+  float a6;
+  Struct32BytesHomogeneousDouble a7;
+  float 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;
+
+  std::cout << "Calling TestPassFloatStruct32BytesHomogeneousDoubleFloatStruct("
+            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
+            << ", " << a1.a3 << "), " << a2 << ", (" << a3.a0 << ", " << a3.a1
+            << ", " << a3.a2 << ", " << a3.a3 << "), " << a4 << ", (" << a5.a0
+            << ", " << a5.a1 << ", " << a5.a2 << ", " << a5.a3 << "), " << a6
+            << ", (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2 << ", " << a7.a3
+            << "), " << a8 << ")"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-11.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(int8_t a0,
+                Struct16BytesMixed a1,
+                int8_t a2,
+                Struct16BytesMixed a3,
+                int8_t a4,
+                Struct16BytesMixed a5,
+                int8_t a6,
+                Struct16BytesMixed a7,
+                int8_t a8)) {
+  int8_t a0;
+  Struct16BytesMixed a1;
+  int8_t a2;
+  Struct16BytesMixed a3;
+  int8_t a4;
+  Struct16BytesMixed a5;
+  int8_t a6;
+  Struct16BytesMixed a7;
+  int8_t 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;
+
+  std::cout << "Calling TestPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn("
+            << "(" << static_cast<int>(a0) << ", (" << a1.a0 << ", " << a1.a1
+            << "), " << static_cast<int>(a2) << ", (" << a3.a0 << ", " << a3.a1
+            << "), " << static_cast<int>(a4) << ", (" << a5.a0 << ", " << a5.a1
+            << "), " << static_cast<int>(a6) << ", (" << a7.a0 << ", " << a7.a1
+            << "), " << static_cast<int>(a8) << ")"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-7.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassDoublex6Struct16BytesMixedx4Int32(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(double a0,
+                double a1,
+                double a2,
+                double a3,
+                double a4,
+                double a5,
+                Struct16BytesMixed a6,
+                Struct16BytesMixed a7,
+                Struct16BytesMixed a8,
+                Struct16BytesMixed a9,
+                int32_t a10)) {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+  double a4;
+  double a5;
+  Struct16BytesMixed a6;
+  Struct16BytesMixed a7;
+  Struct16BytesMixed a8;
+  Struct16BytesMixed a9;
+  int32_t 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;
+
+  std::cout << "Calling TestPassDoublex6Struct16BytesMixedx4Int32("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", (" << a6.a0 << ", " << a6.a1 << "), (" << a7.a0
+            << ", " << a7.a1 << "), (" << a8.a0 << ", " << a8.a1 << "), ("
+            << a9.a0 << ", " << a9.a1 << "), " << a10 << ")"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-8.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestPassInt32x4Struct16BytesMixedx4Double(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(int32_t a0,
+                int32_t a1,
+                int32_t a2,
+                int32_t a3,
+                Struct16BytesMixed a4,
+                Struct16BytesMixed a5,
+                Struct16BytesMixed a6,
+                Struct16BytesMixed a7,
+                double a8)) {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  Struct16BytesMixed a4;
+  Struct16BytesMixed a5;
+  Struct16BytesMixed a6;
+  Struct16BytesMixed a7;
+  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;
+
+  std::cout << "Calling TestPassInt32x4Struct16BytesMixedx4Double("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", ("
+            << a4.a0 << ", " << a4.a1 << "), (" << a5.a0 << ", " << a5.a1
+            << "), (" << a6.a0 << ", " << a6.a1 << "), (" << a7.a0 << ", "
+            << a7.a1 << "), " << a8 << ")"
+            << ")\n";
+
+  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-7.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// On various architectures, first struct is allocated on stack.
+// Check that the other two arguments are allocated on registers.
+DART_EXPORT intptr_t TestPassStruct40BytesHomogeneousDoubleStruct4BytesHomo(
+    // NOLINTNEXTLINE(whitespace/parens)
+    double (*f)(Struct40BytesHomogeneousDouble a0,
+                Struct4BytesHomogeneousInt16 a1,
+                Struct8BytesHomogeneousFloat a2)) {
+  Struct40BytesHomogeneousDouble a0;
+  Struct4BytesHomogeneousInt16 a1;
+  Struct8BytesHomogeneousFloat a2;
+
+  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;
+
+  std::cout << "Calling TestPassStruct40BytesHomogeneousDoubleStruct4BytesHomo("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "), (" << a1.a0 << ", " << a1.a1 << "), ("
+            << a2.a0 << ", " << a2.a1 << "))"
+            << ")\n";
+
+  double result = f(a0, a1, a2);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_APPROX(-5.0, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 16 byte int within struct.
+DART_EXPORT intptr_t TestPassStructAlignmentInt16(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(StructAlignmentInt16 a0)) {
+  StructAlignmentInt16 a0;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  std::cout << "Calling TestPassStructAlignmentInt16("
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << ")\n";
+
+  int64_t result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(-2, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 32 byte int within struct.
+DART_EXPORT intptr_t TestPassStructAlignmentInt32(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(StructAlignmentInt32 a0)) {
+  StructAlignmentInt32 a0;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  std::cout << "Calling TestPassStructAlignmentInt32("
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << ")\n";
+
+  int64_t result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(-2, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 64 byte int within struct.
+DART_EXPORT intptr_t TestPassStructAlignmentInt64(
+    // NOLINTNEXTLINE(whitespace/parens)
+    int64_t (*f)(StructAlignmentInt64 a0)) {
+  StructAlignmentInt64 a0;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  std::cout << "Calling TestPassStructAlignmentInt64("
+            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
+            << static_cast<int>(a0.a2) << "))"
+            << ")\n";
+
+  int64_t result = f(a0);
+
+  std::cout << "result = " << result << "\n";
+
+  CHECK_EQ(-2, result);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Smallest struct with data.
+DART_EXPORT intptr_t TestReturnStruct1ByteInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct1ByteInt (*f)(int8_t a0)) {
+  int8_t a0;
+
+  a0 = -1;
+
+  std::cout << "Calling TestReturnStruct1ByteInt("
+            << "(" << static_cast<int>(a0) << ")"
+            << ")\n";
+
+  Struct1ByteInt result = f(a0);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Smaller than word size return value on all architectures.
+DART_EXPORT intptr_t TestReturnStruct3BytesInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct3BytesInt (*f)(int16_t a0, int8_t a1)) {
+  int16_t a0;
+  int8_t a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  std::cout << "Calling TestReturnStruct3BytesInt("
+            << "(" << a0 << ", " << static_cast<int>(a1) << ")"
+            << ")\n";
+
+  Struct3BytesInt result = f(a0, a1);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << static_cast<int>(result.a1) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Word size return value on 32 bit architectures..
+DART_EXPORT intptr_t TestReturnStruct4BytesHomogeneousInt16(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct4BytesHomogeneousInt16 (*f)(int16_t a0, int16_t a1)) {
+  int16_t a0;
+  int16_t a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  std::cout << "Calling TestReturnStruct4BytesHomogeneousInt16("
+            << "(" << a0 << ", " << a1 << ")"
+            << ")\n";
+
+  Struct4BytesHomogeneousInt16 result = f(a0, a1);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Non-wordsize return value.
+DART_EXPORT intptr_t TestReturnStruct7BytesInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct7BytesInt (*f)(int32_t a0, int16_t a1, int8_t a2)) {
+  int32_t a0;
+  int16_t a1;
+  int8_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStruct7BytesInt("
+            << "(" << a0 << ", " << a1 << ", " << static_cast<int>(a2) << ")"
+            << ")\n";
+
+  Struct7BytesInt result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in integer registers on many architectures.
+DART_EXPORT intptr_t TestReturnStruct8BytesInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct8BytesInt (*f)(int16_t a0, int16_t a1, int32_t a2)) {
+  int16_t a0;
+  int16_t a1;
+  int32_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStruct8BytesInt("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << ")\n";
+
+  Struct8BytesInt result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in FP registers on many architectures.
+DART_EXPORT intptr_t TestReturnStruct8BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct8BytesHomogeneousFloat (*f)(float a0, float a1)) {
+  float a0;
+  float a1;
+
+  a0 = -1.0;
+  a1 = 2.0;
+
+  std::cout << "Calling TestReturnStruct8BytesHomogeneousFloat("
+            << "(" << a0 << ", " << a1 << ")"
+            << ")\n";
+
+  Struct8BytesHomogeneousFloat result = f(a0, a1);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+DART_EXPORT intptr_t TestReturnStruct8BytesMixed(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct8BytesMixed (*f)(float a0, int16_t a1, int16_t a2)) {
+  float a0;
+  int16_t a1;
+  int16_t a2;
+
+  a0 = -1.0;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStruct8BytesMixed("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << ")\n";
+
+  Struct8BytesMixed result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in two integer registers on x64.
+// The second register only contains a single byte.
+DART_EXPORT intptr_t TestReturnStruct9BytesInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct9BytesInt (*f)(int64_t a0, int8_t a1)) {
+  int64_t a0;
+  int8_t a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  std::cout << "Calling TestReturnStruct9BytesInt("
+            << "(" << a0 << ", " << static_cast<int>(a1) << ")"
+            << ")\n";
+
+  Struct9BytesInt result = f(a0, a1);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << static_cast<int>(result.a1) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestReturnStruct9BytesHomogeneousUint82(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct9BytesHomogeneousUint82 (*f)(uint8_t a0,
+                                       uint8_t a1,
+                                       uint8_t a2,
+                                       uint8_t a3,
+                                       uint8_t a4,
+                                       uint8_t a5,
+                                       uint8_t a6,
+                                       uint8_t a7,
+                                       uint8_t a8)) {
+  uint8_t a0;
+  uint8_t a1;
+  uint8_t a2;
+  uint8_t a3;
+  uint8_t a4;
+  uint8_t a5;
+  uint8_t a6;
+  uint8_t a7;
+  uint8_t a8;
+
+  a0 = 1;
+  a1 = 2;
+  a2 = 3;
+  a3 = 4;
+  a4 = 5;
+  a5 = 6;
+  a6 = 7;
+  a7 = 8;
+  a8 = 9;
+
+  std::cout << "Calling TestReturnStruct9BytesHomogeneousUint82("
+            << "(" << static_cast<int>(a0) << ", " << static_cast<int>(a1)
+            << ", " << static_cast<int>(a2) << ", " << static_cast<int>(a3)
+            << ", " << static_cast<int>(a4) << ", " << static_cast<int>(a5)
+            << ", " << static_cast<int>(a6) << ", " << static_cast<int>(a7)
+            << ", " << static_cast<int>(a8) << ")"
+            << ")\n";
+
+  Struct9BytesHomogeneousUint82 result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", "
+            << static_cast<int>(result.a1) << ", "
+            << static_cast<int>(result.a2) << ", "
+            << static_cast<int>(result.a3) << ", "
+            << static_cast<int>(result.a4) << ", "
+            << static_cast<int>(result.a5) << ", "
+            << static_cast<int>(result.a6) << ", "
+            << static_cast<int>(result.a7) << ", "
+            << static_cast<int>(result.a8) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+  CHECK_EQ(a3, result.a3);
+  CHECK_EQ(a4, result.a4);
+  CHECK_EQ(a5, result.a5);
+  CHECK_EQ(a6, result.a6);
+  CHECK_EQ(a7, result.a7);
+  CHECK_EQ(a8, result.a8);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers, but does not use all registers on arm hardfp
+// and arm64.
+DART_EXPORT intptr_t TestReturnStruct12BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct12BytesHomogeneousFloat (*f)(float a0, float a1, float a2)) {
+  float a0;
+  float a1;
+  float a2;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+
+  std::cout << "Calling TestReturnStruct12BytesHomogeneousFloat("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ")"
+            << ")\n";
+
+  Struct12BytesHomogeneousFloat result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers on arm hardfp and arm64.
+DART_EXPORT intptr_t TestReturnStruct16BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct16BytesHomogeneousFloat (
+        *f)(float a0, float a1, float a2, float a3)) {
+  float a0;
+  float a1;
+  float a2;
+  float a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  std::cout << "Calling TestReturnStruct16BytesHomogeneousFloat("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << ")\n";
+
+  Struct16BytesHomogeneousFloat result = f(a0, a1, a2, a3);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+  CHECK_APPROX(a3, result.a3);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+DART_EXPORT intptr_t TestReturnStruct16BytesMixed(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct16BytesMixed (*f)(double a0, int64_t a1)) {
+  double a0;
+  int64_t a1;
+
+  a0 = -1.0;
+  a1 = 2;
+
+  std::cout << "Calling TestReturnStruct16BytesMixed("
+            << "(" << a0 << ", " << a1 << ")"
+            << ")\n";
+
+  Struct16BytesMixed result = f(a0, a1);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_EQ(0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value split over FP and integer register in x64.
+// The integer register contains half float half int.
+DART_EXPORT intptr_t TestReturnStruct16BytesMixed2(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct16BytesMixed2 (*f)(float a0, float a1, float a2, int32_t a3)) {
+  float a0;
+  float a1;
+  float a2;
+  int32_t a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4;
+
+  std::cout << "Calling TestReturnStruct16BytesMixed2("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << ")\n";
+
+  Struct16BytesMixed2 result = f(a0, a1, a2, a3);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+  CHECK_EQ(a3, result.a3);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_EQ(0, result.a3);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_EQ(0, result.a3);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestReturnStruct17BytesInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct17BytesInt (*f)(int64_t a0, int64_t a1, int8_t a2)) {
+  int64_t a0;
+  int64_t a1;
+  int8_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStruct17BytesInt("
+            << "(" << a0 << ", " << a1 << ", " << static_cast<int>(a2) << ")"
+            << ")\n";
+
+  Struct17BytesInt result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// 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.
+DART_EXPORT intptr_t TestReturnStruct19BytesHomogeneousUint8(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct19BytesHomogeneousUint8 (*f)(uint8_t a0,
+                                       uint8_t a1,
+                                       uint8_t a2,
+                                       uint8_t a3,
+                                       uint8_t a4,
+                                       uint8_t a5,
+                                       uint8_t a6,
+                                       uint8_t a7,
+                                       uint8_t a8,
+                                       uint8_t a9,
+                                       uint8_t a10,
+                                       uint8_t a11,
+                                       uint8_t a12,
+                                       uint8_t a13,
+                                       uint8_t a14,
+                                       uint8_t a15,
+                                       uint8_t a16,
+                                       uint8_t a17,
+                                       uint8_t a18)) {
+  uint8_t a0;
+  uint8_t a1;
+  uint8_t a2;
+  uint8_t a3;
+  uint8_t a4;
+  uint8_t a5;
+  uint8_t a6;
+  uint8_t a7;
+  uint8_t a8;
+  uint8_t a9;
+  uint8_t a10;
+  uint8_t a11;
+  uint8_t a12;
+  uint8_t a13;
+  uint8_t a14;
+  uint8_t a15;
+  uint8_t a16;
+  uint8_t a17;
+  uint8_t 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;
+
+  std::cout << "Calling TestReturnStruct19BytesHomogeneousUint8("
+            << "(" << static_cast<int>(a0) << ", " << static_cast<int>(a1)
+            << ", " << static_cast<int>(a2) << ", " << static_cast<int>(a3)
+            << ", " << static_cast<int>(a4) << ", " << static_cast<int>(a5)
+            << ", " << static_cast<int>(a6) << ", " << static_cast<int>(a7)
+            << ", " << static_cast<int>(a8) << ", " << static_cast<int>(a9)
+            << ", " << static_cast<int>(a10) << ", " << static_cast<int>(a11)
+            << ", " << static_cast<int>(a12) << ", " << static_cast<int>(a13)
+            << ", " << static_cast<int>(a14) << ", " << static_cast<int>(a15)
+            << ", " << static_cast<int>(a16) << ", " << static_cast<int>(a17)
+            << ", " << static_cast<int>(a18) << ")"
+            << ")\n";
+
+  Struct19BytesHomogeneousUint8 result =
+      f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,
+        a16, a17, a18);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", "
+            << static_cast<int>(result.a1) << ", "
+            << static_cast<int>(result.a2) << ", "
+            << static_cast<int>(result.a3) << ", "
+            << static_cast<int>(result.a4) << ", "
+            << static_cast<int>(result.a5) << ", "
+            << static_cast<int>(result.a6) << ", "
+            << static_cast<int>(result.a7) << ", "
+            << static_cast<int>(result.a8) << ", "
+            << static_cast<int>(result.a9) << ", "
+            << static_cast<int>(result.a10) << ", "
+            << static_cast<int>(result.a11) << ", "
+            << static_cast<int>(result.a12) << ", "
+            << static_cast<int>(result.a13) << ", "
+            << static_cast<int>(result.a14) << ", "
+            << static_cast<int>(result.a15) << ", "
+            << static_cast<int>(result.a16) << ", "
+            << static_cast<int>(result.a17) << ", "
+            << static_cast<int>(result.a18) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+  CHECK_EQ(a3, result.a3);
+  CHECK_EQ(a4, result.a4);
+  CHECK_EQ(a5, result.a5);
+  CHECK_EQ(a6, result.a6);
+  CHECK_EQ(a7, result.a7);
+  CHECK_EQ(a8, result.a8);
+  CHECK_EQ(a9, result.a9);
+  CHECK_EQ(a10, result.a10);
+  CHECK_EQ(a11, result.a11);
+  CHECK_EQ(a12, result.a12);
+  CHECK_EQ(a13, result.a13);
+  CHECK_EQ(a14, result.a14);
+  CHECK_EQ(a15, result.a15);
+  CHECK_EQ(a16, result.a16);
+  CHECK_EQ(a17, result.a17);
+  CHECK_EQ(a18, result.a18);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14,
+             a15, a16, a17, a18);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+  CHECK_EQ(0, result.a9);
+  CHECK_EQ(0, result.a10);
+  CHECK_EQ(0, result.a11);
+  CHECK_EQ(0, result.a12);
+  CHECK_EQ(0, result.a13);
+  CHECK_EQ(0, result.a14);
+  CHECK_EQ(0, result.a15);
+  CHECK_EQ(0, result.a16);
+  CHECK_EQ(0, result.a17);
+  CHECK_EQ(0, result.a18);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14,
+             a15, a16, a17, a18);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+  CHECK_EQ(0, result.a9);
+  CHECK_EQ(0, result.a10);
+  CHECK_EQ(0, result.a11);
+  CHECK_EQ(0, result.a12);
+  CHECK_EQ(0, result.a13);
+  CHECK_EQ(0, result.a14);
+  CHECK_EQ(0, result.a15);
+  CHECK_EQ(0, result.a16);
+  CHECK_EQ(0, result.a17);
+  CHECK_EQ(0, result.a18);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in cpu registers on arm64.
+DART_EXPORT intptr_t TestReturnStruct20BytesHomogeneousInt32(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct20BytesHomogeneousInt32 (
+        *f)(int32_t a0, int32_t a1, int32_t a2, int32_t a3, int32_t a4)) {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  int32_t a4;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+
+  std::cout << "Calling TestReturnStruct20BytesHomogeneousInt32("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << ")\n";
+
+  Struct20BytesHomogeneousInt32 result = f(a0, a1, a2, a3, a4);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+  CHECK_EQ(a3, result.a3);
+  CHECK_EQ(a4, result.a4);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+DART_EXPORT intptr_t TestReturnStruct20BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct20BytesHomogeneousFloat (
+        *f)(float a0, float a1, float a2, float a3, float a4)) {
+  float a0;
+  float a1;
+  float a2;
+  float a3;
+  float a4;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+  a4 = -5.0;
+
+  std::cout << "Calling TestReturnStruct20BytesHomogeneousFloat("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << ")\n";
+
+  Struct20BytesHomogeneousFloat result = f(a0, a1, a2, a3, a4);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+  CHECK_APPROX(a3, result.a3);
+  CHECK_APPROX(a4, result.a4);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+  CHECK_APPROX(0.0, result.a4);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+  CHECK_APPROX(0.0, result.a4);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value in FPU registers on arm64.
+DART_EXPORT intptr_t TestReturnStruct32BytesHomogeneousDouble(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct32BytesHomogeneousDouble (
+        *f)(double a0, double a1, double a2, double a3)) {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  std::cout << "Calling TestReturnStruct32BytesHomogeneousDouble("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")"
+            << ")\n";
+
+  Struct32BytesHomogeneousDouble result = f(a0, a1, a2, a3);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+  CHECK_APPROX(a3, result.a3);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Return value too big to go in FPU registers on arm64.
+DART_EXPORT intptr_t TestReturnStruct40BytesHomogeneousDouble(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct40BytesHomogeneousDouble (
+        *f)(double a0, double a1, double a2, double a3, double a4)) {
+  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;
+
+  std::cout << "Calling TestReturnStruct40BytesHomogeneousDouble("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ")"
+            << ")\n";
+
+  Struct40BytesHomogeneousDouble result = f(a0, a1, a2, a3, a4);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0, result.a0);
+  CHECK_APPROX(a1, result.a1);
+  CHECK_APPROX(a2, result.a2);
+  CHECK_APPROX(a3, result.a3);
+  CHECK_APPROX(a4, result.a4);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+  CHECK_APPROX(0.0, result.a4);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+  CHECK_APPROX(0.0, result.a2);
+  CHECK_APPROX(0.0, result.a3);
+  CHECK_APPROX(0.0, result.a4);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test 1kb struct.
+DART_EXPORT intptr_t TestReturnStruct1024BytesHomogeneousUint64(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct1024BytesHomogeneousUint64 (*f)(uint64_t a0,
+                                          uint64_t a1,
+                                          uint64_t a2,
+                                          uint64_t a3,
+                                          uint64_t a4,
+                                          uint64_t a5,
+                                          uint64_t a6,
+                                          uint64_t a7,
+                                          uint64_t a8,
+                                          uint64_t a9,
+                                          uint64_t a10,
+                                          uint64_t a11,
+                                          uint64_t a12,
+                                          uint64_t a13,
+                                          uint64_t a14,
+                                          uint64_t a15,
+                                          uint64_t a16,
+                                          uint64_t a17,
+                                          uint64_t a18,
+                                          uint64_t a19,
+                                          uint64_t a20,
+                                          uint64_t a21,
+                                          uint64_t a22,
+                                          uint64_t a23,
+                                          uint64_t a24,
+                                          uint64_t a25,
+                                          uint64_t a26,
+                                          uint64_t a27,
+                                          uint64_t a28,
+                                          uint64_t a29,
+                                          uint64_t a30,
+                                          uint64_t a31,
+                                          uint64_t a32,
+                                          uint64_t a33,
+                                          uint64_t a34,
+                                          uint64_t a35,
+                                          uint64_t a36,
+                                          uint64_t a37,
+                                          uint64_t a38,
+                                          uint64_t a39,
+                                          uint64_t a40,
+                                          uint64_t a41,
+                                          uint64_t a42,
+                                          uint64_t a43,
+                                          uint64_t a44,
+                                          uint64_t a45,
+                                          uint64_t a46,
+                                          uint64_t a47,
+                                          uint64_t a48,
+                                          uint64_t a49,
+                                          uint64_t a50,
+                                          uint64_t a51,
+                                          uint64_t a52,
+                                          uint64_t a53,
+                                          uint64_t a54,
+                                          uint64_t a55,
+                                          uint64_t a56,
+                                          uint64_t a57,
+                                          uint64_t a58,
+                                          uint64_t a59,
+                                          uint64_t a60,
+                                          uint64_t a61,
+                                          uint64_t a62,
+                                          uint64_t a63,
+                                          uint64_t a64,
+                                          uint64_t a65,
+                                          uint64_t a66,
+                                          uint64_t a67,
+                                          uint64_t a68,
+                                          uint64_t a69,
+                                          uint64_t a70,
+                                          uint64_t a71,
+                                          uint64_t a72,
+                                          uint64_t a73,
+                                          uint64_t a74,
+                                          uint64_t a75,
+                                          uint64_t a76,
+                                          uint64_t a77,
+                                          uint64_t a78,
+                                          uint64_t a79,
+                                          uint64_t a80,
+                                          uint64_t a81,
+                                          uint64_t a82,
+                                          uint64_t a83,
+                                          uint64_t a84,
+                                          uint64_t a85,
+                                          uint64_t a86,
+                                          uint64_t a87,
+                                          uint64_t a88,
+                                          uint64_t a89,
+                                          uint64_t a90,
+                                          uint64_t a91,
+                                          uint64_t a92,
+                                          uint64_t a93,
+                                          uint64_t a94,
+                                          uint64_t a95,
+                                          uint64_t a96,
+                                          uint64_t a97,
+                                          uint64_t a98,
+                                          uint64_t a99,
+                                          uint64_t a100,
+                                          uint64_t a101,
+                                          uint64_t a102,
+                                          uint64_t a103,
+                                          uint64_t a104,
+                                          uint64_t a105,
+                                          uint64_t a106,
+                                          uint64_t a107,
+                                          uint64_t a108,
+                                          uint64_t a109,
+                                          uint64_t a110,
+                                          uint64_t a111,
+                                          uint64_t a112,
+                                          uint64_t a113,
+                                          uint64_t a114,
+                                          uint64_t a115,
+                                          uint64_t a116,
+                                          uint64_t a117,
+                                          uint64_t a118,
+                                          uint64_t a119,
+                                          uint64_t a120,
+                                          uint64_t a121,
+                                          uint64_t a122,
+                                          uint64_t a123,
+                                          uint64_t a124,
+                                          uint64_t a125,
+                                          uint64_t a126,
+                                          uint64_t a127)) {
+  uint64_t a0;
+  uint64_t a1;
+  uint64_t a2;
+  uint64_t a3;
+  uint64_t a4;
+  uint64_t a5;
+  uint64_t a6;
+  uint64_t a7;
+  uint64_t a8;
+  uint64_t a9;
+  uint64_t a10;
+  uint64_t a11;
+  uint64_t a12;
+  uint64_t a13;
+  uint64_t a14;
+  uint64_t a15;
+  uint64_t a16;
+  uint64_t a17;
+  uint64_t a18;
+  uint64_t a19;
+  uint64_t a20;
+  uint64_t a21;
+  uint64_t a22;
+  uint64_t a23;
+  uint64_t a24;
+  uint64_t a25;
+  uint64_t a26;
+  uint64_t a27;
+  uint64_t a28;
+  uint64_t a29;
+  uint64_t a30;
+  uint64_t a31;
+  uint64_t a32;
+  uint64_t a33;
+  uint64_t a34;
+  uint64_t a35;
+  uint64_t a36;
+  uint64_t a37;
+  uint64_t a38;
+  uint64_t a39;
+  uint64_t a40;
+  uint64_t a41;
+  uint64_t a42;
+  uint64_t a43;
+  uint64_t a44;
+  uint64_t a45;
+  uint64_t a46;
+  uint64_t a47;
+  uint64_t a48;
+  uint64_t a49;
+  uint64_t a50;
+  uint64_t a51;
+  uint64_t a52;
+  uint64_t a53;
+  uint64_t a54;
+  uint64_t a55;
+  uint64_t a56;
+  uint64_t a57;
+  uint64_t a58;
+  uint64_t a59;
+  uint64_t a60;
+  uint64_t a61;
+  uint64_t a62;
+  uint64_t a63;
+  uint64_t a64;
+  uint64_t a65;
+  uint64_t a66;
+  uint64_t a67;
+  uint64_t a68;
+  uint64_t a69;
+  uint64_t a70;
+  uint64_t a71;
+  uint64_t a72;
+  uint64_t a73;
+  uint64_t a74;
+  uint64_t a75;
+  uint64_t a76;
+  uint64_t a77;
+  uint64_t a78;
+  uint64_t a79;
+  uint64_t a80;
+  uint64_t a81;
+  uint64_t a82;
+  uint64_t a83;
+  uint64_t a84;
+  uint64_t a85;
+  uint64_t a86;
+  uint64_t a87;
+  uint64_t a88;
+  uint64_t a89;
+  uint64_t a90;
+  uint64_t a91;
+  uint64_t a92;
+  uint64_t a93;
+  uint64_t a94;
+  uint64_t a95;
+  uint64_t a96;
+  uint64_t a97;
+  uint64_t a98;
+  uint64_t a99;
+  uint64_t a100;
+  uint64_t a101;
+  uint64_t a102;
+  uint64_t a103;
+  uint64_t a104;
+  uint64_t a105;
+  uint64_t a106;
+  uint64_t a107;
+  uint64_t a108;
+  uint64_t a109;
+  uint64_t a110;
+  uint64_t a111;
+  uint64_t a112;
+  uint64_t a113;
+  uint64_t a114;
+  uint64_t a115;
+  uint64_t a116;
+  uint64_t a117;
+  uint64_t a118;
+  uint64_t a119;
+  uint64_t a120;
+  uint64_t a121;
+  uint64_t a122;
+  uint64_t a123;
+  uint64_t a124;
+  uint64_t a125;
+  uint64_t a126;
+  uint64_t 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;
+
+  std::cout << "Calling TestReturnStruct1024BytesHomogeneousUint64("
+            << "(" << 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 << ")"
+            << ")\n";
+
+  Struct1024BytesHomogeneousUint64 result = f(
+      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);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ", " << result.a5
+            << ", " << result.a6 << ", " << result.a7 << ", " << result.a8
+            << ", " << result.a9 << ", " << result.a10 << ", " << result.a11
+            << ", " << result.a12 << ", " << result.a13 << ", " << result.a14
+            << ", " << result.a15 << ", " << result.a16 << ", " << result.a17
+            << ", " << result.a18 << ", " << result.a19 << ", " << result.a20
+            << ", " << result.a21 << ", " << result.a22 << ", " << result.a23
+            << ", " << result.a24 << ", " << result.a25 << ", " << result.a26
+            << ", " << result.a27 << ", " << result.a28 << ", " << result.a29
+            << ", " << result.a30 << ", " << result.a31 << ", " << result.a32
+            << ", " << result.a33 << ", " << result.a34 << ", " << result.a35
+            << ", " << result.a36 << ", " << result.a37 << ", " << result.a38
+            << ", " << result.a39 << ", " << result.a40 << ", " << result.a41
+            << ", " << result.a42 << ", " << result.a43 << ", " << result.a44
+            << ", " << result.a45 << ", " << result.a46 << ", " << result.a47
+            << ", " << result.a48 << ", " << result.a49 << ", " << result.a50
+            << ", " << result.a51 << ", " << result.a52 << ", " << result.a53
+            << ", " << result.a54 << ", " << result.a55 << ", " << result.a56
+            << ", " << result.a57 << ", " << result.a58 << ", " << result.a59
+            << ", " << result.a60 << ", " << result.a61 << ", " << result.a62
+            << ", " << result.a63 << ", " << result.a64 << ", " << result.a65
+            << ", " << result.a66 << ", " << result.a67 << ", " << result.a68
+            << ", " << result.a69 << ", " << result.a70 << ", " << result.a71
+            << ", " << result.a72 << ", " << result.a73 << ", " << result.a74
+            << ", " << result.a75 << ", " << result.a76 << ", " << result.a77
+            << ", " << result.a78 << ", " << result.a79 << ", " << result.a80
+            << ", " << result.a81 << ", " << result.a82 << ", " << result.a83
+            << ", " << result.a84 << ", " << result.a85 << ", " << result.a86
+            << ", " << result.a87 << ", " << result.a88 << ", " << result.a89
+            << ", " << result.a90 << ", " << result.a91 << ", " << result.a92
+            << ", " << result.a93 << ", " << result.a94 << ", " << result.a95
+            << ", " << result.a96 << ", " << result.a97 << ", " << result.a98
+            << ", " << result.a99 << ", " << result.a100 << ", " << result.a101
+            << ", " << result.a102 << ", " << result.a103 << ", " << result.a104
+            << ", " << result.a105 << ", " << result.a106 << ", " << result.a107
+            << ", " << result.a108 << ", " << result.a109 << ", " << result.a110
+            << ", " << result.a111 << ", " << result.a112 << ", " << result.a113
+            << ", " << result.a114 << ", " << result.a115 << ", " << result.a116
+            << ", " << result.a117 << ", " << result.a118 << ", " << result.a119
+            << ", " << result.a120 << ", " << result.a121 << ", " << result.a122
+            << ", " << result.a123 << ", " << result.a124 << ", " << result.a125
+            << ", " << result.a126 << ", " << result.a127 << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+  CHECK_EQ(a3, result.a3);
+  CHECK_EQ(a4, result.a4);
+  CHECK_EQ(a5, result.a5);
+  CHECK_EQ(a6, result.a6);
+  CHECK_EQ(a7, result.a7);
+  CHECK_EQ(a8, result.a8);
+  CHECK_EQ(a9, result.a9);
+  CHECK_EQ(a10, result.a10);
+  CHECK_EQ(a11, result.a11);
+  CHECK_EQ(a12, result.a12);
+  CHECK_EQ(a13, result.a13);
+  CHECK_EQ(a14, result.a14);
+  CHECK_EQ(a15, result.a15);
+  CHECK_EQ(a16, result.a16);
+  CHECK_EQ(a17, result.a17);
+  CHECK_EQ(a18, result.a18);
+  CHECK_EQ(a19, result.a19);
+  CHECK_EQ(a20, result.a20);
+  CHECK_EQ(a21, result.a21);
+  CHECK_EQ(a22, result.a22);
+  CHECK_EQ(a23, result.a23);
+  CHECK_EQ(a24, result.a24);
+  CHECK_EQ(a25, result.a25);
+  CHECK_EQ(a26, result.a26);
+  CHECK_EQ(a27, result.a27);
+  CHECK_EQ(a28, result.a28);
+  CHECK_EQ(a29, result.a29);
+  CHECK_EQ(a30, result.a30);
+  CHECK_EQ(a31, result.a31);
+  CHECK_EQ(a32, result.a32);
+  CHECK_EQ(a33, result.a33);
+  CHECK_EQ(a34, result.a34);
+  CHECK_EQ(a35, result.a35);
+  CHECK_EQ(a36, result.a36);
+  CHECK_EQ(a37, result.a37);
+  CHECK_EQ(a38, result.a38);
+  CHECK_EQ(a39, result.a39);
+  CHECK_EQ(a40, result.a40);
+  CHECK_EQ(a41, result.a41);
+  CHECK_EQ(a42, result.a42);
+  CHECK_EQ(a43, result.a43);
+  CHECK_EQ(a44, result.a44);
+  CHECK_EQ(a45, result.a45);
+  CHECK_EQ(a46, result.a46);
+  CHECK_EQ(a47, result.a47);
+  CHECK_EQ(a48, result.a48);
+  CHECK_EQ(a49, result.a49);
+  CHECK_EQ(a50, result.a50);
+  CHECK_EQ(a51, result.a51);
+  CHECK_EQ(a52, result.a52);
+  CHECK_EQ(a53, result.a53);
+  CHECK_EQ(a54, result.a54);
+  CHECK_EQ(a55, result.a55);
+  CHECK_EQ(a56, result.a56);
+  CHECK_EQ(a57, result.a57);
+  CHECK_EQ(a58, result.a58);
+  CHECK_EQ(a59, result.a59);
+  CHECK_EQ(a60, result.a60);
+  CHECK_EQ(a61, result.a61);
+  CHECK_EQ(a62, result.a62);
+  CHECK_EQ(a63, result.a63);
+  CHECK_EQ(a64, result.a64);
+  CHECK_EQ(a65, result.a65);
+  CHECK_EQ(a66, result.a66);
+  CHECK_EQ(a67, result.a67);
+  CHECK_EQ(a68, result.a68);
+  CHECK_EQ(a69, result.a69);
+  CHECK_EQ(a70, result.a70);
+  CHECK_EQ(a71, result.a71);
+  CHECK_EQ(a72, result.a72);
+  CHECK_EQ(a73, result.a73);
+  CHECK_EQ(a74, result.a74);
+  CHECK_EQ(a75, result.a75);
+  CHECK_EQ(a76, result.a76);
+  CHECK_EQ(a77, result.a77);
+  CHECK_EQ(a78, result.a78);
+  CHECK_EQ(a79, result.a79);
+  CHECK_EQ(a80, result.a80);
+  CHECK_EQ(a81, result.a81);
+  CHECK_EQ(a82, result.a82);
+  CHECK_EQ(a83, result.a83);
+  CHECK_EQ(a84, result.a84);
+  CHECK_EQ(a85, result.a85);
+  CHECK_EQ(a86, result.a86);
+  CHECK_EQ(a87, result.a87);
+  CHECK_EQ(a88, result.a88);
+  CHECK_EQ(a89, result.a89);
+  CHECK_EQ(a90, result.a90);
+  CHECK_EQ(a91, result.a91);
+  CHECK_EQ(a92, result.a92);
+  CHECK_EQ(a93, result.a93);
+  CHECK_EQ(a94, result.a94);
+  CHECK_EQ(a95, result.a95);
+  CHECK_EQ(a96, result.a96);
+  CHECK_EQ(a97, result.a97);
+  CHECK_EQ(a98, result.a98);
+  CHECK_EQ(a99, result.a99);
+  CHECK_EQ(a100, result.a100);
+  CHECK_EQ(a101, result.a101);
+  CHECK_EQ(a102, result.a102);
+  CHECK_EQ(a103, result.a103);
+  CHECK_EQ(a104, result.a104);
+  CHECK_EQ(a105, result.a105);
+  CHECK_EQ(a106, result.a106);
+  CHECK_EQ(a107, result.a107);
+  CHECK_EQ(a108, result.a108);
+  CHECK_EQ(a109, result.a109);
+  CHECK_EQ(a110, result.a110);
+  CHECK_EQ(a111, result.a111);
+  CHECK_EQ(a112, result.a112);
+  CHECK_EQ(a113, result.a113);
+  CHECK_EQ(a114, result.a114);
+  CHECK_EQ(a115, result.a115);
+  CHECK_EQ(a116, result.a116);
+  CHECK_EQ(a117, result.a117);
+  CHECK_EQ(a118, result.a118);
+  CHECK_EQ(a119, result.a119);
+  CHECK_EQ(a120, result.a120);
+  CHECK_EQ(a121, result.a121);
+  CHECK_EQ(a122, result.a122);
+  CHECK_EQ(a123, result.a123);
+  CHECK_EQ(a124, result.a124);
+  CHECK_EQ(a125, result.a125);
+  CHECK_EQ(a126, result.a126);
+  CHECK_EQ(a127, result.a127);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(
+      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);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+  CHECK_EQ(0, result.a9);
+  CHECK_EQ(0, result.a10);
+  CHECK_EQ(0, result.a11);
+  CHECK_EQ(0, result.a12);
+  CHECK_EQ(0, result.a13);
+  CHECK_EQ(0, result.a14);
+  CHECK_EQ(0, result.a15);
+  CHECK_EQ(0, result.a16);
+  CHECK_EQ(0, result.a17);
+  CHECK_EQ(0, result.a18);
+  CHECK_EQ(0, result.a19);
+  CHECK_EQ(0, result.a20);
+  CHECK_EQ(0, result.a21);
+  CHECK_EQ(0, result.a22);
+  CHECK_EQ(0, result.a23);
+  CHECK_EQ(0, result.a24);
+  CHECK_EQ(0, result.a25);
+  CHECK_EQ(0, result.a26);
+  CHECK_EQ(0, result.a27);
+  CHECK_EQ(0, result.a28);
+  CHECK_EQ(0, result.a29);
+  CHECK_EQ(0, result.a30);
+  CHECK_EQ(0, result.a31);
+  CHECK_EQ(0, result.a32);
+  CHECK_EQ(0, result.a33);
+  CHECK_EQ(0, result.a34);
+  CHECK_EQ(0, result.a35);
+  CHECK_EQ(0, result.a36);
+  CHECK_EQ(0, result.a37);
+  CHECK_EQ(0, result.a38);
+  CHECK_EQ(0, result.a39);
+  CHECK_EQ(0, result.a40);
+  CHECK_EQ(0, result.a41);
+  CHECK_EQ(0, result.a42);
+  CHECK_EQ(0, result.a43);
+  CHECK_EQ(0, result.a44);
+  CHECK_EQ(0, result.a45);
+  CHECK_EQ(0, result.a46);
+  CHECK_EQ(0, result.a47);
+  CHECK_EQ(0, result.a48);
+  CHECK_EQ(0, result.a49);
+  CHECK_EQ(0, result.a50);
+  CHECK_EQ(0, result.a51);
+  CHECK_EQ(0, result.a52);
+  CHECK_EQ(0, result.a53);
+  CHECK_EQ(0, result.a54);
+  CHECK_EQ(0, result.a55);
+  CHECK_EQ(0, result.a56);
+  CHECK_EQ(0, result.a57);
+  CHECK_EQ(0, result.a58);
+  CHECK_EQ(0, result.a59);
+  CHECK_EQ(0, result.a60);
+  CHECK_EQ(0, result.a61);
+  CHECK_EQ(0, result.a62);
+  CHECK_EQ(0, result.a63);
+  CHECK_EQ(0, result.a64);
+  CHECK_EQ(0, result.a65);
+  CHECK_EQ(0, result.a66);
+  CHECK_EQ(0, result.a67);
+  CHECK_EQ(0, result.a68);
+  CHECK_EQ(0, result.a69);
+  CHECK_EQ(0, result.a70);
+  CHECK_EQ(0, result.a71);
+  CHECK_EQ(0, result.a72);
+  CHECK_EQ(0, result.a73);
+  CHECK_EQ(0, result.a74);
+  CHECK_EQ(0, result.a75);
+  CHECK_EQ(0, result.a76);
+  CHECK_EQ(0, result.a77);
+  CHECK_EQ(0, result.a78);
+  CHECK_EQ(0, result.a79);
+  CHECK_EQ(0, result.a80);
+  CHECK_EQ(0, result.a81);
+  CHECK_EQ(0, result.a82);
+  CHECK_EQ(0, result.a83);
+  CHECK_EQ(0, result.a84);
+  CHECK_EQ(0, result.a85);
+  CHECK_EQ(0, result.a86);
+  CHECK_EQ(0, result.a87);
+  CHECK_EQ(0, result.a88);
+  CHECK_EQ(0, result.a89);
+  CHECK_EQ(0, result.a90);
+  CHECK_EQ(0, result.a91);
+  CHECK_EQ(0, result.a92);
+  CHECK_EQ(0, result.a93);
+  CHECK_EQ(0, result.a94);
+  CHECK_EQ(0, result.a95);
+  CHECK_EQ(0, result.a96);
+  CHECK_EQ(0, result.a97);
+  CHECK_EQ(0, result.a98);
+  CHECK_EQ(0, result.a99);
+  CHECK_EQ(0, result.a100);
+  CHECK_EQ(0, result.a101);
+  CHECK_EQ(0, result.a102);
+  CHECK_EQ(0, result.a103);
+  CHECK_EQ(0, result.a104);
+  CHECK_EQ(0, result.a105);
+  CHECK_EQ(0, result.a106);
+  CHECK_EQ(0, result.a107);
+  CHECK_EQ(0, result.a108);
+  CHECK_EQ(0, result.a109);
+  CHECK_EQ(0, result.a110);
+  CHECK_EQ(0, result.a111);
+  CHECK_EQ(0, result.a112);
+  CHECK_EQ(0, result.a113);
+  CHECK_EQ(0, result.a114);
+  CHECK_EQ(0, result.a115);
+  CHECK_EQ(0, result.a116);
+  CHECK_EQ(0, result.a117);
+  CHECK_EQ(0, result.a118);
+  CHECK_EQ(0, result.a119);
+  CHECK_EQ(0, result.a120);
+  CHECK_EQ(0, result.a121);
+  CHECK_EQ(0, result.a122);
+  CHECK_EQ(0, result.a123);
+  CHECK_EQ(0, result.a124);
+  CHECK_EQ(0, result.a125);
+  CHECK_EQ(0, result.a126);
+  CHECK_EQ(0, result.a127);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(
+      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);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+  CHECK_EQ(0, result.a5);
+  CHECK_EQ(0, result.a6);
+  CHECK_EQ(0, result.a7);
+  CHECK_EQ(0, result.a8);
+  CHECK_EQ(0, result.a9);
+  CHECK_EQ(0, result.a10);
+  CHECK_EQ(0, result.a11);
+  CHECK_EQ(0, result.a12);
+  CHECK_EQ(0, result.a13);
+  CHECK_EQ(0, result.a14);
+  CHECK_EQ(0, result.a15);
+  CHECK_EQ(0, result.a16);
+  CHECK_EQ(0, result.a17);
+  CHECK_EQ(0, result.a18);
+  CHECK_EQ(0, result.a19);
+  CHECK_EQ(0, result.a20);
+  CHECK_EQ(0, result.a21);
+  CHECK_EQ(0, result.a22);
+  CHECK_EQ(0, result.a23);
+  CHECK_EQ(0, result.a24);
+  CHECK_EQ(0, result.a25);
+  CHECK_EQ(0, result.a26);
+  CHECK_EQ(0, result.a27);
+  CHECK_EQ(0, result.a28);
+  CHECK_EQ(0, result.a29);
+  CHECK_EQ(0, result.a30);
+  CHECK_EQ(0, result.a31);
+  CHECK_EQ(0, result.a32);
+  CHECK_EQ(0, result.a33);
+  CHECK_EQ(0, result.a34);
+  CHECK_EQ(0, result.a35);
+  CHECK_EQ(0, result.a36);
+  CHECK_EQ(0, result.a37);
+  CHECK_EQ(0, result.a38);
+  CHECK_EQ(0, result.a39);
+  CHECK_EQ(0, result.a40);
+  CHECK_EQ(0, result.a41);
+  CHECK_EQ(0, result.a42);
+  CHECK_EQ(0, result.a43);
+  CHECK_EQ(0, result.a44);
+  CHECK_EQ(0, result.a45);
+  CHECK_EQ(0, result.a46);
+  CHECK_EQ(0, result.a47);
+  CHECK_EQ(0, result.a48);
+  CHECK_EQ(0, result.a49);
+  CHECK_EQ(0, result.a50);
+  CHECK_EQ(0, result.a51);
+  CHECK_EQ(0, result.a52);
+  CHECK_EQ(0, result.a53);
+  CHECK_EQ(0, result.a54);
+  CHECK_EQ(0, result.a55);
+  CHECK_EQ(0, result.a56);
+  CHECK_EQ(0, result.a57);
+  CHECK_EQ(0, result.a58);
+  CHECK_EQ(0, result.a59);
+  CHECK_EQ(0, result.a60);
+  CHECK_EQ(0, result.a61);
+  CHECK_EQ(0, result.a62);
+  CHECK_EQ(0, result.a63);
+  CHECK_EQ(0, result.a64);
+  CHECK_EQ(0, result.a65);
+  CHECK_EQ(0, result.a66);
+  CHECK_EQ(0, result.a67);
+  CHECK_EQ(0, result.a68);
+  CHECK_EQ(0, result.a69);
+  CHECK_EQ(0, result.a70);
+  CHECK_EQ(0, result.a71);
+  CHECK_EQ(0, result.a72);
+  CHECK_EQ(0, result.a73);
+  CHECK_EQ(0, result.a74);
+  CHECK_EQ(0, result.a75);
+  CHECK_EQ(0, result.a76);
+  CHECK_EQ(0, result.a77);
+  CHECK_EQ(0, result.a78);
+  CHECK_EQ(0, result.a79);
+  CHECK_EQ(0, result.a80);
+  CHECK_EQ(0, result.a81);
+  CHECK_EQ(0, result.a82);
+  CHECK_EQ(0, result.a83);
+  CHECK_EQ(0, result.a84);
+  CHECK_EQ(0, result.a85);
+  CHECK_EQ(0, result.a86);
+  CHECK_EQ(0, result.a87);
+  CHECK_EQ(0, result.a88);
+  CHECK_EQ(0, result.a89);
+  CHECK_EQ(0, result.a90);
+  CHECK_EQ(0, result.a91);
+  CHECK_EQ(0, result.a92);
+  CHECK_EQ(0, result.a93);
+  CHECK_EQ(0, result.a94);
+  CHECK_EQ(0, result.a95);
+  CHECK_EQ(0, result.a96);
+  CHECK_EQ(0, result.a97);
+  CHECK_EQ(0, result.a98);
+  CHECK_EQ(0, result.a99);
+  CHECK_EQ(0, result.a100);
+  CHECK_EQ(0, result.a101);
+  CHECK_EQ(0, result.a102);
+  CHECK_EQ(0, result.a103);
+  CHECK_EQ(0, result.a104);
+  CHECK_EQ(0, result.a105);
+  CHECK_EQ(0, result.a106);
+  CHECK_EQ(0, result.a107);
+  CHECK_EQ(0, result.a108);
+  CHECK_EQ(0, result.a109);
+  CHECK_EQ(0, result.a110);
+  CHECK_EQ(0, result.a111);
+  CHECK_EQ(0, result.a112);
+  CHECK_EQ(0, result.a113);
+  CHECK_EQ(0, result.a114);
+  CHECK_EQ(0, result.a115);
+  CHECK_EQ(0, result.a116);
+  CHECK_EQ(0, result.a117);
+  CHECK_EQ(0, result.a118);
+  CHECK_EQ(0, result.a119);
+  CHECK_EQ(0, result.a120);
+  CHECK_EQ(0, result.a121);
+  CHECK_EQ(0, result.a122);
+  CHECK_EQ(0, result.a123);
+  CHECK_EQ(0, result.a124);
+  CHECK_EQ(0, result.a125);
+  CHECK_EQ(0, result.a126);
+  CHECK_EQ(0, result.a127);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed in int registers in most ABIs.
+DART_EXPORT intptr_t TestReturnStructArgumentStruct1ByteInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct1ByteInt (*f)(Struct1ByteInt a0)) {
+  Struct1ByteInt a0;
+
+  a0.a0 = -1;
+
+  std::cout << "Calling TestReturnStructArgumentStruct1ByteInt("
+            << "((" << static_cast<int>(a0.a0) << "))"
+            << ")\n";
+
+  Struct1ByteInt result = f(a0);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  CHECK_EQ(a0.a0, result.a0);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed on stack on all ABIs.
+DART_EXPORT intptr_t TestReturnStructArgumentInt32x8Struct1ByteInt(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct1ByteInt (*f)(int32_t a0,
+                        int32_t a1,
+                        int32_t a2,
+                        int32_t a3,
+                        int32_t a4,
+                        int32_t a5,
+                        int32_t a6,
+                        int32_t a7,
+                        Struct1ByteInt a8)) {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  int32_t a4;
+  int32_t a5;
+  int32_t a6;
+  int32_t a7;
+  Struct1ByteInt a8;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+  a5 = 6;
+  a6 = -7;
+  a7 = 8;
+  a8.a0 = -9;
+
+  std::cout << "Calling TestReturnStructArgumentInt32x8Struct1ByteInt("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", " << a6 << ", " << a7 << ", ("
+            << static_cast<int>(a8.a0) << "))"
+            << ")\n";
+
+  Struct1ByteInt result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ")"
+            << "\n";
+
+  CHECK_EQ(a8.a0, result.a0);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test that a struct passed in as argument can be returned.
+// Especially for ffi callbacks.
+// Struct is passed in float registers in most ABIs.
+DART_EXPORT intptr_t TestReturnStructArgumentStruct8BytesHomogeneousFloat(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct8BytesHomogeneousFloat (*f)(Struct8BytesHomogeneousFloat a0)) {
+  Struct8BytesHomogeneousFloat a0;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+
+  std::cout << "Calling TestReturnStructArgumentStruct8BytesHomogeneousFloat("
+            << "((" << a0.a0 << ", " << a0.a1 << "))"
+            << ")\n";
+
+  Struct8BytesHomogeneousFloat result = f(a0);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ")"
+            << "\n";
+
+  CHECK_APPROX(a0.a0, result.a0);
+  CHECK_APPROX(a0.a1, result.a1);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_APPROX(0.0, result.a0);
+  CHECK_APPROX(0.0, result.a1);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// On arm64, both argument and return value are passed in by pointer.
+DART_EXPORT intptr_t TestReturnStructArgumentStruct20BytesHomogeneousInt32(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct20BytesHomogeneousInt32 (*f)(Struct20BytesHomogeneousInt32 a0)) {
+  Struct20BytesHomogeneousInt32 a0;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+  a0.a3 = 4;
+  a0.a4 = -5;
+
+  std::cout << "Calling TestReturnStructArgumentStruct20BytesHomogeneousInt32("
+            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
+            << ", " << a0.a4 << "))"
+            << ")\n";
+
+  Struct20BytesHomogeneousInt32 result = f(a0);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  CHECK_EQ(a0.a0, result.a0);
+  CHECK_EQ(a0.a1, result.a1);
+  CHECK_EQ(a0.a2, result.a2);
+  CHECK_EQ(a0.a3, result.a3);
+  CHECK_EQ(a0.a4, result.a4);
+
+  // Pass argument that will make the Dart callback throw.
+  a0.a0 = 42;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  // Pass argument that will make the Dart callback return null.
+  a0.a0 = 84;
+
+  result = f(a0);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// On arm64, both argument and return value are passed in by pointer.
+// Ints exhaust registers, so that pointer is passed on stack.
+DART_EXPORT intptr_t TestReturnStructArgumentInt32x8Struct20BytesHomogeneou(
+    // NOLINTNEXTLINE(whitespace/parens)
+    Struct20BytesHomogeneousInt32 (*f)(int32_t a0,
+                                       int32_t a1,
+                                       int32_t a2,
+                                       int32_t a3,
+                                       int32_t a4,
+                                       int32_t a5,
+                                       int32_t a6,
+                                       int32_t a7,
+                                       Struct20BytesHomogeneousInt32 a8)) {
+  int32_t a0;
+  int32_t a1;
+  int32_t a2;
+  int32_t a3;
+  int32_t a4;
+  int32_t a5;
+  int32_t a6;
+  int32_t a7;
+  Struct20BytesHomogeneousInt32 a8;
+
+  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;
+
+  std::cout << "Calling TestReturnStructArgumentInt32x8Struct20BytesHomogeneou("
+            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
+            << ", " << a5 << ", " << a6 << ", " << a7 << ", (" << a8.a0 << ", "
+            << a8.a1 << ", " << a8.a2 << ", " << a8.a3 << ", " << a8.a4 << "))"
+            << ")\n";
+
+  Struct20BytesHomogeneousInt32 result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  std::cout << "result = "
+            << "(" << result.a0 << ", " << result.a1 << ", " << result.a2
+            << ", " << result.a3 << ", " << result.a4 << ")"
+            << "\n";
+
+  CHECK_EQ(a8.a0, result.a0);
+  CHECK_EQ(a8.a1, result.a1);
+  CHECK_EQ(a8.a2, result.a2);
+  CHECK_EQ(a8.a3, result.a3);
+  CHECK_EQ(a8.a4, result.a4);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+  CHECK_EQ(0, result.a3);
+  CHECK_EQ(0, result.a4);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 16 byte int within struct.
+DART_EXPORT intptr_t TestReturnStructAlignmentInt16(
+    // NOLINTNEXTLINE(whitespace/parens)
+    StructAlignmentInt16 (*f)(int8_t a0, int16_t a1, int8_t a2)) {
+  int8_t a0;
+  int16_t a1;
+  int8_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStructAlignmentInt16("
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << ")\n";
+
+  StructAlignmentInt16 result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 32 byte int within struct.
+DART_EXPORT intptr_t TestReturnStructAlignmentInt32(
+    // NOLINTNEXTLINE(whitespace/parens)
+    StructAlignmentInt32 (*f)(int8_t a0, int32_t a1, int8_t a2)) {
+  int8_t a0;
+  int32_t a1;
+  int8_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStructAlignmentInt32("
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << ")\n";
+
+  StructAlignmentInt32 result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+// Used for testing structs by value.
+// Test alignment and padding of 64 byte int within struct.
+DART_EXPORT intptr_t TestReturnStructAlignmentInt64(
+    // NOLINTNEXTLINE(whitespace/parens)
+    StructAlignmentInt64 (*f)(int8_t a0, int64_t a1, int8_t a2)) {
+  int8_t a0;
+  int64_t a1;
+  int8_t a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  std::cout << "Calling TestReturnStructAlignmentInt64("
+            << "(" << static_cast<int>(a0) << ", " << a1 << ", "
+            << static_cast<int>(a2) << ")"
+            << ")\n";
+
+  StructAlignmentInt64 result = f(a0, a1, a2);
+
+  std::cout << "result = "
+            << "(" << static_cast<int>(result.a0) << ", " << result.a1 << ", "
+            << static_cast<int>(result.a2) << ")"
+            << "\n";
+
+  CHECK_EQ(a0, result.a0);
+  CHECK_EQ(a1, result.a1);
+  CHECK_EQ(a2, result.a2);
+
+  // Pass argument that will make the Dart callback throw.
+  a0 = 42;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  // Pass argument that will make the Dart callback return null.
+  a0 = 84;
+
+  result = f(a0, a1, a2);
+
+  CHECK_EQ(0, result.a0);
+  CHECK_EQ(0, result.a1);
+  CHECK_EQ(0, result.a2);
+
+  return 0;
+}
+
+}  // namespace dart
diff --git a/tests/ffi/callback_tests_utils.dart b/tests/ffi/callback_tests_utils.dart
index ac5fdcb..e34a52b 100644
--- a/tests/ffi/callback_tests_utils.dart
+++ b/tests/ffi/callback_tests_utils.dart
@@ -16,19 +16,23 @@
 class CallbackTest {
   final String name;
   final Pointer callback;
-  final bool skip;
+  final void Function() afterCallbackChecks;
 
-  CallbackTest(this.name, this.callback, {bool skipIf: false})
-      : skip = skipIf {}
+  CallbackTest(this.name, this.callback) : afterCallbackChecks = noChecks {}
+  CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks) {}
 
   void run() {
-    if (skip) return;
-
     final NativeCallbackTestFn tester = ffiTestFunctions
         .lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
+
     final int testCode = tester(callback);
+
     if (testCode != 0) {
       Expect.fail("Test $name failed.");
     }
+
+    afterCallbackChecks();
   }
 }
+
+void noChecks() {}
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 37ab3e9..3baf069 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -2,6 +2,11 @@
 # 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.
 
+# TODO(dartbug.com/36730): Implement structs by value.
+function_callbacks_structs_by_value_generated_test: Skip
+function_callbacks_structs_by_value_test: Skip
+function_structs_by_value_generated_test: Skip
+
 [ $builder_tag == msan ]
 vmspecific_handle_test: Skip # https://dartbug.com/42314
 
diff --git a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
new file mode 100644
index 0000000..8499285
--- /dev/null
+++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
@@ -0,0 +1,5896 @@
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=10
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'callback_tests_utils.dart';
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+void main() {
+  testCases.forEach((t) {
+    print("==== Running " + t.name);
+    t.run();
+  });
+}
+
+final testCases = [
+  CallbackTest.withCheck(
+      "PassStruct1ByteIntx10",
+      Pointer.fromFunction<PassStruct1ByteIntx10Type>(passStruct1ByteIntx10, 0),
+      passStruct1ByteIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct3BytesIntx10",
+      Pointer.fromFunction<PassStruct3BytesIntx10Type>(
+          passStruct3BytesIntx10, 0),
+      passStruct3BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct4BytesHomogeneousInt16x10",
+      Pointer.fromFunction<PassStruct4BytesHomogeneousInt16x10Type>(
+          passStruct4BytesHomogeneousInt16x10, 0),
+      passStruct4BytesHomogeneousInt16x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct7BytesIntx10",
+      Pointer.fromFunction<PassStruct7BytesIntx10Type>(
+          passStruct7BytesIntx10, 0),
+      passStruct7BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesIntx10",
+      Pointer.fromFunction<PassStruct8BytesIntx10Type>(
+          passStruct8BytesIntx10, 0),
+      passStruct8BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesHomogeneousFloatx10",
+      Pointer.fromFunction<PassStruct8BytesHomogeneousFloatx10Type>(
+          passStruct8BytesHomogeneousFloatx10, 0.0),
+      passStruct8BytesHomogeneousFloatx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesMixedx10",
+      Pointer.fromFunction<PassStruct8BytesMixedx10Type>(
+          passStruct8BytesMixedx10, 0.0),
+      passStruct8BytesMixedx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct9BytesIntx10",
+      Pointer.fromFunction<PassStruct9BytesIntx10Type>(
+          passStruct9BytesIntx10, 0),
+      passStruct9BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct9BytesHomogeneousUint82x10",
+      Pointer.fromFunction<PassStruct9BytesHomogeneousUint82x10Type>(
+          passStruct9BytesHomogeneousUint82x10, 0),
+      passStruct9BytesHomogeneousUint82x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct12BytesHomogeneousFloatx6",
+      Pointer.fromFunction<PassStruct12BytesHomogeneousFloatx6Type>(
+          passStruct12BytesHomogeneousFloatx6, 0.0),
+      passStruct12BytesHomogeneousFloatx6AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesHomogeneousFloatx5",
+      Pointer.fromFunction<PassStruct16BytesHomogeneousFloatx5Type>(
+          passStruct16BytesHomogeneousFloatx5, 0.0),
+      passStruct16BytesHomogeneousFloatx5AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesMixedx10",
+      Pointer.fromFunction<PassStruct16BytesMixedx10Type>(
+          passStruct16BytesMixedx10, 0.0),
+      passStruct16BytesMixedx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesMixed2x10",
+      Pointer.fromFunction<PassStruct16BytesMixed2x10Type>(
+          passStruct16BytesMixed2x10, 0.0),
+      passStruct16BytesMixed2x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct17BytesIntx10",
+      Pointer.fromFunction<PassStruct17BytesIntx10Type>(
+          passStruct17BytesIntx10, 0),
+      passStruct17BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct19BytesHomogeneousUint8x10",
+      Pointer.fromFunction<PassStruct19BytesHomogeneousUint8x10Type>(
+          passStruct19BytesHomogeneousUint8x10, 0),
+      passStruct19BytesHomogeneousUint8x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct20BytesHomogeneousInt32x10",
+      Pointer.fromFunction<PassStruct20BytesHomogeneousInt32x10Type>(
+          passStruct20BytesHomogeneousInt32x10, 0),
+      passStruct20BytesHomogeneousInt32x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct20BytesHomogeneousFloat",
+      Pointer.fromFunction<PassStruct20BytesHomogeneousFloatType>(
+          passStruct20BytesHomogeneousFloat, 0.0),
+      passStruct20BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct32BytesHomogeneousDoublex5",
+      Pointer.fromFunction<PassStruct32BytesHomogeneousDoublex5Type>(
+          passStruct32BytesHomogeneousDoublex5, 0.0),
+      passStruct32BytesHomogeneousDoublex5AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct40BytesHomogeneousDouble",
+      Pointer.fromFunction<PassStruct40BytesHomogeneousDoubleType>(
+          passStruct40BytesHomogeneousDouble, 0.0),
+      passStruct40BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct1024BytesHomogeneousUint64",
+      Pointer.fromFunction<PassStruct1024BytesHomogeneousUint64Type>(
+          passStruct1024BytesHomogeneousUint64, 0),
+      passStruct1024BytesHomogeneousUint64AfterCallback),
+  CallbackTest.withCheck(
+      "PassFloatStruct16BytesHomogeneousFloatFloatStruct1",
+      Pointer.fromFunction<
+              PassFloatStruct16BytesHomogeneousFloatFloatStruct1Type>(
+          passFloatStruct16BytesHomogeneousFloatFloatStruct1, 0.0),
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1AfterCallback),
+  CallbackTest.withCheck(
+      "PassFloatStruct32BytesHomogeneousDoubleFloatStruct",
+      Pointer.fromFunction<
+              PassFloatStruct32BytesHomogeneousDoubleFloatStructType>(
+          passFloatStruct32BytesHomogeneousDoubleFloatStruct, 0.0),
+      passFloatStruct32BytesHomogeneousDoubleFloatStructAfterCallback),
+  CallbackTest.withCheck(
+      "PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn",
+      Pointer.fromFunction<
+              PassInt8Struct16BytesMixedInt8Struct16BytesMixedInType>(
+          passInt8Struct16BytesMixedInt8Struct16BytesMixedIn, 0.0),
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInAfterCallback),
+  CallbackTest.withCheck(
+      "PassDoublex6Struct16BytesMixedx4Int32",
+      Pointer.fromFunction<PassDoublex6Struct16BytesMixedx4Int32Type>(
+          passDoublex6Struct16BytesMixedx4Int32, 0.0),
+      passDoublex6Struct16BytesMixedx4Int32AfterCallback),
+  CallbackTest.withCheck(
+      "PassInt32x4Struct16BytesMixedx4Double",
+      Pointer.fromFunction<PassInt32x4Struct16BytesMixedx4DoubleType>(
+          passInt32x4Struct16BytesMixedx4Double, 0.0),
+      passInt32x4Struct16BytesMixedx4DoubleAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo",
+      Pointer.fromFunction<
+              PassStruct40BytesHomogeneousDoubleStruct4BytesHomoType>(
+          passStruct40BytesHomogeneousDoubleStruct4BytesHomo, 0.0),
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt16",
+      Pointer.fromFunction<PassStructAlignmentInt16Type>(
+          passStructAlignmentInt16, 0),
+      passStructAlignmentInt16AfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt32",
+      Pointer.fromFunction<PassStructAlignmentInt32Type>(
+          passStructAlignmentInt32, 0),
+      passStructAlignmentInt32AfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt64",
+      Pointer.fromFunction<PassStructAlignmentInt64Type>(
+          passStructAlignmentInt64, 0),
+      passStructAlignmentInt64AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct1ByteInt",
+      Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
+      returnStruct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct3BytesInt",
+      Pointer.fromFunction<ReturnStruct3BytesIntType>(returnStruct3BytesInt),
+      returnStruct3BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct4BytesHomogeneousInt16",
+      Pointer.fromFunction<ReturnStruct4BytesHomogeneousInt16Type>(
+          returnStruct4BytesHomogeneousInt16),
+      returnStruct4BytesHomogeneousInt16AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct7BytesInt",
+      Pointer.fromFunction<ReturnStruct7BytesIntType>(returnStruct7BytesInt),
+      returnStruct7BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesInt",
+      Pointer.fromFunction<ReturnStruct8BytesIntType>(returnStruct8BytesInt),
+      returnStruct8BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct8BytesHomogeneousFloatType>(
+          returnStruct8BytesHomogeneousFloat),
+      returnStruct8BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesMixed",
+      Pointer.fromFunction<ReturnStruct8BytesMixedType>(
+          returnStruct8BytesMixed),
+      returnStruct8BytesMixedAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct9BytesInt",
+      Pointer.fromFunction<ReturnStruct9BytesIntType>(returnStruct9BytesInt),
+      returnStruct9BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct9BytesHomogeneousUint82",
+      Pointer.fromFunction<ReturnStruct9BytesHomogeneousUint82Type>(
+          returnStruct9BytesHomogeneousUint82),
+      returnStruct9BytesHomogeneousUint82AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct12BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct12BytesHomogeneousFloatType>(
+          returnStruct12BytesHomogeneousFloat),
+      returnStruct12BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct16BytesHomogeneousFloatType>(
+          returnStruct16BytesHomogeneousFloat),
+      returnStruct16BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesMixed",
+      Pointer.fromFunction<ReturnStruct16BytesMixedType>(
+          returnStruct16BytesMixed),
+      returnStruct16BytesMixedAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesMixed2",
+      Pointer.fromFunction<ReturnStruct16BytesMixed2Type>(
+          returnStruct16BytesMixed2),
+      returnStruct16BytesMixed2AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct17BytesInt",
+      Pointer.fromFunction<ReturnStruct17BytesIntType>(returnStruct17BytesInt),
+      returnStruct17BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct19BytesHomogeneousUint8",
+      Pointer.fromFunction<ReturnStruct19BytesHomogeneousUint8Type>(
+          returnStruct19BytesHomogeneousUint8),
+      returnStruct19BytesHomogeneousUint8AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct20BytesHomogeneousInt32",
+      Pointer.fromFunction<ReturnStruct20BytesHomogeneousInt32Type>(
+          returnStruct20BytesHomogeneousInt32),
+      returnStruct20BytesHomogeneousInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct20BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct20BytesHomogeneousFloatType>(
+          returnStruct20BytesHomogeneousFloat),
+      returnStruct20BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct32BytesHomogeneousDouble",
+      Pointer.fromFunction<ReturnStruct32BytesHomogeneousDoubleType>(
+          returnStruct32BytesHomogeneousDouble),
+      returnStruct32BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct40BytesHomogeneousDouble",
+      Pointer.fromFunction<ReturnStruct40BytesHomogeneousDoubleType>(
+          returnStruct40BytesHomogeneousDouble),
+      returnStruct40BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct1024BytesHomogeneousUint64",
+      Pointer.fromFunction<ReturnStruct1024BytesHomogeneousUint64Type>(
+          returnStruct1024BytesHomogeneousUint64),
+      returnStruct1024BytesHomogeneousUint64AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct1ByteInt",
+      Pointer.fromFunction<ReturnStructArgumentStruct1ByteIntType>(
+          returnStructArgumentStruct1ByteInt),
+      returnStructArgumentStruct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentInt32x8Struct1ByteInt",
+      Pointer.fromFunction<ReturnStructArgumentInt32x8Struct1ByteIntType>(
+          returnStructArgumentInt32x8Struct1ByteInt),
+      returnStructArgumentInt32x8Struct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct8BytesHomogeneousFloat",
+      Pointer.fromFunction<
+              ReturnStructArgumentStruct8BytesHomogeneousFloatType>(
+          returnStructArgumentStruct8BytesHomogeneousFloat),
+      returnStructArgumentStruct8BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct20BytesHomogeneousInt32",
+      Pointer.fromFunction<
+              ReturnStructArgumentStruct20BytesHomogeneousInt32Type>(
+          returnStructArgumentStruct20BytesHomogeneousInt32),
+      returnStructArgumentStruct20BytesHomogeneousInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentInt32x8Struct20BytesHomogeneou",
+      Pointer.fromFunction<
+              ReturnStructArgumentInt32x8Struct20BytesHomogeneouType>(
+          returnStructArgumentInt32x8Struct20BytesHomogeneou),
+      returnStructArgumentInt32x8Struct20BytesHomogeneouAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt16",
+      Pointer.fromFunction<ReturnStructAlignmentInt16Type>(
+          returnStructAlignmentInt16),
+      returnStructAlignmentInt16AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt32",
+      Pointer.fromFunction<ReturnStructAlignmentInt32Type>(
+          returnStructAlignmentInt32),
+      returnStructAlignmentInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt64",
+      Pointer.fromFunction<ReturnStructAlignmentInt64Type>(
+          returnStructAlignmentInt64),
+      returnStructAlignmentInt64AfterCallback),
+];
+typedef PassStruct1ByteIntx10Type = Int64 Function(
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1ByteInt passStruct1ByteIntx10_a0 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a1 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a2 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a3 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a4 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a5 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a6 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a7 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a8 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a9 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct1ByteIntx10Result = 0;
+
+int passStruct1ByteIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct1ByteIntx10_a0.a0;
+  result += passStruct1ByteIntx10_a1.a0;
+  result += passStruct1ByteIntx10_a2.a0;
+  result += passStruct1ByteIntx10_a3.a0;
+  result += passStruct1ByteIntx10_a4.a0;
+  result += passStruct1ByteIntx10_a5.a0;
+  result += passStruct1ByteIntx10_a6.a0;
+  result += passStruct1ByteIntx10_a7.a0;
+  result += passStruct1ByteIntx10_a8.a0;
+  result += passStruct1ByteIntx10_a9.a0;
+
+  passStruct1ByteIntx10Result = result;
+
+  return result;
+}
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+int passStruct1ByteIntx10(
+    Struct1ByteInt a0,
+    Struct1ByteInt a1,
+    Struct1ByteInt a2,
+    Struct1ByteInt a3,
+    Struct1ByteInt a4,
+    Struct1ByteInt a5,
+    Struct1ByteInt a6,
+    Struct1ByteInt a7,
+    Struct1ByteInt a8,
+    Struct1ByteInt a9) {
+  print(
+      "passStruct1ByteIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct1ByteIntx10 throwing on purpuse!");
+  }
+
+  passStruct1ByteIntx10_a0 = a0;
+  passStruct1ByteIntx10_a1 = a1;
+  passStruct1ByteIntx10_a2 = a2;
+  passStruct1ByteIntx10_a3 = a3;
+  passStruct1ByteIntx10_a4 = a4;
+  passStruct1ByteIntx10_a5 = a5;
+  passStruct1ByteIntx10_a6 = a6;
+  passStruct1ByteIntx10_a7 = a7;
+  passStruct1ByteIntx10_a8 = a8;
+  passStruct1ByteIntx10_a9 = a9;
+
+  final result = passStruct1ByteIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct1ByteIntx10AfterCallback() {
+  final result = passStruct1ByteIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(5, result);
+}
+
+typedef PassStruct3BytesIntx10Type = Int64 Function(
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct3BytesInt passStruct3BytesIntx10_a0 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a1 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a2 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a3 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a4 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a5 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a6 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a7 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a8 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a9 = Struct3BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct3BytesIntx10Result = 0;
+
+int passStruct3BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct3BytesIntx10_a0.a0;
+  result += passStruct3BytesIntx10_a0.a1;
+  result += passStruct3BytesIntx10_a1.a0;
+  result += passStruct3BytesIntx10_a1.a1;
+  result += passStruct3BytesIntx10_a2.a0;
+  result += passStruct3BytesIntx10_a2.a1;
+  result += passStruct3BytesIntx10_a3.a0;
+  result += passStruct3BytesIntx10_a3.a1;
+  result += passStruct3BytesIntx10_a4.a0;
+  result += passStruct3BytesIntx10_a4.a1;
+  result += passStruct3BytesIntx10_a5.a0;
+  result += passStruct3BytesIntx10_a5.a1;
+  result += passStruct3BytesIntx10_a6.a0;
+  result += passStruct3BytesIntx10_a6.a1;
+  result += passStruct3BytesIntx10_a7.a0;
+  result += passStruct3BytesIntx10_a7.a1;
+  result += passStruct3BytesIntx10_a8.a0;
+  result += passStruct3BytesIntx10_a8.a1;
+  result += passStruct3BytesIntx10_a9.a0;
+  result += passStruct3BytesIntx10_a9.a1;
+
+  passStruct3BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+int passStruct3BytesIntx10(
+    Struct3BytesInt a0,
+    Struct3BytesInt a1,
+    Struct3BytesInt a2,
+    Struct3BytesInt a3,
+    Struct3BytesInt a4,
+    Struct3BytesInt a5,
+    Struct3BytesInt a6,
+    Struct3BytesInt a7,
+    Struct3BytesInt a8,
+    Struct3BytesInt a9) {
+  print(
+      "passStruct3BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct3BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct3BytesIntx10_a0 = a0;
+  passStruct3BytesIntx10_a1 = a1;
+  passStruct3BytesIntx10_a2 = a2;
+  passStruct3BytesIntx10_a3 = a3;
+  passStruct3BytesIntx10_a4 = a4;
+  passStruct3BytesIntx10_a5 = a5;
+  passStruct3BytesIntx10_a6 = a6;
+  passStruct3BytesIntx10_a7 = a7;
+  passStruct3BytesIntx10_a8 = a8;
+  passStruct3BytesIntx10_a9 = a9;
+
+  final result = passStruct3BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct3BytesIntx10AfterCallback() {
+  final result = passStruct3BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct4BytesHomogeneousInt16x10Type = Int64 Function(
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16);
+
+// Global variables to be able to test inputs after callback returned.
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a0 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a1 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a2 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a3 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a4 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a5 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a6 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a7 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a8 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a9 =
+    Struct4BytesHomogeneousInt16();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct4BytesHomogeneousInt16x10Result = 0;
+
+int passStruct4BytesHomogeneousInt16x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct4BytesHomogeneousInt16x10_a0.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a0.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a1.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a1.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a2.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a2.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a3.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a3.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a4.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a4.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a5.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a5.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a6.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a6.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a7.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a7.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a8.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a8.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a9.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a9.a1;
+
+  passStruct4BytesHomogeneousInt16x10Result = result;
+
+  return result;
+}
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct4BytesHomogeneousInt16x10(
+    Struct4BytesHomogeneousInt16 a0,
+    Struct4BytesHomogeneousInt16 a1,
+    Struct4BytesHomogeneousInt16 a2,
+    Struct4BytesHomogeneousInt16 a3,
+    Struct4BytesHomogeneousInt16 a4,
+    Struct4BytesHomogeneousInt16 a5,
+    Struct4BytesHomogeneousInt16 a6,
+    Struct4BytesHomogeneousInt16 a7,
+    Struct4BytesHomogeneousInt16 a8,
+    Struct4BytesHomogeneousInt16 a9) {
+  print(
+      "passStruct4BytesHomogeneousInt16x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct4BytesHomogeneousInt16x10 throwing on purpuse!");
+  }
+
+  passStruct4BytesHomogeneousInt16x10_a0 = a0;
+  passStruct4BytesHomogeneousInt16x10_a1 = a1;
+  passStruct4BytesHomogeneousInt16x10_a2 = a2;
+  passStruct4BytesHomogeneousInt16x10_a3 = a3;
+  passStruct4BytesHomogeneousInt16x10_a4 = a4;
+  passStruct4BytesHomogeneousInt16x10_a5 = a5;
+  passStruct4BytesHomogeneousInt16x10_a6 = a6;
+  passStruct4BytesHomogeneousInt16x10_a7 = a7;
+  passStruct4BytesHomogeneousInt16x10_a8 = a8;
+  passStruct4BytesHomogeneousInt16x10_a9 = a9;
+
+  final result = passStruct4BytesHomogeneousInt16x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct4BytesHomogeneousInt16x10AfterCallback() {
+  final result = passStruct4BytesHomogeneousInt16x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct7BytesIntx10Type = Int64 Function(
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct7BytesInt passStruct7BytesIntx10_a0 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a1 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a2 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a3 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a4 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a5 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a6 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a7 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a8 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a9 = Struct7BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct7BytesIntx10Result = 0;
+
+int passStruct7BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct7BytesIntx10_a0.a0;
+  result += passStruct7BytesIntx10_a0.a1;
+  result += passStruct7BytesIntx10_a0.a2;
+  result += passStruct7BytesIntx10_a1.a0;
+  result += passStruct7BytesIntx10_a1.a1;
+  result += passStruct7BytesIntx10_a1.a2;
+  result += passStruct7BytesIntx10_a2.a0;
+  result += passStruct7BytesIntx10_a2.a1;
+  result += passStruct7BytesIntx10_a2.a2;
+  result += passStruct7BytesIntx10_a3.a0;
+  result += passStruct7BytesIntx10_a3.a1;
+  result += passStruct7BytesIntx10_a3.a2;
+  result += passStruct7BytesIntx10_a4.a0;
+  result += passStruct7BytesIntx10_a4.a1;
+  result += passStruct7BytesIntx10_a4.a2;
+  result += passStruct7BytesIntx10_a5.a0;
+  result += passStruct7BytesIntx10_a5.a1;
+  result += passStruct7BytesIntx10_a5.a2;
+  result += passStruct7BytesIntx10_a6.a0;
+  result += passStruct7BytesIntx10_a6.a1;
+  result += passStruct7BytesIntx10_a6.a2;
+  result += passStruct7BytesIntx10_a7.a0;
+  result += passStruct7BytesIntx10_a7.a1;
+  result += passStruct7BytesIntx10_a7.a2;
+  result += passStruct7BytesIntx10_a8.a0;
+  result += passStruct7BytesIntx10_a8.a1;
+  result += passStruct7BytesIntx10_a8.a2;
+  result += passStruct7BytesIntx10_a9.a0;
+  result += passStruct7BytesIntx10_a9.a1;
+  result += passStruct7BytesIntx10_a9.a2;
+
+  passStruct7BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct7BytesIntx10(
+    Struct7BytesInt a0,
+    Struct7BytesInt a1,
+    Struct7BytesInt a2,
+    Struct7BytesInt a3,
+    Struct7BytesInt a4,
+    Struct7BytesInt a5,
+    Struct7BytesInt a6,
+    Struct7BytesInt a7,
+    Struct7BytesInt a8,
+    Struct7BytesInt a9) {
+  print(
+      "passStruct7BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct7BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct7BytesIntx10_a0 = a0;
+  passStruct7BytesIntx10_a1 = a1;
+  passStruct7BytesIntx10_a2 = a2;
+  passStruct7BytesIntx10_a3 = a3;
+  passStruct7BytesIntx10_a4 = a4;
+  passStruct7BytesIntx10_a5 = a5;
+  passStruct7BytesIntx10_a6 = a6;
+  passStruct7BytesIntx10_a7 = a7;
+  passStruct7BytesIntx10_a8 = a8;
+  passStruct7BytesIntx10_a9 = a9;
+
+  final result = passStruct7BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct7BytesIntx10AfterCallback() {
+  final result = passStruct7BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct8BytesIntx10Type = Int64 Function(
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesInt passStruct8BytesIntx10_a0 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a1 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a2 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a3 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a4 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a5 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a6 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a7 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a8 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a9 = Struct8BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct8BytesIntx10Result = 0;
+
+int passStruct8BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct8BytesIntx10_a0.a0;
+  result += passStruct8BytesIntx10_a0.a1;
+  result += passStruct8BytesIntx10_a0.a2;
+  result += passStruct8BytesIntx10_a1.a0;
+  result += passStruct8BytesIntx10_a1.a1;
+  result += passStruct8BytesIntx10_a1.a2;
+  result += passStruct8BytesIntx10_a2.a0;
+  result += passStruct8BytesIntx10_a2.a1;
+  result += passStruct8BytesIntx10_a2.a2;
+  result += passStruct8BytesIntx10_a3.a0;
+  result += passStruct8BytesIntx10_a3.a1;
+  result += passStruct8BytesIntx10_a3.a2;
+  result += passStruct8BytesIntx10_a4.a0;
+  result += passStruct8BytesIntx10_a4.a1;
+  result += passStruct8BytesIntx10_a4.a2;
+  result += passStruct8BytesIntx10_a5.a0;
+  result += passStruct8BytesIntx10_a5.a1;
+  result += passStruct8BytesIntx10_a5.a2;
+  result += passStruct8BytesIntx10_a6.a0;
+  result += passStruct8BytesIntx10_a6.a1;
+  result += passStruct8BytesIntx10_a6.a2;
+  result += passStruct8BytesIntx10_a7.a0;
+  result += passStruct8BytesIntx10_a7.a1;
+  result += passStruct8BytesIntx10_a7.a2;
+  result += passStruct8BytesIntx10_a8.a0;
+  result += passStruct8BytesIntx10_a8.a1;
+  result += passStruct8BytesIntx10_a8.a2;
+  result += passStruct8BytesIntx10_a9.a0;
+  result += passStruct8BytesIntx10_a9.a1;
+  result += passStruct8BytesIntx10_a9.a2;
+
+  passStruct8BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct8BytesIntx10(
+    Struct8BytesInt a0,
+    Struct8BytesInt a1,
+    Struct8BytesInt a2,
+    Struct8BytesInt a3,
+    Struct8BytesInt a4,
+    Struct8BytesInt a5,
+    Struct8BytesInt a6,
+    Struct8BytesInt a7,
+    Struct8BytesInt a8,
+    Struct8BytesInt a9) {
+  print(
+      "passStruct8BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesIntx10_a0 = a0;
+  passStruct8BytesIntx10_a1 = a1;
+  passStruct8BytesIntx10_a2 = a2;
+  passStruct8BytesIntx10_a3 = a3;
+  passStruct8BytesIntx10_a4 = a4;
+  passStruct8BytesIntx10_a5 = a5;
+  passStruct8BytesIntx10_a6 = a6;
+  passStruct8BytesIntx10_a7 = a7;
+  passStruct8BytesIntx10_a8 = a8;
+  passStruct8BytesIntx10_a9 = a9;
+
+  final result = passStruct8BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesIntx10AfterCallback() {
+  final result = passStruct8BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct8BytesHomogeneousFloatx10Type = Float Function(
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a0 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a1 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a2 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a3 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a4 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a5 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a6 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a7 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a8 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a9 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct8BytesHomogeneousFloatx10Result = 0.0;
+
+double passStruct8BytesHomogeneousFloatx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct8BytesHomogeneousFloatx10_a0.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a0.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a1.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a1.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a2.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a2.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a3.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a3.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a4.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a4.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a5.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a5.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a6.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a6.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a7.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a7.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a8.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a8.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a9.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a9.a1;
+
+  passStruct8BytesHomogeneousFloatx10Result = result;
+
+  return result;
+}
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+double passStruct8BytesHomogeneousFloatx10(
+    Struct8BytesHomogeneousFloat a0,
+    Struct8BytesHomogeneousFloat a1,
+    Struct8BytesHomogeneousFloat a2,
+    Struct8BytesHomogeneousFloat a3,
+    Struct8BytesHomogeneousFloat a4,
+    Struct8BytesHomogeneousFloat a5,
+    Struct8BytesHomogeneousFloat a6,
+    Struct8BytesHomogeneousFloat a7,
+    Struct8BytesHomogeneousFloat a8,
+    Struct8BytesHomogeneousFloat a9) {
+  print(
+      "passStruct8BytesHomogeneousFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesHomogeneousFloatx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesHomogeneousFloatx10_a0 = a0;
+  passStruct8BytesHomogeneousFloatx10_a1 = a1;
+  passStruct8BytesHomogeneousFloatx10_a2 = a2;
+  passStruct8BytesHomogeneousFloatx10_a3 = a3;
+  passStruct8BytesHomogeneousFloatx10_a4 = a4;
+  passStruct8BytesHomogeneousFloatx10_a5 = a5;
+  passStruct8BytesHomogeneousFloatx10_a6 = a6;
+  passStruct8BytesHomogeneousFloatx10_a7 = a7;
+  passStruct8BytesHomogeneousFloatx10_a8 = a8;
+  passStruct8BytesHomogeneousFloatx10_a9 = a9;
+
+  final result = passStruct8BytesHomogeneousFloatx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesHomogeneousFloatx10AfterCallback() {
+  final result = passStruct8BytesHomogeneousFloatx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct8BytesMixedx10Type = Float Function(
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesMixed passStruct8BytesMixedx10_a0 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a1 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a2 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a3 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a4 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a5 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a6 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a7 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a8 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a9 = Struct8BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct8BytesMixedx10Result = 0.0;
+
+double passStruct8BytesMixedx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct8BytesMixedx10_a0.a0;
+  result += passStruct8BytesMixedx10_a0.a1;
+  result += passStruct8BytesMixedx10_a0.a2;
+  result += passStruct8BytesMixedx10_a1.a0;
+  result += passStruct8BytesMixedx10_a1.a1;
+  result += passStruct8BytesMixedx10_a1.a2;
+  result += passStruct8BytesMixedx10_a2.a0;
+  result += passStruct8BytesMixedx10_a2.a1;
+  result += passStruct8BytesMixedx10_a2.a2;
+  result += passStruct8BytesMixedx10_a3.a0;
+  result += passStruct8BytesMixedx10_a3.a1;
+  result += passStruct8BytesMixedx10_a3.a2;
+  result += passStruct8BytesMixedx10_a4.a0;
+  result += passStruct8BytesMixedx10_a4.a1;
+  result += passStruct8BytesMixedx10_a4.a2;
+  result += passStruct8BytesMixedx10_a5.a0;
+  result += passStruct8BytesMixedx10_a5.a1;
+  result += passStruct8BytesMixedx10_a5.a2;
+  result += passStruct8BytesMixedx10_a6.a0;
+  result += passStruct8BytesMixedx10_a6.a1;
+  result += passStruct8BytesMixedx10_a6.a2;
+  result += passStruct8BytesMixedx10_a7.a0;
+  result += passStruct8BytesMixedx10_a7.a1;
+  result += passStruct8BytesMixedx10_a7.a2;
+  result += passStruct8BytesMixedx10_a8.a0;
+  result += passStruct8BytesMixedx10_a8.a1;
+  result += passStruct8BytesMixedx10_a8.a2;
+  result += passStruct8BytesMixedx10_a9.a0;
+  result += passStruct8BytesMixedx10_a9.a1;
+  result += passStruct8BytesMixedx10_a9.a2;
+
+  passStruct8BytesMixedx10Result = result;
+
+  return result;
+}
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+double passStruct8BytesMixedx10(
+    Struct8BytesMixed a0,
+    Struct8BytesMixed a1,
+    Struct8BytesMixed a2,
+    Struct8BytesMixed a3,
+    Struct8BytesMixed a4,
+    Struct8BytesMixed a5,
+    Struct8BytesMixed a6,
+    Struct8BytesMixed a7,
+    Struct8BytesMixed a8,
+    Struct8BytesMixed a9) {
+  print(
+      "passStruct8BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesMixedx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesMixedx10_a0 = a0;
+  passStruct8BytesMixedx10_a1 = a1;
+  passStruct8BytesMixedx10_a2 = a2;
+  passStruct8BytesMixedx10_a3 = a3;
+  passStruct8BytesMixedx10_a4 = a4;
+  passStruct8BytesMixedx10_a5 = a5;
+  passStruct8BytesMixedx10_a6 = a6;
+  passStruct8BytesMixedx10_a7 = a7;
+  passStruct8BytesMixedx10_a8 = a8;
+  passStruct8BytesMixedx10_a9 = a9;
+
+  final result = passStruct8BytesMixedx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesMixedx10AfterCallback() {
+  final result = passStruct8BytesMixedx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(15.0, result);
+}
+
+typedef PassStruct9BytesIntx10Type = Int64 Function(
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct9BytesInt passStruct9BytesIntx10_a0 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a1 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a2 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a3 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a4 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a5 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a6 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a7 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a8 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a9 = Struct9BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct9BytesIntx10Result = 0;
+
+int passStruct9BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct9BytesIntx10_a0.a0;
+  result += passStruct9BytesIntx10_a0.a1;
+  result += passStruct9BytesIntx10_a1.a0;
+  result += passStruct9BytesIntx10_a1.a1;
+  result += passStruct9BytesIntx10_a2.a0;
+  result += passStruct9BytesIntx10_a2.a1;
+  result += passStruct9BytesIntx10_a3.a0;
+  result += passStruct9BytesIntx10_a3.a1;
+  result += passStruct9BytesIntx10_a4.a0;
+  result += passStruct9BytesIntx10_a4.a1;
+  result += passStruct9BytesIntx10_a5.a0;
+  result += passStruct9BytesIntx10_a5.a1;
+  result += passStruct9BytesIntx10_a6.a0;
+  result += passStruct9BytesIntx10_a6.a1;
+  result += passStruct9BytesIntx10_a7.a0;
+  result += passStruct9BytesIntx10_a7.a1;
+  result += passStruct9BytesIntx10_a8.a0;
+  result += passStruct9BytesIntx10_a8.a1;
+  result += passStruct9BytesIntx10_a9.a0;
+  result += passStruct9BytesIntx10_a9.a1;
+
+  passStruct9BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+int passStruct9BytesIntx10(
+    Struct9BytesInt a0,
+    Struct9BytesInt a1,
+    Struct9BytesInt a2,
+    Struct9BytesInt a3,
+    Struct9BytesInt a4,
+    Struct9BytesInt a5,
+    Struct9BytesInt a6,
+    Struct9BytesInt a7,
+    Struct9BytesInt a8,
+    Struct9BytesInt a9) {
+  print(
+      "passStruct9BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct9BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct9BytesIntx10_a0 = a0;
+  passStruct9BytesIntx10_a1 = a1;
+  passStruct9BytesIntx10_a2 = a2;
+  passStruct9BytesIntx10_a3 = a3;
+  passStruct9BytesIntx10_a4 = a4;
+  passStruct9BytesIntx10_a5 = a5;
+  passStruct9BytesIntx10_a6 = a6;
+  passStruct9BytesIntx10_a7 = a7;
+  passStruct9BytesIntx10_a8 = a8;
+  passStruct9BytesIntx10_a9 = a9;
+
+  final result = passStruct9BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct9BytesIntx10AfterCallback() {
+  final result = passStruct9BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct9BytesHomogeneousUint82x10Type = Int64 Function(
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82);
+
+// Global variables to be able to test inputs after callback returned.
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a0 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a1 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a2 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a3 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a4 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a5 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a6 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a7 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a8 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a9 =
+    Struct9BytesHomogeneousUint82();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct9BytesHomogeneousUint82x10Result = 0;
+
+int passStruct9BytesHomogeneousUint82x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct9BytesHomogeneousUint82x10_a0.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a8;
+
+  passStruct9BytesHomogeneousUint82x10Result = result;
+
+  return result;
+}
+
+/// 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.
+///
+int passStruct9BytesHomogeneousUint82x10(
+    Struct9BytesHomogeneousUint82 a0,
+    Struct9BytesHomogeneousUint82 a1,
+    Struct9BytesHomogeneousUint82 a2,
+    Struct9BytesHomogeneousUint82 a3,
+    Struct9BytesHomogeneousUint82 a4,
+    Struct9BytesHomogeneousUint82 a5,
+    Struct9BytesHomogeneousUint82 a6,
+    Struct9BytesHomogeneousUint82 a7,
+    Struct9BytesHomogeneousUint82 a8,
+    Struct9BytesHomogeneousUint82 a9) {
+  print(
+      "passStruct9BytesHomogeneousUint82x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct9BytesHomogeneousUint82x10 throwing on purpuse!");
+  }
+
+  passStruct9BytesHomogeneousUint82x10_a0 = a0;
+  passStruct9BytesHomogeneousUint82x10_a1 = a1;
+  passStruct9BytesHomogeneousUint82x10_a2 = a2;
+  passStruct9BytesHomogeneousUint82x10_a3 = a3;
+  passStruct9BytesHomogeneousUint82x10_a4 = a4;
+  passStruct9BytesHomogeneousUint82x10_a5 = a5;
+  passStruct9BytesHomogeneousUint82x10_a6 = a6;
+  passStruct9BytesHomogeneousUint82x10_a7 = a7;
+  passStruct9BytesHomogeneousUint82x10_a8 = a8;
+  passStruct9BytesHomogeneousUint82x10_a9 = a9;
+
+  final result = passStruct9BytesHomogeneousUint82x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct9BytesHomogeneousUint82x10AfterCallback() {
+  final result = passStruct9BytesHomogeneousUint82x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(4095, result);
+}
+
+typedef PassStruct12BytesHomogeneousFloatx6Type = Float Function(
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a0 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a1 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a2 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a3 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a4 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a5 =
+    Struct12BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct12BytesHomogeneousFloatx6Result = 0.0;
+
+double passStruct12BytesHomogeneousFloatx6CalculateResult() {
+  double result = 0;
+
+  result += passStruct12BytesHomogeneousFloatx6_a0.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a0.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a0.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a2;
+
+  passStruct12BytesHomogeneousFloatx6Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct12BytesHomogeneousFloatx6(
+    Struct12BytesHomogeneousFloat a0,
+    Struct12BytesHomogeneousFloat a1,
+    Struct12BytesHomogeneousFloat a2,
+    Struct12BytesHomogeneousFloat a3,
+    Struct12BytesHomogeneousFloat a4,
+    Struct12BytesHomogeneousFloat a5) {
+  print(
+      "passStruct12BytesHomogeneousFloatx6(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct12BytesHomogeneousFloatx6 throwing on purpuse!");
+  }
+
+  passStruct12BytesHomogeneousFloatx6_a0 = a0;
+  passStruct12BytesHomogeneousFloatx6_a1 = a1;
+  passStruct12BytesHomogeneousFloatx6_a2 = a2;
+  passStruct12BytesHomogeneousFloatx6_a3 = a3;
+  passStruct12BytesHomogeneousFloatx6_a4 = a4;
+  passStruct12BytesHomogeneousFloatx6_a5 = a5;
+
+  final result = passStruct12BytesHomogeneousFloatx6CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct12BytesHomogeneousFloatx6AfterCallback() {
+  final result = passStruct12BytesHomogeneousFloatx6CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(9.0, result);
+}
+
+typedef PassStruct16BytesHomogeneousFloatx5Type = Float Function(
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a0 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a1 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a2 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a3 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a4 =
+    Struct16BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesHomogeneousFloatx5Result = 0.0;
+
+double passStruct16BytesHomogeneousFloatx5CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesHomogeneousFloatx5_a0.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a3;
+
+  passStruct16BytesHomogeneousFloatx5Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesHomogeneousFloatx5(
+    Struct16BytesHomogeneousFloat a0,
+    Struct16BytesHomogeneousFloat a1,
+    Struct16BytesHomogeneousFloat a2,
+    Struct16BytesHomogeneousFloat a3,
+    Struct16BytesHomogeneousFloat a4) {
+  print(
+      "passStruct16BytesHomogeneousFloatx5(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesHomogeneousFloatx5 throwing on purpuse!");
+  }
+
+  passStruct16BytesHomogeneousFloatx5_a0 = a0;
+  passStruct16BytesHomogeneousFloatx5_a1 = a1;
+  passStruct16BytesHomogeneousFloatx5_a2 = a2;
+  passStruct16BytesHomogeneousFloatx5_a3 = a3;
+  passStruct16BytesHomogeneousFloatx5_a4 = a4;
+
+  final result = passStruct16BytesHomogeneousFloatx5CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesHomogeneousFloatx5AfterCallback() {
+  final result = passStruct16BytesHomogeneousFloatx5CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct16BytesMixedx10Type = Double Function(
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesMixed passStruct16BytesMixedx10_a0 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a1 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a2 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a3 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a4 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a5 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a6 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a7 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a8 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a9 = Struct16BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesMixedx10Result = 0.0;
+
+double passStruct16BytesMixedx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesMixedx10_a0.a0;
+  result += passStruct16BytesMixedx10_a0.a1;
+  result += passStruct16BytesMixedx10_a1.a0;
+  result += passStruct16BytesMixedx10_a1.a1;
+  result += passStruct16BytesMixedx10_a2.a0;
+  result += passStruct16BytesMixedx10_a2.a1;
+  result += passStruct16BytesMixedx10_a3.a0;
+  result += passStruct16BytesMixedx10_a3.a1;
+  result += passStruct16BytesMixedx10_a4.a0;
+  result += passStruct16BytesMixedx10_a4.a1;
+  result += passStruct16BytesMixedx10_a5.a0;
+  result += passStruct16BytesMixedx10_a5.a1;
+  result += passStruct16BytesMixedx10_a6.a0;
+  result += passStruct16BytesMixedx10_a6.a1;
+  result += passStruct16BytesMixedx10_a7.a0;
+  result += passStruct16BytesMixedx10_a7.a1;
+  result += passStruct16BytesMixedx10_a8.a0;
+  result += passStruct16BytesMixedx10_a8.a1;
+  result += passStruct16BytesMixedx10_a9.a0;
+  result += passStruct16BytesMixedx10_a9.a1;
+
+  passStruct16BytesMixedx10Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesMixedx10(
+    Struct16BytesMixed a0,
+    Struct16BytesMixed a1,
+    Struct16BytesMixed a2,
+    Struct16BytesMixed a3,
+    Struct16BytesMixed a4,
+    Struct16BytesMixed a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    Struct16BytesMixed a8,
+    Struct16BytesMixed a9) {
+  print(
+      "passStruct16BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesMixedx10 throwing on purpuse!");
+  }
+
+  passStruct16BytesMixedx10_a0 = a0;
+  passStruct16BytesMixedx10_a1 = a1;
+  passStruct16BytesMixedx10_a2 = a2;
+  passStruct16BytesMixedx10_a3 = a3;
+  passStruct16BytesMixedx10_a4 = a4;
+  passStruct16BytesMixedx10_a5 = a5;
+  passStruct16BytesMixedx10_a6 = a6;
+  passStruct16BytesMixedx10_a7 = a7;
+  passStruct16BytesMixedx10_a8 = a8;
+  passStruct16BytesMixedx10_a9 = a9;
+
+  final result = passStruct16BytesMixedx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesMixedx10AfterCallback() {
+  final result = passStruct16BytesMixedx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct16BytesMixed2x10Type = Float Function(
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a0 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a1 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a2 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a3 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a4 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a5 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a6 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a7 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a8 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a9 = Struct16BytesMixed2();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesMixed2x10Result = 0.0;
+
+double passStruct16BytesMixed2x10CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesMixed2x10_a0.a0;
+  result += passStruct16BytesMixed2x10_a0.a1;
+  result += passStruct16BytesMixed2x10_a0.a2;
+  result += passStruct16BytesMixed2x10_a0.a3;
+  result += passStruct16BytesMixed2x10_a1.a0;
+  result += passStruct16BytesMixed2x10_a1.a1;
+  result += passStruct16BytesMixed2x10_a1.a2;
+  result += passStruct16BytesMixed2x10_a1.a3;
+  result += passStruct16BytesMixed2x10_a2.a0;
+  result += passStruct16BytesMixed2x10_a2.a1;
+  result += passStruct16BytesMixed2x10_a2.a2;
+  result += passStruct16BytesMixed2x10_a2.a3;
+  result += passStruct16BytesMixed2x10_a3.a0;
+  result += passStruct16BytesMixed2x10_a3.a1;
+  result += passStruct16BytesMixed2x10_a3.a2;
+  result += passStruct16BytesMixed2x10_a3.a3;
+  result += passStruct16BytesMixed2x10_a4.a0;
+  result += passStruct16BytesMixed2x10_a4.a1;
+  result += passStruct16BytesMixed2x10_a4.a2;
+  result += passStruct16BytesMixed2x10_a4.a3;
+  result += passStruct16BytesMixed2x10_a5.a0;
+  result += passStruct16BytesMixed2x10_a5.a1;
+  result += passStruct16BytesMixed2x10_a5.a2;
+  result += passStruct16BytesMixed2x10_a5.a3;
+  result += passStruct16BytesMixed2x10_a6.a0;
+  result += passStruct16BytesMixed2x10_a6.a1;
+  result += passStruct16BytesMixed2x10_a6.a2;
+  result += passStruct16BytesMixed2x10_a6.a3;
+  result += passStruct16BytesMixed2x10_a7.a0;
+  result += passStruct16BytesMixed2x10_a7.a1;
+  result += passStruct16BytesMixed2x10_a7.a2;
+  result += passStruct16BytesMixed2x10_a7.a3;
+  result += passStruct16BytesMixed2x10_a8.a0;
+  result += passStruct16BytesMixed2x10_a8.a1;
+  result += passStruct16BytesMixed2x10_a8.a2;
+  result += passStruct16BytesMixed2x10_a8.a3;
+  result += passStruct16BytesMixed2x10_a9.a0;
+  result += passStruct16BytesMixed2x10_a9.a1;
+  result += passStruct16BytesMixed2x10_a9.a2;
+  result += passStruct16BytesMixed2x10_a9.a3;
+
+  passStruct16BytesMixed2x10Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesMixed2x10(
+    Struct16BytesMixed2 a0,
+    Struct16BytesMixed2 a1,
+    Struct16BytesMixed2 a2,
+    Struct16BytesMixed2 a3,
+    Struct16BytesMixed2 a4,
+    Struct16BytesMixed2 a5,
+    Struct16BytesMixed2 a6,
+    Struct16BytesMixed2 a7,
+    Struct16BytesMixed2 a8,
+    Struct16BytesMixed2 a9) {
+  print(
+      "passStruct16BytesMixed2x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesMixed2x10 throwing on purpuse!");
+  }
+
+  passStruct16BytesMixed2x10_a0 = a0;
+  passStruct16BytesMixed2x10_a1 = a1;
+  passStruct16BytesMixed2x10_a2 = a2;
+  passStruct16BytesMixed2x10_a3 = a3;
+  passStruct16BytesMixed2x10_a4 = a4;
+  passStruct16BytesMixed2x10_a5 = a5;
+  passStruct16BytesMixed2x10_a6 = a6;
+  passStruct16BytesMixed2x10_a7 = a7;
+  passStruct16BytesMixed2x10_a8 = a8;
+  passStruct16BytesMixed2x10_a9 = a9;
+
+  final result = passStruct16BytesMixed2x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesMixed2x10AfterCallback() {
+  final result = passStruct16BytesMixed2x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(20.0, result);
+}
+
+typedef PassStruct17BytesIntx10Type = Int64 Function(
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct17BytesInt passStruct17BytesIntx10_a0 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a1 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a2 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a3 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a4 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a5 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a6 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a7 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a8 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a9 = Struct17BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct17BytesIntx10Result = 0;
+
+int passStruct17BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct17BytesIntx10_a0.a0;
+  result += passStruct17BytesIntx10_a0.a1;
+  result += passStruct17BytesIntx10_a0.a2;
+  result += passStruct17BytesIntx10_a1.a0;
+  result += passStruct17BytesIntx10_a1.a1;
+  result += passStruct17BytesIntx10_a1.a2;
+  result += passStruct17BytesIntx10_a2.a0;
+  result += passStruct17BytesIntx10_a2.a1;
+  result += passStruct17BytesIntx10_a2.a2;
+  result += passStruct17BytesIntx10_a3.a0;
+  result += passStruct17BytesIntx10_a3.a1;
+  result += passStruct17BytesIntx10_a3.a2;
+  result += passStruct17BytesIntx10_a4.a0;
+  result += passStruct17BytesIntx10_a4.a1;
+  result += passStruct17BytesIntx10_a4.a2;
+  result += passStruct17BytesIntx10_a5.a0;
+  result += passStruct17BytesIntx10_a5.a1;
+  result += passStruct17BytesIntx10_a5.a2;
+  result += passStruct17BytesIntx10_a6.a0;
+  result += passStruct17BytesIntx10_a6.a1;
+  result += passStruct17BytesIntx10_a6.a2;
+  result += passStruct17BytesIntx10_a7.a0;
+  result += passStruct17BytesIntx10_a7.a1;
+  result += passStruct17BytesIntx10_a7.a2;
+  result += passStruct17BytesIntx10_a8.a0;
+  result += passStruct17BytesIntx10_a8.a1;
+  result += passStruct17BytesIntx10_a8.a2;
+  result += passStruct17BytesIntx10_a9.a0;
+  result += passStruct17BytesIntx10_a9.a1;
+  result += passStruct17BytesIntx10_a9.a2;
+
+  passStruct17BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+int passStruct17BytesIntx10(
+    Struct17BytesInt a0,
+    Struct17BytesInt a1,
+    Struct17BytesInt a2,
+    Struct17BytesInt a3,
+    Struct17BytesInt a4,
+    Struct17BytesInt a5,
+    Struct17BytesInt a6,
+    Struct17BytesInt a7,
+    Struct17BytesInt a8,
+    Struct17BytesInt a9) {
+  print(
+      "passStruct17BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct17BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct17BytesIntx10_a0 = a0;
+  passStruct17BytesIntx10_a1 = a1;
+  passStruct17BytesIntx10_a2 = a2;
+  passStruct17BytesIntx10_a3 = a3;
+  passStruct17BytesIntx10_a4 = a4;
+  passStruct17BytesIntx10_a5 = a5;
+  passStruct17BytesIntx10_a6 = a6;
+  passStruct17BytesIntx10_a7 = a7;
+  passStruct17BytesIntx10_a8 = a8;
+  passStruct17BytesIntx10_a9 = a9;
+
+  final result = passStruct17BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct17BytesIntx10AfterCallback() {
+  final result = passStruct17BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct19BytesHomogeneousUint8x10Type = Int64 Function(
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8);
+
+// Global variables to be able to test inputs after callback returned.
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a0 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a1 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a2 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a3 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a4 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a5 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a6 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a7 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a8 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a9 =
+    Struct19BytesHomogeneousUint8();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct19BytesHomogeneousUint8x10Result = 0;
+
+int passStruct19BytesHomogeneousUint8x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct19BytesHomogeneousUint8x10_a0.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a18;
+
+  passStruct19BytesHomogeneousUint8x10Result = result;
+
+  return result;
+}
+
+/// 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.
+///
+int passStruct19BytesHomogeneousUint8x10(
+    Struct19BytesHomogeneousUint8 a0,
+    Struct19BytesHomogeneousUint8 a1,
+    Struct19BytesHomogeneousUint8 a2,
+    Struct19BytesHomogeneousUint8 a3,
+    Struct19BytesHomogeneousUint8 a4,
+    Struct19BytesHomogeneousUint8 a5,
+    Struct19BytesHomogeneousUint8 a6,
+    Struct19BytesHomogeneousUint8 a7,
+    Struct19BytesHomogeneousUint8 a8,
+    Struct19BytesHomogeneousUint8 a9) {
+  print(
+      "passStruct19BytesHomogeneousUint8x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct19BytesHomogeneousUint8x10 throwing on purpuse!");
+  }
+
+  passStruct19BytesHomogeneousUint8x10_a0 = a0;
+  passStruct19BytesHomogeneousUint8x10_a1 = a1;
+  passStruct19BytesHomogeneousUint8x10_a2 = a2;
+  passStruct19BytesHomogeneousUint8x10_a3 = a3;
+  passStruct19BytesHomogeneousUint8x10_a4 = a4;
+  passStruct19BytesHomogeneousUint8x10_a5 = a5;
+  passStruct19BytesHomogeneousUint8x10_a6 = a6;
+  passStruct19BytesHomogeneousUint8x10_a7 = a7;
+  passStruct19BytesHomogeneousUint8x10_a8 = a8;
+  passStruct19BytesHomogeneousUint8x10_a9 = a9;
+
+  final result = passStruct19BytesHomogeneousUint8x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct19BytesHomogeneousUint8x10AfterCallback() {
+  final result = passStruct19BytesHomogeneousUint8x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(18145, result);
+}
+
+typedef PassStruct20BytesHomogeneousInt32x10Type = Int32 Function(
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a0 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a1 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a2 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a3 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a4 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a5 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a6 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a7 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a8 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a9 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct20BytesHomogeneousInt32x10Result = 0;
+
+int passStruct20BytesHomogeneousInt32x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct20BytesHomogeneousInt32x10_a0.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a4;
+
+  passStruct20BytesHomogeneousInt32x10Result = result;
+
+  return result;
+}
+
+/// 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.
+int passStruct20BytesHomogeneousInt32x10(
+    Struct20BytesHomogeneousInt32 a0,
+    Struct20BytesHomogeneousInt32 a1,
+    Struct20BytesHomogeneousInt32 a2,
+    Struct20BytesHomogeneousInt32 a3,
+    Struct20BytesHomogeneousInt32 a4,
+    Struct20BytesHomogeneousInt32 a5,
+    Struct20BytesHomogeneousInt32 a6,
+    Struct20BytesHomogeneousInt32 a7,
+    Struct20BytesHomogeneousInt32 a8,
+    Struct20BytesHomogeneousInt32 a9) {
+  print(
+      "passStruct20BytesHomogeneousInt32x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct20BytesHomogeneousInt32x10 throwing on purpuse!");
+  }
+
+  passStruct20BytesHomogeneousInt32x10_a0 = a0;
+  passStruct20BytesHomogeneousInt32x10_a1 = a1;
+  passStruct20BytesHomogeneousInt32x10_a2 = a2;
+  passStruct20BytesHomogeneousInt32x10_a3 = a3;
+  passStruct20BytesHomogeneousInt32x10_a4 = a4;
+  passStruct20BytesHomogeneousInt32x10_a5 = a5;
+  passStruct20BytesHomogeneousInt32x10_a6 = a6;
+  passStruct20BytesHomogeneousInt32x10_a7 = a7;
+  passStruct20BytesHomogeneousInt32x10_a8 = a8;
+  passStruct20BytesHomogeneousInt32x10_a9 = a9;
+
+  final result = passStruct20BytesHomogeneousInt32x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct20BytesHomogeneousInt32x10AfterCallback() {
+  final result = passStruct20BytesHomogeneousInt32x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(25, result);
+}
+
+typedef PassStruct20BytesHomogeneousFloatType = Float Function(
+    Struct20BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousFloat passStruct20BytesHomogeneousFloat_a0 =
+    Struct20BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct20BytesHomogeneousFloatResult = 0.0;
+
+double passStruct20BytesHomogeneousFloatCalculateResult() {
+  double result = 0;
+
+  result += passStruct20BytesHomogeneousFloat_a0.a0;
+  result += passStruct20BytesHomogeneousFloat_a0.a1;
+  result += passStruct20BytesHomogeneousFloat_a0.a2;
+  result += passStruct20BytesHomogeneousFloat_a0.a3;
+  result += passStruct20BytesHomogeneousFloat_a0.a4;
+
+  passStruct20BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+double passStruct20BytesHomogeneousFloat(Struct20BytesHomogeneousFloat a0) {
+  print("passStruct20BytesHomogeneousFloat(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct20BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  passStruct20BytesHomogeneousFloat_a0 = a0;
+
+  final result = passStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct20BytesHomogeneousFloatAfterCallback() {
+  final result = passStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-3.0, result);
+}
+
+typedef PassStruct32BytesHomogeneousDoublex5Type = Double Function(
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble);
+
+// Global variables to be able to test inputs after callback returned.
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a0 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a1 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a2 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a3 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a4 =
+    Struct32BytesHomogeneousDouble();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct32BytesHomogeneousDoublex5Result = 0.0;
+
+double passStruct32BytesHomogeneousDoublex5CalculateResult() {
+  double result = 0;
+
+  result += passStruct32BytesHomogeneousDoublex5_a0.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a3;
+
+  passStruct32BytesHomogeneousDoublex5Result = result;
+
+  return result;
+}
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+double passStruct32BytesHomogeneousDoublex5(
+    Struct32BytesHomogeneousDouble a0,
+    Struct32BytesHomogeneousDouble a1,
+    Struct32BytesHomogeneousDouble a2,
+    Struct32BytesHomogeneousDouble a3,
+    Struct32BytesHomogeneousDouble a4) {
+  print(
+      "passStruct32BytesHomogeneousDoublex5(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct32BytesHomogeneousDoublex5 throwing on purpuse!");
+  }
+
+  passStruct32BytesHomogeneousDoublex5_a0 = a0;
+  passStruct32BytesHomogeneousDoublex5_a1 = a1;
+  passStruct32BytesHomogeneousDoublex5_a2 = a2;
+  passStruct32BytesHomogeneousDoublex5_a3 = a3;
+  passStruct32BytesHomogeneousDoublex5_a4 = a4;
+
+  final result = passStruct32BytesHomogeneousDoublex5CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct32BytesHomogeneousDoublex5AfterCallback() {
+  final result = passStruct32BytesHomogeneousDoublex5CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct40BytesHomogeneousDoubleType = Double Function(
+    Struct40BytesHomogeneousDouble);
+
+// Global variables to be able to test inputs after callback returned.
+Struct40BytesHomogeneousDouble passStruct40BytesHomogeneousDouble_a0 =
+    Struct40BytesHomogeneousDouble();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct40BytesHomogeneousDoubleResult = 0.0;
+
+double passStruct40BytesHomogeneousDoubleCalculateResult() {
+  double result = 0;
+
+  result += passStruct40BytesHomogeneousDouble_a0.a0;
+  result += passStruct40BytesHomogeneousDouble_a0.a1;
+  result += passStruct40BytesHomogeneousDouble_a0.a2;
+  result += passStruct40BytesHomogeneousDouble_a0.a3;
+  result += passStruct40BytesHomogeneousDouble_a0.a4;
+
+  passStruct40BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Argument too big to go into FPU registers in arm64.
+double passStruct40BytesHomogeneousDouble(Struct40BytesHomogeneousDouble a0) {
+  print("passStruct40BytesHomogeneousDouble(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct40BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  passStruct40BytesHomogeneousDouble_a0 = a0;
+
+  final result = passStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct40BytesHomogeneousDoubleAfterCallback() {
+  final result = passStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-3.0, result);
+}
+
+typedef PassStruct1024BytesHomogeneousUint64Type = Uint64 Function(
+    Struct1024BytesHomogeneousUint64);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1024BytesHomogeneousUint64 passStruct1024BytesHomogeneousUint64_a0 =
+    Struct1024BytesHomogeneousUint64();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct1024BytesHomogeneousUint64Result = 0;
+
+int passStruct1024BytesHomogeneousUint64CalculateResult() {
+  int result = 0;
+
+  result += passStruct1024BytesHomogeneousUint64_a0.a0;
+  result += passStruct1024BytesHomogeneousUint64_a0.a1;
+  result += passStruct1024BytesHomogeneousUint64_a0.a2;
+  result += passStruct1024BytesHomogeneousUint64_a0.a3;
+  result += passStruct1024BytesHomogeneousUint64_a0.a4;
+  result += passStruct1024BytesHomogeneousUint64_a0.a5;
+  result += passStruct1024BytesHomogeneousUint64_a0.a6;
+  result += passStruct1024BytesHomogeneousUint64_a0.a7;
+  result += passStruct1024BytesHomogeneousUint64_a0.a8;
+  result += passStruct1024BytesHomogeneousUint64_a0.a9;
+  result += passStruct1024BytesHomogeneousUint64_a0.a10;
+  result += passStruct1024BytesHomogeneousUint64_a0.a11;
+  result += passStruct1024BytesHomogeneousUint64_a0.a12;
+  result += passStruct1024BytesHomogeneousUint64_a0.a13;
+  result += passStruct1024BytesHomogeneousUint64_a0.a14;
+  result += passStruct1024BytesHomogeneousUint64_a0.a15;
+  result += passStruct1024BytesHomogeneousUint64_a0.a16;
+  result += passStruct1024BytesHomogeneousUint64_a0.a17;
+  result += passStruct1024BytesHomogeneousUint64_a0.a18;
+  result += passStruct1024BytesHomogeneousUint64_a0.a19;
+  result += passStruct1024BytesHomogeneousUint64_a0.a20;
+  result += passStruct1024BytesHomogeneousUint64_a0.a21;
+  result += passStruct1024BytesHomogeneousUint64_a0.a22;
+  result += passStruct1024BytesHomogeneousUint64_a0.a23;
+  result += passStruct1024BytesHomogeneousUint64_a0.a24;
+  result += passStruct1024BytesHomogeneousUint64_a0.a25;
+  result += passStruct1024BytesHomogeneousUint64_a0.a26;
+  result += passStruct1024BytesHomogeneousUint64_a0.a27;
+  result += passStruct1024BytesHomogeneousUint64_a0.a28;
+  result += passStruct1024BytesHomogeneousUint64_a0.a29;
+  result += passStruct1024BytesHomogeneousUint64_a0.a30;
+  result += passStruct1024BytesHomogeneousUint64_a0.a31;
+  result += passStruct1024BytesHomogeneousUint64_a0.a32;
+  result += passStruct1024BytesHomogeneousUint64_a0.a33;
+  result += passStruct1024BytesHomogeneousUint64_a0.a34;
+  result += passStruct1024BytesHomogeneousUint64_a0.a35;
+  result += passStruct1024BytesHomogeneousUint64_a0.a36;
+  result += passStruct1024BytesHomogeneousUint64_a0.a37;
+  result += passStruct1024BytesHomogeneousUint64_a0.a38;
+  result += passStruct1024BytesHomogeneousUint64_a0.a39;
+  result += passStruct1024BytesHomogeneousUint64_a0.a40;
+  result += passStruct1024BytesHomogeneousUint64_a0.a41;
+  result += passStruct1024BytesHomogeneousUint64_a0.a42;
+  result += passStruct1024BytesHomogeneousUint64_a0.a43;
+  result += passStruct1024BytesHomogeneousUint64_a0.a44;
+  result += passStruct1024BytesHomogeneousUint64_a0.a45;
+  result += passStruct1024BytesHomogeneousUint64_a0.a46;
+  result += passStruct1024BytesHomogeneousUint64_a0.a47;
+  result += passStruct1024BytesHomogeneousUint64_a0.a48;
+  result += passStruct1024BytesHomogeneousUint64_a0.a49;
+  result += passStruct1024BytesHomogeneousUint64_a0.a50;
+  result += passStruct1024BytesHomogeneousUint64_a0.a51;
+  result += passStruct1024BytesHomogeneousUint64_a0.a52;
+  result += passStruct1024BytesHomogeneousUint64_a0.a53;
+  result += passStruct1024BytesHomogeneousUint64_a0.a54;
+  result += passStruct1024BytesHomogeneousUint64_a0.a55;
+  result += passStruct1024BytesHomogeneousUint64_a0.a56;
+  result += passStruct1024BytesHomogeneousUint64_a0.a57;
+  result += passStruct1024BytesHomogeneousUint64_a0.a58;
+  result += passStruct1024BytesHomogeneousUint64_a0.a59;
+  result += passStruct1024BytesHomogeneousUint64_a0.a60;
+  result += passStruct1024BytesHomogeneousUint64_a0.a61;
+  result += passStruct1024BytesHomogeneousUint64_a0.a62;
+  result += passStruct1024BytesHomogeneousUint64_a0.a63;
+  result += passStruct1024BytesHomogeneousUint64_a0.a64;
+  result += passStruct1024BytesHomogeneousUint64_a0.a65;
+  result += passStruct1024BytesHomogeneousUint64_a0.a66;
+  result += passStruct1024BytesHomogeneousUint64_a0.a67;
+  result += passStruct1024BytesHomogeneousUint64_a0.a68;
+  result += passStruct1024BytesHomogeneousUint64_a0.a69;
+  result += passStruct1024BytesHomogeneousUint64_a0.a70;
+  result += passStruct1024BytesHomogeneousUint64_a0.a71;
+  result += passStruct1024BytesHomogeneousUint64_a0.a72;
+  result += passStruct1024BytesHomogeneousUint64_a0.a73;
+  result += passStruct1024BytesHomogeneousUint64_a0.a74;
+  result += passStruct1024BytesHomogeneousUint64_a0.a75;
+  result += passStruct1024BytesHomogeneousUint64_a0.a76;
+  result += passStruct1024BytesHomogeneousUint64_a0.a77;
+  result += passStruct1024BytesHomogeneousUint64_a0.a78;
+  result += passStruct1024BytesHomogeneousUint64_a0.a79;
+  result += passStruct1024BytesHomogeneousUint64_a0.a80;
+  result += passStruct1024BytesHomogeneousUint64_a0.a81;
+  result += passStruct1024BytesHomogeneousUint64_a0.a82;
+  result += passStruct1024BytesHomogeneousUint64_a0.a83;
+  result += passStruct1024BytesHomogeneousUint64_a0.a84;
+  result += passStruct1024BytesHomogeneousUint64_a0.a85;
+  result += passStruct1024BytesHomogeneousUint64_a0.a86;
+  result += passStruct1024BytesHomogeneousUint64_a0.a87;
+  result += passStruct1024BytesHomogeneousUint64_a0.a88;
+  result += passStruct1024BytesHomogeneousUint64_a0.a89;
+  result += passStruct1024BytesHomogeneousUint64_a0.a90;
+  result += passStruct1024BytesHomogeneousUint64_a0.a91;
+  result += passStruct1024BytesHomogeneousUint64_a0.a92;
+  result += passStruct1024BytesHomogeneousUint64_a0.a93;
+  result += passStruct1024BytesHomogeneousUint64_a0.a94;
+  result += passStruct1024BytesHomogeneousUint64_a0.a95;
+  result += passStruct1024BytesHomogeneousUint64_a0.a96;
+  result += passStruct1024BytesHomogeneousUint64_a0.a97;
+  result += passStruct1024BytesHomogeneousUint64_a0.a98;
+  result += passStruct1024BytesHomogeneousUint64_a0.a99;
+  result += passStruct1024BytesHomogeneousUint64_a0.a100;
+  result += passStruct1024BytesHomogeneousUint64_a0.a101;
+  result += passStruct1024BytesHomogeneousUint64_a0.a102;
+  result += passStruct1024BytesHomogeneousUint64_a0.a103;
+  result += passStruct1024BytesHomogeneousUint64_a0.a104;
+  result += passStruct1024BytesHomogeneousUint64_a0.a105;
+  result += passStruct1024BytesHomogeneousUint64_a0.a106;
+  result += passStruct1024BytesHomogeneousUint64_a0.a107;
+  result += passStruct1024BytesHomogeneousUint64_a0.a108;
+  result += passStruct1024BytesHomogeneousUint64_a0.a109;
+  result += passStruct1024BytesHomogeneousUint64_a0.a110;
+  result += passStruct1024BytesHomogeneousUint64_a0.a111;
+  result += passStruct1024BytesHomogeneousUint64_a0.a112;
+  result += passStruct1024BytesHomogeneousUint64_a0.a113;
+  result += passStruct1024BytesHomogeneousUint64_a0.a114;
+  result += passStruct1024BytesHomogeneousUint64_a0.a115;
+  result += passStruct1024BytesHomogeneousUint64_a0.a116;
+  result += passStruct1024BytesHomogeneousUint64_a0.a117;
+  result += passStruct1024BytesHomogeneousUint64_a0.a118;
+  result += passStruct1024BytesHomogeneousUint64_a0.a119;
+  result += passStruct1024BytesHomogeneousUint64_a0.a120;
+  result += passStruct1024BytesHomogeneousUint64_a0.a121;
+  result += passStruct1024BytesHomogeneousUint64_a0.a122;
+  result += passStruct1024BytesHomogeneousUint64_a0.a123;
+  result += passStruct1024BytesHomogeneousUint64_a0.a124;
+  result += passStruct1024BytesHomogeneousUint64_a0.a125;
+  result += passStruct1024BytesHomogeneousUint64_a0.a126;
+  result += passStruct1024BytesHomogeneousUint64_a0.a127;
+
+  passStruct1024BytesHomogeneousUint64Result = result;
+
+  return result;
+}
+
+/// Test 1kb struct.
+int passStruct1024BytesHomogeneousUint64(Struct1024BytesHomogeneousUint64 a0) {
+  print("passStruct1024BytesHomogeneousUint64(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct1024BytesHomogeneousUint64 throwing on purpuse!");
+  }
+
+  passStruct1024BytesHomogeneousUint64_a0 = a0;
+
+  final result = passStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct1024BytesHomogeneousUint64AfterCallback() {
+  final result = passStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(8256, result);
+}
+
+typedef PassFloatStruct16BytesHomogeneousFloatFloatStruct1Type = Float Function(
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float);
+
+// Global variables to be able to test inputs after callback returned.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1Result = 0.0;
+
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult() {
+  double result = 0;
+
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8;
+
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1Result = result;
+
+  return result;
+}
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1(
+    double a0,
+    Struct16BytesHomogeneousFloat a1,
+    double a2,
+    Struct16BytesHomogeneousFloat a3,
+    double a4,
+    Struct16BytesHomogeneousFloat a5,
+    double a6,
+    Struct16BytesHomogeneousFloat a7,
+    double a8) {
+  print(
+      "passFloatStruct16BytesHomogeneousFloatFloatStruct1(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassFloatStruct16BytesHomogeneousFloatFloatStruct1 throwing on purpuse!");
+  }
+
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0 = a0;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1 = a1;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2 = a2;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3 = a3;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4 = a4;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5 = a5;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6 = a6;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7 = a7;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8 = a8;
+
+  final result =
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passFloatStruct16BytesHomogeneousFloatFloatStruct1AfterCallback() {
+  final result =
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-11.0, result);
+}
+
+typedef PassFloatStruct32BytesHomogeneousDoubleFloatStructType
+    = Double Function(
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float);
+
+// Global variables to be able to test inputs after callback returned.
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passFloatStruct32BytesHomogeneousDoubleFloatStructResult = 0.0;
+
+double passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult() {
+  double result = 0;
+
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8;
+
+  passFloatStruct32BytesHomogeneousDoubleFloatStructResult = result;
+
+  return result;
+}
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct(
+    double a0,
+    Struct32BytesHomogeneousDouble a1,
+    double a2,
+    Struct32BytesHomogeneousDouble a3,
+    double a4,
+    Struct32BytesHomogeneousDouble a5,
+    double a6,
+    Struct32BytesHomogeneousDouble a7,
+    double a8) {
+  print(
+      "passFloatStruct32BytesHomogeneousDoubleFloatStruct(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassFloatStruct32BytesHomogeneousDoubleFloatStruct throwing on purpuse!");
+  }
+
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0 = a0;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1 = a1;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2 = a2;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3 = a3;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4 = a4;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5 = a5;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6 = a6;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7 = a7;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8 = a8;
+
+  final result =
+      passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passFloatStruct32BytesHomogeneousDoubleFloatStructAfterCallback() {
+  final result =
+      passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-11.0, result);
+}
+
+typedef PassInt8Struct16BytesMixedInt8Struct16BytesMixedInType
+    = Double Function(Int8, Struct16BytesMixed, Int8, Struct16BytesMixed, Int8,
+        Struct16BytesMixed, Int8, Struct16BytesMixed, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedInResult = 0.0;
+
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult() {
+  double result = 0;
+
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8;
+
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedInResult = result;
+
+  return result;
+}
+
+/// 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.
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+    int a0,
+    Struct16BytesMixed a1,
+    int a2,
+    Struct16BytesMixed a3,
+    int a4,
+    Struct16BytesMixed a5,
+    int a6,
+    Struct16BytesMixed a7,
+    int a8) {
+  print(
+      "passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn throwing on purpuse!");
+  }
+
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0 = a0;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1 = a1;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2 = a2;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3 = a3;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4 = a4;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5 = a5;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6 = a6;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7 = a7;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8 = a8;
+
+  final result =
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt8Struct16BytesMixedInt8Struct16BytesMixedInAfterCallback() {
+  final result =
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-7.0, result);
+}
+
+typedef PassDoublex6Struct16BytesMixedx4Int32Type = Double Function(
+    Double,
+    Double,
+    Double,
+    Double,
+    Double,
+    Double,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Int32);
+
+// Global variables to be able to test inputs after callback returned.
+double passDoublex6Struct16BytesMixedx4Int32_a0 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a1 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a2 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a3 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a4 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a5 = 0.0;
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a6 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a7 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a8 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a9 =
+    Struct16BytesMixed();
+int passDoublex6Struct16BytesMixedx4Int32_a10 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+double passDoublex6Struct16BytesMixedx4Int32Result = 0.0;
+
+double passDoublex6Struct16BytesMixedx4Int32CalculateResult() {
+  double result = 0;
+
+  result += passDoublex6Struct16BytesMixedx4Int32_a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a2;
+  result += passDoublex6Struct16BytesMixedx4Int32_a3;
+  result += passDoublex6Struct16BytesMixedx4Int32_a4;
+  result += passDoublex6Struct16BytesMixedx4Int32_a5;
+  result += passDoublex6Struct16BytesMixedx4Int32_a6.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a6.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a7.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a7.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a8.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a8.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a9.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a9.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a10;
+
+  passDoublex6Struct16BytesMixedx4Int32Result = result;
+
+  return result;
+}
+
+/// 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.
+double passDoublex6Struct16BytesMixedx4Int32(
+    double a0,
+    double a1,
+    double a2,
+    double a3,
+    double a4,
+    double a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    Struct16BytesMixed a8,
+    Struct16BytesMixed a9,
+    int a10) {
+  print(
+      "passDoublex6Struct16BytesMixedx4Int32(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassDoublex6Struct16BytesMixedx4Int32 throwing on purpuse!");
+  }
+
+  passDoublex6Struct16BytesMixedx4Int32_a0 = a0;
+  passDoublex6Struct16BytesMixedx4Int32_a1 = a1;
+  passDoublex6Struct16BytesMixedx4Int32_a2 = a2;
+  passDoublex6Struct16BytesMixedx4Int32_a3 = a3;
+  passDoublex6Struct16BytesMixedx4Int32_a4 = a4;
+  passDoublex6Struct16BytesMixedx4Int32_a5 = a5;
+  passDoublex6Struct16BytesMixedx4Int32_a6 = a6;
+  passDoublex6Struct16BytesMixedx4Int32_a7 = a7;
+  passDoublex6Struct16BytesMixedx4Int32_a8 = a8;
+  passDoublex6Struct16BytesMixedx4Int32_a9 = a9;
+  passDoublex6Struct16BytesMixedx4Int32_a10 = a10;
+
+  final result = passDoublex6Struct16BytesMixedx4Int32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passDoublex6Struct16BytesMixedx4Int32AfterCallback() {
+  final result = passDoublex6Struct16BytesMixedx4Int32CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-8.0, result);
+}
+
+typedef PassInt32x4Struct16BytesMixedx4DoubleType = Double Function(
+    Int32,
+    Int32,
+    Int32,
+    Int32,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Double);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt32x4Struct16BytesMixedx4Double_a0 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a1 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a2 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a3 = 0;
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a4 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a5 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a6 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a7 =
+    Struct16BytesMixed();
+double passInt32x4Struct16BytesMixedx4Double_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passInt32x4Struct16BytesMixedx4DoubleResult = 0.0;
+
+double passInt32x4Struct16BytesMixedx4DoubleCalculateResult() {
+  double result = 0;
+
+  result += passInt32x4Struct16BytesMixedx4Double_a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a2;
+  result += passInt32x4Struct16BytesMixedx4Double_a3;
+  result += passInt32x4Struct16BytesMixedx4Double_a4.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a4.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a5.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a5.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a6.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a6.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a7.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a7.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a8;
+
+  passInt32x4Struct16BytesMixedx4DoubleResult = result;
+
+  return result;
+}
+
+/// 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.
+double passInt32x4Struct16BytesMixedx4Double(
+    int a0,
+    int a1,
+    int a2,
+    int a3,
+    Struct16BytesMixed a4,
+    Struct16BytesMixed a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    double a8) {
+  print(
+      "passInt32x4Struct16BytesMixedx4Double(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt32x4Struct16BytesMixedx4Double throwing on purpuse!");
+  }
+
+  passInt32x4Struct16BytesMixedx4Double_a0 = a0;
+  passInt32x4Struct16BytesMixedx4Double_a1 = a1;
+  passInt32x4Struct16BytesMixedx4Double_a2 = a2;
+  passInt32x4Struct16BytesMixedx4Double_a3 = a3;
+  passInt32x4Struct16BytesMixedx4Double_a4 = a4;
+  passInt32x4Struct16BytesMixedx4Double_a5 = a5;
+  passInt32x4Struct16BytesMixedx4Double_a6 = a6;
+  passInt32x4Struct16BytesMixedx4Double_a7 = a7;
+  passInt32x4Struct16BytesMixedx4Double_a8 = a8;
+
+  final result = passInt32x4Struct16BytesMixedx4DoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt32x4Struct16BytesMixedx4DoubleAfterCallback() {
+  final result = passInt32x4Struct16BytesMixedx4DoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-7.0, result);
+}
+
+typedef PassStruct40BytesHomogeneousDoubleStruct4BytesHomoType
+    = Double Function(Struct40BytesHomogeneousDouble,
+        Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct40BytesHomogeneousDouble
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0 =
+    Struct40BytesHomogeneousDouble();
+Struct4BytesHomogeneousInt16
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1 =
+    Struct4BytesHomogeneousInt16();
+Struct8BytesHomogeneousFloat
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomoResult = 0.0;
+
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult() {
+  double result = 0;
+
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a1;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a2;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a3;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a4;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1.a1;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2.a1;
+
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomoResult = result;
+
+  return result;
+}
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomo(
+    Struct40BytesHomogeneousDouble a0,
+    Struct4BytesHomogeneousInt16 a1,
+    Struct8BytesHomogeneousFloat a2) {
+  print(
+      "passStruct40BytesHomogeneousDoubleStruct4BytesHomo(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo throwing on purpuse!");
+  }
+
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0 = a0;
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1 = a1;
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2 = a2;
+
+  final result =
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback() {
+  final result =
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-5.0, result);
+}
+
+typedef PassStructAlignmentInt16Type = Int64 Function(StructAlignmentInt16);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt16 passStructAlignmentInt16_a0 = StructAlignmentInt16();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt16Result = 0;
+
+int passStructAlignmentInt16CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt16_a0.a0;
+  result += passStructAlignmentInt16_a0.a1;
+  result += passStructAlignmentInt16_a0.a2;
+
+  passStructAlignmentInt16Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+int passStructAlignmentInt16(StructAlignmentInt16 a0) {
+  print("passStructAlignmentInt16(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt16 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt16_a0 = a0;
+
+  final result = passStructAlignmentInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt16AfterCallback() {
+  final result = passStructAlignmentInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef PassStructAlignmentInt32Type = Int64 Function(StructAlignmentInt32);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt32 passStructAlignmentInt32_a0 = StructAlignmentInt32();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt32Result = 0;
+
+int passStructAlignmentInt32CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt32_a0.a0;
+  result += passStructAlignmentInt32_a0.a1;
+  result += passStructAlignmentInt32_a0.a2;
+
+  passStructAlignmentInt32Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 32 byte int within struct.
+int passStructAlignmentInt32(StructAlignmentInt32 a0) {
+  print("passStructAlignmentInt32(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt32 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt32_a0 = a0;
+
+  final result = passStructAlignmentInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt32AfterCallback() {
+  final result = passStructAlignmentInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef PassStructAlignmentInt64Type = Int64 Function(StructAlignmentInt64);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt64 passStructAlignmentInt64_a0 = StructAlignmentInt64();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt64Result = 0;
+
+int passStructAlignmentInt64CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt64_a0.a0;
+  result += passStructAlignmentInt64_a0.a1;
+  result += passStructAlignmentInt64_a0.a2;
+
+  passStructAlignmentInt64Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 64 byte int within struct.
+int passStructAlignmentInt64(StructAlignmentInt64 a0) {
+  print("passStructAlignmentInt64(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt64 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt64_a0 = a0;
+
+  final result = passStructAlignmentInt64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt64AfterCallback() {
+  final result = passStructAlignmentInt64CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct1ByteInt_a0 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStruct1ByteIntResult = Struct1ByteInt();
+
+Struct1ByteInt returnStruct1ByteIntCalculateResult() {
+  Struct1ByteInt result = allocate<Struct1ByteInt>().ref;
+
+  result.a0 = returnStruct1ByteInt_a0;
+
+  returnStruct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Smallest struct with data.
+Struct1ByteInt returnStruct1ByteInt(int a0) {
+  print("returnStruct1ByteInt(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct1ByteInt throwing on purpuse!");
+  }
+
+  returnStruct1ByteInt_a0 = a0;
+
+  final result = returnStruct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct1ByteIntAfterCallback() {
+  free(returnStruct1ByteIntResult.addressOf);
+
+  final result = returnStruct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct1ByteIntResult.addressOf);
+}
+
+typedef ReturnStruct3BytesIntType = Struct3BytesInt Function(Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct3BytesInt_a0 = 0;
+int returnStruct3BytesInt_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct3BytesInt returnStruct3BytesIntResult = Struct3BytesInt();
+
+Struct3BytesInt returnStruct3BytesIntCalculateResult() {
+  Struct3BytesInt result = allocate<Struct3BytesInt>().ref;
+
+  result.a0 = returnStruct3BytesInt_a0;
+  result.a1 = returnStruct3BytesInt_a1;
+
+  returnStruct3BytesIntResult = result;
+
+  return result;
+}
+
+/// Smaller than word size return value on all architectures.
+Struct3BytesInt returnStruct3BytesInt(int a0, int a1) {
+  print("returnStruct3BytesInt(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct3BytesInt throwing on purpuse!");
+  }
+
+  returnStruct3BytesInt_a0 = a0;
+  returnStruct3BytesInt_a1 = a1;
+
+  final result = returnStruct3BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct3BytesIntAfterCallback() {
+  free(returnStruct3BytesIntResult.addressOf);
+
+  final result = returnStruct3BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct3BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct4BytesHomogeneousInt16Type = Struct4BytesHomogeneousInt16
+    Function(Int16, Int16);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct4BytesHomogeneousInt16_a0 = 0;
+int returnStruct4BytesHomogeneousInt16_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct4BytesHomogeneousInt16 returnStruct4BytesHomogeneousInt16Result =
+    Struct4BytesHomogeneousInt16();
+
+Struct4BytesHomogeneousInt16
+    returnStruct4BytesHomogeneousInt16CalculateResult() {
+  Struct4BytesHomogeneousInt16 result =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+
+  result.a0 = returnStruct4BytesHomogeneousInt16_a0;
+  result.a1 = returnStruct4BytesHomogeneousInt16_a1;
+
+  returnStruct4BytesHomogeneousInt16Result = result;
+
+  return result;
+}
+
+/// Word size return value on 32 bit architectures..
+Struct4BytesHomogeneousInt16 returnStruct4BytesHomogeneousInt16(
+    int a0, int a1) {
+  print("returnStruct4BytesHomogeneousInt16(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct4BytesHomogeneousInt16 throwing on purpuse!");
+  }
+
+  returnStruct4BytesHomogeneousInt16_a0 = a0;
+  returnStruct4BytesHomogeneousInt16_a1 = a1;
+
+  final result = returnStruct4BytesHomogeneousInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct4BytesHomogeneousInt16AfterCallback() {
+  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+
+  final result = returnStruct4BytesHomogeneousInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+}
+
+typedef ReturnStruct7BytesIntType = Struct7BytesInt Function(
+    Int32, Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct7BytesInt_a0 = 0;
+int returnStruct7BytesInt_a1 = 0;
+int returnStruct7BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct7BytesInt returnStruct7BytesIntResult = Struct7BytesInt();
+
+Struct7BytesInt returnStruct7BytesIntCalculateResult() {
+  Struct7BytesInt result = allocate<Struct7BytesInt>().ref;
+
+  result.a0 = returnStruct7BytesInt_a0;
+  result.a1 = returnStruct7BytesInt_a1;
+  result.a2 = returnStruct7BytesInt_a2;
+
+  returnStruct7BytesIntResult = result;
+
+  return result;
+}
+
+/// Non-wordsize return value.
+Struct7BytesInt returnStruct7BytesInt(int a0, int a1, int a2) {
+  print("returnStruct7BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct7BytesInt throwing on purpuse!");
+  }
+
+  returnStruct7BytesInt_a0 = a0;
+  returnStruct7BytesInt_a1 = a1;
+  returnStruct7BytesInt_a2 = a2;
+
+  final result = returnStruct7BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct7BytesIntAfterCallback() {
+  free(returnStruct7BytesIntResult.addressOf);
+
+  final result = returnStruct7BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct7BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct8BytesIntType = Struct8BytesInt Function(
+    Int16, Int16, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct8BytesInt_a0 = 0;
+int returnStruct8BytesInt_a1 = 0;
+int returnStruct8BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesInt returnStruct8BytesIntResult = Struct8BytesInt();
+
+Struct8BytesInt returnStruct8BytesIntCalculateResult() {
+  Struct8BytesInt result = allocate<Struct8BytesInt>().ref;
+
+  result.a0 = returnStruct8BytesInt_a0;
+  result.a1 = returnStruct8BytesInt_a1;
+  result.a2 = returnStruct8BytesInt_a2;
+
+  returnStruct8BytesIntResult = result;
+
+  return result;
+}
+
+/// Return value in integer registers on many architectures.
+Struct8BytesInt returnStruct8BytesInt(int a0, int a1, int a2) {
+  print("returnStruct8BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesInt throwing on purpuse!");
+  }
+
+  returnStruct8BytesInt_a0 = a0;
+  returnStruct8BytesInt_a1 = a1;
+  returnStruct8BytesInt_a2 = a2;
+
+  final result = returnStruct8BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesIntAfterCallback() {
+  free(returnStruct8BytesIntResult.addressOf);
+
+  final result = returnStruct8BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct8BytesHomogeneousFloatType = Struct8BytesHomogeneousFloat
+    Function(Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct8BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct8BytesHomogeneousFloat_a1 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesHomogeneousFloat returnStruct8BytesHomogeneousFloatResult =
+    Struct8BytesHomogeneousFloat();
+
+Struct8BytesHomogeneousFloat
+    returnStruct8BytesHomogeneousFloatCalculateResult() {
+  Struct8BytesHomogeneousFloat result =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct8BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct8BytesHomogeneousFloat_a1;
+
+  returnStruct8BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FP registers on many architectures.
+Struct8BytesHomogeneousFloat returnStruct8BytesHomogeneousFloat(
+    double a0, double a1) {
+  print("returnStruct8BytesHomogeneousFloat(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct8BytesHomogeneousFloat_a0 = a0;
+  returnStruct8BytesHomogeneousFloat_a1 = a1;
+
+  final result = returnStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct8BytesMixedType = Struct8BytesMixed Function(
+    Float, Int16, Int16);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct8BytesMixed_a0 = 0.0;
+int returnStruct8BytesMixed_a1 = 0;
+int returnStruct8BytesMixed_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesMixed returnStruct8BytesMixedResult = Struct8BytesMixed();
+
+Struct8BytesMixed returnStruct8BytesMixedCalculateResult() {
+  Struct8BytesMixed result = allocate<Struct8BytesMixed>().ref;
+
+  result.a0 = returnStruct8BytesMixed_a0;
+  result.a1 = returnStruct8BytesMixed_a1;
+  result.a2 = returnStruct8BytesMixed_a2;
+
+  returnStruct8BytesMixedResult = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+Struct8BytesMixed returnStruct8BytesMixed(double a0, int a1, int a2) {
+  print("returnStruct8BytesMixed(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesMixed throwing on purpuse!");
+  }
+
+  returnStruct8BytesMixed_a0 = a0;
+  returnStruct8BytesMixed_a1 = a1;
+  returnStruct8BytesMixed_a2 = a2;
+
+  final result = returnStruct8BytesMixedCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesMixedAfterCallback() {
+  free(returnStruct8BytesMixedResult.addressOf);
+
+  final result = returnStruct8BytesMixedCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesMixedResult.addressOf);
+}
+
+typedef ReturnStruct9BytesIntType = Struct9BytesInt Function(Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct9BytesInt_a0 = 0;
+int returnStruct9BytesInt_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct9BytesInt returnStruct9BytesIntResult = Struct9BytesInt();
+
+Struct9BytesInt returnStruct9BytesIntCalculateResult() {
+  Struct9BytesInt result = allocate<Struct9BytesInt>().ref;
+
+  result.a0 = returnStruct9BytesInt_a0;
+  result.a1 = returnStruct9BytesInt_a1;
+
+  returnStruct9BytesIntResult = result;
+
+  return result;
+}
+
+/// Return value in two integer registers on x64.
+/// The second register only contains a single byte.
+Struct9BytesInt returnStruct9BytesInt(int a0, int a1) {
+  print("returnStruct9BytesInt(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct9BytesInt throwing on purpuse!");
+  }
+
+  returnStruct9BytesInt_a0 = a0;
+  returnStruct9BytesInt_a1 = a1;
+
+  final result = returnStruct9BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct9BytesIntAfterCallback() {
+  free(returnStruct9BytesIntResult.addressOf);
+
+  final result = returnStruct9BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct9BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct9BytesHomogeneousUint82Type = Struct9BytesHomogeneousUint82
+    Function(Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct9BytesHomogeneousUint82_a0 = 0;
+int returnStruct9BytesHomogeneousUint82_a1 = 0;
+int returnStruct9BytesHomogeneousUint82_a2 = 0;
+int returnStruct9BytesHomogeneousUint82_a3 = 0;
+int returnStruct9BytesHomogeneousUint82_a4 = 0;
+int returnStruct9BytesHomogeneousUint82_a5 = 0;
+int returnStruct9BytesHomogeneousUint82_a6 = 0;
+int returnStruct9BytesHomogeneousUint82_a7 = 0;
+int returnStruct9BytesHomogeneousUint82_a8 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct9BytesHomogeneousUint82 returnStruct9BytesHomogeneousUint82Result =
+    Struct9BytesHomogeneousUint82();
+
+Struct9BytesHomogeneousUint82
+    returnStruct9BytesHomogeneousUint82CalculateResult() {
+  Struct9BytesHomogeneousUint82 result =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+
+  result.a0 = returnStruct9BytesHomogeneousUint82_a0;
+  result.a1 = returnStruct9BytesHomogeneousUint82_a1;
+  result.a2 = returnStruct9BytesHomogeneousUint82_a2;
+  result.a3 = returnStruct9BytesHomogeneousUint82_a3;
+  result.a4 = returnStruct9BytesHomogeneousUint82_a4;
+  result.a5 = returnStruct9BytesHomogeneousUint82_a5;
+  result.a6 = returnStruct9BytesHomogeneousUint82_a6;
+  result.a7 = returnStruct9BytesHomogeneousUint82_a7;
+  result.a8 = returnStruct9BytesHomogeneousUint82_a8;
+
+  returnStruct9BytesHomogeneousUint82Result = result;
+
+  return result;
+}
+
+/// 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.
+Struct9BytesHomogeneousUint82 returnStruct9BytesHomogeneousUint82(
+    int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
+  print(
+      "returnStruct9BytesHomogeneousUint82(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct9BytesHomogeneousUint82 throwing on purpuse!");
+  }
+
+  returnStruct9BytesHomogeneousUint82_a0 = a0;
+  returnStruct9BytesHomogeneousUint82_a1 = a1;
+  returnStruct9BytesHomogeneousUint82_a2 = a2;
+  returnStruct9BytesHomogeneousUint82_a3 = a3;
+  returnStruct9BytesHomogeneousUint82_a4 = a4;
+  returnStruct9BytesHomogeneousUint82_a5 = a5;
+  returnStruct9BytesHomogeneousUint82_a6 = a6;
+  returnStruct9BytesHomogeneousUint82_a7 = a7;
+  returnStruct9BytesHomogeneousUint82_a8 = a8;
+
+  final result = returnStruct9BytesHomogeneousUint82CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct9BytesHomogeneousUint82AfterCallback() {
+  free(returnStruct9BytesHomogeneousUint82Result.addressOf);
+
+  final result = returnStruct9BytesHomogeneousUint82CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct9BytesHomogeneousUint82Result.addressOf);
+}
+
+typedef ReturnStruct12BytesHomogeneousFloatType = Struct12BytesHomogeneousFloat
+    Function(Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct12BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct12BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct12BytesHomogeneousFloat_a2 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct12BytesHomogeneousFloat returnStruct12BytesHomogeneousFloatResult =
+    Struct12BytesHomogeneousFloat();
+
+Struct12BytesHomogeneousFloat
+    returnStruct12BytesHomogeneousFloatCalculateResult() {
+  Struct12BytesHomogeneousFloat result =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct12BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct12BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct12BytesHomogeneousFloat_a2;
+
+  returnStruct12BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+Struct12BytesHomogeneousFloat returnStruct12BytesHomogeneousFloat(
+    double a0, double a1, double a2) {
+  print("returnStruct12BytesHomogeneousFloat(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct12BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct12BytesHomogeneousFloat_a0 = a0;
+  returnStruct12BytesHomogeneousFloat_a1 = a1;
+  returnStruct12BytesHomogeneousFloat_a2 = a2;
+
+  final result = returnStruct12BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct12BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct12BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct16BytesHomogeneousFloatType = Struct16BytesHomogeneousFloat
+    Function(Float, Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a2 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a3 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesHomogeneousFloat returnStruct16BytesHomogeneousFloatResult =
+    Struct16BytesHomogeneousFloat();
+
+Struct16BytesHomogeneousFloat
+    returnStruct16BytesHomogeneousFloatCalculateResult() {
+  Struct16BytesHomogeneousFloat result =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct16BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct16BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct16BytesHomogeneousFloat_a2;
+  result.a3 = returnStruct16BytesHomogeneousFloat_a3;
+
+  returnStruct16BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers on arm hardfp and arm64.
+Struct16BytesHomogeneousFloat returnStruct16BytesHomogeneousFloat(
+    double a0, double a1, double a2, double a3) {
+  print("returnStruct16BytesHomogeneousFloat(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct16BytesHomogeneousFloat_a0 = a0;
+  returnStruct16BytesHomogeneousFloat_a1 = a1;
+  returnStruct16BytesHomogeneousFloat_a2 = a2;
+  returnStruct16BytesHomogeneousFloat_a3 = a3;
+
+  final result = returnStruct16BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct16BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct16BytesMixedType = Struct16BytesMixed Function(
+    Double, Int64);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesMixed_a0 = 0.0;
+int returnStruct16BytesMixed_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesMixed returnStruct16BytesMixedResult = Struct16BytesMixed();
+
+Struct16BytesMixed returnStruct16BytesMixedCalculateResult() {
+  Struct16BytesMixed result = allocate<Struct16BytesMixed>().ref;
+
+  result.a0 = returnStruct16BytesMixed_a0;
+  result.a1 = returnStruct16BytesMixed_a1;
+
+  returnStruct16BytesMixedResult = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+Struct16BytesMixed returnStruct16BytesMixed(double a0, int a1) {
+  print("returnStruct16BytesMixed(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesMixed throwing on purpuse!");
+  }
+
+  returnStruct16BytesMixed_a0 = a0;
+  returnStruct16BytesMixed_a1 = a1;
+
+  final result = returnStruct16BytesMixedCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesMixedAfterCallback() {
+  free(returnStruct16BytesMixedResult.addressOf);
+
+  final result = returnStruct16BytesMixedCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesMixedResult.addressOf);
+}
+
+typedef ReturnStruct16BytesMixed2Type = Struct16BytesMixed2 Function(
+    Float, Float, Float, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesMixed2_a0 = 0.0;
+double returnStruct16BytesMixed2_a1 = 0.0;
+double returnStruct16BytesMixed2_a2 = 0.0;
+int returnStruct16BytesMixed2_a3 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesMixed2 returnStruct16BytesMixed2Result = Struct16BytesMixed2();
+
+Struct16BytesMixed2 returnStruct16BytesMixed2CalculateResult() {
+  Struct16BytesMixed2 result = allocate<Struct16BytesMixed2>().ref;
+
+  result.a0 = returnStruct16BytesMixed2_a0;
+  result.a1 = returnStruct16BytesMixed2_a1;
+  result.a2 = returnStruct16BytesMixed2_a2;
+  result.a3 = returnStruct16BytesMixed2_a3;
+
+  returnStruct16BytesMixed2Result = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+Struct16BytesMixed2 returnStruct16BytesMixed2(
+    double a0, double a1, double a2, int a3) {
+  print("returnStruct16BytesMixed2(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesMixed2 throwing on purpuse!");
+  }
+
+  returnStruct16BytesMixed2_a0 = a0;
+  returnStruct16BytesMixed2_a1 = a1;
+  returnStruct16BytesMixed2_a2 = a2;
+  returnStruct16BytesMixed2_a3 = a3;
+
+  final result = returnStruct16BytesMixed2CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesMixed2AfterCallback() {
+  free(returnStruct16BytesMixed2Result.addressOf);
+
+  final result = returnStruct16BytesMixed2CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesMixed2Result.addressOf);
+}
+
+typedef ReturnStruct17BytesIntType = Struct17BytesInt Function(
+    Int64, Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct17BytesInt_a0 = 0;
+int returnStruct17BytesInt_a1 = 0;
+int returnStruct17BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct17BytesInt returnStruct17BytesIntResult = Struct17BytesInt();
+
+Struct17BytesInt returnStruct17BytesIntCalculateResult() {
+  Struct17BytesInt result = allocate<Struct17BytesInt>().ref;
+
+  result.a0 = returnStruct17BytesInt_a0;
+  result.a1 = returnStruct17BytesInt_a1;
+  result.a2 = returnStruct17BytesInt_a2;
+
+  returnStruct17BytesIntResult = result;
+
+  return result;
+}
+
+/// 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.
+Struct17BytesInt returnStruct17BytesInt(int a0, int a1, int a2) {
+  print("returnStruct17BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct17BytesInt throwing on purpuse!");
+  }
+
+  returnStruct17BytesInt_a0 = a0;
+  returnStruct17BytesInt_a1 = a1;
+  returnStruct17BytesInt_a2 = a2;
+
+  final result = returnStruct17BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct17BytesIntAfterCallback() {
+  free(returnStruct17BytesIntResult.addressOf);
+
+  final result = returnStruct17BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct17BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct19BytesHomogeneousUint8Type
+    = Struct19BytesHomogeneousUint8 Function(
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct19BytesHomogeneousUint8_a0 = 0;
+int returnStruct19BytesHomogeneousUint8_a1 = 0;
+int returnStruct19BytesHomogeneousUint8_a2 = 0;
+int returnStruct19BytesHomogeneousUint8_a3 = 0;
+int returnStruct19BytesHomogeneousUint8_a4 = 0;
+int returnStruct19BytesHomogeneousUint8_a5 = 0;
+int returnStruct19BytesHomogeneousUint8_a6 = 0;
+int returnStruct19BytesHomogeneousUint8_a7 = 0;
+int returnStruct19BytesHomogeneousUint8_a8 = 0;
+int returnStruct19BytesHomogeneousUint8_a9 = 0;
+int returnStruct19BytesHomogeneousUint8_a10 = 0;
+int returnStruct19BytesHomogeneousUint8_a11 = 0;
+int returnStruct19BytesHomogeneousUint8_a12 = 0;
+int returnStruct19BytesHomogeneousUint8_a13 = 0;
+int returnStruct19BytesHomogeneousUint8_a14 = 0;
+int returnStruct19BytesHomogeneousUint8_a15 = 0;
+int returnStruct19BytesHomogeneousUint8_a16 = 0;
+int returnStruct19BytesHomogeneousUint8_a17 = 0;
+int returnStruct19BytesHomogeneousUint8_a18 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct19BytesHomogeneousUint8 returnStruct19BytesHomogeneousUint8Result =
+    Struct19BytesHomogeneousUint8();
+
+Struct19BytesHomogeneousUint8
+    returnStruct19BytesHomogeneousUint8CalculateResult() {
+  Struct19BytesHomogeneousUint8 result =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+
+  result.a0 = returnStruct19BytesHomogeneousUint8_a0;
+  result.a1 = returnStruct19BytesHomogeneousUint8_a1;
+  result.a2 = returnStruct19BytesHomogeneousUint8_a2;
+  result.a3 = returnStruct19BytesHomogeneousUint8_a3;
+  result.a4 = returnStruct19BytesHomogeneousUint8_a4;
+  result.a5 = returnStruct19BytesHomogeneousUint8_a5;
+  result.a6 = returnStruct19BytesHomogeneousUint8_a6;
+  result.a7 = returnStruct19BytesHomogeneousUint8_a7;
+  result.a8 = returnStruct19BytesHomogeneousUint8_a8;
+  result.a9 = returnStruct19BytesHomogeneousUint8_a9;
+  result.a10 = returnStruct19BytesHomogeneousUint8_a10;
+  result.a11 = returnStruct19BytesHomogeneousUint8_a11;
+  result.a12 = returnStruct19BytesHomogeneousUint8_a12;
+  result.a13 = returnStruct19BytesHomogeneousUint8_a13;
+  result.a14 = returnStruct19BytesHomogeneousUint8_a14;
+  result.a15 = returnStruct19BytesHomogeneousUint8_a15;
+  result.a16 = returnStruct19BytesHomogeneousUint8_a16;
+  result.a17 = returnStruct19BytesHomogeneousUint8_a17;
+  result.a18 = returnStruct19BytesHomogeneousUint8_a18;
+
+  returnStruct19BytesHomogeneousUint8Result = result;
+
+  return result;
+}
+
+/// 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.
+Struct19BytesHomogeneousUint8 returnStruct19BytesHomogeneousUint8(
+    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) {
+  print(
+      "returnStruct19BytesHomogeneousUint8(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12}, ${a13}, ${a14}, ${a15}, ${a16}, ${a17}, ${a18})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct19BytesHomogeneousUint8 throwing on purpuse!");
+  }
+
+  returnStruct19BytesHomogeneousUint8_a0 = a0;
+  returnStruct19BytesHomogeneousUint8_a1 = a1;
+  returnStruct19BytesHomogeneousUint8_a2 = a2;
+  returnStruct19BytesHomogeneousUint8_a3 = a3;
+  returnStruct19BytesHomogeneousUint8_a4 = a4;
+  returnStruct19BytesHomogeneousUint8_a5 = a5;
+  returnStruct19BytesHomogeneousUint8_a6 = a6;
+  returnStruct19BytesHomogeneousUint8_a7 = a7;
+  returnStruct19BytesHomogeneousUint8_a8 = a8;
+  returnStruct19BytesHomogeneousUint8_a9 = a9;
+  returnStruct19BytesHomogeneousUint8_a10 = a10;
+  returnStruct19BytesHomogeneousUint8_a11 = a11;
+  returnStruct19BytesHomogeneousUint8_a12 = a12;
+  returnStruct19BytesHomogeneousUint8_a13 = a13;
+  returnStruct19BytesHomogeneousUint8_a14 = a14;
+  returnStruct19BytesHomogeneousUint8_a15 = a15;
+  returnStruct19BytesHomogeneousUint8_a16 = a16;
+  returnStruct19BytesHomogeneousUint8_a17 = a17;
+  returnStruct19BytesHomogeneousUint8_a18 = a18;
+
+  final result = returnStruct19BytesHomogeneousUint8CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct19BytesHomogeneousUint8AfterCallback() {
+  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+
+  final result = returnStruct19BytesHomogeneousUint8CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+}
+
+typedef ReturnStruct20BytesHomogeneousInt32Type = Struct20BytesHomogeneousInt32
+    Function(Int32, Int32, Int32, Int32, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct20BytesHomogeneousInt32_a0 = 0;
+int returnStruct20BytesHomogeneousInt32_a1 = 0;
+int returnStruct20BytesHomogeneousInt32_a2 = 0;
+int returnStruct20BytesHomogeneousInt32_a3 = 0;
+int returnStruct20BytesHomogeneousInt32_a4 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32 returnStruct20BytesHomogeneousInt32Result =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStruct20BytesHomogeneousInt32CalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+
+  result.a0 = returnStruct20BytesHomogeneousInt32_a0;
+  result.a1 = returnStruct20BytesHomogeneousInt32_a1;
+  result.a2 = returnStruct20BytesHomogeneousInt32_a2;
+  result.a3 = returnStruct20BytesHomogeneousInt32_a3;
+  result.a4 = returnStruct20BytesHomogeneousInt32_a4;
+
+  returnStruct20BytesHomogeneousInt32Result = result;
+
+  return result;
+}
+
+/// Return value too big to go in cpu registers on arm64.
+Struct20BytesHomogeneousInt32 returnStruct20BytesHomogeneousInt32(
+    int a0, int a1, int a2, int a3, int a4) {
+  print(
+      "returnStruct20BytesHomogeneousInt32(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct20BytesHomogeneousInt32 throwing on purpuse!");
+  }
+
+  returnStruct20BytesHomogeneousInt32_a0 = a0;
+  returnStruct20BytesHomogeneousInt32_a1 = a1;
+  returnStruct20BytesHomogeneousInt32_a2 = a2;
+  returnStruct20BytesHomogeneousInt32_a3 = a3;
+  returnStruct20BytesHomogeneousInt32_a4 = a4;
+
+  final result = returnStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct20BytesHomogeneousInt32AfterCallback() {
+  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+
+  final result = returnStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+}
+
+typedef ReturnStruct20BytesHomogeneousFloatType = Struct20BytesHomogeneousFloat
+    Function(Float, Float, Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct20BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a2 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a3 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a4 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousFloat returnStruct20BytesHomogeneousFloatResult =
+    Struct20BytesHomogeneousFloat();
+
+Struct20BytesHomogeneousFloat
+    returnStruct20BytesHomogeneousFloatCalculateResult() {
+  Struct20BytesHomogeneousFloat result =
+      allocate<Struct20BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct20BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct20BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct20BytesHomogeneousFloat_a2;
+  result.a3 = returnStruct20BytesHomogeneousFloat_a3;
+  result.a4 = returnStruct20BytesHomogeneousFloat_a4;
+
+  returnStruct20BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+Struct20BytesHomogeneousFloat returnStruct20BytesHomogeneousFloat(
+    double a0, double a1, double a2, double a3, double a4) {
+  print(
+      "returnStruct20BytesHomogeneousFloat(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct20BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct20BytesHomogeneousFloat_a0 = a0;
+  returnStruct20BytesHomogeneousFloat_a1 = a1;
+  returnStruct20BytesHomogeneousFloat_a2 = a2;
+  returnStruct20BytesHomogeneousFloat_a3 = a3;
+  returnStruct20BytesHomogeneousFloat_a4 = a4;
+
+  final result = returnStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct20BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct32BytesHomogeneousDoubleType
+    = Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct32BytesHomogeneousDouble_a0 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a1 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a2 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a3 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct32BytesHomogeneousDouble returnStruct32BytesHomogeneousDoubleResult =
+    Struct32BytesHomogeneousDouble();
+
+Struct32BytesHomogeneousDouble
+    returnStruct32BytesHomogeneousDoubleCalculateResult() {
+  Struct32BytesHomogeneousDouble result =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+
+  result.a0 = returnStruct32BytesHomogeneousDouble_a0;
+  result.a1 = returnStruct32BytesHomogeneousDouble_a1;
+  result.a2 = returnStruct32BytesHomogeneousDouble_a2;
+  result.a3 = returnStruct32BytesHomogeneousDouble_a3;
+
+  returnStruct32BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers on arm64.
+Struct32BytesHomogeneousDouble returnStruct32BytesHomogeneousDouble(
+    double a0, double a1, double a2, double a3) {
+  print("returnStruct32BytesHomogeneousDouble(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct32BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  returnStruct32BytesHomogeneousDouble_a0 = a0;
+  returnStruct32BytesHomogeneousDouble_a1 = a1;
+  returnStruct32BytesHomogeneousDouble_a2 = a2;
+  returnStruct32BytesHomogeneousDouble_a3 = a3;
+
+  final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct32BytesHomogeneousDoubleAfterCallback() {
+  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+
+  final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+}
+
+typedef ReturnStruct40BytesHomogeneousDoubleType
+    = Struct40BytesHomogeneousDouble Function(
+        Double, Double, Double, Double, Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct40BytesHomogeneousDouble_a0 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a1 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a2 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a3 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a4 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct40BytesHomogeneousDouble returnStruct40BytesHomogeneousDoubleResult =
+    Struct40BytesHomogeneousDouble();
+
+Struct40BytesHomogeneousDouble
+    returnStruct40BytesHomogeneousDoubleCalculateResult() {
+  Struct40BytesHomogeneousDouble result =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+
+  result.a0 = returnStruct40BytesHomogeneousDouble_a0;
+  result.a1 = returnStruct40BytesHomogeneousDouble_a1;
+  result.a2 = returnStruct40BytesHomogeneousDouble_a2;
+  result.a3 = returnStruct40BytesHomogeneousDouble_a3;
+  result.a4 = returnStruct40BytesHomogeneousDouble_a4;
+
+  returnStruct40BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Return value too big to go in FPU registers on arm64.
+Struct40BytesHomogeneousDouble returnStruct40BytesHomogeneousDouble(
+    double a0, double a1, double a2, double a3, double a4) {
+  print(
+      "returnStruct40BytesHomogeneousDouble(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct40BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  returnStruct40BytesHomogeneousDouble_a0 = a0;
+  returnStruct40BytesHomogeneousDouble_a1 = a1;
+  returnStruct40BytesHomogeneousDouble_a2 = a2;
+  returnStruct40BytesHomogeneousDouble_a3 = a3;
+  returnStruct40BytesHomogeneousDouble_a4 = a4;
+
+  final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct40BytesHomogeneousDoubleAfterCallback() {
+  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+
+  final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+}
+
+typedef ReturnStruct1024BytesHomogeneousUint64Type
+    = 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);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct1024BytesHomogeneousUint64_a0 = 0;
+int returnStruct1024BytesHomogeneousUint64_a1 = 0;
+int returnStruct1024BytesHomogeneousUint64_a2 = 0;
+int returnStruct1024BytesHomogeneousUint64_a3 = 0;
+int returnStruct1024BytesHomogeneousUint64_a4 = 0;
+int returnStruct1024BytesHomogeneousUint64_a5 = 0;
+int returnStruct1024BytesHomogeneousUint64_a6 = 0;
+int returnStruct1024BytesHomogeneousUint64_a7 = 0;
+int returnStruct1024BytesHomogeneousUint64_a8 = 0;
+int returnStruct1024BytesHomogeneousUint64_a9 = 0;
+int returnStruct1024BytesHomogeneousUint64_a10 = 0;
+int returnStruct1024BytesHomogeneousUint64_a11 = 0;
+int returnStruct1024BytesHomogeneousUint64_a12 = 0;
+int returnStruct1024BytesHomogeneousUint64_a13 = 0;
+int returnStruct1024BytesHomogeneousUint64_a14 = 0;
+int returnStruct1024BytesHomogeneousUint64_a15 = 0;
+int returnStruct1024BytesHomogeneousUint64_a16 = 0;
+int returnStruct1024BytesHomogeneousUint64_a17 = 0;
+int returnStruct1024BytesHomogeneousUint64_a18 = 0;
+int returnStruct1024BytesHomogeneousUint64_a19 = 0;
+int returnStruct1024BytesHomogeneousUint64_a20 = 0;
+int returnStruct1024BytesHomogeneousUint64_a21 = 0;
+int returnStruct1024BytesHomogeneousUint64_a22 = 0;
+int returnStruct1024BytesHomogeneousUint64_a23 = 0;
+int returnStruct1024BytesHomogeneousUint64_a24 = 0;
+int returnStruct1024BytesHomogeneousUint64_a25 = 0;
+int returnStruct1024BytesHomogeneousUint64_a26 = 0;
+int returnStruct1024BytesHomogeneousUint64_a27 = 0;
+int returnStruct1024BytesHomogeneousUint64_a28 = 0;
+int returnStruct1024BytesHomogeneousUint64_a29 = 0;
+int returnStruct1024BytesHomogeneousUint64_a30 = 0;
+int returnStruct1024BytesHomogeneousUint64_a31 = 0;
+int returnStruct1024BytesHomogeneousUint64_a32 = 0;
+int returnStruct1024BytesHomogeneousUint64_a33 = 0;
+int returnStruct1024BytesHomogeneousUint64_a34 = 0;
+int returnStruct1024BytesHomogeneousUint64_a35 = 0;
+int returnStruct1024BytesHomogeneousUint64_a36 = 0;
+int returnStruct1024BytesHomogeneousUint64_a37 = 0;
+int returnStruct1024BytesHomogeneousUint64_a38 = 0;
+int returnStruct1024BytesHomogeneousUint64_a39 = 0;
+int returnStruct1024BytesHomogeneousUint64_a40 = 0;
+int returnStruct1024BytesHomogeneousUint64_a41 = 0;
+int returnStruct1024BytesHomogeneousUint64_a42 = 0;
+int returnStruct1024BytesHomogeneousUint64_a43 = 0;
+int returnStruct1024BytesHomogeneousUint64_a44 = 0;
+int returnStruct1024BytesHomogeneousUint64_a45 = 0;
+int returnStruct1024BytesHomogeneousUint64_a46 = 0;
+int returnStruct1024BytesHomogeneousUint64_a47 = 0;
+int returnStruct1024BytesHomogeneousUint64_a48 = 0;
+int returnStruct1024BytesHomogeneousUint64_a49 = 0;
+int returnStruct1024BytesHomogeneousUint64_a50 = 0;
+int returnStruct1024BytesHomogeneousUint64_a51 = 0;
+int returnStruct1024BytesHomogeneousUint64_a52 = 0;
+int returnStruct1024BytesHomogeneousUint64_a53 = 0;
+int returnStruct1024BytesHomogeneousUint64_a54 = 0;
+int returnStruct1024BytesHomogeneousUint64_a55 = 0;
+int returnStruct1024BytesHomogeneousUint64_a56 = 0;
+int returnStruct1024BytesHomogeneousUint64_a57 = 0;
+int returnStruct1024BytesHomogeneousUint64_a58 = 0;
+int returnStruct1024BytesHomogeneousUint64_a59 = 0;
+int returnStruct1024BytesHomogeneousUint64_a60 = 0;
+int returnStruct1024BytesHomogeneousUint64_a61 = 0;
+int returnStruct1024BytesHomogeneousUint64_a62 = 0;
+int returnStruct1024BytesHomogeneousUint64_a63 = 0;
+int returnStruct1024BytesHomogeneousUint64_a64 = 0;
+int returnStruct1024BytesHomogeneousUint64_a65 = 0;
+int returnStruct1024BytesHomogeneousUint64_a66 = 0;
+int returnStruct1024BytesHomogeneousUint64_a67 = 0;
+int returnStruct1024BytesHomogeneousUint64_a68 = 0;
+int returnStruct1024BytesHomogeneousUint64_a69 = 0;
+int returnStruct1024BytesHomogeneousUint64_a70 = 0;
+int returnStruct1024BytesHomogeneousUint64_a71 = 0;
+int returnStruct1024BytesHomogeneousUint64_a72 = 0;
+int returnStruct1024BytesHomogeneousUint64_a73 = 0;
+int returnStruct1024BytesHomogeneousUint64_a74 = 0;
+int returnStruct1024BytesHomogeneousUint64_a75 = 0;
+int returnStruct1024BytesHomogeneousUint64_a76 = 0;
+int returnStruct1024BytesHomogeneousUint64_a77 = 0;
+int returnStruct1024BytesHomogeneousUint64_a78 = 0;
+int returnStruct1024BytesHomogeneousUint64_a79 = 0;
+int returnStruct1024BytesHomogeneousUint64_a80 = 0;
+int returnStruct1024BytesHomogeneousUint64_a81 = 0;
+int returnStruct1024BytesHomogeneousUint64_a82 = 0;
+int returnStruct1024BytesHomogeneousUint64_a83 = 0;
+int returnStruct1024BytesHomogeneousUint64_a84 = 0;
+int returnStruct1024BytesHomogeneousUint64_a85 = 0;
+int returnStruct1024BytesHomogeneousUint64_a86 = 0;
+int returnStruct1024BytesHomogeneousUint64_a87 = 0;
+int returnStruct1024BytesHomogeneousUint64_a88 = 0;
+int returnStruct1024BytesHomogeneousUint64_a89 = 0;
+int returnStruct1024BytesHomogeneousUint64_a90 = 0;
+int returnStruct1024BytesHomogeneousUint64_a91 = 0;
+int returnStruct1024BytesHomogeneousUint64_a92 = 0;
+int returnStruct1024BytesHomogeneousUint64_a93 = 0;
+int returnStruct1024BytesHomogeneousUint64_a94 = 0;
+int returnStruct1024BytesHomogeneousUint64_a95 = 0;
+int returnStruct1024BytesHomogeneousUint64_a96 = 0;
+int returnStruct1024BytesHomogeneousUint64_a97 = 0;
+int returnStruct1024BytesHomogeneousUint64_a98 = 0;
+int returnStruct1024BytesHomogeneousUint64_a99 = 0;
+int returnStruct1024BytesHomogeneousUint64_a100 = 0;
+int returnStruct1024BytesHomogeneousUint64_a101 = 0;
+int returnStruct1024BytesHomogeneousUint64_a102 = 0;
+int returnStruct1024BytesHomogeneousUint64_a103 = 0;
+int returnStruct1024BytesHomogeneousUint64_a104 = 0;
+int returnStruct1024BytesHomogeneousUint64_a105 = 0;
+int returnStruct1024BytesHomogeneousUint64_a106 = 0;
+int returnStruct1024BytesHomogeneousUint64_a107 = 0;
+int returnStruct1024BytesHomogeneousUint64_a108 = 0;
+int returnStruct1024BytesHomogeneousUint64_a109 = 0;
+int returnStruct1024BytesHomogeneousUint64_a110 = 0;
+int returnStruct1024BytesHomogeneousUint64_a111 = 0;
+int returnStruct1024BytesHomogeneousUint64_a112 = 0;
+int returnStruct1024BytesHomogeneousUint64_a113 = 0;
+int returnStruct1024BytesHomogeneousUint64_a114 = 0;
+int returnStruct1024BytesHomogeneousUint64_a115 = 0;
+int returnStruct1024BytesHomogeneousUint64_a116 = 0;
+int returnStruct1024BytesHomogeneousUint64_a117 = 0;
+int returnStruct1024BytesHomogeneousUint64_a118 = 0;
+int returnStruct1024BytesHomogeneousUint64_a119 = 0;
+int returnStruct1024BytesHomogeneousUint64_a120 = 0;
+int returnStruct1024BytesHomogeneousUint64_a121 = 0;
+int returnStruct1024BytesHomogeneousUint64_a122 = 0;
+int returnStruct1024BytesHomogeneousUint64_a123 = 0;
+int returnStruct1024BytesHomogeneousUint64_a124 = 0;
+int returnStruct1024BytesHomogeneousUint64_a125 = 0;
+int returnStruct1024BytesHomogeneousUint64_a126 = 0;
+int returnStruct1024BytesHomogeneousUint64_a127 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct1024BytesHomogeneousUint64 returnStruct1024BytesHomogeneousUint64Result =
+    Struct1024BytesHomogeneousUint64();
+
+Struct1024BytesHomogeneousUint64
+    returnStruct1024BytesHomogeneousUint64CalculateResult() {
+  Struct1024BytesHomogeneousUint64 result =
+      allocate<Struct1024BytesHomogeneousUint64>().ref;
+
+  result.a0 = returnStruct1024BytesHomogeneousUint64_a0;
+  result.a1 = returnStruct1024BytesHomogeneousUint64_a1;
+  result.a2 = returnStruct1024BytesHomogeneousUint64_a2;
+  result.a3 = returnStruct1024BytesHomogeneousUint64_a3;
+  result.a4 = returnStruct1024BytesHomogeneousUint64_a4;
+  result.a5 = returnStruct1024BytesHomogeneousUint64_a5;
+  result.a6 = returnStruct1024BytesHomogeneousUint64_a6;
+  result.a7 = returnStruct1024BytesHomogeneousUint64_a7;
+  result.a8 = returnStruct1024BytesHomogeneousUint64_a8;
+  result.a9 = returnStruct1024BytesHomogeneousUint64_a9;
+  result.a10 = returnStruct1024BytesHomogeneousUint64_a10;
+  result.a11 = returnStruct1024BytesHomogeneousUint64_a11;
+  result.a12 = returnStruct1024BytesHomogeneousUint64_a12;
+  result.a13 = returnStruct1024BytesHomogeneousUint64_a13;
+  result.a14 = returnStruct1024BytesHomogeneousUint64_a14;
+  result.a15 = returnStruct1024BytesHomogeneousUint64_a15;
+  result.a16 = returnStruct1024BytesHomogeneousUint64_a16;
+  result.a17 = returnStruct1024BytesHomogeneousUint64_a17;
+  result.a18 = returnStruct1024BytesHomogeneousUint64_a18;
+  result.a19 = returnStruct1024BytesHomogeneousUint64_a19;
+  result.a20 = returnStruct1024BytesHomogeneousUint64_a20;
+  result.a21 = returnStruct1024BytesHomogeneousUint64_a21;
+  result.a22 = returnStruct1024BytesHomogeneousUint64_a22;
+  result.a23 = returnStruct1024BytesHomogeneousUint64_a23;
+  result.a24 = returnStruct1024BytesHomogeneousUint64_a24;
+  result.a25 = returnStruct1024BytesHomogeneousUint64_a25;
+  result.a26 = returnStruct1024BytesHomogeneousUint64_a26;
+  result.a27 = returnStruct1024BytesHomogeneousUint64_a27;
+  result.a28 = returnStruct1024BytesHomogeneousUint64_a28;
+  result.a29 = returnStruct1024BytesHomogeneousUint64_a29;
+  result.a30 = returnStruct1024BytesHomogeneousUint64_a30;
+  result.a31 = returnStruct1024BytesHomogeneousUint64_a31;
+  result.a32 = returnStruct1024BytesHomogeneousUint64_a32;
+  result.a33 = returnStruct1024BytesHomogeneousUint64_a33;
+  result.a34 = returnStruct1024BytesHomogeneousUint64_a34;
+  result.a35 = returnStruct1024BytesHomogeneousUint64_a35;
+  result.a36 = returnStruct1024BytesHomogeneousUint64_a36;
+  result.a37 = returnStruct1024BytesHomogeneousUint64_a37;
+  result.a38 = returnStruct1024BytesHomogeneousUint64_a38;
+  result.a39 = returnStruct1024BytesHomogeneousUint64_a39;
+  result.a40 = returnStruct1024BytesHomogeneousUint64_a40;
+  result.a41 = returnStruct1024BytesHomogeneousUint64_a41;
+  result.a42 = returnStruct1024BytesHomogeneousUint64_a42;
+  result.a43 = returnStruct1024BytesHomogeneousUint64_a43;
+  result.a44 = returnStruct1024BytesHomogeneousUint64_a44;
+  result.a45 = returnStruct1024BytesHomogeneousUint64_a45;
+  result.a46 = returnStruct1024BytesHomogeneousUint64_a46;
+  result.a47 = returnStruct1024BytesHomogeneousUint64_a47;
+  result.a48 = returnStruct1024BytesHomogeneousUint64_a48;
+  result.a49 = returnStruct1024BytesHomogeneousUint64_a49;
+  result.a50 = returnStruct1024BytesHomogeneousUint64_a50;
+  result.a51 = returnStruct1024BytesHomogeneousUint64_a51;
+  result.a52 = returnStruct1024BytesHomogeneousUint64_a52;
+  result.a53 = returnStruct1024BytesHomogeneousUint64_a53;
+  result.a54 = returnStruct1024BytesHomogeneousUint64_a54;
+  result.a55 = returnStruct1024BytesHomogeneousUint64_a55;
+  result.a56 = returnStruct1024BytesHomogeneousUint64_a56;
+  result.a57 = returnStruct1024BytesHomogeneousUint64_a57;
+  result.a58 = returnStruct1024BytesHomogeneousUint64_a58;
+  result.a59 = returnStruct1024BytesHomogeneousUint64_a59;
+  result.a60 = returnStruct1024BytesHomogeneousUint64_a60;
+  result.a61 = returnStruct1024BytesHomogeneousUint64_a61;
+  result.a62 = returnStruct1024BytesHomogeneousUint64_a62;
+  result.a63 = returnStruct1024BytesHomogeneousUint64_a63;
+  result.a64 = returnStruct1024BytesHomogeneousUint64_a64;
+  result.a65 = returnStruct1024BytesHomogeneousUint64_a65;
+  result.a66 = returnStruct1024BytesHomogeneousUint64_a66;
+  result.a67 = returnStruct1024BytesHomogeneousUint64_a67;
+  result.a68 = returnStruct1024BytesHomogeneousUint64_a68;
+  result.a69 = returnStruct1024BytesHomogeneousUint64_a69;
+  result.a70 = returnStruct1024BytesHomogeneousUint64_a70;
+  result.a71 = returnStruct1024BytesHomogeneousUint64_a71;
+  result.a72 = returnStruct1024BytesHomogeneousUint64_a72;
+  result.a73 = returnStruct1024BytesHomogeneousUint64_a73;
+  result.a74 = returnStruct1024BytesHomogeneousUint64_a74;
+  result.a75 = returnStruct1024BytesHomogeneousUint64_a75;
+  result.a76 = returnStruct1024BytesHomogeneousUint64_a76;
+  result.a77 = returnStruct1024BytesHomogeneousUint64_a77;
+  result.a78 = returnStruct1024BytesHomogeneousUint64_a78;
+  result.a79 = returnStruct1024BytesHomogeneousUint64_a79;
+  result.a80 = returnStruct1024BytesHomogeneousUint64_a80;
+  result.a81 = returnStruct1024BytesHomogeneousUint64_a81;
+  result.a82 = returnStruct1024BytesHomogeneousUint64_a82;
+  result.a83 = returnStruct1024BytesHomogeneousUint64_a83;
+  result.a84 = returnStruct1024BytesHomogeneousUint64_a84;
+  result.a85 = returnStruct1024BytesHomogeneousUint64_a85;
+  result.a86 = returnStruct1024BytesHomogeneousUint64_a86;
+  result.a87 = returnStruct1024BytesHomogeneousUint64_a87;
+  result.a88 = returnStruct1024BytesHomogeneousUint64_a88;
+  result.a89 = returnStruct1024BytesHomogeneousUint64_a89;
+  result.a90 = returnStruct1024BytesHomogeneousUint64_a90;
+  result.a91 = returnStruct1024BytesHomogeneousUint64_a91;
+  result.a92 = returnStruct1024BytesHomogeneousUint64_a92;
+  result.a93 = returnStruct1024BytesHomogeneousUint64_a93;
+  result.a94 = returnStruct1024BytesHomogeneousUint64_a94;
+  result.a95 = returnStruct1024BytesHomogeneousUint64_a95;
+  result.a96 = returnStruct1024BytesHomogeneousUint64_a96;
+  result.a97 = returnStruct1024BytesHomogeneousUint64_a97;
+  result.a98 = returnStruct1024BytesHomogeneousUint64_a98;
+  result.a99 = returnStruct1024BytesHomogeneousUint64_a99;
+  result.a100 = returnStruct1024BytesHomogeneousUint64_a100;
+  result.a101 = returnStruct1024BytesHomogeneousUint64_a101;
+  result.a102 = returnStruct1024BytesHomogeneousUint64_a102;
+  result.a103 = returnStruct1024BytesHomogeneousUint64_a103;
+  result.a104 = returnStruct1024BytesHomogeneousUint64_a104;
+  result.a105 = returnStruct1024BytesHomogeneousUint64_a105;
+  result.a106 = returnStruct1024BytesHomogeneousUint64_a106;
+  result.a107 = returnStruct1024BytesHomogeneousUint64_a107;
+  result.a108 = returnStruct1024BytesHomogeneousUint64_a108;
+  result.a109 = returnStruct1024BytesHomogeneousUint64_a109;
+  result.a110 = returnStruct1024BytesHomogeneousUint64_a110;
+  result.a111 = returnStruct1024BytesHomogeneousUint64_a111;
+  result.a112 = returnStruct1024BytesHomogeneousUint64_a112;
+  result.a113 = returnStruct1024BytesHomogeneousUint64_a113;
+  result.a114 = returnStruct1024BytesHomogeneousUint64_a114;
+  result.a115 = returnStruct1024BytesHomogeneousUint64_a115;
+  result.a116 = returnStruct1024BytesHomogeneousUint64_a116;
+  result.a117 = returnStruct1024BytesHomogeneousUint64_a117;
+  result.a118 = returnStruct1024BytesHomogeneousUint64_a118;
+  result.a119 = returnStruct1024BytesHomogeneousUint64_a119;
+  result.a120 = returnStruct1024BytesHomogeneousUint64_a120;
+  result.a121 = returnStruct1024BytesHomogeneousUint64_a121;
+  result.a122 = returnStruct1024BytesHomogeneousUint64_a122;
+  result.a123 = returnStruct1024BytesHomogeneousUint64_a123;
+  result.a124 = returnStruct1024BytesHomogeneousUint64_a124;
+  result.a125 = returnStruct1024BytesHomogeneousUint64_a125;
+  result.a126 = returnStruct1024BytesHomogeneousUint64_a126;
+  result.a127 = returnStruct1024BytesHomogeneousUint64_a127;
+
+  returnStruct1024BytesHomogeneousUint64Result = result;
+
+  return result;
+}
+
+/// Test 1kb struct.
+Struct1024BytesHomogeneousUint64 returnStruct1024BytesHomogeneousUint64(
+    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) {
+  print(
+      "returnStruct1024BytesHomogeneousUint64(${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})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct1024BytesHomogeneousUint64 throwing on purpuse!");
+  }
+
+  returnStruct1024BytesHomogeneousUint64_a0 = a0;
+  returnStruct1024BytesHomogeneousUint64_a1 = a1;
+  returnStruct1024BytesHomogeneousUint64_a2 = a2;
+  returnStruct1024BytesHomogeneousUint64_a3 = a3;
+  returnStruct1024BytesHomogeneousUint64_a4 = a4;
+  returnStruct1024BytesHomogeneousUint64_a5 = a5;
+  returnStruct1024BytesHomogeneousUint64_a6 = a6;
+  returnStruct1024BytesHomogeneousUint64_a7 = a7;
+  returnStruct1024BytesHomogeneousUint64_a8 = a8;
+  returnStruct1024BytesHomogeneousUint64_a9 = a9;
+  returnStruct1024BytesHomogeneousUint64_a10 = a10;
+  returnStruct1024BytesHomogeneousUint64_a11 = a11;
+  returnStruct1024BytesHomogeneousUint64_a12 = a12;
+  returnStruct1024BytesHomogeneousUint64_a13 = a13;
+  returnStruct1024BytesHomogeneousUint64_a14 = a14;
+  returnStruct1024BytesHomogeneousUint64_a15 = a15;
+  returnStruct1024BytesHomogeneousUint64_a16 = a16;
+  returnStruct1024BytesHomogeneousUint64_a17 = a17;
+  returnStruct1024BytesHomogeneousUint64_a18 = a18;
+  returnStruct1024BytesHomogeneousUint64_a19 = a19;
+  returnStruct1024BytesHomogeneousUint64_a20 = a20;
+  returnStruct1024BytesHomogeneousUint64_a21 = a21;
+  returnStruct1024BytesHomogeneousUint64_a22 = a22;
+  returnStruct1024BytesHomogeneousUint64_a23 = a23;
+  returnStruct1024BytesHomogeneousUint64_a24 = a24;
+  returnStruct1024BytesHomogeneousUint64_a25 = a25;
+  returnStruct1024BytesHomogeneousUint64_a26 = a26;
+  returnStruct1024BytesHomogeneousUint64_a27 = a27;
+  returnStruct1024BytesHomogeneousUint64_a28 = a28;
+  returnStruct1024BytesHomogeneousUint64_a29 = a29;
+  returnStruct1024BytesHomogeneousUint64_a30 = a30;
+  returnStruct1024BytesHomogeneousUint64_a31 = a31;
+  returnStruct1024BytesHomogeneousUint64_a32 = a32;
+  returnStruct1024BytesHomogeneousUint64_a33 = a33;
+  returnStruct1024BytesHomogeneousUint64_a34 = a34;
+  returnStruct1024BytesHomogeneousUint64_a35 = a35;
+  returnStruct1024BytesHomogeneousUint64_a36 = a36;
+  returnStruct1024BytesHomogeneousUint64_a37 = a37;
+  returnStruct1024BytesHomogeneousUint64_a38 = a38;
+  returnStruct1024BytesHomogeneousUint64_a39 = a39;
+  returnStruct1024BytesHomogeneousUint64_a40 = a40;
+  returnStruct1024BytesHomogeneousUint64_a41 = a41;
+  returnStruct1024BytesHomogeneousUint64_a42 = a42;
+  returnStruct1024BytesHomogeneousUint64_a43 = a43;
+  returnStruct1024BytesHomogeneousUint64_a44 = a44;
+  returnStruct1024BytesHomogeneousUint64_a45 = a45;
+  returnStruct1024BytesHomogeneousUint64_a46 = a46;
+  returnStruct1024BytesHomogeneousUint64_a47 = a47;
+  returnStruct1024BytesHomogeneousUint64_a48 = a48;
+  returnStruct1024BytesHomogeneousUint64_a49 = a49;
+  returnStruct1024BytesHomogeneousUint64_a50 = a50;
+  returnStruct1024BytesHomogeneousUint64_a51 = a51;
+  returnStruct1024BytesHomogeneousUint64_a52 = a52;
+  returnStruct1024BytesHomogeneousUint64_a53 = a53;
+  returnStruct1024BytesHomogeneousUint64_a54 = a54;
+  returnStruct1024BytesHomogeneousUint64_a55 = a55;
+  returnStruct1024BytesHomogeneousUint64_a56 = a56;
+  returnStruct1024BytesHomogeneousUint64_a57 = a57;
+  returnStruct1024BytesHomogeneousUint64_a58 = a58;
+  returnStruct1024BytesHomogeneousUint64_a59 = a59;
+  returnStruct1024BytesHomogeneousUint64_a60 = a60;
+  returnStruct1024BytesHomogeneousUint64_a61 = a61;
+  returnStruct1024BytesHomogeneousUint64_a62 = a62;
+  returnStruct1024BytesHomogeneousUint64_a63 = a63;
+  returnStruct1024BytesHomogeneousUint64_a64 = a64;
+  returnStruct1024BytesHomogeneousUint64_a65 = a65;
+  returnStruct1024BytesHomogeneousUint64_a66 = a66;
+  returnStruct1024BytesHomogeneousUint64_a67 = a67;
+  returnStruct1024BytesHomogeneousUint64_a68 = a68;
+  returnStruct1024BytesHomogeneousUint64_a69 = a69;
+  returnStruct1024BytesHomogeneousUint64_a70 = a70;
+  returnStruct1024BytesHomogeneousUint64_a71 = a71;
+  returnStruct1024BytesHomogeneousUint64_a72 = a72;
+  returnStruct1024BytesHomogeneousUint64_a73 = a73;
+  returnStruct1024BytesHomogeneousUint64_a74 = a74;
+  returnStruct1024BytesHomogeneousUint64_a75 = a75;
+  returnStruct1024BytesHomogeneousUint64_a76 = a76;
+  returnStruct1024BytesHomogeneousUint64_a77 = a77;
+  returnStruct1024BytesHomogeneousUint64_a78 = a78;
+  returnStruct1024BytesHomogeneousUint64_a79 = a79;
+  returnStruct1024BytesHomogeneousUint64_a80 = a80;
+  returnStruct1024BytesHomogeneousUint64_a81 = a81;
+  returnStruct1024BytesHomogeneousUint64_a82 = a82;
+  returnStruct1024BytesHomogeneousUint64_a83 = a83;
+  returnStruct1024BytesHomogeneousUint64_a84 = a84;
+  returnStruct1024BytesHomogeneousUint64_a85 = a85;
+  returnStruct1024BytesHomogeneousUint64_a86 = a86;
+  returnStruct1024BytesHomogeneousUint64_a87 = a87;
+  returnStruct1024BytesHomogeneousUint64_a88 = a88;
+  returnStruct1024BytesHomogeneousUint64_a89 = a89;
+  returnStruct1024BytesHomogeneousUint64_a90 = a90;
+  returnStruct1024BytesHomogeneousUint64_a91 = a91;
+  returnStruct1024BytesHomogeneousUint64_a92 = a92;
+  returnStruct1024BytesHomogeneousUint64_a93 = a93;
+  returnStruct1024BytesHomogeneousUint64_a94 = a94;
+  returnStruct1024BytesHomogeneousUint64_a95 = a95;
+  returnStruct1024BytesHomogeneousUint64_a96 = a96;
+  returnStruct1024BytesHomogeneousUint64_a97 = a97;
+  returnStruct1024BytesHomogeneousUint64_a98 = a98;
+  returnStruct1024BytesHomogeneousUint64_a99 = a99;
+  returnStruct1024BytesHomogeneousUint64_a100 = a100;
+  returnStruct1024BytesHomogeneousUint64_a101 = a101;
+  returnStruct1024BytesHomogeneousUint64_a102 = a102;
+  returnStruct1024BytesHomogeneousUint64_a103 = a103;
+  returnStruct1024BytesHomogeneousUint64_a104 = a104;
+  returnStruct1024BytesHomogeneousUint64_a105 = a105;
+  returnStruct1024BytesHomogeneousUint64_a106 = a106;
+  returnStruct1024BytesHomogeneousUint64_a107 = a107;
+  returnStruct1024BytesHomogeneousUint64_a108 = a108;
+  returnStruct1024BytesHomogeneousUint64_a109 = a109;
+  returnStruct1024BytesHomogeneousUint64_a110 = a110;
+  returnStruct1024BytesHomogeneousUint64_a111 = a111;
+  returnStruct1024BytesHomogeneousUint64_a112 = a112;
+  returnStruct1024BytesHomogeneousUint64_a113 = a113;
+  returnStruct1024BytesHomogeneousUint64_a114 = a114;
+  returnStruct1024BytesHomogeneousUint64_a115 = a115;
+  returnStruct1024BytesHomogeneousUint64_a116 = a116;
+  returnStruct1024BytesHomogeneousUint64_a117 = a117;
+  returnStruct1024BytesHomogeneousUint64_a118 = a118;
+  returnStruct1024BytesHomogeneousUint64_a119 = a119;
+  returnStruct1024BytesHomogeneousUint64_a120 = a120;
+  returnStruct1024BytesHomogeneousUint64_a121 = a121;
+  returnStruct1024BytesHomogeneousUint64_a122 = a122;
+  returnStruct1024BytesHomogeneousUint64_a123 = a123;
+  returnStruct1024BytesHomogeneousUint64_a124 = a124;
+  returnStruct1024BytesHomogeneousUint64_a125 = a125;
+  returnStruct1024BytesHomogeneousUint64_a126 = a126;
+  returnStruct1024BytesHomogeneousUint64_a127 = a127;
+
+  final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct1024BytesHomogeneousUint64AfterCallback() {
+  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+
+  final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+}
+
+typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
+    Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1ByteInt returnStructArgumentStruct1ByteInt_a0 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStructArgumentStruct1ByteIntResult = Struct1ByteInt();
+
+Struct1ByteInt returnStructArgumentStruct1ByteIntCalculateResult() {
+  Struct1ByteInt result = returnStructArgumentStruct1ByteInt_a0;
+
+  returnStructArgumentStruct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in int registers in most ABIs.
+Struct1ByteInt returnStructArgumentStruct1ByteInt(Struct1ByteInt a0) {
+  print("returnStructArgumentStruct1ByteInt(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructArgumentStruct1ByteInt throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct1ByteInt_a0 = a0;
+
+  final result = returnStructArgumentStruct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct1ByteIntAfterCallback() {
+  final result = returnStructArgumentStruct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentInt32x8Struct1ByteIntType = Struct1ByteInt Function(
+    Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructArgumentInt32x8Struct1ByteInt_a0 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a1 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a2 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a3 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a4 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a5 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a6 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a7 = 0;
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteInt_a8 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteIntResult =
+    Struct1ByteInt();
+
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteIntCalculateResult() {
+  Struct1ByteInt result = returnStructArgumentInt32x8Struct1ByteInt_a8;
+
+  returnStructArgumentInt32x8Struct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteInt(int a0, int a1, int a2,
+    int a3, int a4, int a5, int a6, int a7, Struct1ByteInt a8) {
+  print(
+      "returnStructArgumentInt32x8Struct1ByteInt(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentInt32x8Struct1ByteInt throwing on purpuse!");
+  }
+
+  returnStructArgumentInt32x8Struct1ByteInt_a0 = a0;
+  returnStructArgumentInt32x8Struct1ByteInt_a1 = a1;
+  returnStructArgumentInt32x8Struct1ByteInt_a2 = a2;
+  returnStructArgumentInt32x8Struct1ByteInt_a3 = a3;
+  returnStructArgumentInt32x8Struct1ByteInt_a4 = a4;
+  returnStructArgumentInt32x8Struct1ByteInt_a5 = a5;
+  returnStructArgumentInt32x8Struct1ByteInt_a6 = a6;
+  returnStructArgumentInt32x8Struct1ByteInt_a7 = a7;
+  returnStructArgumentInt32x8Struct1ByteInt_a8 = a8;
+
+  final result = returnStructArgumentInt32x8Struct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentInt32x8Struct1ByteIntAfterCallback() {
+  final result = returnStructArgumentInt32x8Struct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentStruct8BytesHomogeneousFloatType
+    = Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloat_a0 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloatResult =
+    Struct8BytesHomogeneousFloat();
+
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult() {
+  Struct8BytesHomogeneousFloat result =
+      returnStructArgumentStruct8BytesHomogeneousFloat_a0;
+
+  returnStructArgumentStruct8BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in float registers in most ABIs.
+Struct8BytesHomogeneousFloat returnStructArgumentStruct8BytesHomogeneousFloat(
+    Struct8BytesHomogeneousFloat a0) {
+  print("returnStructArgumentStruct8BytesHomogeneousFloat(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentStruct8BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct8BytesHomogeneousFloat_a0 = a0;
+
+  final result =
+      returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct8BytesHomogeneousFloatAfterCallback() {
+  final result =
+      returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentStruct20BytesHomogeneousInt32Type
+    = Struct20BytesHomogeneousInt32 Function(Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32_a0 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32Result =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      returnStructArgumentStruct20BytesHomogeneousInt32_a0;
+
+  returnStructArgumentStruct20BytesHomogeneousInt32Result = result;
+
+  return result;
+}
+
+/// On arm64, both argument and return value are passed in by pointer.
+Struct20BytesHomogeneousInt32 returnStructArgumentStruct20BytesHomogeneousInt32(
+    Struct20BytesHomogeneousInt32 a0) {
+  print("returnStructArgumentStruct20BytesHomogeneousInt32(${a0})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentStruct20BytesHomogeneousInt32 throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct20BytesHomogeneousInt32_a0 = a0;
+
+  final result =
+      returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct20BytesHomogeneousInt32AfterCallback() {
+  final result =
+      returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentInt32x8Struct20BytesHomogeneouType
+    = Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32,
+        Int32, Int32, Int32, Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a0 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a1 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a2 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a3 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a4 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a5 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a6 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a7 = 0;
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneou_a8 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneouResult =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneou_a8;
+
+  returnStructArgumentInt32x8Struct20BytesHomogeneouResult = result;
+
+  return result;
+}
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneou(
+        int a0,
+        int a1,
+        int a2,
+        int a3,
+        int a4,
+        int a5,
+        int a6,
+        int a7,
+        Struct20BytesHomogeneousInt32 a8) {
+  print(
+      "returnStructArgumentInt32x8Struct20BytesHomogeneou(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentInt32x8Struct20BytesHomogeneou throwing on purpuse!");
+  }
+
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a0 = a0;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a1 = a1;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a2 = a2;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a3 = a3;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a4 = a4;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a5 = a5;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a6 = a6;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a7 = a7;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a8 = a8;
+
+  final result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentInt32x8Struct20BytesHomogeneouAfterCallback() {
+  final result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructAlignmentInt16Type = StructAlignmentInt16 Function(
+    Int8, Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt16_a0 = 0;
+int returnStructAlignmentInt16_a1 = 0;
+int returnStructAlignmentInt16_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt16 returnStructAlignmentInt16Result = StructAlignmentInt16();
+
+StructAlignmentInt16 returnStructAlignmentInt16CalculateResult() {
+  StructAlignmentInt16 result = allocate<StructAlignmentInt16>().ref;
+
+  result.a0 = returnStructAlignmentInt16_a0;
+  result.a1 = returnStructAlignmentInt16_a1;
+  result.a2 = returnStructAlignmentInt16_a2;
+
+  returnStructAlignmentInt16Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+StructAlignmentInt16 returnStructAlignmentInt16(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt16(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt16 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt16_a0 = a0;
+  returnStructAlignmentInt16_a1 = a1;
+  returnStructAlignmentInt16_a2 = a2;
+
+  final result = returnStructAlignmentInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt16AfterCallback() {
+  free(returnStructAlignmentInt16Result.addressOf);
+
+  final result = returnStructAlignmentInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt16Result.addressOf);
+}
+
+typedef ReturnStructAlignmentInt32Type = StructAlignmentInt32 Function(
+    Int8, Int32, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt32_a0 = 0;
+int returnStructAlignmentInt32_a1 = 0;
+int returnStructAlignmentInt32_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt32 returnStructAlignmentInt32Result = StructAlignmentInt32();
+
+StructAlignmentInt32 returnStructAlignmentInt32CalculateResult() {
+  StructAlignmentInt32 result = allocate<StructAlignmentInt32>().ref;
+
+  result.a0 = returnStructAlignmentInt32_a0;
+  result.a1 = returnStructAlignmentInt32_a1;
+  result.a2 = returnStructAlignmentInt32_a2;
+
+  returnStructAlignmentInt32Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 32 byte int within struct.
+StructAlignmentInt32 returnStructAlignmentInt32(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt32(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt32 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt32_a0 = a0;
+  returnStructAlignmentInt32_a1 = a1;
+  returnStructAlignmentInt32_a2 = a2;
+
+  final result = returnStructAlignmentInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt32AfterCallback() {
+  free(returnStructAlignmentInt32Result.addressOf);
+
+  final result = returnStructAlignmentInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt32Result.addressOf);
+}
+
+typedef ReturnStructAlignmentInt64Type = StructAlignmentInt64 Function(
+    Int8, Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt64_a0 = 0;
+int returnStructAlignmentInt64_a1 = 0;
+int returnStructAlignmentInt64_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt64 returnStructAlignmentInt64Result = StructAlignmentInt64();
+
+StructAlignmentInt64 returnStructAlignmentInt64CalculateResult() {
+  StructAlignmentInt64 result = allocate<StructAlignmentInt64>().ref;
+
+  result.a0 = returnStructAlignmentInt64_a0;
+  result.a1 = returnStructAlignmentInt64_a1;
+  result.a2 = returnStructAlignmentInt64_a2;
+
+  returnStructAlignmentInt64Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 64 byte int within struct.
+StructAlignmentInt64 returnStructAlignmentInt64(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt64(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt64 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt64_a0 = a0;
+  returnStructAlignmentInt64_a1 = a1;
+  returnStructAlignmentInt64_a2 = a2;
+
+  final result = returnStructAlignmentInt64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt64AfterCallback() {
+  free(returnStructAlignmentInt64Result.addressOf);
+
+  final result = returnStructAlignmentInt64CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt64Result.addressOf);
+}
diff --git a/tests/ffi/function_callbacks_structs_by_value_test.dart b/tests/ffi/function_callbacks_structs_by_value_test.dart
new file mode 100644
index 0000000..98ab518
--- /dev/null
+++ b/tests/ffi/function_callbacks_structs_by_value_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2020, 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
+//
+// VMOptions=--deterministic --optimization-counter-threshold=5 --use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+void main() {
+  for (int i = 0; i < 10; i++) {
+    recursiveTest(10);
+    recursiveTest(11);
+  }
+}
+
+void recursiveTest(int recursionCounter) {
+  final struct = allocate<Struct20BytesHomogeneousInt32>().ref;
+  struct.a0 = 1;
+  struct.a1 = 2;
+  struct.a2 = 3;
+  struct.a3 = 4;
+  struct.a4 = 5;
+  final result = dartPassStructRecursive(recursionCounter, struct);
+  Expect.equals(struct.a0 + recursionCounter * 2, result.a0);
+  Expect.equals(struct.a1, result.a1);
+  Expect.equals(struct.a2, result.a2);
+  Expect.equals(struct.a3, result.a3);
+  Expect.equals(struct.a4, result.a4);
+  free(struct.addressOf);
+}
+
+Struct20BytesHomogeneousInt32 dartPassStructRecursive(
+    int recursionCounter, Struct20BytesHomogeneousInt32 struct) {
+  print("callbackPassStructRecurisive($recursionCounter, $struct)");
+  struct.a0++;
+  final structA0Saved = struct.a0;
+  if (recursionCounter <= 0) {
+    print("returning");
+    return struct;
+  }
+
+  final result =
+      cPassStructRecursive(recursionCounter - 1, struct, functionPointer);
+  result.a0++;
+
+  // Check struct.a0 is not modified by Dart->C call.
+  Expect.equals(structA0Saved, struct.a0);
+
+  // Check struct.a0 is not modified by C->Dart callback, if so struct.a4 == 0.
+  Expect.notEquals(0, struct.a4);
+
+  return result;
+}
+
+final functionPointer = Pointer.fromFunction<
+    Struct20BytesHomogeneousInt32 Function(
+        Int64, Struct20BytesHomogeneousInt32)>(dartPassStructRecursive);
+
+final cPassStructRecursive = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousInt32 Function(Int64 recursionCounter,
+        Struct20BytesHomogeneousInt32 struct, Pointer callbackAddress),
+    Struct20BytesHomogeneousInt32 Function(int recursionCounter,
+        Struct20BytesHomogeneousInt32, Pointer)>("PassStructRecursive");
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
new file mode 100644
index 0000000..3cbdf98
--- /dev/null
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -0,0 +1,4720 @@
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=5
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'dylib_utils.dart';
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+void main() {
+  for (int i = 0; i < 10; ++i) {
+    testPassStruct1ByteIntx10();
+    testPassStruct3BytesIntx10();
+    testPassStruct4BytesHomogeneousInt16x10();
+    testPassStruct7BytesIntx10();
+    testPassStruct8BytesIntx10();
+    testPassStruct8BytesHomogeneousFloatx10();
+    testPassStruct8BytesMixedx10();
+    testPassStruct9BytesIntx10();
+    testPassStruct9BytesHomogeneousUint82x10();
+    testPassStruct12BytesHomogeneousFloatx6();
+    testPassStruct16BytesHomogeneousFloatx5();
+    testPassStruct16BytesMixedx10();
+    testPassStruct16BytesMixed2x10();
+    testPassStruct17BytesIntx10();
+    testPassStruct19BytesHomogeneousUint8x10();
+    testPassStruct20BytesHomogeneousInt32x10();
+    testPassStruct20BytesHomogeneousFloat();
+    testPassStruct32BytesHomogeneousDoublex5();
+    testPassStruct40BytesHomogeneousDouble();
+    testPassStruct1024BytesHomogeneousUint64();
+    testPassFloatStruct16BytesHomogeneousFloatFloatStruct1();
+    testPassFloatStruct32BytesHomogeneousDoubleFloatStruct();
+    testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn();
+    testPassDoublex6Struct16BytesMixedx4Int32();
+    testPassInt32x4Struct16BytesMixedx4Double();
+    testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo();
+    testPassStructAlignmentInt16();
+    testPassStructAlignmentInt32();
+    testPassStructAlignmentInt64();
+    testReturnStruct1ByteInt();
+    testReturnStruct3BytesInt();
+    testReturnStruct4BytesHomogeneousInt16();
+    testReturnStruct7BytesInt();
+    testReturnStruct8BytesInt();
+    testReturnStruct8BytesHomogeneousFloat();
+    testReturnStruct8BytesMixed();
+    testReturnStruct9BytesInt();
+    testReturnStruct9BytesHomogeneousUint82();
+    testReturnStruct12BytesHomogeneousFloat();
+    testReturnStruct16BytesHomogeneousFloat();
+    testReturnStruct16BytesMixed();
+    testReturnStruct16BytesMixed2();
+    testReturnStruct17BytesInt();
+    testReturnStruct19BytesHomogeneousUint8();
+    testReturnStruct20BytesHomogeneousInt32();
+    testReturnStruct20BytesHomogeneousFloat();
+    testReturnStruct32BytesHomogeneousDouble();
+    testReturnStruct40BytesHomogeneousDouble();
+    testReturnStruct1024BytesHomogeneousUint64();
+    testReturnStructArgumentStruct1ByteInt();
+    testReturnStructArgumentInt32x8Struct1ByteInt();
+    testReturnStructArgumentStruct8BytesHomogeneousFloat();
+    testReturnStructArgumentStruct20BytesHomogeneousInt32();
+    testReturnStructArgumentInt32x8Struct20BytesHomogeneou();
+    testReturnStructAlignmentInt16();
+    testReturnStructAlignmentInt32();
+    testReturnStructAlignmentInt64();
+  }
+}
+
+class Struct0Bytes extends Struct {
+  String toString() => "()";
+}
+
+class Struct1ByteInt extends Struct {
+  @Int8()
+  external int a0;
+
+  String toString() => "(${a0})";
+}
+
+class Struct3BytesInt extends Struct {
+  @Int16()
+  external int a0;
+
+  @Int8()
+  external int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct4BytesHomogeneousInt16 extends Struct {
+  @Int16()
+  external int a0;
+
+  @Int16()
+  external int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct7BytesInt extends Struct {
+  @Int32()
+  external int a0;
+
+  @Int16()
+  external int a1;
+
+  @Int8()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct8BytesInt extends Struct {
+  @Int16()
+  external int a0;
+
+  @Int16()
+  external int a1;
+
+  @Int32()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct8BytesHomogeneousFloat extends Struct {
+  @Float()
+  external double a0;
+
+  @Float()
+  external double a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct8BytesMixed extends Struct {
+  @Float()
+  external double a0;
+
+  @Int16()
+  external int a1;
+
+  @Int16()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct9BytesInt extends Struct {
+  @Int64()
+  external int a0;
+
+  @Int8()
+  external int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct9BytesHomogeneousUint82 extends Struct {
+  @Uint8()
+  external int a0;
+
+  @Uint8()
+  external int a1;
+
+  @Uint8()
+  external int a2;
+
+  @Uint8()
+  external int a3;
+
+  @Uint8()
+  external int a4;
+
+  @Uint8()
+  external int a5;
+
+  @Uint8()
+  external int a6;
+
+  @Uint8()
+  external int a7;
+
+  @Uint8()
+  external int a8;
+
+  String toString() =>
+      "(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})";
+}
+
+class Struct12BytesHomogeneousFloat extends Struct {
+  @Float()
+  external double a0;
+
+  @Float()
+  external double a1;
+
+  @Float()
+  external double a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct16BytesHomogeneousFloat extends Struct {
+  @Float()
+  external double a0;
+
+  @Float()
+  external double a1;
+
+  @Float()
+  external double a2;
+
+  @Float()
+  external double a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct16BytesMixed extends Struct {
+  @Double()
+  external double a0;
+
+  @Int64()
+  external int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct16BytesMixed2 extends Struct {
+  @Float()
+  external double a0;
+
+  @Float()
+  external double a1;
+
+  @Float()
+  external double a2;
+
+  @Int32()
+  external int a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct17BytesInt extends Struct {
+  @Int64()
+  external int a0;
+
+  @Int64()
+  external int a1;
+
+  @Int8()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct19BytesHomogeneousUint8 extends Struct {
+  @Uint8()
+  external int a0;
+
+  @Uint8()
+  external int a1;
+
+  @Uint8()
+  external int a2;
+
+  @Uint8()
+  external int a3;
+
+  @Uint8()
+  external int a4;
+
+  @Uint8()
+  external int a5;
+
+  @Uint8()
+  external int a6;
+
+  @Uint8()
+  external int a7;
+
+  @Uint8()
+  external int a8;
+
+  @Uint8()
+  external int a9;
+
+  @Uint8()
+  external int a10;
+
+  @Uint8()
+  external int a11;
+
+  @Uint8()
+  external int a12;
+
+  @Uint8()
+  external int a13;
+
+  @Uint8()
+  external int a14;
+
+  @Uint8()
+  external int a15;
+
+  @Uint8()
+  external int a16;
+
+  @Uint8()
+  external int a17;
+
+  @Uint8()
+  external int a18;
+
+  String toString() =>
+      "(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12}, ${a13}, ${a14}, ${a15}, ${a16}, ${a17}, ${a18})";
+}
+
+class Struct20BytesHomogeneousInt32 extends Struct {
+  @Int32()
+  external int a0;
+
+  @Int32()
+  external int a1;
+
+  @Int32()
+  external int a2;
+
+  @Int32()
+  external int a3;
+
+  @Int32()
+  external int a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct20BytesHomogeneousFloat extends Struct {
+  @Float()
+  external double a0;
+
+  @Float()
+  external double a1;
+
+  @Float()
+  external double a2;
+
+  @Float()
+  external double a3;
+
+  @Float()
+  external double a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct32BytesHomogeneousDouble extends Struct {
+  @Double()
+  external double a0;
+
+  @Double()
+  external double a1;
+
+  @Double()
+  external double a2;
+
+  @Double()
+  external double a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct40BytesHomogeneousDouble extends Struct {
+  @Double()
+  external double a0;
+
+  @Double()
+  external double a1;
+
+  @Double()
+  external double a2;
+
+  @Double()
+  external double a3;
+
+  @Double()
+  external double a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct1024BytesHomogeneousUint64 extends Struct {
+  @Uint64()
+  external int a0;
+
+  @Uint64()
+  external int a1;
+
+  @Uint64()
+  external int a2;
+
+  @Uint64()
+  external int a3;
+
+  @Uint64()
+  external int a4;
+
+  @Uint64()
+  external int a5;
+
+  @Uint64()
+  external int a6;
+
+  @Uint64()
+  external int a7;
+
+  @Uint64()
+  external int a8;
+
+  @Uint64()
+  external int a9;
+
+  @Uint64()
+  external int a10;
+
+  @Uint64()
+  external int a11;
+
+  @Uint64()
+  external int a12;
+
+  @Uint64()
+  external int a13;
+
+  @Uint64()
+  external int a14;
+
+  @Uint64()
+  external int a15;
+
+  @Uint64()
+  external int a16;
+
+  @Uint64()
+  external int a17;
+
+  @Uint64()
+  external int a18;
+
+  @Uint64()
+  external int a19;
+
+  @Uint64()
+  external int a20;
+
+  @Uint64()
+  external int a21;
+
+  @Uint64()
+  external int a22;
+
+  @Uint64()
+  external int a23;
+
+  @Uint64()
+  external int a24;
+
+  @Uint64()
+  external int a25;
+
+  @Uint64()
+  external int a26;
+
+  @Uint64()
+  external int a27;
+
+  @Uint64()
+  external int a28;
+
+  @Uint64()
+  external int a29;
+
+  @Uint64()
+  external int a30;
+
+  @Uint64()
+  external int a31;
+
+  @Uint64()
+  external int a32;
+
+  @Uint64()
+  external int a33;
+
+  @Uint64()
+  external int a34;
+
+  @Uint64()
+  external int a35;
+
+  @Uint64()
+  external int a36;
+
+  @Uint64()
+  external int a37;
+
+  @Uint64()
+  external int a38;
+
+  @Uint64()
+  external int a39;
+
+  @Uint64()
+  external int a40;
+
+  @Uint64()
+  external int a41;
+
+  @Uint64()
+  external int a42;
+
+  @Uint64()
+  external int a43;
+
+  @Uint64()
+  external int a44;
+
+  @Uint64()
+  external int a45;
+
+  @Uint64()
+  external int a46;
+
+  @Uint64()
+  external int a47;
+
+  @Uint64()
+  external int a48;
+
+  @Uint64()
+  external int a49;
+
+  @Uint64()
+  external int a50;
+
+  @Uint64()
+  external int a51;
+
+  @Uint64()
+  external int a52;
+
+  @Uint64()
+  external int a53;
+
+  @Uint64()
+  external int a54;
+
+  @Uint64()
+  external int a55;
+
+  @Uint64()
+  external int a56;
+
+  @Uint64()
+  external int a57;
+
+  @Uint64()
+  external int a58;
+
+  @Uint64()
+  external int a59;
+
+  @Uint64()
+  external int a60;
+
+  @Uint64()
+  external int a61;
+
+  @Uint64()
+  external int a62;
+
+  @Uint64()
+  external int a63;
+
+  @Uint64()
+  external int a64;
+
+  @Uint64()
+  external int a65;
+
+  @Uint64()
+  external int a66;
+
+  @Uint64()
+  external int a67;
+
+  @Uint64()
+  external int a68;
+
+  @Uint64()
+  external int a69;
+
+  @Uint64()
+  external int a70;
+
+  @Uint64()
+  external int a71;
+
+  @Uint64()
+  external int a72;
+
+  @Uint64()
+  external int a73;
+
+  @Uint64()
+  external int a74;
+
+  @Uint64()
+  external int a75;
+
+  @Uint64()
+  external int a76;
+
+  @Uint64()
+  external int a77;
+
+  @Uint64()
+  external int a78;
+
+  @Uint64()
+  external int a79;
+
+  @Uint64()
+  external int a80;
+
+  @Uint64()
+  external int a81;
+
+  @Uint64()
+  external int a82;
+
+  @Uint64()
+  external int a83;
+
+  @Uint64()
+  external int a84;
+
+  @Uint64()
+  external int a85;
+
+  @Uint64()
+  external int a86;
+
+  @Uint64()
+  external int a87;
+
+  @Uint64()
+  external int a88;
+
+  @Uint64()
+  external int a89;
+
+  @Uint64()
+  external int a90;
+
+  @Uint64()
+  external int a91;
+
+  @Uint64()
+  external int a92;
+
+  @Uint64()
+  external int a93;
+
+  @Uint64()
+  external int a94;
+
+  @Uint64()
+  external int a95;
+
+  @Uint64()
+  external int a96;
+
+  @Uint64()
+  external int a97;
+
+  @Uint64()
+  external int a98;
+
+  @Uint64()
+  external int a99;
+
+  @Uint64()
+  external int a100;
+
+  @Uint64()
+  external int a101;
+
+  @Uint64()
+  external int a102;
+
+  @Uint64()
+  external int a103;
+
+  @Uint64()
+  external int a104;
+
+  @Uint64()
+  external int a105;
+
+  @Uint64()
+  external int a106;
+
+  @Uint64()
+  external int a107;
+
+  @Uint64()
+  external int a108;
+
+  @Uint64()
+  external int a109;
+
+  @Uint64()
+  external int a110;
+
+  @Uint64()
+  external int a111;
+
+  @Uint64()
+  external int a112;
+
+  @Uint64()
+  external int a113;
+
+  @Uint64()
+  external int a114;
+
+  @Uint64()
+  external int a115;
+
+  @Uint64()
+  external int a116;
+
+  @Uint64()
+  external int a117;
+
+  @Uint64()
+  external int a118;
+
+  @Uint64()
+  external int a119;
+
+  @Uint64()
+  external int a120;
+
+  @Uint64()
+  external int a121;
+
+  @Uint64()
+  external int a122;
+
+  @Uint64()
+  external int a123;
+
+  @Uint64()
+  external int a124;
+
+  @Uint64()
+  external int a125;
+
+  @Uint64()
+  external int a126;
+
+  @Uint64()
+  external int a127;
+
+  String toString() =>
+      "(${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})";
+}
+
+class StructAlignmentInt16 extends Struct {
+  @Int8()
+  external int a0;
+
+  @Int16()
+  external int a1;
+
+  @Int8()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class StructAlignmentInt32 extends Struct {
+  @Int8()
+  external int a0;
+
+  @Int32()
+  external int a1;
+
+  @Int8()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class StructAlignmentInt64 extends Struct {
+  @Int8()
+  external int a0;
+
+  @Int64()
+  external int a1;
+
+  @Int8()
+  external int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+final passStruct1ByteIntx10 = 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");
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct1ByteIntx10() {
+  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a1 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a2 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a3 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a4 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a5 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a6 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a7 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a9 = allocate<Struct1ByteInt>().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 = passStruct1ByteIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(5, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct3BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt),
+    int Function(
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt)>("PassStruct3BytesIntx10");
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesIntx10() {
+  Struct3BytesInt a0 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a1 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a2 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a3 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a4 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a5 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a6 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a7 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a8 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a9 = allocate<Struct3BytesInt>().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 = passStruct3BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct4BytesHomogeneousInt16x10 = 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");
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct4BytesHomogeneousInt16x10() {
+  Struct4BytesHomogeneousInt16 a0 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a2 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a3 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a4 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a5 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a6 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a7 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a8 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a9 =
+      allocate<Struct4BytesHomogeneousInt16>().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 = passStruct4BytesHomogeneousInt16x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct7BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt),
+    int Function(
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt)>("PassStruct7BytesIntx10");
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesIntx10() {
+  Struct7BytesInt a0 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a1 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a2 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a3 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a4 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a5 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a6 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a7 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a8 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a9 = allocate<Struct7BytesInt>().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 = passStruct7BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesIntx10 = 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");
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesIntx10() {
+  Struct8BytesInt a0 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a1 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a2 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a3 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a4 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a5 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a6 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a7 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a8 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a9 = allocate<Struct8BytesInt>().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 = passStruct8BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesHomogeneousFloatx10 = 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");
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesHomogeneousFloatx10() {
+  Struct8BytesHomogeneousFloat a0 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a1 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a2 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a3 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a4 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a5 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a6 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a7 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a8 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a9 =
+      allocate<Struct8BytesHomogeneousFloat>().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 = passStruct8BytesHomogeneousFloatx10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesMixedx10 = 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");
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesMixedx10() {
+  Struct8BytesMixed a0 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a1 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a2 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a3 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a4 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a5 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a6 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a7 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a8 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a9 = allocate<Struct8BytesMixed>().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 =
+      passStruct8BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(15.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct9BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt),
+    int Function(
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt)>("PassStruct9BytesIntx10");
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+void testPassStruct9BytesIntx10() {
+  Struct9BytesInt a0 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a1 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a2 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a3 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a4 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a5 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a6 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a7 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a8 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a9 = allocate<Struct9BytesInt>().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 = passStruct9BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct9BytesHomogeneousUint82x10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82),
+    int Function(
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82)>("PassStruct9BytesHomogeneousUint82x10");
+
+/// 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.
+///
+void testPassStruct9BytesHomogeneousUint82x10() {
+  Struct9BytesHomogeneousUint82 a0 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a1 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a2 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a3 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a4 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a5 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a6 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a7 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a8 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a9 =
+      allocate<Struct9BytesHomogeneousUint82>().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 = passStruct9BytesHomogeneousUint82x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(4095, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct12BytesHomogeneousFloatx6 = ffiTestFunctions.lookupFunction<
+    Float Function(
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat),
+    double Function(
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat)>("PassStruct12BytesHomogeneousFloatx6");
+
+/// 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 testPassStruct12BytesHomogeneousFloatx6() {
+  Struct12BytesHomogeneousFloat a0 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a1 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a2 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a3 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a4 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a5 =
+      allocate<Struct12BytesHomogeneousFloat>().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 = passStruct12BytesHomogeneousFloatx6(a0, a1, a2, a3, a4, a5);
+
+  print("result = $result");
+
+  Expect.approxEquals(9.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+}
+
+final passStruct16BytesHomogeneousFloatx5 = ffiTestFunctions.lookupFunction<
+    Float Function(
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat),
+    double Function(
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat)>("PassStruct16BytesHomogeneousFloatx5");
+
+/// 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 testPassStruct16BytesHomogeneousFloatx5() {
+  Struct16BytesHomogeneousFloat a0 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a1 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a2 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a3 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a4 =
+      allocate<Struct16BytesHomogeneousFloat>().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 = passStruct16BytesHomogeneousFloatx5(a0, a1, a2, a3, a4);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+}
+
+final passStruct16BytesMixedx10 = 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");
+
+/// 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 testPassStruct16BytesMixedx10() {
+  Struct16BytesMixed a0 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a2 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().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 =
+      passStruct16BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct16BytesMixed2x10 = 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");
+
+/// 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 testPassStruct16BytesMixed2x10() {
+  Struct16BytesMixed2 a0 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a1 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a2 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a3 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a4 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a5 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a6 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a7 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a8 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a9 = allocate<Struct16BytesMixed2>().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 =
+      passStruct16BytesMixed2x10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(20.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct17BytesIntx10 = 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");
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+void testPassStruct17BytesIntx10() {
+  Struct17BytesInt a0 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a1 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a2 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a3 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a4 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a5 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a6 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a7 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a8 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a9 = allocate<Struct17BytesInt>().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 =
+      passStruct17BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct19BytesHomogeneousUint8x10 = 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");
+
+/// 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 testPassStruct19BytesHomogeneousUint8x10() {
+  Struct19BytesHomogeneousUint8 a0 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a1 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a2 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a3 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a4 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a5 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a6 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a7 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a8 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a9 =
+      allocate<Struct19BytesHomogeneousUint8>().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 = passStruct19BytesHomogeneousUint8x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(18145, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct20BytesHomogeneousInt32x10 = 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");
+
+/// 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 testPassStruct20BytesHomogeneousInt32x10() {
+  Struct20BytesHomogeneousInt32 a0 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a1 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a2 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a3 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a4 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a5 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a6 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a7 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a8 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a9 =
+      allocate<Struct20BytesHomogeneousInt32>().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 = passStruct20BytesHomogeneousInt32x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(25, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Float Function(Struct20BytesHomogeneousFloat),
+    double Function(
+        Struct20BytesHomogeneousFloat)>("PassStruct20BytesHomogeneousFloat");
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+void testPassStruct20BytesHomogeneousFloat() {
+  Struct20BytesHomogeneousFloat a0 =
+      allocate<Struct20BytesHomogeneousFloat>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  final result = passStruct20BytesHomogeneousFloat(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(-3.0, result);
+
+  free(a0.addressOf);
+}
+
+final passStruct32BytesHomogeneousDoublex5 = ffiTestFunctions.lookupFunction<
+        Double Function(
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble),
+        double Function(
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble)>(
+    "PassStruct32BytesHomogeneousDoublex5");
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct32BytesHomogeneousDoublex5() {
+  Struct32BytesHomogeneousDouble a0 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a1 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a2 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a3 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a4 =
+      allocate<Struct32BytesHomogeneousDouble>().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 = passStruct32BytesHomogeneousDoublex5(a0, a1, a2, a3, a4);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+}
+
+final passStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Double Function(Struct40BytesHomogeneousDouble),
+    double Function(
+        Struct40BytesHomogeneousDouble)>("PassStruct40BytesHomogeneousDouble");
+
+/// Argument too big to go into FPU registers in arm64.
+void testPassStruct40BytesHomogeneousDouble() {
+  Struct40BytesHomogeneousDouble a0 =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  final result = passStruct40BytesHomogeneousDouble(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(-3.0, result);
+
+  free(a0.addressOf);
+}
+
+final passStruct1024BytesHomogeneousUint64 = ffiTestFunctions.lookupFunction<
+        Uint64 Function(Struct1024BytesHomogeneousUint64),
+        int Function(Struct1024BytesHomogeneousUint64)>(
+    "PassStruct1024BytesHomogeneousUint64");
+
+/// Test 1kb struct.
+void testPassStruct1024BytesHomogeneousUint64() {
+  Struct1024BytesHomogeneousUint64 a0 =
+      allocate<Struct1024BytesHomogeneousUint64>().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 = passStruct1024BytesHomogeneousUint64(a0);
+
+  print("result = $result");
+
+  Expect.equals(8256, result);
+
+  free(a0.addressOf);
+}
+
+final passFloatStruct16BytesHomogeneousFloatFloatStruct1 =
+    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");
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1() {
+  double a0;
+  Struct16BytesHomogeneousFloat a1 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a2;
+  Struct16BytesHomogeneousFloat a3 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a4;
+  Struct16BytesHomogeneousFloat a5 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a6;
+  Struct16BytesHomogeneousFloat a7 =
+      allocate<Struct16BytesHomogeneousFloat>().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 = passFloatStruct16BytesHomogeneousFloatFloatStruct1(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-11.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passFloatStruct32BytesHomogeneousDoubleFloatStruct =
+    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");
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct32BytesHomogeneousDoubleFloatStruct() {
+  double a0;
+  Struct32BytesHomogeneousDouble a1 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a2;
+  Struct32BytesHomogeneousDouble a3 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a4;
+  Struct32BytesHomogeneousDouble a5 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a6;
+  Struct32BytesHomogeneousDouble a7 =
+      allocate<Struct32BytesHomogeneousDouble>().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 = passFloatStruct32BytesHomogeneousDoubleFloatStruct(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-11.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passInt8Struct16BytesMixedInt8Struct16BytesMixedIn =
+    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");
+
+/// 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 testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn() {
+  int a0;
+  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  int a2;
+  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  int a4;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  int a6;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().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 = passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-7.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passDoublex6Struct16BytesMixedx4Int32 = 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");
+
+/// 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 testPassDoublex6Struct16BytesMixedx4Int32() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+  double a4;
+  double a5;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().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 = passDoublex6Struct16BytesMixedx4Int32(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+  print("result = $result");
+
+  Expect.approxEquals(-8.0, result);
+
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passInt32x4Struct16BytesMixedx4Double = 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");
+
+/// 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 testPassInt32x4Struct16BytesMixedx4Double() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().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 =
+      passInt32x4Struct16BytesMixedx4Double(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-7.0, result);
+
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+}
+
+final passStruct40BytesHomogeneousDoubleStruct4BytesHomo =
+    ffiTestFunctions.lookupFunction<
+            Double Function(Struct40BytesHomogeneousDouble,
+                Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat),
+            double Function(Struct40BytesHomogeneousDouble,
+                Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat)>(
+        "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo");
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo() {
+  Struct40BytesHomogeneousDouble a0 =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+  Struct4BytesHomogeneousInt16 a1 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct8BytesHomogeneousFloat a2 =
+      allocate<Struct8BytesHomogeneousFloat>().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 = passStruct40BytesHomogeneousDoubleStruct4BytesHomo(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(-5.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+}
+
+final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt16),
+    int Function(StructAlignmentInt16)>("PassStructAlignmentInt16");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassStructAlignmentInt16() {
+  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt16(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final passStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt32),
+    int Function(StructAlignmentInt32)>("PassStructAlignmentInt32");
+
+/// Test alignment and padding of 32 byte int within struct.
+void testPassStructAlignmentInt32() {
+  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt32(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final passStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt64),
+    int Function(StructAlignmentInt64)>("PassStructAlignmentInt64");
+
+/// Test alignment and padding of 64 byte int within struct.
+void testPassStructAlignmentInt64() {
+  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt64(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
+    Struct1ByteInt Function(Int8),
+    Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
+
+/// Smallest struct with data.
+void testReturnStruct1ByteInt() {
+  int a0;
+
+  a0 = -1;
+
+  final result = returnStruct1ByteInt(a0);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+}
+
+final returnStruct3BytesInt = ffiTestFunctions.lookupFunction<
+    Struct3BytesInt Function(Int16, Int8),
+    Struct3BytesInt Function(int, int)>("ReturnStruct3BytesInt");
+
+/// Smaller than word size return value on all architectures.
+void testReturnStruct3BytesInt() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct3BytesInt(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct4BytesHomogeneousInt16 = ffiTestFunctions.lookupFunction<
+    Struct4BytesHomogeneousInt16 Function(Int16, Int16),
+    Struct4BytesHomogeneousInt16 Function(
+        int, int)>("ReturnStruct4BytesHomogeneousInt16");
+
+/// Word size return value on 32 bit architectures..
+void testReturnStruct4BytesHomogeneousInt16() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct4BytesHomogeneousInt16(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct7BytesInt = ffiTestFunctions.lookupFunction<
+    Struct7BytesInt Function(Int32, Int16, Int8),
+    Struct7BytesInt Function(int, int, int)>("ReturnStruct7BytesInt");
+
+/// Non-wordsize return value.
+void testReturnStruct7BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct7BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesInt = ffiTestFunctions.lookupFunction<
+    Struct8BytesInt Function(Int16, Int16, Int32),
+    Struct8BytesInt Function(int, int, int)>("ReturnStruct8BytesInt");
+
+/// Return value in integer registers on many architectures.
+void testReturnStruct8BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct8BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct8BytesHomogeneousFloat Function(Float, Float),
+    Struct8BytesHomogeneousFloat Function(
+        double, double)>("ReturnStruct8BytesHomogeneousFloat");
+
+/// Return value in FP registers on many architectures.
+void testReturnStruct8BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+
+  a0 = -1.0;
+  a1 = 2.0;
+
+  final result = returnStruct8BytesHomogeneousFloat(a0, a1);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.approxEquals(a1, result.a1);
+}
+
+final returnStruct8BytesMixed = ffiTestFunctions.lookupFunction<
+    Struct8BytesMixed Function(Float, Int16, Int16),
+    Struct8BytesMixed Function(double, int, int)>("ReturnStruct8BytesMixed");
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct8BytesMixed() {
+  double a0;
+  int a1;
+  int a2;
+
+  a0 = -1.0;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct8BytesMixed(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct9BytesInt = ffiTestFunctions.lookupFunction<
+    Struct9BytesInt Function(Int64, Int8),
+    Struct9BytesInt Function(int, int)>("ReturnStruct9BytesInt");
+
+/// Return value in two integer registers on x64.
+/// The second register only contains a single byte.
+void testReturnStruct9BytesInt() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct9BytesInt(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct9BytesHomogeneousUint82 = ffiTestFunctions.lookupFunction<
+    Struct9BytesHomogeneousUint82 Function(
+        Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+    Struct9BytesHomogeneousUint82 Function(int, int, int, int, int, int, int,
+        int, int)>("ReturnStruct9BytesHomogeneousUint82");
+
+/// 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 testReturnStruct9BytesHomogeneousUint82() {
+  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 =
+      returnStruct9BytesHomogeneousUint82(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 returnStruct12BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct12BytesHomogeneousFloat Function(Float, Float, Float),
+    Struct12BytesHomogeneousFloat Function(
+        double, double, double)>("ReturnStruct12BytesHomogeneousFloat");
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+void testReturnStruct12BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+  double a2;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+
+  final result = returnStruct12BytesHomogeneousFloat(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.approxEquals(a1, result.a1);
+  Expect.approxEquals(a2, result.a2);
+}
+
+final returnStruct16BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct16BytesHomogeneousFloat Function(Float, Float, Float, Float),
+    Struct16BytesHomogeneousFloat Function(
+        double, double, double, double)>("ReturnStruct16BytesHomogeneousFloat");
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStruct16BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  final result = returnStruct16BytesHomogeneousFloat(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 returnStruct16BytesMixed = ffiTestFunctions.lookupFunction<
+    Struct16BytesMixed Function(Double, Int64),
+    Struct16BytesMixed Function(double, int)>("ReturnStruct16BytesMixed");
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct16BytesMixed() {
+  double a0;
+  int a1;
+
+  a0 = -1.0;
+  a1 = 2;
+
+  final result = returnStruct16BytesMixed(a0, a1);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct16BytesMixed2 = ffiTestFunctions.lookupFunction<
+    Struct16BytesMixed2 Function(Float, Float, Float, Int32),
+    Struct16BytesMixed2 Function(
+        double, double, double, int)>("ReturnStruct16BytesMixed2");
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+void testReturnStruct16BytesMixed2() {
+  double a0;
+  double a1;
+  double a2;
+  int a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4;
+
+  final result = returnStruct16BytesMixed2(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 returnStruct17BytesInt = ffiTestFunctions.lookupFunction<
+    Struct17BytesInt Function(Int64, Int64, Int8),
+    Struct17BytesInt Function(int, int, int)>("ReturnStruct17BytesInt");
+
+/// 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 testReturnStruct17BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct17BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct19BytesHomogeneousUint8 = 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");
+
+/// 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 testReturnStruct19BytesHomogeneousUint8() {
+  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 = returnStruct19BytesHomogeneousUint8(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 returnStruct20BytesHomogeneousInt32 = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32),
+    Struct20BytesHomogeneousInt32 Function(
+        int, int, int, int, int)>("ReturnStruct20BytesHomogeneousInt32");
+
+/// Return value too big to go in cpu registers on arm64.
+void testReturnStruct20BytesHomogeneousInt32() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+
+  final result = returnStruct20BytesHomogeneousInt32(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 returnStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousFloat Function(Float, Float, Float, Float, Float),
+    Struct20BytesHomogeneousFloat Function(double, double, double, double,
+        double)>("ReturnStruct20BytesHomogeneousFloat");
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+void testReturnStruct20BytesHomogeneousFloat() {
+  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 = returnStruct20BytesHomogeneousFloat(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 returnStruct32BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double),
+    Struct32BytesHomogeneousDouble Function(double, double, double,
+        double)>("ReturnStruct32BytesHomogeneousDouble");
+
+/// Return value in FPU registers on arm64.
+void testReturnStruct32BytesHomogeneousDouble() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  final result = returnStruct32BytesHomogeneousDouble(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 returnStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Struct40BytesHomogeneousDouble Function(
+        Double, Double, Double, Double, Double),
+    Struct40BytesHomogeneousDouble Function(double, double, double, double,
+        double)>("ReturnStruct40BytesHomogeneousDouble");
+
+/// Return value too big to go in FPU registers on arm64.
+void testReturnStruct40BytesHomogeneousDouble() {
+  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 = returnStruct40BytesHomogeneousDouble(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 returnStruct1024BytesHomogeneousUint64 = 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");
+
+/// Test 1kb struct.
+void testReturnStruct1024BytesHomogeneousUint64() {
+  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 = returnStruct1024BytesHomogeneousUint64(
+      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 returnStructArgumentStruct1ByteInt = ffiTestFunctions.lookupFunction<
+    Struct1ByteInt Function(Struct1ByteInt),
+    Struct1ByteInt Function(
+        Struct1ByteInt)>("ReturnStructArgumentStruct1ByteInt");
+
+/// 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 testReturnStructArgumentStruct1ByteInt() {
+  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+
+  a0.a0 = -1;
+
+  final result = returnStructArgumentStruct1ByteInt(a0);
+
+  print("result = $result");
+
+  Expect.equals(a0.a0, result.a0);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentInt32x8Struct1ByteInt =
+    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");
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+void testReturnStructArgumentInt32x8Struct1ByteInt() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+  a5 = 6;
+  a6 = -7;
+  a7 = 8;
+  a8.a0 = -9;
+
+  final result = returnStructArgumentInt32x8Struct1ByteInt(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.equals(a8.a0, result.a0);
+
+  free(a8.addressOf);
+}
+
+final returnStructArgumentStruct8BytesHomogeneousFloat =
+    ffiTestFunctions.lookupFunction<
+            Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat),
+            Struct8BytesHomogeneousFloat Function(
+                Struct8BytesHomogeneousFloat)>(
+        "ReturnStructArgumentStruct8BytesHomogeneousFloat");
+
+/// 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 testReturnStructArgumentStruct8BytesHomogeneousFloat() {
+  Struct8BytesHomogeneousFloat a0 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+
+  final result = returnStructArgumentStruct8BytesHomogeneousFloat(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0.a0, result.a0);
+  Expect.approxEquals(a0.a1, result.a1);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentStruct20BytesHomogeneousInt32 =
+    ffiTestFunctions
+        .lookupFunction<
+                Struct20BytesHomogeneousInt32 Function(
+                    Struct20BytesHomogeneousInt32),
+                Struct20BytesHomogeneousInt32 Function(
+                    Struct20BytesHomogeneousInt32)>(
+            "ReturnStructArgumentStruct20BytesHomogeneousInt32");
+
+/// On arm64, both argument and return value are passed in by pointer.
+void testReturnStructArgumentStruct20BytesHomogeneousInt32() {
+  Struct20BytesHomogeneousInt32 a0 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+  a0.a3 = 4;
+  a0.a4 = -5;
+
+  final result = returnStructArgumentStruct20BytesHomogeneousInt32(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);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentInt32x8Struct20BytesHomogeneou =
+    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");
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+void testReturnStructArgumentInt32x8Struct20BytesHomogeneou() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  Struct20BytesHomogeneousInt32 a8 =
+      allocate<Struct20BytesHomogeneousInt32>().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 = returnStructArgumentInt32x8Struct20BytesHomogeneou(
+      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);
+
+  free(a8.addressOf);
+}
+
+final returnStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt16 Function(Int8, Int16, Int8),
+    StructAlignmentInt16 Function(int, int, int)>("ReturnStructAlignmentInt16");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testReturnStructAlignmentInt16() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt16(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt32 Function(Int8, Int32, Int8),
+    StructAlignmentInt32 Function(int, int, int)>("ReturnStructAlignmentInt32");
+
+/// Test alignment and padding of 32 byte int within struct.
+void testReturnStructAlignmentInt32() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt32(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt64 Function(Int8, Int64, Int8),
+    StructAlignmentInt64 Function(int, int, int)>("ReturnStructAlignmentInt64");
+
+/// Test alignment and padding of 64 byte int within struct.
+void testReturnStructAlignmentInt64() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt64(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
diff --git a/tests/ffi/generator/c_types.dart b/tests/ffi/generator/c_types.dart
new file mode 100644
index 0000000..f2948fa
--- /dev/null
+++ b/tests/ffi/generator/c_types.dart
@@ -0,0 +1,299 @@
+// Copyright (c) 2020, 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 'utils.dart';
+
+const int8 = FundamentalType(PrimitiveType.int8);
+const int16 = FundamentalType(PrimitiveType.int16);
+const int32 = FundamentalType(PrimitiveType.int32);
+const int64 = FundamentalType(PrimitiveType.int64);
+const uint8 = FundamentalType(PrimitiveType.uint8);
+const uint16 = FundamentalType(PrimitiveType.uint16);
+const uint32 = FundamentalType(PrimitiveType.uint32);
+const uint64 = FundamentalType(PrimitiveType.uint64);
+const intptr = FundamentalType(PrimitiveType.intptr);
+const float = FundamentalType(PrimitiveType.float);
+const double_ = FundamentalType(PrimitiveType.double_);
+
+enum PrimitiveType {
+  int8,
+  int16,
+  int32,
+  int64,
+  uint8,
+  uint16,
+  uint32,
+  uint64,
+  intptr,
+  float,
+  double_,
+}
+
+const primitiveNames = [
+  "int8",
+  "int16",
+  "int32",
+  "int64",
+  "uint8",
+  "uint16",
+  "uint32",
+  "uint64",
+  "intptr",
+  "float",
+  "double",
+];
+
+const intptrSize = -1;
+const primitiveSizesInBytes = [1, 2, 4, 8, 1, 2, 4, 8, intptrSize, 4, 8];
+
+abstract class CType {
+  String get cType;
+  String get dartCType;
+  String get dartType;
+  String get dartStructFieldAnnotation;
+
+  /// Has a known [size] that is the same for all architectures.
+  bool get hasSize;
+
+  /// Get a size in bytes that is the same on all architectures.
+  int get size;
+
+  String toString() => dartCType;
+
+  const CType();
+}
+
+class FundamentalType extends CType {
+  final PrimitiveType primitive;
+
+  const FundamentalType(this.primitive);
+
+  bool get isFloatingPoint =>
+      primitive == PrimitiveType.float || primitive == PrimitiveType.double_;
+  bool get isInteger => !isFloatingPoint;
+  bool get isUnsigned =>
+      primitive == PrimitiveType.uint8 ||
+      primitive == PrimitiveType.uint16 ||
+      primitive == PrimitiveType.uint32 ||
+      primitive == PrimitiveType.uint64;
+  bool get isSigned => !isUnsigned;
+
+  String get name => primitiveNames[primitive.index];
+
+  String get cType => "${name}${isInteger ? "_t" : ""}";
+  String get dartCType => name.upperCaseFirst();
+  String get dartType => isInteger ? "int" : "double";
+  String get dartStructFieldAnnotation => "@${dartCType}()";
+  bool get hasSize => primitive != PrimitiveType.intptr;
+  int get size {
+    if (!hasSize) {
+      throw "Size unknown.";
+    }
+    return primitiveSizesInBytes[primitive.index];
+  }
+}
+
+class PointerType extends CType {
+  final CType pointerTo;
+
+  PointerType(this.pointerTo);
+
+  String get cType => "${pointerTo.cType}*";
+  String get dartCType => "Pointer<${pointerTo.dartCType}>";
+  String get dartType => "Pointer<${pointerTo.dartType}>";
+  String get dartStructFieldAnnotation => "";
+  bool get hasSize => false;
+  int get size => throw "Size unknown";
+}
+
+/// Used to give [StructType] fields and [FunctionType] arguments names.
+class Member {
+  final CType type;
+  final String name;
+
+  Member(this.type, this.name);
+
+  String dartStructField(bool nnbd) {
+    final modifier = nnbd ? "external" : "";
+    return "${type.dartStructFieldAnnotation} $modifier ${type.dartType} $name;";
+  }
+
+  String get cStructField => "${type.cType} $name;";
+
+  String toString() => "$type $name";
+}
+
+List<Member> generateMemberNames(List<CType> memberTypes) {
+  int index = 0;
+  List<Member> result = [];
+  for (final type in memberTypes) {
+    result.add(Member(type, "a$index"));
+    index++;
+  }
+  return result;
+}
+
+class StructType extends CType {
+  final List<Member> members;
+
+  /// To disambiguate same size structs.
+  final String suffix;
+
+  StructType(List<CType> memberTypes)
+      : this.members = generateMemberNames(memberTypes),
+        this.suffix = "";
+  StructType.disambiguate(List<CType> memberTypes, this.suffix)
+      : this.members = generateMemberNames(memberTypes);
+
+  List<CType> get memberTypes => members.map((a) => a.type).toList();
+
+  String get cType => name;
+  String get dartCType => name;
+  String get dartType => name;
+  String get dartStructFieldAnnotation => "";
+
+  bool get hasSize =>
+      !memberTypes.map((e) => e.hasSize).contains(false) && !hasPadding;
+  int get size => memberTypes.fold(0, (int acc, e) => acc + e.size);
+
+  /// Rough approximation, to not redo all ABI logic here.
+  bool get hasPadding =>
+      members.length < 2 ? false : members[0].type.size < members[1].type.size;
+
+  bool get hasNestedStructs =>
+      members.map((e) => e.type is StructType).contains(true);
+
+  /// All members have the same type.
+  bool get isHomogeneous => memberTypes.toSet().length == 1;
+
+  /// All members have a floating point type.
+  bool get isOnlyFloatingPoint => !memberTypes.map((e) {
+        if (e is FundamentalType) {
+          return e.isFloatingPoint;
+        }
+        if (e is StructType) {
+          return e.isOnlyFloatingPoint;
+        }
+      }).contains(false);
+
+  /// All members have a integer type.
+  bool get isOnlyInteger => !memberTypes.map((e) {
+        if (e is FundamentalType) {
+          return e.isInteger;
+        }
+        if (e is StructType) {
+          return e.isOnlyInteger;
+        }
+      }).contains(false);
+
+  bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
+
+  String get name {
+    String result = "Struct";
+    if (hasSize) {
+      result += "${size}Byte" + (size != 1 ? "s" : "");
+    }
+    if (hasNestedStructs) {
+      result += "Nested";
+    }
+    if (members.length == 0) {
+      // No suffix.
+    } else if (hasPadding) {
+      result += "Alignment${memberTypes[1].dartCType}";
+    } else if (isHomogeneous && members.length > 1 && !hasNestedStructs) {
+      result += "Homogeneous${memberTypes.first.dartCType}";
+    } else if (isOnlyFloatingPoint) {
+      result += "Float";
+    } else if (isOnlyInteger) {
+      result += "Int";
+    } else {
+      result += "Mixed";
+    }
+    result += suffix;
+    return result;
+  }
+}
+
+class FunctionType extends CType {
+  final List<Member> arguments;
+  final CType returnValue;
+  final String reason;
+
+  List<CType> get argumentTypes => arguments.map((a) => a.type).toList();
+
+  FunctionType(List<CType> argumentTypes, this.returnValue, this.reason)
+      : this.arguments = generateMemberNames(argumentTypes);
+
+  String get cType =>
+      throw "Are not represented without function or variable name in C.";
+
+  String get dartCType {
+    final argumentsDartCType = argumentTypes.map((e) => e.dartCType).join(", ");
+    return "${returnValue.dartCType} Function($argumentsDartCType)";
+  }
+
+  String get dartType {
+    final argumentsDartType = argumentTypes.map((e) => e.dartType).join(", ");
+    return "${returnValue.dartType} Function($argumentsDartType)";
+  }
+
+  String get dartStructFieldAnnotation => throw "No nested function pointers.";
+
+  bool get hasSize => false;
+  int get size => throw "Unknown size.";
+
+  /// Group consecutive [arguments] by same type.
+  ///
+  /// Used for naming.
+  List<List<Member>> get argumentsGrouped {
+    List<List<Member>> result = [];
+    for (final a in arguments) {
+      if (result.isEmpty) {
+        result.add([a]);
+      } else if (result.last.first.type.dartCType == a.type.dartCType) {
+        result.last.add(a);
+      } else {
+        result.add([a]);
+      }
+    }
+    return result;
+  }
+
+  /// A suitable name based on the signature.
+  String get cName {
+    String result = "";
+    if (arguments.containsStructs && returnValue is FundamentalType) {
+      result = "Pass";
+    } else if (returnValue is StructType &&
+        argumentTypes.contains(returnValue)) {
+      result = "ReturnStructArgument";
+    } else if (returnValue is StructType) {
+      if (arguments.length == (returnValue as StructType).members.length) {
+        return "Return${returnValue.dartCType}";
+      }
+    } else {
+      result = "Uncategorized";
+    }
+
+    for (final group in argumentsGrouped) {
+      result += group.first.type.dartCType;
+      if (group.length > 1) {
+        result += "x${group.length}";
+      }
+    }
+    return result.limitTo(50);
+  }
+
+  String get dartTestName => "test$cName";
+
+  String get dartName => cName.lowerCaseFirst();
+
+  /// Only valid for [TestType.structReturnArgument].
+  Member get structReturnArgument =>
+      arguments.firstWhere((a) => a.type == returnValue);
+}
+
+extension MemberList on List<Member> {
+  bool get containsStructs => map((m) => m.type is StructType).contains(true);
+}
diff --git a/tests/ffi/generator/structs_by_value_tests_confguration.dart b/tests/ffi/generator/structs_by_value_tests_confguration.dart
new file mode 100644
index 0000000..487a68e
--- /dev/null
+++ b/tests/ffi/generator/structs_by_value_tests_confguration.dart
@@ -0,0 +1,373 @@
+// Copyright (c) 2020, 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 'c_types.dart';
+
+final functions = [
+  FunctionType(List.filled(10, struct1byteInt), int64, """
+Smallest struct with data.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct3bytesInt), int64, """
+Not a multiple of word size, not a power of two.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct4bytesInt), int64, """
+Exactly word size on 32-bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct7bytesInt), int64, """
+Sub word size on 64 bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8bytesInt), int64, """
+Exactly word size struct on 64bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8bytesFloat), float, """
+Arguments passed in FP registers as long as they fit.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8BytesMixed), float, """
+On x64, arguments go in int registers because it is not only float.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct9bytesInt), int64, """
+Argument is a single byte over a multiple of word size.
+10 struct arguments will exhaust available registers.
+Tests upper bytes in the integer registers that are partly filled.
+Tests stack alignment of non word size stack arguments."""),
+  FunctionType(List.filled(10, struct9bytesInt2), int64, """
+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.
+"""),
+  FunctionType(List.filled(6, struct12bytesFloat), float, """
+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."""),
+  FunctionType(List.filled(5, struct16bytesFloat), float, """
+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."""),
+  FunctionType(List.filled(10, struct16bytesMixed), double_, """
+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."""),
+  FunctionType(List.filled(10, struct16bytesMixed2), float, """
+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."""),
+  FunctionType(List.filled(10, struct17bytesInt), int64, """
+Arguments are passed as pointer to copy on arm64.
+Tests that the memory allocated for copies are rounded up to word size."""),
+  FunctionType(List.filled(10, struct19bytesInt), int64, """
+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.
+"""),
+  FunctionType(List.filled(10, struct20bytesInt), int32, """
+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."""),
+  FunctionType(
+      [struct20bytesFloat],
+      float,
+      """
+Argument too big to go into FPU registers in hardfp and arm64."""),
+  FunctionType(List.filled(5, struct32bytesDouble), double_, """
+Arguments in FPU registers on arm64.
+5 struct arguments will exhaust available registers."""),
+  FunctionType(
+      [struct40bytesDouble],
+      double_,
+      """
+Argument too big to go into FPU registers in arm64."""),
+  FunctionType(
+      [struct1024bytesInt],
+      uint64,
+      """
+Test 1kb struct."""),
+  FunctionType(
+      [
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float
+      ],
+      float,
+      """
+Tests the alignment of structs in FPU registers and backfilling."""),
+  FunctionType(
+      [
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float
+      ],
+      double_,
+      """
+Tests the alignment of structs in FPU registers and backfilling."""),
+  FunctionType(
+      [
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        int32,
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        int32,
+        int32,
+        int32,
+        int32,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        double_,
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        struct40bytesDouble,
+        struct4bytesInt,
+        struct8bytesFloat,
+      ],
+      double_,
+      """
+On various architectures, first struct is allocated on stack.
+Check that the other two arguments are allocated on registers."""),
+  FunctionType(
+      [structAlignmentInt16],
+      int64,
+      """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(
+      [structAlignmentInt32],
+      int64,
+      """
+Test alignment and padding of 32 byte int within struct."""),
+  FunctionType(
+      [structAlignmentInt64],
+      int64,
+      """
+Test alignment and padding of 64 byte int within struct."""),
+  FunctionType(struct1byteInt.memberTypes, struct1byteInt, """
+Smallest struct with data."""),
+  FunctionType(struct3bytesInt.memberTypes, struct3bytesInt, """
+Smaller than word size return value on all architectures."""),
+  FunctionType(struct4bytesInt.memberTypes, struct4bytesInt, """
+Word size return value on 32 bit architectures.."""),
+  FunctionType(struct7bytesInt.memberTypes, struct7bytesInt, """
+Non-wordsize return value."""),
+  FunctionType(struct8bytesInt.memberTypes, struct8bytesInt, """
+Return value in integer registers on many architectures."""),
+  FunctionType(struct8bytesFloat.memberTypes, struct8bytesFloat, """
+Return value in FP registers on many architectures."""),
+  FunctionType(struct8BytesMixed.memberTypes, struct8BytesMixed, """
+Return value split over FP and integer register in x64."""),
+  FunctionType(struct9bytesInt.memberTypes, struct9bytesInt, """
+Return value in two integer registers on x64.
+The second register only contains a single byte."""),
+  FunctionType(struct9bytesInt2.memberTypes, struct9bytesInt2, """
+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."""),
+  FunctionType(struct12bytesFloat.memberTypes, struct12bytesFloat, """
+Return value in FPU registers, but does not use all registers on arm hardfp
+and arm64."""),
+  FunctionType(struct16bytesFloat.memberTypes, struct16bytesFloat, """
+Return value in FPU registers on arm hardfp and arm64."""),
+  FunctionType(struct16bytesMixed.memberTypes, struct16bytesMixed, """
+Return value split over FP and integer register in x64."""),
+  FunctionType(struct16bytesMixed2.memberTypes, struct16bytesMixed2, """
+Return value split over FP and integer register in x64.
+The integer register contains half float half int."""),
+  FunctionType(struct17bytesInt.memberTypes, struct17bytesInt, """
+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."""),
+  FunctionType(struct19bytesInt.memberTypes, struct19bytesInt, """
+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."""),
+  FunctionType(struct20bytesInt.memberTypes, struct20bytesInt, """
+Return value too big to go in cpu registers on arm64."""),
+  FunctionType(struct20bytesFloat.memberTypes, struct20bytesFloat, """
+Return value too big to go in FPU registers on x64, arm hardfp and arm64."""),
+  FunctionType(struct32bytesDouble.memberTypes, struct32bytesDouble, """
+Return value in FPU registers on arm64."""),
+  FunctionType(struct40bytesDouble.memberTypes, struct40bytesDouble, """
+Return value too big to go in FPU registers on arm64."""),
+  FunctionType(struct1024bytesInt.memberTypes, struct1024bytesInt, """
+Test 1kb struct."""),
+  FunctionType(
+      [struct1byteInt],
+      struct1byteInt,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed in int registers in most ABIs."""),
+  FunctionType(
+      [int32, int32, int32, int32, int32, int32, int32, int32, struct1byteInt],
+      struct1byteInt,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed on stack on all ABIs."""),
+  FunctionType(
+      [struct8bytesFloat],
+      struct8bytesFloat,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed in float registers in most ABIs."""),
+  FunctionType(
+      [struct20bytesInt],
+      struct20bytesInt,
+      """
+On arm64, both argument and return value are passed in by pointer."""),
+  FunctionType(
+      [
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        struct20bytesInt
+      ],
+      struct20bytesInt,
+      """
+On arm64, both argument and return value are passed in by pointer.
+Ints exhaust registers, so that pointer is passed on stack."""),
+  FunctionType(structAlignmentInt16.memberTypes, structAlignmentInt16, """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(structAlignmentInt32.memberTypes, structAlignmentInt32, """
+Test alignment and padding of 32 byte int within struct."""),
+  FunctionType(structAlignmentInt64.memberTypes, structAlignmentInt64, """
+Test alignment and padding of 64 byte int within struct."""),
+];
+
+final structs = [
+  struct0bytes,
+  struct1byteInt,
+  struct3bytesInt,
+  struct4bytesInt,
+  struct7bytesInt,
+  struct8bytesInt,
+  struct8bytesFloat,
+  struct8BytesMixed,
+  struct9bytesInt,
+  struct9bytesInt2,
+  struct12bytesFloat,
+  struct16bytesFloat,
+  struct16bytesMixed,
+  struct16bytesMixed2,
+  struct17bytesInt,
+  struct19bytesInt,
+  struct20bytesInt,
+  struct20bytesFloat,
+  struct32bytesDouble,
+  struct40bytesDouble,
+  struct1024bytesInt,
+  structAlignmentInt16,
+  structAlignmentInt32,
+  structAlignmentInt64,
+];
+
+/// Using empty structs is undefined behavior in C.
+final struct0bytes = StructType([]);
+
+final struct1byteInt = StructType([int8]);
+final struct3bytesInt = StructType([int16, int8]);
+final struct4bytesInt = StructType([int16, int16]);
+final struct7bytesInt = StructType([int32, int16, int8]);
+final struct8bytesInt = StructType([int16, int16, int32]);
+final struct8bytesFloat = StructType([float, float]);
+final struct8BytesMixed = StructType([float, int16, int16]);
+final struct9bytesInt = StructType([int64, int8]);
+final struct9bytesInt2 = StructType.disambiguate(List.filled(9, uint8), "2");
+final struct12bytesFloat = StructType([float, float, float]);
+
+/// The largest homogenous float that goes into FPU registers on softfp and
+/// arm64.
+final struct16bytesFloat = StructType([float, float, float, float]);
+
+/// This struct will be 8 byte aligned on arm.
+final struct16bytesMixed = StructType([double_, int64]);
+
+/// This struct will be 4 byte aligned on arm.
+final struct16bytesMixed2 =
+    StructType.disambiguate([float, float, float, int32], "2");
+
+final struct17bytesInt = StructType([int64, int64, int8]);
+
+/// This struct has only 1 byte field-alignmnent requirements.
+final struct19bytesInt = StructType(List.filled(19, uint8));
+
+/// The first homogenous integer struct that does not go into registers
+/// anymore on arm64.
+final struct20bytesInt = StructType([int32, int32, int32, int32, int32]);
+
+/// The first homogenous float that does not go into FPU registers anymore on
+/// softfp and arm64.
+final struct20bytesFloat = StructType([float, float, float, float, float]);
+
+/// Largest homogenous doubles in arm64 that goes into FPU registers.
+final struct32bytesDouble = StructType([double_, double_, double_, double_]);
+
+/// The first homogenous doubles that does not go into FPU registers anymore on
+/// arm64.
+final struct40bytesDouble =
+    StructType([double_, double_, double_, double_, double_]);
+
+final struct1024bytesInt = StructType(List.filled(128, uint64));
+
+final structAlignmentInt16 = StructType([int8, int16, int8]);
+final structAlignmentInt32 = StructType([int8, int32, int8]);
+final structAlignmentInt64 = StructType([int8, int64, int8]);
diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart
new file mode 100644
index 0000000..e233753
--- /dev/null
+++ b/tests/ffi/generator/structs_by_value_tests_generator.dart
@@ -0,0 +1,930 @@
+// Copyright (c) 2020, 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 'dart:io';
+
+import 'c_types.dart';
+import 'structs_by_value_tests_confguration.dart';
+import 'utils.dart';
+
+/// The test type determines how to convert the arguments into return values
+/// such that the caller knows what to check.
+enum TestType {
+  /// Tested by getting all the individual fields out of the structs and
+  /// summing their values.
+  structArguments,
+
+  /// Tested by passing assigning the arguments to the struct fields.
+  structReturn,
+
+  /// Tested by returning the struct passed in.
+  structReturnArgument,
+}
+
+extension on FunctionType {
+  TestType get testType {
+    if (arguments.containsStructs && returnValue is FundamentalType) {
+      return TestType.structArguments;
+    }
+    if (returnValue is StructType && argumentTypes.contains(returnValue)) {
+      return TestType.structReturnArgument;
+    }
+    if (returnValue is StructType) {
+      if (arguments.length == (returnValue as StructType).members.length) {
+        return TestType.structReturn;
+      }
+    }
+    throw Exception("Unknown test type: $this");
+  }
+}
+
+/// We use the class structure as an algebraic data type in order to keep the
+/// relevant parts of the code generation closer together.
+extension on CType {
+  /// The part of the cout expression after `std::cout` and before the `;`.
+  String coutExpression(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        if (this == uint8 || this == int8) {
+          return "<< static_cast<int>($variableName)";
+        }
+        return "<< $variableName";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.coutExpression("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A statement recursively outputting all members.
+  String coutStatement(String variableName) {
+    final coutExpr = this.coutExpression(variableName);
+    return 'std::cout << "$variableName = " $coutExpr << "\\n";';
+  }
+}
+
+extension on List<Member> {
+  /// The part of the cout expression after `std::cout` and before the `;`.
+  String coutExpression([String namePrefix = ""]) {
+    String result = '<< "("';
+    result += this
+        .map((m) => m.type.coutExpression("$namePrefix${m.name}"))
+        .join('<< ", "');
+    result += '<< ")"';
+    return result.trimCouts();
+  }
+}
+
+extension on CType {
+  /// A list of statements adding all members recurisvely to `result`.
+  ///
+  /// Both valid in Dart and C.
+  String addToResultStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "result += $variableName;\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.addToResultStatements("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of statements adding all members recurisvely to `result`.
+  ///
+  /// Both valid in Dart and C.
+  String addToResultStatements([String namePrefix = ""]) {
+    return map((m) => m.type.addToResultStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of statements recursively assigning all members with [a].
+  ///
+  /// Both valid in Dart and C.
+  String assignValueStatements(ArgumentValueAssigner a, String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        return "$variableName = ${a.nextValue(this_)};\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.assignValueStatements(a, "$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of statements recursively coping all members from [source].
+  ///
+  /// Both valid in Dart and C.
+  String copyValueStatements(String source, String destination) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "$destination = $source;\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.copyValueStatements("$source.", "$destination.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of statements recursively assigning all members with [a].
+  ///
+  /// Both valid in Dart and C.
+  String assignValueStatements(ArgumentValueAssigner a,
+      [String namePrefix = ""]) {
+    return map((m) => m.type.assignValueStatements(a, "$namePrefix${m.name}"))
+        .join();
+  }
+
+  /// A list of statements recursively coping all members from [source].
+  ///
+  /// Both valid in Dart and C.
+  String copyValueStatements([sourcePrefix = "", destinationPrefix = ""]) {
+    return map((m) => m.type.copyValueStatements(
+        "$sourcePrefix${m.name}", "$destinationPrefix${m.name}")).join();
+  }
+}
+
+/// A helper class that assigns values to fundamental types.
+///
+/// Also keeps track of a sum of all values, to be used for testing the result.
+class ArgumentValueAssigner {
+  int i = 1;
+  int sum = 0;
+  String nextValue(FundamentalType type) {
+    int argumentValue = i;
+    i++;
+    if (type.isSigned && i % 2 == 0) {
+      argumentValue = -argumentValue;
+    }
+    sum += argumentValue;
+    if (type.isFloatingPoint) {
+      return argumentValue.toDouble().toString();
+    } else {
+      return argumentValue.toString();
+    }
+  }
+
+  String sumValue(FundamentalType type) {
+    if (type.isFloatingPoint) {
+      return sum.toDouble().toString();
+    } else {
+      return sum.toString();
+    }
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively allocating all members.
+  String dartAllocateStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "${dartType} ${variableName};\n";
+
+      case StructType:
+        return "${dartType} ${variableName} = allocate<$dartType>().ref;\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of Dart statements allocating as zero or nullptr.
+  String dartAllocateZeroStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "${dartType} ${variableName} = 0;\n";
+        }
+        return "${dartType} ${variableName} = 0.0;\n";
+
+      case StructType:
+        return "${dartType} ${variableName} = ${dartType}();\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively allocating all members.
+  String dartAllocateStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartAllocateStatements("$namePrefix${m.name}"))
+        .join();
+  }
+
+  /// A list of Dart statements as zero or nullptr.
+  String dartAllocateZeroStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartAllocateZeroStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively freeing all members.
+  String dartFreeStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "";
+
+      case StructType:
+        return "free($variableName.addressOf);\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively freeing all members.
+  String dartFreeStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartFreeStatements("$namePrefix${m.name}")).join();
+  }
+}
+
+extension on CType {
+  /// A list of C statements recursively allocating all members.
+  String cAllocateStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+      case StructType:
+        return "${cType} ${variableName};\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of C statements recursively allocating all members.
+  String cAllocateStatements([String namePrefix = ""]) {
+    return map((m) => m.type.cAllocateStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively checking all members.
+  String dartExpectsStatements(String expected, String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "Expect.equals(${expected}, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "Expect.approxEquals(${expected}, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.dartExpectsStatements("$expected.", "$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively checking all members.
+  String dartExpectsStatements(
+      [String expectedPrefix = "", String actualPrefix = ""]) {
+    return map((m) => m.type.dartExpectsStatements(
+        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
+  }
+}
+
+extension on CType {
+  /// A list of C statements recursively checking all members.
+  String cExpectsStatements(String expected, String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "CHECK_EQ(${expected}, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "CHECK_APPROX(${expected}, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.cExpectsStatements("$expected.", "$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of C statements recursively checking all members for zero.
+  String cExpectsZeroStatements(String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "CHECK_EQ(0, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "CHECK_APPROX(0.0, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.cExpectsZeroStatements("$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of C statements recursively checking all members.
+  String cExpectsStatements(
+      [String expectedPrefix = "", String actualPrefix = ""]) {
+    return map((m) => m.type.cExpectsStatements(
+        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
+  }
+
+  /// A list of C statements recursively checking all members for zero.
+  String cExpectsZeroStatements([String actualPrefix = ""]) {
+    return map((m) => m.type.cExpectsZeroStatements("$actualPrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// Expression denoting the first FundamentalType field.
+  ///
+  /// Both valid in Dart and C.
+  String firstArgumentName(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return variableName;
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.firstArgumentName("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// Expression denoting the first FundamentalType field.
+  ///
+  /// Both valid in Dart and C.
+  String firstArgumentName([String prefix = ""]) {
+    return this[0].type.firstArgumentName("$prefix${this[0].name}");
+  }
+}
+
+extension on StructType {
+  String dartClass(bool nnbd) {
+    String dartFields = "";
+    for (final member in members) {
+      dartFields += "${member.dartStructField(nnbd)}\n\n";
+    }
+    String toStringBody = members.map((m) => "\$\{${m.name}\}").join(", ");
+    return """
+    class $name extends Struct {
+      $dartFields
+
+      String toString() => "($toStringBody)";
+    }
+    """;
+  }
+
+  String get cDefinition {
+    String cFields = "";
+    for (final member in members) {
+      cFields += "  ${member.cStructField}\n";
+    }
+    return """
+    struct $name {
+      $cFields
+    };
+
+    """;
+  }
+}
+
+extension on FunctionType {
+  String get dartCallCode {
+    final a = ArgumentValueAssigner();
+    final assignValues = arguments.assignValueStatements(a);
+    final argumentFrees = arguments.dartFreeStatements();
+
+    final argumentNames = arguments.map((e) => e.name).join(", ");
+
+    String expects;
+    switch (testType) {
+      case TestType.structArguments:
+        // Check against sum value.
+        final expectedResult = a.sumValue(returnValue as FundamentalType);
+        expects = returnValue.dartExpectsStatements(expectedResult, "result");
+        break;
+      case TestType.structReturn:
+        // Check against input arguments.
+        expects = arguments.dartExpectsStatements("", "result.");
+        break;
+      case TestType.structReturnArgument:
+        expects = returnValue.dartExpectsStatements(
+            structReturnArgument.name, "result");
+        break;
+    }
+
+    return """
+    final $dartName =
+      ffiTestFunctions.lookupFunction<$dartCType, $dartType>("$cName");
+
+    ${reason.makeDartDocComment()}
+    void $dartTestName() {
+      ${arguments.dartAllocateStatements()}
+
+      ${assignValues}
+
+      final result = $dartName($argumentNames);
+
+      print("result = \$result");
+
+      $expects
+
+      $argumentFrees
+    }
+    """;
+  }
+
+  String dartCallbackCode(bool nnbd) {
+    final argumentss =
+        arguments.map((a) => "${a.type.dartType} ${a.name}").join(", ");
+
+    final prints = arguments.map((a) => "\$\{${a.name}\}").join(", ");
+
+    String buildReturnValue = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Sum all input values.
+        buildReturnValue = """
+        ${returnValue.dartType} result = 0;
+
+        ${arguments.addToResultStatements('${dartName}_')}
+        """;
+        break;
+      case TestType.structReturn:
+        // Allocate a struct.
+        buildReturnValue = """
+        ${returnValue.dartType} result = allocate<${returnValue.dartType}>().ref;
+
+        ${arguments.copyValueStatements("${dartName}_", "result.")}
+        """;
+        break;
+      case TestType.structReturnArgument:
+        buildReturnValue = """
+        ${returnValue.cType} result = ${dartName}_${structReturnArgument.name};
+        """;
+        break;
+    }
+
+    final globals = arguments.dartAllocateZeroStatements("${dartName}_");
+
+    final copyToGlobals =
+        arguments.map((a) => '${dartName}_${a.name} = ${a.name};').join("\n");
+
+    // Simulate assigning values the same way as in C, so that we know what the
+    // final return value should be.
+    final a = ArgumentValueAssigner();
+    arguments.assignValueStatements(a);
+    String afterCallbackExpects = "";
+    String afterCallbackFrees = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Check that the input structs are still available.
+        // Check against sum value.
+        final expectedResult = a.sumValue(returnValue as FundamentalType);
+        afterCallbackExpects =
+            returnValue.dartExpectsStatements(expectedResult, "result");
+        break;
+      case TestType.structReturn:
+        // We're passing allocating structs in [buildReturnValue].
+        afterCallbackFrees =
+            returnValue.dartFreeStatements("${dartName}Result");
+        break;
+      case TestType.structReturnArgument:
+        break;
+    }
+
+    String returnNull = "";
+    if (!nnbd) {
+      returnNull = """
+      if (${arguments.firstArgumentName()} == $returnNullValue) {
+        print("returning null!");
+        return null;
+      }
+      """;
+    }
+
+    return """
+    typedef ${cName}Type = $dartCType;
+
+    // Global variables to be able to test inputs after callback returned.
+    $globals
+
+    // Result variable also global, so we can delete it after the callback.
+    ${returnValue.dartAllocateZeroStatements("${dartName}Result")}
+
+    ${returnValue.dartType} ${dartName}CalculateResult() {
+      $buildReturnValue
+
+      ${dartName}Result = result;
+
+      return result;
+    }
+
+    ${reason.makeDartDocComment()}
+    ${returnValue.dartType} $dartName($argumentss) {
+      print("$dartName($prints)");
+
+      // In legacy mode, possibly return null.
+      $returnNull
+
+      // In both nnbd and legacy mode, possibly throw.
+      if (${arguments.firstArgumentName()} == $throwExceptionValue ||
+          ${arguments.firstArgumentName()} == $returnNullValue) {
+        print("throwing!");
+        throw Exception("$cName throwing on purpuse!");
+      }
+
+      $copyToGlobals
+
+      final result = ${dartName}CalculateResult();
+
+      print(\"result = \$result\");
+
+      return result;
+    }
+
+    void ${dartName}AfterCallback() {
+      $afterCallbackFrees
+
+      final result = ${dartName}CalculateResult();
+
+      print(\"after callback result = \$result\");
+
+      $afterCallbackExpects
+
+      $afterCallbackFrees
+    }
+
+    """;
+  }
+
+  String get dartCallbackTestConstructor {
+    String exceptionalReturn = "";
+    if (returnValue is FundamentalType) {
+      if ((returnValue as FundamentalType).isFloatingPoint) {
+        exceptionalReturn = ", 0.0";
+      } else {
+        exceptionalReturn = ", 0";
+      }
+    }
+    return """
+    CallbackTest.withCheck("$cName",
+      Pointer.fromFunction<${cName}Type>($dartName$exceptionalReturn),
+      ${dartName}AfterCallback),
+    """;
+  }
+
+  String get cCallCode {
+    String body = "";
+    switch (testType) {
+      case TestType.structArguments:
+        body = """
+        ${returnValue.cType} result = 0;
+
+        ${arguments.addToResultStatements()}
+        """;
+        break;
+      case TestType.structReturn:
+        body = """
+        ${returnValue.cType} result;
+
+        ${arguments.copyValueStatements("", "result.")}
+        """;
+        break;
+      case TestType.structReturnArgument:
+        body = """
+        ${returnValue.cType} result = ${structReturnArgument.name};
+        """;
+        break;
+    }
+
+    final argumentss =
+        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
+
+    return """
+    // Used for testing structs by value.
+    ${reason.makeCComment()}
+    DART_EXPORT ${returnValue.cType} $cName($argumentss) {
+      std::cout << \"$cName\" ${arguments.coutExpression()} << \"\\n\";
+
+      $body
+
+      ${returnValue.coutStatement("result")}
+
+      return result;
+    }
+
+    """;
+  }
+
+  String get cCallbackCode {
+    final a = ArgumentValueAssigner();
+    final argumentAllocations = arguments.cAllocateStatements();
+    final assignValues = arguments.assignValueStatements(a);
+
+    final argumentss =
+        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
+
+    final argumentNames = arguments.map((e) => e.name).join(", ");
+
+    String expects = "";
+    String expectsZero = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Check against sum value.
+        final returnValue_ = returnValue as FundamentalType;
+        final expectedResult = a.sumValue(returnValue_);
+        expects = returnValue.cExpectsStatements(expectedResult, "result");
+
+        expectsZero = returnValue.cExpectsZeroStatements("result");
+        break;
+      case TestType.structReturn:
+        // Check against input statements.
+        expects = arguments.cExpectsStatements("", "result.");
+
+        expectsZero = arguments.cExpectsZeroStatements("result.");
+        break;
+      case TestType.structReturnArgument:
+        // Check against input struct fields.
+        expects =
+            returnValue.cExpectsStatements(structReturnArgument.name, "result");
+
+        expectsZero = returnValue.cExpectsZeroStatements("result");
+        break;
+    }
+
+    return """
+    // Used for testing structs by value.
+    ${reason.makeCComment()}
+    DART_EXPORT intptr_t
+    Test$cName(
+        // NOLINTNEXTLINE(whitespace/parens)
+        ${returnValue.cType} (*f)($argumentss)) {
+      $argumentAllocations
+
+      $assignValues
+
+      std::cout << \"Calling Test$cName(\" ${arguments.coutExpression()} << \")\\n\";
+
+      ${returnValue.cType} result = f($argumentNames);
+
+      ${returnValue.coutStatement("result")}
+
+      $expects
+
+      // Pass argument that will make the Dart callback throw.
+      ${arguments.firstArgumentName()} = $throwExceptionValue;
+
+      result = f($argumentNames);
+
+      $expectsZero
+
+      // Pass argument that will make the Dart callback return null.
+      ${arguments.firstArgumentName()} = $returnNullValue;
+
+      result = f($argumentNames);
+
+      $expectsZero
+
+      return 0;
+    }
+
+    """;
+  }
+}
+
+/// Some value between 0 and 127 (works in every native type).
+const throwExceptionValue = 42;
+
+/// Some value between 0 and 127 (works in every native type).
+const returnNullValue = 84;
+
+const headerDartCallTest = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=5
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'dylib_utils.dart';
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+""";
+
+void writeDartCallTest() {
+  for (bool nnbd in [true, false]) {
+    final StringBuffer buffer = StringBuffer();
+    buffer.write(headerDartCallTest);
+
+    buffer.write("""
+    void main() {
+      for (int i = 0; i < 10; ++i) {
+        ${functions.map((e) => "${e.dartTestName}();").join("\n")}
+      }
+    }
+    """);
+    buffer.writeAll(structs.map((e) => e.dartClass(nnbd)));
+    buffer.writeAll(functions.map((e) => e.dartCallCode));
+
+    final path = callTestPath(nnbd);
+    File(path).writeAsStringSync(buffer.toString());
+    Process.runSync("dartfmt", ["-w", path]);
+  }
+}
+
+String callTestPath(bool nnbd) {
+  final folder = nnbd ? "ffi" : "ffi_2";
+  return Platform.script
+      .resolve("../../$folder/function_structs_by_value_generated_test.dart")
+      .path;
+}
+
+const headerDartCallbackTest = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=10
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'callback_tests_utils.dart';
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+
+void main() {
+  testCases.forEach((t) {
+    print("==== Running " + t.name);
+    t.run();
+  });
+}
+
+
+""";
+
+void writeDartCallbackTest() {
+  for (bool nnbd in [true, false]) {
+    final StringBuffer buffer = StringBuffer();
+    buffer.write(headerDartCallbackTest);
+
+    buffer.write("""
+  final testCases = [
+    ${functions.map((e) => e.dartCallbackTestConstructor).join("\n")}
+  ];
+  """);
+
+    buffer.writeAll(functions.map((e) => e.dartCallbackCode(nnbd)));
+
+    final path = callbackTestPath(nnbd);
+    File(path).writeAsStringSync(buffer.toString());
+    Process.runSync("dartfmt", ["-w", path]);
+  }
+}
+
+String callbackTestPath(bool nnbd) {
+  final folder = nnbd ? "ffi" : "ffi_2";
+  return Platform.script
+      .resolve(
+          "../../$folder/function_callbacks_structs_by_value_generated_test.dart")
+      .path;
+}
+
+const headerC = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+#if defined(_WIN32)
+#define DART_EXPORT extern "C" __declspec(dllexport)
+#else
+#define DART_EXPORT                                                            \\
+  extern "C" __attribute__((visibility("default"))) __attribute((used))
+#endif
+
+namespace dart {
+
+#define CHECK(X)                                                               \\
+  if (!(X)) {                                                                  \\
+    fprintf(stderr, "%s\\n", "Check failed: " #X);                              \\
+    return 1;                                                                  \\
+  }
+
+#define CHECK_EQ(X, Y) CHECK((X) == (Y))
+
+// Works for positive, negative and zero.
+#define CHECK_APPROX(EXPECTED, ACTUAL)                                         \\
+  CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \\
+        ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
+
+""";
+
+const footerC = """
+
+}  // namespace dart
+""";
+
+void writeC() {
+  final StringBuffer buffer = StringBuffer();
+  buffer.write(headerC);
+
+  buffer.writeAll(structs.map((e) => e.cDefinition));
+  buffer.writeAll(functions.map((e) => e.cCallCode));
+  buffer.writeAll(functions.map((e) => e.cCallbackCode));
+
+  buffer.write(footerC);
+
+  File(ccPath).writeAsStringSync(buffer.toString());
+  Process.runSync("clang-format", ["-i", ccPath]);
+}
+
+final ccPath = Platform.script
+    .resolve("../../../runtime/bin/ffi_test/ffi_test_functions_generated.cc")
+    .path;
+
+void printUsage() {
+  print("""
+Generates structs by value tests.
+
+Generates:
+- $ccPath
+- ${callbackTestPath(true)}
+- ${callTestPath(true)}
+- ${callbackTestPath(false)}
+- ${callTestPath(false)}
+""");
+}
+
+void main(List<String> arguments) {
+  if (arguments.length != 0) {
+    printUsage();
+    return;
+  }
+
+  writeDartCallTest();
+  writeDartCallbackTest();
+  writeC();
+}
diff --git a/tests/ffi/generator/utils.dart b/tests/ffi/generator/utils.dart
new file mode 100644
index 0000000..735e769
--- /dev/null
+++ b/tests/ffi/generator/utils.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, 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.
+
+extension TestGeneratorStringExtension on String {
+  String upperCaseFirst() => "${this[0].toUpperCase()}${this.substring(1)}";
+
+  String lowerCaseFirst() => "${this[0].toLowerCase()}${this.substring(1)}";
+
+  String makeCComment() => "// " + split("\n").join("\n// ");
+
+  String makeDartDocComment() => "/// " + split("\n").join("\n/// ");
+
+  String limitTo(int lenght) {
+    if (this.length > lenght) {
+      return substring(0, lenght);
+    }
+    return this;
+  }
+
+  String trimCouts() => replaceAll('" << "', '').replaceAll('"<< "', '');
+}
diff --git a/tests/ffi_2/callback_tests_utils.dart b/tests/ffi_2/callback_tests_utils.dart
index ac5fdcb..e34a52b 100644
--- a/tests/ffi_2/callback_tests_utils.dart
+++ b/tests/ffi_2/callback_tests_utils.dart
@@ -16,19 +16,23 @@
 class CallbackTest {
   final String name;
   final Pointer callback;
-  final bool skip;
+  final void Function() afterCallbackChecks;
 
-  CallbackTest(this.name, this.callback, {bool skipIf: false})
-      : skip = skipIf {}
+  CallbackTest(this.name, this.callback) : afterCallbackChecks = noChecks {}
+  CallbackTest.withCheck(this.name, this.callback, this.afterCallbackChecks) {}
 
   void run() {
-    if (skip) return;
-
     final NativeCallbackTestFn tester = ffiTestFunctions
         .lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
+
     final int testCode = tester(callback);
+
     if (testCode != 0) {
       Expect.fail("Test $name failed.");
     }
+
+    afterCallbackChecks();
   }
 }
+
+void noChecks() {}
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index 37ab3e9..3baf069 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -2,6 +2,11 @@
 # 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.
 
+# TODO(dartbug.com/36730): Implement structs by value.
+function_callbacks_structs_by_value_generated_test: Skip
+function_callbacks_structs_by_value_test: Skip
+function_structs_by_value_generated_test: Skip
+
 [ $builder_tag == msan ]
 vmspecific_handle_test: Skip # https://dartbug.com/42314
 
diff --git a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
new file mode 100644
index 0000000..4db290f
--- /dev/null
+++ b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
@@ -0,0 +1,6124 @@
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=10
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'callback_tests_utils.dart';
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+void main() {
+  testCases.forEach((t) {
+    print("==== Running " + t.name);
+    t.run();
+  });
+}
+
+final testCases = [
+  CallbackTest.withCheck(
+      "PassStruct1ByteIntx10",
+      Pointer.fromFunction<PassStruct1ByteIntx10Type>(passStruct1ByteIntx10, 0),
+      passStruct1ByteIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct3BytesIntx10",
+      Pointer.fromFunction<PassStruct3BytesIntx10Type>(
+          passStruct3BytesIntx10, 0),
+      passStruct3BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct4BytesHomogeneousInt16x10",
+      Pointer.fromFunction<PassStruct4BytesHomogeneousInt16x10Type>(
+          passStruct4BytesHomogeneousInt16x10, 0),
+      passStruct4BytesHomogeneousInt16x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct7BytesIntx10",
+      Pointer.fromFunction<PassStruct7BytesIntx10Type>(
+          passStruct7BytesIntx10, 0),
+      passStruct7BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesIntx10",
+      Pointer.fromFunction<PassStruct8BytesIntx10Type>(
+          passStruct8BytesIntx10, 0),
+      passStruct8BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesHomogeneousFloatx10",
+      Pointer.fromFunction<PassStruct8BytesHomogeneousFloatx10Type>(
+          passStruct8BytesHomogeneousFloatx10, 0.0),
+      passStruct8BytesHomogeneousFloatx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct8BytesMixedx10",
+      Pointer.fromFunction<PassStruct8BytesMixedx10Type>(
+          passStruct8BytesMixedx10, 0.0),
+      passStruct8BytesMixedx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct9BytesIntx10",
+      Pointer.fromFunction<PassStruct9BytesIntx10Type>(
+          passStruct9BytesIntx10, 0),
+      passStruct9BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct9BytesHomogeneousUint82x10",
+      Pointer.fromFunction<PassStruct9BytesHomogeneousUint82x10Type>(
+          passStruct9BytesHomogeneousUint82x10, 0),
+      passStruct9BytesHomogeneousUint82x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct12BytesHomogeneousFloatx6",
+      Pointer.fromFunction<PassStruct12BytesHomogeneousFloatx6Type>(
+          passStruct12BytesHomogeneousFloatx6, 0.0),
+      passStruct12BytesHomogeneousFloatx6AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesHomogeneousFloatx5",
+      Pointer.fromFunction<PassStruct16BytesHomogeneousFloatx5Type>(
+          passStruct16BytesHomogeneousFloatx5, 0.0),
+      passStruct16BytesHomogeneousFloatx5AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesMixedx10",
+      Pointer.fromFunction<PassStruct16BytesMixedx10Type>(
+          passStruct16BytesMixedx10, 0.0),
+      passStruct16BytesMixedx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct16BytesMixed2x10",
+      Pointer.fromFunction<PassStruct16BytesMixed2x10Type>(
+          passStruct16BytesMixed2x10, 0.0),
+      passStruct16BytesMixed2x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct17BytesIntx10",
+      Pointer.fromFunction<PassStruct17BytesIntx10Type>(
+          passStruct17BytesIntx10, 0),
+      passStruct17BytesIntx10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct19BytesHomogeneousUint8x10",
+      Pointer.fromFunction<PassStruct19BytesHomogeneousUint8x10Type>(
+          passStruct19BytesHomogeneousUint8x10, 0),
+      passStruct19BytesHomogeneousUint8x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct20BytesHomogeneousInt32x10",
+      Pointer.fromFunction<PassStruct20BytesHomogeneousInt32x10Type>(
+          passStruct20BytesHomogeneousInt32x10, 0),
+      passStruct20BytesHomogeneousInt32x10AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct20BytesHomogeneousFloat",
+      Pointer.fromFunction<PassStruct20BytesHomogeneousFloatType>(
+          passStruct20BytesHomogeneousFloat, 0.0),
+      passStruct20BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct32BytesHomogeneousDoublex5",
+      Pointer.fromFunction<PassStruct32BytesHomogeneousDoublex5Type>(
+          passStruct32BytesHomogeneousDoublex5, 0.0),
+      passStruct32BytesHomogeneousDoublex5AfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct40BytesHomogeneousDouble",
+      Pointer.fromFunction<PassStruct40BytesHomogeneousDoubleType>(
+          passStruct40BytesHomogeneousDouble, 0.0),
+      passStruct40BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct1024BytesHomogeneousUint64",
+      Pointer.fromFunction<PassStruct1024BytesHomogeneousUint64Type>(
+          passStruct1024BytesHomogeneousUint64, 0),
+      passStruct1024BytesHomogeneousUint64AfterCallback),
+  CallbackTest.withCheck(
+      "PassFloatStruct16BytesHomogeneousFloatFloatStruct1",
+      Pointer.fromFunction<
+              PassFloatStruct16BytesHomogeneousFloatFloatStruct1Type>(
+          passFloatStruct16BytesHomogeneousFloatFloatStruct1, 0.0),
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1AfterCallback),
+  CallbackTest.withCheck(
+      "PassFloatStruct32BytesHomogeneousDoubleFloatStruct",
+      Pointer.fromFunction<
+              PassFloatStruct32BytesHomogeneousDoubleFloatStructType>(
+          passFloatStruct32BytesHomogeneousDoubleFloatStruct, 0.0),
+      passFloatStruct32BytesHomogeneousDoubleFloatStructAfterCallback),
+  CallbackTest.withCheck(
+      "PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn",
+      Pointer.fromFunction<
+              PassInt8Struct16BytesMixedInt8Struct16BytesMixedInType>(
+          passInt8Struct16BytesMixedInt8Struct16BytesMixedIn, 0.0),
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInAfterCallback),
+  CallbackTest.withCheck(
+      "PassDoublex6Struct16BytesMixedx4Int32",
+      Pointer.fromFunction<PassDoublex6Struct16BytesMixedx4Int32Type>(
+          passDoublex6Struct16BytesMixedx4Int32, 0.0),
+      passDoublex6Struct16BytesMixedx4Int32AfterCallback),
+  CallbackTest.withCheck(
+      "PassInt32x4Struct16BytesMixedx4Double",
+      Pointer.fromFunction<PassInt32x4Struct16BytesMixedx4DoubleType>(
+          passInt32x4Struct16BytesMixedx4Double, 0.0),
+      passInt32x4Struct16BytesMixedx4DoubleAfterCallback),
+  CallbackTest.withCheck(
+      "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo",
+      Pointer.fromFunction<
+              PassStruct40BytesHomogeneousDoubleStruct4BytesHomoType>(
+          passStruct40BytesHomogeneousDoubleStruct4BytesHomo, 0.0),
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt16",
+      Pointer.fromFunction<PassStructAlignmentInt16Type>(
+          passStructAlignmentInt16, 0),
+      passStructAlignmentInt16AfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt32",
+      Pointer.fromFunction<PassStructAlignmentInt32Type>(
+          passStructAlignmentInt32, 0),
+      passStructAlignmentInt32AfterCallback),
+  CallbackTest.withCheck(
+      "PassStructAlignmentInt64",
+      Pointer.fromFunction<PassStructAlignmentInt64Type>(
+          passStructAlignmentInt64, 0),
+      passStructAlignmentInt64AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct1ByteInt",
+      Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
+      returnStruct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct3BytesInt",
+      Pointer.fromFunction<ReturnStruct3BytesIntType>(returnStruct3BytesInt),
+      returnStruct3BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct4BytesHomogeneousInt16",
+      Pointer.fromFunction<ReturnStruct4BytesHomogeneousInt16Type>(
+          returnStruct4BytesHomogeneousInt16),
+      returnStruct4BytesHomogeneousInt16AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct7BytesInt",
+      Pointer.fromFunction<ReturnStruct7BytesIntType>(returnStruct7BytesInt),
+      returnStruct7BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesInt",
+      Pointer.fromFunction<ReturnStruct8BytesIntType>(returnStruct8BytesInt),
+      returnStruct8BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct8BytesHomogeneousFloatType>(
+          returnStruct8BytesHomogeneousFloat),
+      returnStruct8BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct8BytesMixed",
+      Pointer.fromFunction<ReturnStruct8BytesMixedType>(
+          returnStruct8BytesMixed),
+      returnStruct8BytesMixedAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct9BytesInt",
+      Pointer.fromFunction<ReturnStruct9BytesIntType>(returnStruct9BytesInt),
+      returnStruct9BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct9BytesHomogeneousUint82",
+      Pointer.fromFunction<ReturnStruct9BytesHomogeneousUint82Type>(
+          returnStruct9BytesHomogeneousUint82),
+      returnStruct9BytesHomogeneousUint82AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct12BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct12BytesHomogeneousFloatType>(
+          returnStruct12BytesHomogeneousFloat),
+      returnStruct12BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct16BytesHomogeneousFloatType>(
+          returnStruct16BytesHomogeneousFloat),
+      returnStruct16BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesMixed",
+      Pointer.fromFunction<ReturnStruct16BytesMixedType>(
+          returnStruct16BytesMixed),
+      returnStruct16BytesMixedAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct16BytesMixed2",
+      Pointer.fromFunction<ReturnStruct16BytesMixed2Type>(
+          returnStruct16BytesMixed2),
+      returnStruct16BytesMixed2AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct17BytesInt",
+      Pointer.fromFunction<ReturnStruct17BytesIntType>(returnStruct17BytesInt),
+      returnStruct17BytesIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct19BytesHomogeneousUint8",
+      Pointer.fromFunction<ReturnStruct19BytesHomogeneousUint8Type>(
+          returnStruct19BytesHomogeneousUint8),
+      returnStruct19BytesHomogeneousUint8AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct20BytesHomogeneousInt32",
+      Pointer.fromFunction<ReturnStruct20BytesHomogeneousInt32Type>(
+          returnStruct20BytesHomogeneousInt32),
+      returnStruct20BytesHomogeneousInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct20BytesHomogeneousFloat",
+      Pointer.fromFunction<ReturnStruct20BytesHomogeneousFloatType>(
+          returnStruct20BytesHomogeneousFloat),
+      returnStruct20BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct32BytesHomogeneousDouble",
+      Pointer.fromFunction<ReturnStruct32BytesHomogeneousDoubleType>(
+          returnStruct32BytesHomogeneousDouble),
+      returnStruct32BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct40BytesHomogeneousDouble",
+      Pointer.fromFunction<ReturnStruct40BytesHomogeneousDoubleType>(
+          returnStruct40BytesHomogeneousDouble),
+      returnStruct40BytesHomogeneousDoubleAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStruct1024BytesHomogeneousUint64",
+      Pointer.fromFunction<ReturnStruct1024BytesHomogeneousUint64Type>(
+          returnStruct1024BytesHomogeneousUint64),
+      returnStruct1024BytesHomogeneousUint64AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct1ByteInt",
+      Pointer.fromFunction<ReturnStructArgumentStruct1ByteIntType>(
+          returnStructArgumentStruct1ByteInt),
+      returnStructArgumentStruct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentInt32x8Struct1ByteInt",
+      Pointer.fromFunction<ReturnStructArgumentInt32x8Struct1ByteIntType>(
+          returnStructArgumentInt32x8Struct1ByteInt),
+      returnStructArgumentInt32x8Struct1ByteIntAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct8BytesHomogeneousFloat",
+      Pointer.fromFunction<
+              ReturnStructArgumentStruct8BytesHomogeneousFloatType>(
+          returnStructArgumentStruct8BytesHomogeneousFloat),
+      returnStructArgumentStruct8BytesHomogeneousFloatAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentStruct20BytesHomogeneousInt32",
+      Pointer.fromFunction<
+              ReturnStructArgumentStruct20BytesHomogeneousInt32Type>(
+          returnStructArgumentStruct20BytesHomogeneousInt32),
+      returnStructArgumentStruct20BytesHomogeneousInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructArgumentInt32x8Struct20BytesHomogeneou",
+      Pointer.fromFunction<
+              ReturnStructArgumentInt32x8Struct20BytesHomogeneouType>(
+          returnStructArgumentInt32x8Struct20BytesHomogeneou),
+      returnStructArgumentInt32x8Struct20BytesHomogeneouAfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt16",
+      Pointer.fromFunction<ReturnStructAlignmentInt16Type>(
+          returnStructAlignmentInt16),
+      returnStructAlignmentInt16AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt32",
+      Pointer.fromFunction<ReturnStructAlignmentInt32Type>(
+          returnStructAlignmentInt32),
+      returnStructAlignmentInt32AfterCallback),
+  CallbackTest.withCheck(
+      "ReturnStructAlignmentInt64",
+      Pointer.fromFunction<ReturnStructAlignmentInt64Type>(
+          returnStructAlignmentInt64),
+      returnStructAlignmentInt64AfterCallback),
+];
+typedef PassStruct1ByteIntx10Type = Int64 Function(
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt,
+    Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1ByteInt passStruct1ByteIntx10_a0 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a1 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a2 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a3 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a4 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a5 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a6 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a7 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a8 = Struct1ByteInt();
+Struct1ByteInt passStruct1ByteIntx10_a9 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct1ByteIntx10Result = 0;
+
+int passStruct1ByteIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct1ByteIntx10_a0.a0;
+  result += passStruct1ByteIntx10_a1.a0;
+  result += passStruct1ByteIntx10_a2.a0;
+  result += passStruct1ByteIntx10_a3.a0;
+  result += passStruct1ByteIntx10_a4.a0;
+  result += passStruct1ByteIntx10_a5.a0;
+  result += passStruct1ByteIntx10_a6.a0;
+  result += passStruct1ByteIntx10_a7.a0;
+  result += passStruct1ByteIntx10_a8.a0;
+  result += passStruct1ByteIntx10_a9.a0;
+
+  passStruct1ByteIntx10Result = result;
+
+  return result;
+}
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+int passStruct1ByteIntx10(
+    Struct1ByteInt a0,
+    Struct1ByteInt a1,
+    Struct1ByteInt a2,
+    Struct1ByteInt a3,
+    Struct1ByteInt a4,
+    Struct1ByteInt a5,
+    Struct1ByteInt a6,
+    Struct1ByteInt a7,
+    Struct1ByteInt a8,
+    Struct1ByteInt a9) {
+  print(
+      "passStruct1ByteIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct1ByteIntx10 throwing on purpuse!");
+  }
+
+  passStruct1ByteIntx10_a0 = a0;
+  passStruct1ByteIntx10_a1 = a1;
+  passStruct1ByteIntx10_a2 = a2;
+  passStruct1ByteIntx10_a3 = a3;
+  passStruct1ByteIntx10_a4 = a4;
+  passStruct1ByteIntx10_a5 = a5;
+  passStruct1ByteIntx10_a6 = a6;
+  passStruct1ByteIntx10_a7 = a7;
+  passStruct1ByteIntx10_a8 = a8;
+  passStruct1ByteIntx10_a9 = a9;
+
+  final result = passStruct1ByteIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct1ByteIntx10AfterCallback() {
+  final result = passStruct1ByteIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(5, result);
+}
+
+typedef PassStruct3BytesIntx10Type = Int64 Function(
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt,
+    Struct3BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct3BytesInt passStruct3BytesIntx10_a0 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a1 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a2 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a3 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a4 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a5 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a6 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a7 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a8 = Struct3BytesInt();
+Struct3BytesInt passStruct3BytesIntx10_a9 = Struct3BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct3BytesIntx10Result = 0;
+
+int passStruct3BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct3BytesIntx10_a0.a0;
+  result += passStruct3BytesIntx10_a0.a1;
+  result += passStruct3BytesIntx10_a1.a0;
+  result += passStruct3BytesIntx10_a1.a1;
+  result += passStruct3BytesIntx10_a2.a0;
+  result += passStruct3BytesIntx10_a2.a1;
+  result += passStruct3BytesIntx10_a3.a0;
+  result += passStruct3BytesIntx10_a3.a1;
+  result += passStruct3BytesIntx10_a4.a0;
+  result += passStruct3BytesIntx10_a4.a1;
+  result += passStruct3BytesIntx10_a5.a0;
+  result += passStruct3BytesIntx10_a5.a1;
+  result += passStruct3BytesIntx10_a6.a0;
+  result += passStruct3BytesIntx10_a6.a1;
+  result += passStruct3BytesIntx10_a7.a0;
+  result += passStruct3BytesIntx10_a7.a1;
+  result += passStruct3BytesIntx10_a8.a0;
+  result += passStruct3BytesIntx10_a8.a1;
+  result += passStruct3BytesIntx10_a9.a0;
+  result += passStruct3BytesIntx10_a9.a1;
+
+  passStruct3BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+int passStruct3BytesIntx10(
+    Struct3BytesInt a0,
+    Struct3BytesInt a1,
+    Struct3BytesInt a2,
+    Struct3BytesInt a3,
+    Struct3BytesInt a4,
+    Struct3BytesInt a5,
+    Struct3BytesInt a6,
+    Struct3BytesInt a7,
+    Struct3BytesInt a8,
+    Struct3BytesInt a9) {
+  print(
+      "passStruct3BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct3BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct3BytesIntx10_a0 = a0;
+  passStruct3BytesIntx10_a1 = a1;
+  passStruct3BytesIntx10_a2 = a2;
+  passStruct3BytesIntx10_a3 = a3;
+  passStruct3BytesIntx10_a4 = a4;
+  passStruct3BytesIntx10_a5 = a5;
+  passStruct3BytesIntx10_a6 = a6;
+  passStruct3BytesIntx10_a7 = a7;
+  passStruct3BytesIntx10_a8 = a8;
+  passStruct3BytesIntx10_a9 = a9;
+
+  final result = passStruct3BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct3BytesIntx10AfterCallback() {
+  final result = passStruct3BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct4BytesHomogeneousInt16x10Type = Int64 Function(
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16,
+    Struct4BytesHomogeneousInt16);
+
+// Global variables to be able to test inputs after callback returned.
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a0 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a1 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a2 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a3 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a4 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a5 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a6 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a7 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a8 =
+    Struct4BytesHomogeneousInt16();
+Struct4BytesHomogeneousInt16 passStruct4BytesHomogeneousInt16x10_a9 =
+    Struct4BytesHomogeneousInt16();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct4BytesHomogeneousInt16x10Result = 0;
+
+int passStruct4BytesHomogeneousInt16x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct4BytesHomogeneousInt16x10_a0.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a0.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a1.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a1.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a2.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a2.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a3.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a3.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a4.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a4.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a5.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a5.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a6.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a6.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a7.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a7.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a8.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a8.a1;
+  result += passStruct4BytesHomogeneousInt16x10_a9.a0;
+  result += passStruct4BytesHomogeneousInt16x10_a9.a1;
+
+  passStruct4BytesHomogeneousInt16x10Result = result;
+
+  return result;
+}
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct4BytesHomogeneousInt16x10(
+    Struct4BytesHomogeneousInt16 a0,
+    Struct4BytesHomogeneousInt16 a1,
+    Struct4BytesHomogeneousInt16 a2,
+    Struct4BytesHomogeneousInt16 a3,
+    Struct4BytesHomogeneousInt16 a4,
+    Struct4BytesHomogeneousInt16 a5,
+    Struct4BytesHomogeneousInt16 a6,
+    Struct4BytesHomogeneousInt16 a7,
+    Struct4BytesHomogeneousInt16 a8,
+    Struct4BytesHomogeneousInt16 a9) {
+  print(
+      "passStruct4BytesHomogeneousInt16x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct4BytesHomogeneousInt16x10 throwing on purpuse!");
+  }
+
+  passStruct4BytesHomogeneousInt16x10_a0 = a0;
+  passStruct4BytesHomogeneousInt16x10_a1 = a1;
+  passStruct4BytesHomogeneousInt16x10_a2 = a2;
+  passStruct4BytesHomogeneousInt16x10_a3 = a3;
+  passStruct4BytesHomogeneousInt16x10_a4 = a4;
+  passStruct4BytesHomogeneousInt16x10_a5 = a5;
+  passStruct4BytesHomogeneousInt16x10_a6 = a6;
+  passStruct4BytesHomogeneousInt16x10_a7 = a7;
+  passStruct4BytesHomogeneousInt16x10_a8 = a8;
+  passStruct4BytesHomogeneousInt16x10_a9 = a9;
+
+  final result = passStruct4BytesHomogeneousInt16x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct4BytesHomogeneousInt16x10AfterCallback() {
+  final result = passStruct4BytesHomogeneousInt16x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct7BytesIntx10Type = Int64 Function(
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt,
+    Struct7BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct7BytesInt passStruct7BytesIntx10_a0 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a1 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a2 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a3 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a4 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a5 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a6 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a7 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a8 = Struct7BytesInt();
+Struct7BytesInt passStruct7BytesIntx10_a9 = Struct7BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct7BytesIntx10Result = 0;
+
+int passStruct7BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct7BytesIntx10_a0.a0;
+  result += passStruct7BytesIntx10_a0.a1;
+  result += passStruct7BytesIntx10_a0.a2;
+  result += passStruct7BytesIntx10_a1.a0;
+  result += passStruct7BytesIntx10_a1.a1;
+  result += passStruct7BytesIntx10_a1.a2;
+  result += passStruct7BytesIntx10_a2.a0;
+  result += passStruct7BytesIntx10_a2.a1;
+  result += passStruct7BytesIntx10_a2.a2;
+  result += passStruct7BytesIntx10_a3.a0;
+  result += passStruct7BytesIntx10_a3.a1;
+  result += passStruct7BytesIntx10_a3.a2;
+  result += passStruct7BytesIntx10_a4.a0;
+  result += passStruct7BytesIntx10_a4.a1;
+  result += passStruct7BytesIntx10_a4.a2;
+  result += passStruct7BytesIntx10_a5.a0;
+  result += passStruct7BytesIntx10_a5.a1;
+  result += passStruct7BytesIntx10_a5.a2;
+  result += passStruct7BytesIntx10_a6.a0;
+  result += passStruct7BytesIntx10_a6.a1;
+  result += passStruct7BytesIntx10_a6.a2;
+  result += passStruct7BytesIntx10_a7.a0;
+  result += passStruct7BytesIntx10_a7.a1;
+  result += passStruct7BytesIntx10_a7.a2;
+  result += passStruct7BytesIntx10_a8.a0;
+  result += passStruct7BytesIntx10_a8.a1;
+  result += passStruct7BytesIntx10_a8.a2;
+  result += passStruct7BytesIntx10_a9.a0;
+  result += passStruct7BytesIntx10_a9.a1;
+  result += passStruct7BytesIntx10_a9.a2;
+
+  passStruct7BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct7BytesIntx10(
+    Struct7BytesInt a0,
+    Struct7BytesInt a1,
+    Struct7BytesInt a2,
+    Struct7BytesInt a3,
+    Struct7BytesInt a4,
+    Struct7BytesInt a5,
+    Struct7BytesInt a6,
+    Struct7BytesInt a7,
+    Struct7BytesInt a8,
+    Struct7BytesInt a9) {
+  print(
+      "passStruct7BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct7BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct7BytesIntx10_a0 = a0;
+  passStruct7BytesIntx10_a1 = a1;
+  passStruct7BytesIntx10_a2 = a2;
+  passStruct7BytesIntx10_a3 = a3;
+  passStruct7BytesIntx10_a4 = a4;
+  passStruct7BytesIntx10_a5 = a5;
+  passStruct7BytesIntx10_a6 = a6;
+  passStruct7BytesIntx10_a7 = a7;
+  passStruct7BytesIntx10_a8 = a8;
+  passStruct7BytesIntx10_a9 = a9;
+
+  final result = passStruct7BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct7BytesIntx10AfterCallback() {
+  final result = passStruct7BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct8BytesIntx10Type = Int64 Function(
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt,
+    Struct8BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesInt passStruct8BytesIntx10_a0 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a1 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a2 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a3 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a4 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a5 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a6 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a7 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a8 = Struct8BytesInt();
+Struct8BytesInt passStruct8BytesIntx10_a9 = Struct8BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct8BytesIntx10Result = 0;
+
+int passStruct8BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct8BytesIntx10_a0.a0;
+  result += passStruct8BytesIntx10_a0.a1;
+  result += passStruct8BytesIntx10_a0.a2;
+  result += passStruct8BytesIntx10_a1.a0;
+  result += passStruct8BytesIntx10_a1.a1;
+  result += passStruct8BytesIntx10_a1.a2;
+  result += passStruct8BytesIntx10_a2.a0;
+  result += passStruct8BytesIntx10_a2.a1;
+  result += passStruct8BytesIntx10_a2.a2;
+  result += passStruct8BytesIntx10_a3.a0;
+  result += passStruct8BytesIntx10_a3.a1;
+  result += passStruct8BytesIntx10_a3.a2;
+  result += passStruct8BytesIntx10_a4.a0;
+  result += passStruct8BytesIntx10_a4.a1;
+  result += passStruct8BytesIntx10_a4.a2;
+  result += passStruct8BytesIntx10_a5.a0;
+  result += passStruct8BytesIntx10_a5.a1;
+  result += passStruct8BytesIntx10_a5.a2;
+  result += passStruct8BytesIntx10_a6.a0;
+  result += passStruct8BytesIntx10_a6.a1;
+  result += passStruct8BytesIntx10_a6.a2;
+  result += passStruct8BytesIntx10_a7.a0;
+  result += passStruct8BytesIntx10_a7.a1;
+  result += passStruct8BytesIntx10_a7.a2;
+  result += passStruct8BytesIntx10_a8.a0;
+  result += passStruct8BytesIntx10_a8.a1;
+  result += passStruct8BytesIntx10_a8.a2;
+  result += passStruct8BytesIntx10_a9.a0;
+  result += passStruct8BytesIntx10_a9.a1;
+  result += passStruct8BytesIntx10_a9.a2;
+
+  passStruct8BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+int passStruct8BytesIntx10(
+    Struct8BytesInt a0,
+    Struct8BytesInt a1,
+    Struct8BytesInt a2,
+    Struct8BytesInt a3,
+    Struct8BytesInt a4,
+    Struct8BytesInt a5,
+    Struct8BytesInt a6,
+    Struct8BytesInt a7,
+    Struct8BytesInt a8,
+    Struct8BytesInt a9) {
+  print(
+      "passStruct8BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesIntx10_a0 = a0;
+  passStruct8BytesIntx10_a1 = a1;
+  passStruct8BytesIntx10_a2 = a2;
+  passStruct8BytesIntx10_a3 = a3;
+  passStruct8BytesIntx10_a4 = a4;
+  passStruct8BytesIntx10_a5 = a5;
+  passStruct8BytesIntx10_a6 = a6;
+  passStruct8BytesIntx10_a7 = a7;
+  passStruct8BytesIntx10_a8 = a8;
+  passStruct8BytesIntx10_a9 = a9;
+
+  final result = passStruct8BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesIntx10AfterCallback() {
+  final result = passStruct8BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct8BytesHomogeneousFloatx10Type = Float Function(
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat,
+    Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a0 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a1 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a2 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a3 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a4 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a5 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a6 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a7 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a8 =
+    Struct8BytesHomogeneousFloat();
+Struct8BytesHomogeneousFloat passStruct8BytesHomogeneousFloatx10_a9 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct8BytesHomogeneousFloatx10Result = 0.0;
+
+double passStruct8BytesHomogeneousFloatx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct8BytesHomogeneousFloatx10_a0.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a0.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a1.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a1.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a2.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a2.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a3.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a3.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a4.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a4.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a5.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a5.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a6.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a6.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a7.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a7.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a8.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a8.a1;
+  result += passStruct8BytesHomogeneousFloatx10_a9.a0;
+  result += passStruct8BytesHomogeneousFloatx10_a9.a1;
+
+  passStruct8BytesHomogeneousFloatx10Result = result;
+
+  return result;
+}
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+double passStruct8BytesHomogeneousFloatx10(
+    Struct8BytesHomogeneousFloat a0,
+    Struct8BytesHomogeneousFloat a1,
+    Struct8BytesHomogeneousFloat a2,
+    Struct8BytesHomogeneousFloat a3,
+    Struct8BytesHomogeneousFloat a4,
+    Struct8BytesHomogeneousFloat a5,
+    Struct8BytesHomogeneousFloat a6,
+    Struct8BytesHomogeneousFloat a7,
+    Struct8BytesHomogeneousFloat a8,
+    Struct8BytesHomogeneousFloat a9) {
+  print(
+      "passStruct8BytesHomogeneousFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesHomogeneousFloatx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesHomogeneousFloatx10_a0 = a0;
+  passStruct8BytesHomogeneousFloatx10_a1 = a1;
+  passStruct8BytesHomogeneousFloatx10_a2 = a2;
+  passStruct8BytesHomogeneousFloatx10_a3 = a3;
+  passStruct8BytesHomogeneousFloatx10_a4 = a4;
+  passStruct8BytesHomogeneousFloatx10_a5 = a5;
+  passStruct8BytesHomogeneousFloatx10_a6 = a6;
+  passStruct8BytesHomogeneousFloatx10_a7 = a7;
+  passStruct8BytesHomogeneousFloatx10_a8 = a8;
+  passStruct8BytesHomogeneousFloatx10_a9 = a9;
+
+  final result = passStruct8BytesHomogeneousFloatx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesHomogeneousFloatx10AfterCallback() {
+  final result = passStruct8BytesHomogeneousFloatx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct8BytesMixedx10Type = Float Function(
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed,
+    Struct8BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesMixed passStruct8BytesMixedx10_a0 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a1 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a2 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a3 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a4 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a5 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a6 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a7 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a8 = Struct8BytesMixed();
+Struct8BytesMixed passStruct8BytesMixedx10_a9 = Struct8BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct8BytesMixedx10Result = 0.0;
+
+double passStruct8BytesMixedx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct8BytesMixedx10_a0.a0;
+  result += passStruct8BytesMixedx10_a0.a1;
+  result += passStruct8BytesMixedx10_a0.a2;
+  result += passStruct8BytesMixedx10_a1.a0;
+  result += passStruct8BytesMixedx10_a1.a1;
+  result += passStruct8BytesMixedx10_a1.a2;
+  result += passStruct8BytesMixedx10_a2.a0;
+  result += passStruct8BytesMixedx10_a2.a1;
+  result += passStruct8BytesMixedx10_a2.a2;
+  result += passStruct8BytesMixedx10_a3.a0;
+  result += passStruct8BytesMixedx10_a3.a1;
+  result += passStruct8BytesMixedx10_a3.a2;
+  result += passStruct8BytesMixedx10_a4.a0;
+  result += passStruct8BytesMixedx10_a4.a1;
+  result += passStruct8BytesMixedx10_a4.a2;
+  result += passStruct8BytesMixedx10_a5.a0;
+  result += passStruct8BytesMixedx10_a5.a1;
+  result += passStruct8BytesMixedx10_a5.a2;
+  result += passStruct8BytesMixedx10_a6.a0;
+  result += passStruct8BytesMixedx10_a6.a1;
+  result += passStruct8BytesMixedx10_a6.a2;
+  result += passStruct8BytesMixedx10_a7.a0;
+  result += passStruct8BytesMixedx10_a7.a1;
+  result += passStruct8BytesMixedx10_a7.a2;
+  result += passStruct8BytesMixedx10_a8.a0;
+  result += passStruct8BytesMixedx10_a8.a1;
+  result += passStruct8BytesMixedx10_a8.a2;
+  result += passStruct8BytesMixedx10_a9.a0;
+  result += passStruct8BytesMixedx10_a9.a1;
+  result += passStruct8BytesMixedx10_a9.a2;
+
+  passStruct8BytesMixedx10Result = result;
+
+  return result;
+}
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+double passStruct8BytesMixedx10(
+    Struct8BytesMixed a0,
+    Struct8BytesMixed a1,
+    Struct8BytesMixed a2,
+    Struct8BytesMixed a3,
+    Struct8BytesMixed a4,
+    Struct8BytesMixed a5,
+    Struct8BytesMixed a6,
+    Struct8BytesMixed a7,
+    Struct8BytesMixed a8,
+    Struct8BytesMixed a9) {
+  print(
+      "passStruct8BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct8BytesMixedx10 throwing on purpuse!");
+  }
+
+  passStruct8BytesMixedx10_a0 = a0;
+  passStruct8BytesMixedx10_a1 = a1;
+  passStruct8BytesMixedx10_a2 = a2;
+  passStruct8BytesMixedx10_a3 = a3;
+  passStruct8BytesMixedx10_a4 = a4;
+  passStruct8BytesMixedx10_a5 = a5;
+  passStruct8BytesMixedx10_a6 = a6;
+  passStruct8BytesMixedx10_a7 = a7;
+  passStruct8BytesMixedx10_a8 = a8;
+  passStruct8BytesMixedx10_a9 = a9;
+
+  final result = passStruct8BytesMixedx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct8BytesMixedx10AfterCallback() {
+  final result = passStruct8BytesMixedx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(15.0, result);
+}
+
+typedef PassStruct9BytesIntx10Type = Int64 Function(
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt,
+    Struct9BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct9BytesInt passStruct9BytesIntx10_a0 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a1 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a2 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a3 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a4 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a5 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a6 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a7 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a8 = Struct9BytesInt();
+Struct9BytesInt passStruct9BytesIntx10_a9 = Struct9BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct9BytesIntx10Result = 0;
+
+int passStruct9BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct9BytesIntx10_a0.a0;
+  result += passStruct9BytesIntx10_a0.a1;
+  result += passStruct9BytesIntx10_a1.a0;
+  result += passStruct9BytesIntx10_a1.a1;
+  result += passStruct9BytesIntx10_a2.a0;
+  result += passStruct9BytesIntx10_a2.a1;
+  result += passStruct9BytesIntx10_a3.a0;
+  result += passStruct9BytesIntx10_a3.a1;
+  result += passStruct9BytesIntx10_a4.a0;
+  result += passStruct9BytesIntx10_a4.a1;
+  result += passStruct9BytesIntx10_a5.a0;
+  result += passStruct9BytesIntx10_a5.a1;
+  result += passStruct9BytesIntx10_a6.a0;
+  result += passStruct9BytesIntx10_a6.a1;
+  result += passStruct9BytesIntx10_a7.a0;
+  result += passStruct9BytesIntx10_a7.a1;
+  result += passStruct9BytesIntx10_a8.a0;
+  result += passStruct9BytesIntx10_a8.a1;
+  result += passStruct9BytesIntx10_a9.a0;
+  result += passStruct9BytesIntx10_a9.a1;
+
+  passStruct9BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+int passStruct9BytesIntx10(
+    Struct9BytesInt a0,
+    Struct9BytesInt a1,
+    Struct9BytesInt a2,
+    Struct9BytesInt a3,
+    Struct9BytesInt a4,
+    Struct9BytesInt a5,
+    Struct9BytesInt a6,
+    Struct9BytesInt a7,
+    Struct9BytesInt a8,
+    Struct9BytesInt a9) {
+  print(
+      "passStruct9BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct9BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct9BytesIntx10_a0 = a0;
+  passStruct9BytesIntx10_a1 = a1;
+  passStruct9BytesIntx10_a2 = a2;
+  passStruct9BytesIntx10_a3 = a3;
+  passStruct9BytesIntx10_a4 = a4;
+  passStruct9BytesIntx10_a5 = a5;
+  passStruct9BytesIntx10_a6 = a6;
+  passStruct9BytesIntx10_a7 = a7;
+  passStruct9BytesIntx10_a8 = a8;
+  passStruct9BytesIntx10_a9 = a9;
+
+  final result = passStruct9BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct9BytesIntx10AfterCallback() {
+  final result = passStruct9BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(10, result);
+}
+
+typedef PassStruct9BytesHomogeneousUint82x10Type = Int64 Function(
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82,
+    Struct9BytesHomogeneousUint82);
+
+// Global variables to be able to test inputs after callback returned.
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a0 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a1 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a2 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a3 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a4 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a5 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a6 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a7 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a8 =
+    Struct9BytesHomogeneousUint82();
+Struct9BytesHomogeneousUint82 passStruct9BytesHomogeneousUint82x10_a9 =
+    Struct9BytesHomogeneousUint82();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct9BytesHomogeneousUint82x10Result = 0;
+
+int passStruct9BytesHomogeneousUint82x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct9BytesHomogeneousUint82x10_a0.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a0.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a1.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a2.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a3.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a4.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a5.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a6.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a7.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a8.a8;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a0;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a1;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a2;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a3;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a4;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a5;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a6;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a7;
+  result += passStruct9BytesHomogeneousUint82x10_a9.a8;
+
+  passStruct9BytesHomogeneousUint82x10Result = result;
+
+  return result;
+}
+
+/// 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.
+///
+int passStruct9BytesHomogeneousUint82x10(
+    Struct9BytesHomogeneousUint82 a0,
+    Struct9BytesHomogeneousUint82 a1,
+    Struct9BytesHomogeneousUint82 a2,
+    Struct9BytesHomogeneousUint82 a3,
+    Struct9BytesHomogeneousUint82 a4,
+    Struct9BytesHomogeneousUint82 a5,
+    Struct9BytesHomogeneousUint82 a6,
+    Struct9BytesHomogeneousUint82 a7,
+    Struct9BytesHomogeneousUint82 a8,
+    Struct9BytesHomogeneousUint82 a9) {
+  print(
+      "passStruct9BytesHomogeneousUint82x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct9BytesHomogeneousUint82x10 throwing on purpuse!");
+  }
+
+  passStruct9BytesHomogeneousUint82x10_a0 = a0;
+  passStruct9BytesHomogeneousUint82x10_a1 = a1;
+  passStruct9BytesHomogeneousUint82x10_a2 = a2;
+  passStruct9BytesHomogeneousUint82x10_a3 = a3;
+  passStruct9BytesHomogeneousUint82x10_a4 = a4;
+  passStruct9BytesHomogeneousUint82x10_a5 = a5;
+  passStruct9BytesHomogeneousUint82x10_a6 = a6;
+  passStruct9BytesHomogeneousUint82x10_a7 = a7;
+  passStruct9BytesHomogeneousUint82x10_a8 = a8;
+  passStruct9BytesHomogeneousUint82x10_a9 = a9;
+
+  final result = passStruct9BytesHomogeneousUint82x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct9BytesHomogeneousUint82x10AfterCallback() {
+  final result = passStruct9BytesHomogeneousUint82x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(4095, result);
+}
+
+typedef PassStruct12BytesHomogeneousFloatx6Type = Float Function(
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat,
+    Struct12BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a0 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a1 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a2 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a3 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a4 =
+    Struct12BytesHomogeneousFloat();
+Struct12BytesHomogeneousFloat passStruct12BytesHomogeneousFloatx6_a5 =
+    Struct12BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct12BytesHomogeneousFloatx6Result = 0.0;
+
+double passStruct12BytesHomogeneousFloatx6CalculateResult() {
+  double result = 0;
+
+  result += passStruct12BytesHomogeneousFloatx6_a0.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a0.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a0.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a1.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a2.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a3.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a4.a2;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a0;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a1;
+  result += passStruct12BytesHomogeneousFloatx6_a5.a2;
+
+  passStruct12BytesHomogeneousFloatx6Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct12BytesHomogeneousFloatx6(
+    Struct12BytesHomogeneousFloat a0,
+    Struct12BytesHomogeneousFloat a1,
+    Struct12BytesHomogeneousFloat a2,
+    Struct12BytesHomogeneousFloat a3,
+    Struct12BytesHomogeneousFloat a4,
+    Struct12BytesHomogeneousFloat a5) {
+  print(
+      "passStruct12BytesHomogeneousFloatx6(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct12BytesHomogeneousFloatx6 throwing on purpuse!");
+  }
+
+  passStruct12BytesHomogeneousFloatx6_a0 = a0;
+  passStruct12BytesHomogeneousFloatx6_a1 = a1;
+  passStruct12BytesHomogeneousFloatx6_a2 = a2;
+  passStruct12BytesHomogeneousFloatx6_a3 = a3;
+  passStruct12BytesHomogeneousFloatx6_a4 = a4;
+  passStruct12BytesHomogeneousFloatx6_a5 = a5;
+
+  final result = passStruct12BytesHomogeneousFloatx6CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct12BytesHomogeneousFloatx6AfterCallback() {
+  final result = passStruct12BytesHomogeneousFloatx6CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(9.0, result);
+}
+
+typedef PassStruct16BytesHomogeneousFloatx5Type = Float Function(
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat,
+    Struct16BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a0 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a1 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a2 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a3 =
+    Struct16BytesHomogeneousFloat();
+Struct16BytesHomogeneousFloat passStruct16BytesHomogeneousFloatx5_a4 =
+    Struct16BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesHomogeneousFloatx5Result = 0.0;
+
+double passStruct16BytesHomogeneousFloatx5CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesHomogeneousFloatx5_a0.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a0.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a1.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a2.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a3.a3;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a0;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a1;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a2;
+  result += passStruct16BytesHomogeneousFloatx5_a4.a3;
+
+  passStruct16BytesHomogeneousFloatx5Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesHomogeneousFloatx5(
+    Struct16BytesHomogeneousFloat a0,
+    Struct16BytesHomogeneousFloat a1,
+    Struct16BytesHomogeneousFloat a2,
+    Struct16BytesHomogeneousFloat a3,
+    Struct16BytesHomogeneousFloat a4) {
+  print(
+      "passStruct16BytesHomogeneousFloatx5(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesHomogeneousFloatx5 throwing on purpuse!");
+  }
+
+  passStruct16BytesHomogeneousFloatx5_a0 = a0;
+  passStruct16BytesHomogeneousFloatx5_a1 = a1;
+  passStruct16BytesHomogeneousFloatx5_a2 = a2;
+  passStruct16BytesHomogeneousFloatx5_a3 = a3;
+  passStruct16BytesHomogeneousFloatx5_a4 = a4;
+
+  final result = passStruct16BytesHomogeneousFloatx5CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesHomogeneousFloatx5AfterCallback() {
+  final result = passStruct16BytesHomogeneousFloatx5CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct16BytesMixedx10Type = Double Function(
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesMixed passStruct16BytesMixedx10_a0 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a1 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a2 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a3 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a4 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a5 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a6 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a7 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a8 = Struct16BytesMixed();
+Struct16BytesMixed passStruct16BytesMixedx10_a9 = Struct16BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesMixedx10Result = 0.0;
+
+double passStruct16BytesMixedx10CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesMixedx10_a0.a0;
+  result += passStruct16BytesMixedx10_a0.a1;
+  result += passStruct16BytesMixedx10_a1.a0;
+  result += passStruct16BytesMixedx10_a1.a1;
+  result += passStruct16BytesMixedx10_a2.a0;
+  result += passStruct16BytesMixedx10_a2.a1;
+  result += passStruct16BytesMixedx10_a3.a0;
+  result += passStruct16BytesMixedx10_a3.a1;
+  result += passStruct16BytesMixedx10_a4.a0;
+  result += passStruct16BytesMixedx10_a4.a1;
+  result += passStruct16BytesMixedx10_a5.a0;
+  result += passStruct16BytesMixedx10_a5.a1;
+  result += passStruct16BytesMixedx10_a6.a0;
+  result += passStruct16BytesMixedx10_a6.a1;
+  result += passStruct16BytesMixedx10_a7.a0;
+  result += passStruct16BytesMixedx10_a7.a1;
+  result += passStruct16BytesMixedx10_a8.a0;
+  result += passStruct16BytesMixedx10_a8.a1;
+  result += passStruct16BytesMixedx10_a9.a0;
+  result += passStruct16BytesMixedx10_a9.a1;
+
+  passStruct16BytesMixedx10Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesMixedx10(
+    Struct16BytesMixed a0,
+    Struct16BytesMixed a1,
+    Struct16BytesMixed a2,
+    Struct16BytesMixed a3,
+    Struct16BytesMixed a4,
+    Struct16BytesMixed a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    Struct16BytesMixed a8,
+    Struct16BytesMixed a9) {
+  print(
+      "passStruct16BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesMixedx10 throwing on purpuse!");
+  }
+
+  passStruct16BytesMixedx10_a0 = a0;
+  passStruct16BytesMixedx10_a1 = a1;
+  passStruct16BytesMixedx10_a2 = a2;
+  passStruct16BytesMixedx10_a3 = a3;
+  passStruct16BytesMixedx10_a4 = a4;
+  passStruct16BytesMixedx10_a5 = a5;
+  passStruct16BytesMixedx10_a6 = a6;
+  passStruct16BytesMixedx10_a7 = a7;
+  passStruct16BytesMixedx10_a8 = a8;
+  passStruct16BytesMixedx10_a9 = a9;
+
+  final result = passStruct16BytesMixedx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesMixedx10AfterCallback() {
+  final result = passStruct16BytesMixedx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct16BytesMixed2x10Type = Float Function(
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2,
+    Struct16BytesMixed2);
+
+// Global variables to be able to test inputs after callback returned.
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a0 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a1 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a2 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a3 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a4 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a5 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a6 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a7 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a8 = Struct16BytesMixed2();
+Struct16BytesMixed2 passStruct16BytesMixed2x10_a9 = Struct16BytesMixed2();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct16BytesMixed2x10Result = 0.0;
+
+double passStruct16BytesMixed2x10CalculateResult() {
+  double result = 0;
+
+  result += passStruct16BytesMixed2x10_a0.a0;
+  result += passStruct16BytesMixed2x10_a0.a1;
+  result += passStruct16BytesMixed2x10_a0.a2;
+  result += passStruct16BytesMixed2x10_a0.a3;
+  result += passStruct16BytesMixed2x10_a1.a0;
+  result += passStruct16BytesMixed2x10_a1.a1;
+  result += passStruct16BytesMixed2x10_a1.a2;
+  result += passStruct16BytesMixed2x10_a1.a3;
+  result += passStruct16BytesMixed2x10_a2.a0;
+  result += passStruct16BytesMixed2x10_a2.a1;
+  result += passStruct16BytesMixed2x10_a2.a2;
+  result += passStruct16BytesMixed2x10_a2.a3;
+  result += passStruct16BytesMixed2x10_a3.a0;
+  result += passStruct16BytesMixed2x10_a3.a1;
+  result += passStruct16BytesMixed2x10_a3.a2;
+  result += passStruct16BytesMixed2x10_a3.a3;
+  result += passStruct16BytesMixed2x10_a4.a0;
+  result += passStruct16BytesMixed2x10_a4.a1;
+  result += passStruct16BytesMixed2x10_a4.a2;
+  result += passStruct16BytesMixed2x10_a4.a3;
+  result += passStruct16BytesMixed2x10_a5.a0;
+  result += passStruct16BytesMixed2x10_a5.a1;
+  result += passStruct16BytesMixed2x10_a5.a2;
+  result += passStruct16BytesMixed2x10_a5.a3;
+  result += passStruct16BytesMixed2x10_a6.a0;
+  result += passStruct16BytesMixed2x10_a6.a1;
+  result += passStruct16BytesMixed2x10_a6.a2;
+  result += passStruct16BytesMixed2x10_a6.a3;
+  result += passStruct16BytesMixed2x10_a7.a0;
+  result += passStruct16BytesMixed2x10_a7.a1;
+  result += passStruct16BytesMixed2x10_a7.a2;
+  result += passStruct16BytesMixed2x10_a7.a3;
+  result += passStruct16BytesMixed2x10_a8.a0;
+  result += passStruct16BytesMixed2x10_a8.a1;
+  result += passStruct16BytesMixed2x10_a8.a2;
+  result += passStruct16BytesMixed2x10_a8.a3;
+  result += passStruct16BytesMixed2x10_a9.a0;
+  result += passStruct16BytesMixed2x10_a9.a1;
+  result += passStruct16BytesMixed2x10_a9.a2;
+  result += passStruct16BytesMixed2x10_a9.a3;
+
+  passStruct16BytesMixed2x10Result = result;
+
+  return result;
+}
+
+/// 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.
+double passStruct16BytesMixed2x10(
+    Struct16BytesMixed2 a0,
+    Struct16BytesMixed2 a1,
+    Struct16BytesMixed2 a2,
+    Struct16BytesMixed2 a3,
+    Struct16BytesMixed2 a4,
+    Struct16BytesMixed2 a5,
+    Struct16BytesMixed2 a6,
+    Struct16BytesMixed2 a7,
+    Struct16BytesMixed2 a8,
+    Struct16BytesMixed2 a9) {
+  print(
+      "passStruct16BytesMixed2x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct16BytesMixed2x10 throwing on purpuse!");
+  }
+
+  passStruct16BytesMixed2x10_a0 = a0;
+  passStruct16BytesMixed2x10_a1 = a1;
+  passStruct16BytesMixed2x10_a2 = a2;
+  passStruct16BytesMixed2x10_a3 = a3;
+  passStruct16BytesMixed2x10_a4 = a4;
+  passStruct16BytesMixed2x10_a5 = a5;
+  passStruct16BytesMixed2x10_a6 = a6;
+  passStruct16BytesMixed2x10_a7 = a7;
+  passStruct16BytesMixed2x10_a8 = a8;
+  passStruct16BytesMixed2x10_a9 = a9;
+
+  final result = passStruct16BytesMixed2x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct16BytesMixed2x10AfterCallback() {
+  final result = passStruct16BytesMixed2x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(20.0, result);
+}
+
+typedef PassStruct17BytesIntx10Type = Int64 Function(
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt,
+    Struct17BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct17BytesInt passStruct17BytesIntx10_a0 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a1 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a2 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a3 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a4 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a5 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a6 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a7 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a8 = Struct17BytesInt();
+Struct17BytesInt passStruct17BytesIntx10_a9 = Struct17BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct17BytesIntx10Result = 0;
+
+int passStruct17BytesIntx10CalculateResult() {
+  int result = 0;
+
+  result += passStruct17BytesIntx10_a0.a0;
+  result += passStruct17BytesIntx10_a0.a1;
+  result += passStruct17BytesIntx10_a0.a2;
+  result += passStruct17BytesIntx10_a1.a0;
+  result += passStruct17BytesIntx10_a1.a1;
+  result += passStruct17BytesIntx10_a1.a2;
+  result += passStruct17BytesIntx10_a2.a0;
+  result += passStruct17BytesIntx10_a2.a1;
+  result += passStruct17BytesIntx10_a2.a2;
+  result += passStruct17BytesIntx10_a3.a0;
+  result += passStruct17BytesIntx10_a3.a1;
+  result += passStruct17BytesIntx10_a3.a2;
+  result += passStruct17BytesIntx10_a4.a0;
+  result += passStruct17BytesIntx10_a4.a1;
+  result += passStruct17BytesIntx10_a4.a2;
+  result += passStruct17BytesIntx10_a5.a0;
+  result += passStruct17BytesIntx10_a5.a1;
+  result += passStruct17BytesIntx10_a5.a2;
+  result += passStruct17BytesIntx10_a6.a0;
+  result += passStruct17BytesIntx10_a6.a1;
+  result += passStruct17BytesIntx10_a6.a2;
+  result += passStruct17BytesIntx10_a7.a0;
+  result += passStruct17BytesIntx10_a7.a1;
+  result += passStruct17BytesIntx10_a7.a2;
+  result += passStruct17BytesIntx10_a8.a0;
+  result += passStruct17BytesIntx10_a8.a1;
+  result += passStruct17BytesIntx10_a8.a2;
+  result += passStruct17BytesIntx10_a9.a0;
+  result += passStruct17BytesIntx10_a9.a1;
+  result += passStruct17BytesIntx10_a9.a2;
+
+  passStruct17BytesIntx10Result = result;
+
+  return result;
+}
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+int passStruct17BytesIntx10(
+    Struct17BytesInt a0,
+    Struct17BytesInt a1,
+    Struct17BytesInt a2,
+    Struct17BytesInt a3,
+    Struct17BytesInt a4,
+    Struct17BytesInt a5,
+    Struct17BytesInt a6,
+    Struct17BytesInt a7,
+    Struct17BytesInt a8,
+    Struct17BytesInt a9) {
+  print(
+      "passStruct17BytesIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct17BytesIntx10 throwing on purpuse!");
+  }
+
+  passStruct17BytesIntx10_a0 = a0;
+  passStruct17BytesIntx10_a1 = a1;
+  passStruct17BytesIntx10_a2 = a2;
+  passStruct17BytesIntx10_a3 = a3;
+  passStruct17BytesIntx10_a4 = a4;
+  passStruct17BytesIntx10_a5 = a5;
+  passStruct17BytesIntx10_a6 = a6;
+  passStruct17BytesIntx10_a7 = a7;
+  passStruct17BytesIntx10_a8 = a8;
+  passStruct17BytesIntx10_a9 = a9;
+
+  final result = passStruct17BytesIntx10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct17BytesIntx10AfterCallback() {
+  final result = passStruct17BytesIntx10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(15, result);
+}
+
+typedef PassStruct19BytesHomogeneousUint8x10Type = Int64 Function(
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8,
+    Struct19BytesHomogeneousUint8);
+
+// Global variables to be able to test inputs after callback returned.
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a0 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a1 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a2 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a3 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a4 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a5 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a6 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a7 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a8 =
+    Struct19BytesHomogeneousUint8();
+Struct19BytesHomogeneousUint8 passStruct19BytesHomogeneousUint8x10_a9 =
+    Struct19BytesHomogeneousUint8();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct19BytesHomogeneousUint8x10Result = 0;
+
+int passStruct19BytesHomogeneousUint8x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct19BytesHomogeneousUint8x10_a0.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a0.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a1.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a2.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a3.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a4.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a5.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a6.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a7.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a8.a18;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a0;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a1;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a2;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a3;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a4;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a5;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a6;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a7;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a8;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a9;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a10;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a11;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a12;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a13;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a14;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a15;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a16;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a17;
+  result += passStruct19BytesHomogeneousUint8x10_a9.a18;
+
+  passStruct19BytesHomogeneousUint8x10Result = result;
+
+  return result;
+}
+
+/// 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.
+///
+int passStruct19BytesHomogeneousUint8x10(
+    Struct19BytesHomogeneousUint8 a0,
+    Struct19BytesHomogeneousUint8 a1,
+    Struct19BytesHomogeneousUint8 a2,
+    Struct19BytesHomogeneousUint8 a3,
+    Struct19BytesHomogeneousUint8 a4,
+    Struct19BytesHomogeneousUint8 a5,
+    Struct19BytesHomogeneousUint8 a6,
+    Struct19BytesHomogeneousUint8 a7,
+    Struct19BytesHomogeneousUint8 a8,
+    Struct19BytesHomogeneousUint8 a9) {
+  print(
+      "passStruct19BytesHomogeneousUint8x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct19BytesHomogeneousUint8x10 throwing on purpuse!");
+  }
+
+  passStruct19BytesHomogeneousUint8x10_a0 = a0;
+  passStruct19BytesHomogeneousUint8x10_a1 = a1;
+  passStruct19BytesHomogeneousUint8x10_a2 = a2;
+  passStruct19BytesHomogeneousUint8x10_a3 = a3;
+  passStruct19BytesHomogeneousUint8x10_a4 = a4;
+  passStruct19BytesHomogeneousUint8x10_a5 = a5;
+  passStruct19BytesHomogeneousUint8x10_a6 = a6;
+  passStruct19BytesHomogeneousUint8x10_a7 = a7;
+  passStruct19BytesHomogeneousUint8x10_a8 = a8;
+  passStruct19BytesHomogeneousUint8x10_a9 = a9;
+
+  final result = passStruct19BytesHomogeneousUint8x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct19BytesHomogeneousUint8x10AfterCallback() {
+  final result = passStruct19BytesHomogeneousUint8x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(18145, result);
+}
+
+typedef PassStruct20BytesHomogeneousInt32x10Type = Int32 Function(
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32,
+    Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a0 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a1 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a2 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a3 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a4 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a5 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a6 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a7 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a8 =
+    Struct20BytesHomogeneousInt32();
+Struct20BytesHomogeneousInt32 passStruct20BytesHomogeneousInt32x10_a9 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct20BytesHomogeneousInt32x10Result = 0;
+
+int passStruct20BytesHomogeneousInt32x10CalculateResult() {
+  int result = 0;
+
+  result += passStruct20BytesHomogeneousInt32x10_a0.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a0.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a1.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a2.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a3.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a4.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a5.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a6.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a7.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a8.a4;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a0;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a1;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a2;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a3;
+  result += passStruct20BytesHomogeneousInt32x10_a9.a4;
+
+  passStruct20BytesHomogeneousInt32x10Result = result;
+
+  return result;
+}
+
+/// 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.
+int passStruct20BytesHomogeneousInt32x10(
+    Struct20BytesHomogeneousInt32 a0,
+    Struct20BytesHomogeneousInt32 a1,
+    Struct20BytesHomogeneousInt32 a2,
+    Struct20BytesHomogeneousInt32 a3,
+    Struct20BytesHomogeneousInt32 a4,
+    Struct20BytesHomogeneousInt32 a5,
+    Struct20BytesHomogeneousInt32 a6,
+    Struct20BytesHomogeneousInt32 a7,
+    Struct20BytesHomogeneousInt32 a8,
+    Struct20BytesHomogeneousInt32 a9) {
+  print(
+      "passStruct20BytesHomogeneousInt32x10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct20BytesHomogeneousInt32x10 throwing on purpuse!");
+  }
+
+  passStruct20BytesHomogeneousInt32x10_a0 = a0;
+  passStruct20BytesHomogeneousInt32x10_a1 = a1;
+  passStruct20BytesHomogeneousInt32x10_a2 = a2;
+  passStruct20BytesHomogeneousInt32x10_a3 = a3;
+  passStruct20BytesHomogeneousInt32x10_a4 = a4;
+  passStruct20BytesHomogeneousInt32x10_a5 = a5;
+  passStruct20BytesHomogeneousInt32x10_a6 = a6;
+  passStruct20BytesHomogeneousInt32x10_a7 = a7;
+  passStruct20BytesHomogeneousInt32x10_a8 = a8;
+  passStruct20BytesHomogeneousInt32x10_a9 = a9;
+
+  final result = passStruct20BytesHomogeneousInt32x10CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct20BytesHomogeneousInt32x10AfterCallback() {
+  final result = passStruct20BytesHomogeneousInt32x10CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(25, result);
+}
+
+typedef PassStruct20BytesHomogeneousFloatType = Float Function(
+    Struct20BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousFloat passStruct20BytesHomogeneousFloat_a0 =
+    Struct20BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct20BytesHomogeneousFloatResult = 0.0;
+
+double passStruct20BytesHomogeneousFloatCalculateResult() {
+  double result = 0;
+
+  result += passStruct20BytesHomogeneousFloat_a0.a0;
+  result += passStruct20BytesHomogeneousFloat_a0.a1;
+  result += passStruct20BytesHomogeneousFloat_a0.a2;
+  result += passStruct20BytesHomogeneousFloat_a0.a3;
+  result += passStruct20BytesHomogeneousFloat_a0.a4;
+
+  passStruct20BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+double passStruct20BytesHomogeneousFloat(Struct20BytesHomogeneousFloat a0) {
+  print("passStruct20BytesHomogeneousFloat(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct20BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  passStruct20BytesHomogeneousFloat_a0 = a0;
+
+  final result = passStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct20BytesHomogeneousFloatAfterCallback() {
+  final result = passStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-3.0, result);
+}
+
+typedef PassStruct32BytesHomogeneousDoublex5Type = Double Function(
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble,
+    Struct32BytesHomogeneousDouble);
+
+// Global variables to be able to test inputs after callback returned.
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a0 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a1 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a2 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a3 =
+    Struct32BytesHomogeneousDouble();
+Struct32BytesHomogeneousDouble passStruct32BytesHomogeneousDoublex5_a4 =
+    Struct32BytesHomogeneousDouble();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct32BytesHomogeneousDoublex5Result = 0.0;
+
+double passStruct32BytesHomogeneousDoublex5CalculateResult() {
+  double result = 0;
+
+  result += passStruct32BytesHomogeneousDoublex5_a0.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a0.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a1.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a2.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a3.a3;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a0;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a1;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a2;
+  result += passStruct32BytesHomogeneousDoublex5_a4.a3;
+
+  passStruct32BytesHomogeneousDoublex5Result = result;
+
+  return result;
+}
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+double passStruct32BytesHomogeneousDoublex5(
+    Struct32BytesHomogeneousDouble a0,
+    Struct32BytesHomogeneousDouble a1,
+    Struct32BytesHomogeneousDouble a2,
+    Struct32BytesHomogeneousDouble a3,
+    Struct32BytesHomogeneousDouble a4) {
+  print(
+      "passStruct32BytesHomogeneousDoublex5(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct32BytesHomogeneousDoublex5 throwing on purpuse!");
+  }
+
+  passStruct32BytesHomogeneousDoublex5_a0 = a0;
+  passStruct32BytesHomogeneousDoublex5_a1 = a1;
+  passStruct32BytesHomogeneousDoublex5_a2 = a2;
+  passStruct32BytesHomogeneousDoublex5_a3 = a3;
+  passStruct32BytesHomogeneousDoublex5_a4 = a4;
+
+  final result = passStruct32BytesHomogeneousDoublex5CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct32BytesHomogeneousDoublex5AfterCallback() {
+  final result = passStruct32BytesHomogeneousDoublex5CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(10.0, result);
+}
+
+typedef PassStruct40BytesHomogeneousDoubleType = Double Function(
+    Struct40BytesHomogeneousDouble);
+
+// Global variables to be able to test inputs after callback returned.
+Struct40BytesHomogeneousDouble passStruct40BytesHomogeneousDouble_a0 =
+    Struct40BytesHomogeneousDouble();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct40BytesHomogeneousDoubleResult = 0.0;
+
+double passStruct40BytesHomogeneousDoubleCalculateResult() {
+  double result = 0;
+
+  result += passStruct40BytesHomogeneousDouble_a0.a0;
+  result += passStruct40BytesHomogeneousDouble_a0.a1;
+  result += passStruct40BytesHomogeneousDouble_a0.a2;
+  result += passStruct40BytesHomogeneousDouble_a0.a3;
+  result += passStruct40BytesHomogeneousDouble_a0.a4;
+
+  passStruct40BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Argument too big to go into FPU registers in arm64.
+double passStruct40BytesHomogeneousDouble(Struct40BytesHomogeneousDouble a0) {
+  print("passStruct40BytesHomogeneousDouble(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStruct40BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  passStruct40BytesHomogeneousDouble_a0 = a0;
+
+  final result = passStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct40BytesHomogeneousDoubleAfterCallback() {
+  final result = passStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-3.0, result);
+}
+
+typedef PassStruct1024BytesHomogeneousUint64Type = Uint64 Function(
+    Struct1024BytesHomogeneousUint64);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1024BytesHomogeneousUint64 passStruct1024BytesHomogeneousUint64_a0 =
+    Struct1024BytesHomogeneousUint64();
+
+// Result variable also global, so we can delete it after the callback.
+int passStruct1024BytesHomogeneousUint64Result = 0;
+
+int passStruct1024BytesHomogeneousUint64CalculateResult() {
+  int result = 0;
+
+  result += passStruct1024BytesHomogeneousUint64_a0.a0;
+  result += passStruct1024BytesHomogeneousUint64_a0.a1;
+  result += passStruct1024BytesHomogeneousUint64_a0.a2;
+  result += passStruct1024BytesHomogeneousUint64_a0.a3;
+  result += passStruct1024BytesHomogeneousUint64_a0.a4;
+  result += passStruct1024BytesHomogeneousUint64_a0.a5;
+  result += passStruct1024BytesHomogeneousUint64_a0.a6;
+  result += passStruct1024BytesHomogeneousUint64_a0.a7;
+  result += passStruct1024BytesHomogeneousUint64_a0.a8;
+  result += passStruct1024BytesHomogeneousUint64_a0.a9;
+  result += passStruct1024BytesHomogeneousUint64_a0.a10;
+  result += passStruct1024BytesHomogeneousUint64_a0.a11;
+  result += passStruct1024BytesHomogeneousUint64_a0.a12;
+  result += passStruct1024BytesHomogeneousUint64_a0.a13;
+  result += passStruct1024BytesHomogeneousUint64_a0.a14;
+  result += passStruct1024BytesHomogeneousUint64_a0.a15;
+  result += passStruct1024BytesHomogeneousUint64_a0.a16;
+  result += passStruct1024BytesHomogeneousUint64_a0.a17;
+  result += passStruct1024BytesHomogeneousUint64_a0.a18;
+  result += passStruct1024BytesHomogeneousUint64_a0.a19;
+  result += passStruct1024BytesHomogeneousUint64_a0.a20;
+  result += passStruct1024BytesHomogeneousUint64_a0.a21;
+  result += passStruct1024BytesHomogeneousUint64_a0.a22;
+  result += passStruct1024BytesHomogeneousUint64_a0.a23;
+  result += passStruct1024BytesHomogeneousUint64_a0.a24;
+  result += passStruct1024BytesHomogeneousUint64_a0.a25;
+  result += passStruct1024BytesHomogeneousUint64_a0.a26;
+  result += passStruct1024BytesHomogeneousUint64_a0.a27;
+  result += passStruct1024BytesHomogeneousUint64_a0.a28;
+  result += passStruct1024BytesHomogeneousUint64_a0.a29;
+  result += passStruct1024BytesHomogeneousUint64_a0.a30;
+  result += passStruct1024BytesHomogeneousUint64_a0.a31;
+  result += passStruct1024BytesHomogeneousUint64_a0.a32;
+  result += passStruct1024BytesHomogeneousUint64_a0.a33;
+  result += passStruct1024BytesHomogeneousUint64_a0.a34;
+  result += passStruct1024BytesHomogeneousUint64_a0.a35;
+  result += passStruct1024BytesHomogeneousUint64_a0.a36;
+  result += passStruct1024BytesHomogeneousUint64_a0.a37;
+  result += passStruct1024BytesHomogeneousUint64_a0.a38;
+  result += passStruct1024BytesHomogeneousUint64_a0.a39;
+  result += passStruct1024BytesHomogeneousUint64_a0.a40;
+  result += passStruct1024BytesHomogeneousUint64_a0.a41;
+  result += passStruct1024BytesHomogeneousUint64_a0.a42;
+  result += passStruct1024BytesHomogeneousUint64_a0.a43;
+  result += passStruct1024BytesHomogeneousUint64_a0.a44;
+  result += passStruct1024BytesHomogeneousUint64_a0.a45;
+  result += passStruct1024BytesHomogeneousUint64_a0.a46;
+  result += passStruct1024BytesHomogeneousUint64_a0.a47;
+  result += passStruct1024BytesHomogeneousUint64_a0.a48;
+  result += passStruct1024BytesHomogeneousUint64_a0.a49;
+  result += passStruct1024BytesHomogeneousUint64_a0.a50;
+  result += passStruct1024BytesHomogeneousUint64_a0.a51;
+  result += passStruct1024BytesHomogeneousUint64_a0.a52;
+  result += passStruct1024BytesHomogeneousUint64_a0.a53;
+  result += passStruct1024BytesHomogeneousUint64_a0.a54;
+  result += passStruct1024BytesHomogeneousUint64_a0.a55;
+  result += passStruct1024BytesHomogeneousUint64_a0.a56;
+  result += passStruct1024BytesHomogeneousUint64_a0.a57;
+  result += passStruct1024BytesHomogeneousUint64_a0.a58;
+  result += passStruct1024BytesHomogeneousUint64_a0.a59;
+  result += passStruct1024BytesHomogeneousUint64_a0.a60;
+  result += passStruct1024BytesHomogeneousUint64_a0.a61;
+  result += passStruct1024BytesHomogeneousUint64_a0.a62;
+  result += passStruct1024BytesHomogeneousUint64_a0.a63;
+  result += passStruct1024BytesHomogeneousUint64_a0.a64;
+  result += passStruct1024BytesHomogeneousUint64_a0.a65;
+  result += passStruct1024BytesHomogeneousUint64_a0.a66;
+  result += passStruct1024BytesHomogeneousUint64_a0.a67;
+  result += passStruct1024BytesHomogeneousUint64_a0.a68;
+  result += passStruct1024BytesHomogeneousUint64_a0.a69;
+  result += passStruct1024BytesHomogeneousUint64_a0.a70;
+  result += passStruct1024BytesHomogeneousUint64_a0.a71;
+  result += passStruct1024BytesHomogeneousUint64_a0.a72;
+  result += passStruct1024BytesHomogeneousUint64_a0.a73;
+  result += passStruct1024BytesHomogeneousUint64_a0.a74;
+  result += passStruct1024BytesHomogeneousUint64_a0.a75;
+  result += passStruct1024BytesHomogeneousUint64_a0.a76;
+  result += passStruct1024BytesHomogeneousUint64_a0.a77;
+  result += passStruct1024BytesHomogeneousUint64_a0.a78;
+  result += passStruct1024BytesHomogeneousUint64_a0.a79;
+  result += passStruct1024BytesHomogeneousUint64_a0.a80;
+  result += passStruct1024BytesHomogeneousUint64_a0.a81;
+  result += passStruct1024BytesHomogeneousUint64_a0.a82;
+  result += passStruct1024BytesHomogeneousUint64_a0.a83;
+  result += passStruct1024BytesHomogeneousUint64_a0.a84;
+  result += passStruct1024BytesHomogeneousUint64_a0.a85;
+  result += passStruct1024BytesHomogeneousUint64_a0.a86;
+  result += passStruct1024BytesHomogeneousUint64_a0.a87;
+  result += passStruct1024BytesHomogeneousUint64_a0.a88;
+  result += passStruct1024BytesHomogeneousUint64_a0.a89;
+  result += passStruct1024BytesHomogeneousUint64_a0.a90;
+  result += passStruct1024BytesHomogeneousUint64_a0.a91;
+  result += passStruct1024BytesHomogeneousUint64_a0.a92;
+  result += passStruct1024BytesHomogeneousUint64_a0.a93;
+  result += passStruct1024BytesHomogeneousUint64_a0.a94;
+  result += passStruct1024BytesHomogeneousUint64_a0.a95;
+  result += passStruct1024BytesHomogeneousUint64_a0.a96;
+  result += passStruct1024BytesHomogeneousUint64_a0.a97;
+  result += passStruct1024BytesHomogeneousUint64_a0.a98;
+  result += passStruct1024BytesHomogeneousUint64_a0.a99;
+  result += passStruct1024BytesHomogeneousUint64_a0.a100;
+  result += passStruct1024BytesHomogeneousUint64_a0.a101;
+  result += passStruct1024BytesHomogeneousUint64_a0.a102;
+  result += passStruct1024BytesHomogeneousUint64_a0.a103;
+  result += passStruct1024BytesHomogeneousUint64_a0.a104;
+  result += passStruct1024BytesHomogeneousUint64_a0.a105;
+  result += passStruct1024BytesHomogeneousUint64_a0.a106;
+  result += passStruct1024BytesHomogeneousUint64_a0.a107;
+  result += passStruct1024BytesHomogeneousUint64_a0.a108;
+  result += passStruct1024BytesHomogeneousUint64_a0.a109;
+  result += passStruct1024BytesHomogeneousUint64_a0.a110;
+  result += passStruct1024BytesHomogeneousUint64_a0.a111;
+  result += passStruct1024BytesHomogeneousUint64_a0.a112;
+  result += passStruct1024BytesHomogeneousUint64_a0.a113;
+  result += passStruct1024BytesHomogeneousUint64_a0.a114;
+  result += passStruct1024BytesHomogeneousUint64_a0.a115;
+  result += passStruct1024BytesHomogeneousUint64_a0.a116;
+  result += passStruct1024BytesHomogeneousUint64_a0.a117;
+  result += passStruct1024BytesHomogeneousUint64_a0.a118;
+  result += passStruct1024BytesHomogeneousUint64_a0.a119;
+  result += passStruct1024BytesHomogeneousUint64_a0.a120;
+  result += passStruct1024BytesHomogeneousUint64_a0.a121;
+  result += passStruct1024BytesHomogeneousUint64_a0.a122;
+  result += passStruct1024BytesHomogeneousUint64_a0.a123;
+  result += passStruct1024BytesHomogeneousUint64_a0.a124;
+  result += passStruct1024BytesHomogeneousUint64_a0.a125;
+  result += passStruct1024BytesHomogeneousUint64_a0.a126;
+  result += passStruct1024BytesHomogeneousUint64_a0.a127;
+
+  passStruct1024BytesHomogeneousUint64Result = result;
+
+  return result;
+}
+
+/// Test 1kb struct.
+int passStruct1024BytesHomogeneousUint64(Struct1024BytesHomogeneousUint64 a0) {
+  print("passStruct1024BytesHomogeneousUint64(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct1024BytesHomogeneousUint64 throwing on purpuse!");
+  }
+
+  passStruct1024BytesHomogeneousUint64_a0 = a0;
+
+  final result = passStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct1024BytesHomogeneousUint64AfterCallback() {
+  final result = passStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(8256, result);
+}
+
+typedef PassFloatStruct16BytesHomogeneousFloatFloatStruct1Type = Float Function(
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float,
+    Struct16BytesHomogeneousFloat,
+    Float);
+
+// Global variables to be able to test inputs after callback returned.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6 = 0.0;
+Struct16BytesHomogeneousFloat
+    passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7 =
+    Struct16BytesHomogeneousFloat();
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1Result = 0.0;
+
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult() {
+  double result = 0;
+
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a0;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a1;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a2;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7.a3;
+  result += passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8;
+
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1Result = result;
+
+  return result;
+}
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+double passFloatStruct16BytesHomogeneousFloatFloatStruct1(
+    double a0,
+    Struct16BytesHomogeneousFloat a1,
+    double a2,
+    Struct16BytesHomogeneousFloat a3,
+    double a4,
+    Struct16BytesHomogeneousFloat a5,
+    double a6,
+    Struct16BytesHomogeneousFloat a7,
+    double a8) {
+  print(
+      "passFloatStruct16BytesHomogeneousFloatFloatStruct1(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassFloatStruct16BytesHomogeneousFloatFloatStruct1 throwing on purpuse!");
+  }
+
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a0 = a0;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a1 = a1;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a2 = a2;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a3 = a3;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a4 = a4;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a5 = a5;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a6 = a6;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a7 = a7;
+  passFloatStruct16BytesHomogeneousFloatFloatStruct1_a8 = a8;
+
+  final result =
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passFloatStruct16BytesHomogeneousFloatFloatStruct1AfterCallback() {
+  final result =
+      passFloatStruct16BytesHomogeneousFloatFloatStruct1CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-11.0, result);
+}
+
+typedef PassFloatStruct32BytesHomogeneousDoubleFloatStructType
+    = Double Function(
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float,
+        Struct32BytesHomogeneousDouble,
+        Float);
+
+// Global variables to be able to test inputs after callback returned.
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6 = 0.0;
+Struct32BytesHomogeneousDouble
+    passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7 =
+    Struct32BytesHomogeneousDouble();
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passFloatStruct32BytesHomogeneousDoubleFloatStructResult = 0.0;
+
+double passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult() {
+  double result = 0;
+
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a0;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a1;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a2;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7.a3;
+  result += passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8;
+
+  passFloatStruct32BytesHomogeneousDoubleFloatStructResult = result;
+
+  return result;
+}
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+double passFloatStruct32BytesHomogeneousDoubleFloatStruct(
+    double a0,
+    Struct32BytesHomogeneousDouble a1,
+    double a2,
+    Struct32BytesHomogeneousDouble a3,
+    double a4,
+    Struct32BytesHomogeneousDouble a5,
+    double a6,
+    Struct32BytesHomogeneousDouble a7,
+    double a8) {
+  print(
+      "passFloatStruct32BytesHomogeneousDoubleFloatStruct(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassFloatStruct32BytesHomogeneousDoubleFloatStruct throwing on purpuse!");
+  }
+
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a0 = a0;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a1 = a1;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a2 = a2;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a3 = a3;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a4 = a4;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a5 = a5;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a6 = a6;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a7 = a7;
+  passFloatStruct32BytesHomogeneousDoubleFloatStruct_a8 = a8;
+
+  final result =
+      passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passFloatStruct32BytesHomogeneousDoubleFloatStructAfterCallback() {
+  final result =
+      passFloatStruct32BytesHomogeneousDoubleFloatStructCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-11.0, result);
+}
+
+typedef PassInt8Struct16BytesMixedInt8Struct16BytesMixedInType
+    = Double Function(Int8, Struct16BytesMixed, Int8, Struct16BytesMixed, Int8,
+        Struct16BytesMixed, Int8, Struct16BytesMixed, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6 = 0;
+Struct16BytesMixed passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7 =
+    Struct16BytesMixed();
+int passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedInResult = 0.0;
+
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult() {
+  double result = 0;
+
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7.a0;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7.a1;
+  result += passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8;
+
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedInResult = result;
+
+  return result;
+}
+
+/// 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.
+double passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+    int a0,
+    Struct16BytesMixed a1,
+    int a2,
+    Struct16BytesMixed a3,
+    int a4,
+    Struct16BytesMixed a5,
+    int a6,
+    Struct16BytesMixed a7,
+    int a8) {
+  print(
+      "passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt8Struct16BytesMixedInt8Struct16BytesMixedIn throwing on purpuse!");
+  }
+
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a0 = a0;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a1 = a1;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a2 = a2;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a3 = a3;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a4 = a4;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a5 = a5;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a6 = a6;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a7 = a7;
+  passInt8Struct16BytesMixedInt8Struct16BytesMixedIn_a8 = a8;
+
+  final result =
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt8Struct16BytesMixedInt8Struct16BytesMixedInAfterCallback() {
+  final result =
+      passInt8Struct16BytesMixedInt8Struct16BytesMixedInCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-7.0, result);
+}
+
+typedef PassDoublex6Struct16BytesMixedx4Int32Type = Double Function(
+    Double,
+    Double,
+    Double,
+    Double,
+    Double,
+    Double,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Int32);
+
+// Global variables to be able to test inputs after callback returned.
+double passDoublex6Struct16BytesMixedx4Int32_a0 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a1 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a2 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a3 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a4 = 0.0;
+double passDoublex6Struct16BytesMixedx4Int32_a5 = 0.0;
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a6 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a7 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a8 =
+    Struct16BytesMixed();
+Struct16BytesMixed passDoublex6Struct16BytesMixedx4Int32_a9 =
+    Struct16BytesMixed();
+int passDoublex6Struct16BytesMixedx4Int32_a10 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+double passDoublex6Struct16BytesMixedx4Int32Result = 0.0;
+
+double passDoublex6Struct16BytesMixedx4Int32CalculateResult() {
+  double result = 0;
+
+  result += passDoublex6Struct16BytesMixedx4Int32_a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a2;
+  result += passDoublex6Struct16BytesMixedx4Int32_a3;
+  result += passDoublex6Struct16BytesMixedx4Int32_a4;
+  result += passDoublex6Struct16BytesMixedx4Int32_a5;
+  result += passDoublex6Struct16BytesMixedx4Int32_a6.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a6.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a7.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a7.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a8.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a8.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a9.a0;
+  result += passDoublex6Struct16BytesMixedx4Int32_a9.a1;
+  result += passDoublex6Struct16BytesMixedx4Int32_a10;
+
+  passDoublex6Struct16BytesMixedx4Int32Result = result;
+
+  return result;
+}
+
+/// 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.
+double passDoublex6Struct16BytesMixedx4Int32(
+    double a0,
+    double a1,
+    double a2,
+    double a3,
+    double a4,
+    double a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    Struct16BytesMixed a8,
+    Struct16BytesMixed a9,
+    int a10) {
+  print(
+      "passDoublex6Struct16BytesMixedx4Int32(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassDoublex6Struct16BytesMixedx4Int32 throwing on purpuse!");
+  }
+
+  passDoublex6Struct16BytesMixedx4Int32_a0 = a0;
+  passDoublex6Struct16BytesMixedx4Int32_a1 = a1;
+  passDoublex6Struct16BytesMixedx4Int32_a2 = a2;
+  passDoublex6Struct16BytesMixedx4Int32_a3 = a3;
+  passDoublex6Struct16BytesMixedx4Int32_a4 = a4;
+  passDoublex6Struct16BytesMixedx4Int32_a5 = a5;
+  passDoublex6Struct16BytesMixedx4Int32_a6 = a6;
+  passDoublex6Struct16BytesMixedx4Int32_a7 = a7;
+  passDoublex6Struct16BytesMixedx4Int32_a8 = a8;
+  passDoublex6Struct16BytesMixedx4Int32_a9 = a9;
+  passDoublex6Struct16BytesMixedx4Int32_a10 = a10;
+
+  final result = passDoublex6Struct16BytesMixedx4Int32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passDoublex6Struct16BytesMixedx4Int32AfterCallback() {
+  final result = passDoublex6Struct16BytesMixedx4Int32CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-8.0, result);
+}
+
+typedef PassInt32x4Struct16BytesMixedx4DoubleType = Double Function(
+    Int32,
+    Int32,
+    Int32,
+    Int32,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Struct16BytesMixed,
+    Double);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt32x4Struct16BytesMixedx4Double_a0 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a1 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a2 = 0;
+int passInt32x4Struct16BytesMixedx4Double_a3 = 0;
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a4 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a5 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a6 =
+    Struct16BytesMixed();
+Struct16BytesMixed passInt32x4Struct16BytesMixedx4Double_a7 =
+    Struct16BytesMixed();
+double passInt32x4Struct16BytesMixedx4Double_a8 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+double passInt32x4Struct16BytesMixedx4DoubleResult = 0.0;
+
+double passInt32x4Struct16BytesMixedx4DoubleCalculateResult() {
+  double result = 0;
+
+  result += passInt32x4Struct16BytesMixedx4Double_a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a2;
+  result += passInt32x4Struct16BytesMixedx4Double_a3;
+  result += passInt32x4Struct16BytesMixedx4Double_a4.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a4.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a5.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a5.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a6.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a6.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a7.a0;
+  result += passInt32x4Struct16BytesMixedx4Double_a7.a1;
+  result += passInt32x4Struct16BytesMixedx4Double_a8;
+
+  passInt32x4Struct16BytesMixedx4DoubleResult = result;
+
+  return result;
+}
+
+/// 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.
+double passInt32x4Struct16BytesMixedx4Double(
+    int a0,
+    int a1,
+    int a2,
+    int a3,
+    Struct16BytesMixed a4,
+    Struct16BytesMixed a5,
+    Struct16BytesMixed a6,
+    Struct16BytesMixed a7,
+    double a8) {
+  print(
+      "passInt32x4Struct16BytesMixedx4Double(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt32x4Struct16BytesMixedx4Double throwing on purpuse!");
+  }
+
+  passInt32x4Struct16BytesMixedx4Double_a0 = a0;
+  passInt32x4Struct16BytesMixedx4Double_a1 = a1;
+  passInt32x4Struct16BytesMixedx4Double_a2 = a2;
+  passInt32x4Struct16BytesMixedx4Double_a3 = a3;
+  passInt32x4Struct16BytesMixedx4Double_a4 = a4;
+  passInt32x4Struct16BytesMixedx4Double_a5 = a5;
+  passInt32x4Struct16BytesMixedx4Double_a6 = a6;
+  passInt32x4Struct16BytesMixedx4Double_a7 = a7;
+  passInt32x4Struct16BytesMixedx4Double_a8 = a8;
+
+  final result = passInt32x4Struct16BytesMixedx4DoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt32x4Struct16BytesMixedx4DoubleAfterCallback() {
+  final result = passInt32x4Struct16BytesMixedx4DoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-7.0, result);
+}
+
+typedef PassStruct40BytesHomogeneousDoubleStruct4BytesHomoType
+    = Double Function(Struct40BytesHomogeneousDouble,
+        Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct40BytesHomogeneousDouble
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0 =
+    Struct40BytesHomogeneousDouble();
+Struct4BytesHomogeneousInt16
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1 =
+    Struct4BytesHomogeneousInt16();
+Struct8BytesHomogeneousFloat
+    passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomoResult = 0.0;
+
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult() {
+  double result = 0;
+
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a1;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a2;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a3;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0.a4;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1.a1;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2.a0;
+  result += passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2.a1;
+
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomoResult = result;
+
+  return result;
+}
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+double passStruct40BytesHomogeneousDoubleStruct4BytesHomo(
+    Struct40BytesHomogeneousDouble a0,
+    Struct4BytesHomogeneousInt16 a1,
+    Struct8BytesHomogeneousFloat a2) {
+  print(
+      "passStruct40BytesHomogeneousDoubleStruct4BytesHomo(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo throwing on purpuse!");
+  }
+
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a0 = a0;
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a1 = a1;
+  passStruct40BytesHomogeneousDoubleStruct4BytesHomo_a2 = a2;
+
+  final result =
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback() {
+  final result =
+      passStruct40BytesHomogeneousDoubleStruct4BytesHomoCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(-5.0, result);
+}
+
+typedef PassStructAlignmentInt16Type = Int64 Function(StructAlignmentInt16);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt16 passStructAlignmentInt16_a0 = StructAlignmentInt16();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt16Result = 0;
+
+int passStructAlignmentInt16CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt16_a0.a0;
+  result += passStructAlignmentInt16_a0.a1;
+  result += passStructAlignmentInt16_a0.a2;
+
+  passStructAlignmentInt16Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+int passStructAlignmentInt16(StructAlignmentInt16 a0) {
+  print("passStructAlignmentInt16(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt16 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt16_a0 = a0;
+
+  final result = passStructAlignmentInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt16AfterCallback() {
+  final result = passStructAlignmentInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef PassStructAlignmentInt32Type = Int64 Function(StructAlignmentInt32);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt32 passStructAlignmentInt32_a0 = StructAlignmentInt32();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt32Result = 0;
+
+int passStructAlignmentInt32CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt32_a0.a0;
+  result += passStructAlignmentInt32_a0.a1;
+  result += passStructAlignmentInt32_a0.a2;
+
+  passStructAlignmentInt32Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 32 byte int within struct.
+int passStructAlignmentInt32(StructAlignmentInt32 a0) {
+  print("passStructAlignmentInt32(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt32 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt32_a0 = a0;
+
+  final result = passStructAlignmentInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt32AfterCallback() {
+  final result = passStructAlignmentInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef PassStructAlignmentInt64Type = Int64 Function(StructAlignmentInt64);
+
+// Global variables to be able to test inputs after callback returned.
+StructAlignmentInt64 passStructAlignmentInt64_a0 = StructAlignmentInt64();
+
+// Result variable also global, so we can delete it after the callback.
+int passStructAlignmentInt64Result = 0;
+
+int passStructAlignmentInt64CalculateResult() {
+  int result = 0;
+
+  result += passStructAlignmentInt64_a0.a0;
+  result += passStructAlignmentInt64_a0.a1;
+  result += passStructAlignmentInt64_a0.a2;
+
+  passStructAlignmentInt64Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 64 byte int within struct.
+int passStructAlignmentInt64(StructAlignmentInt64 a0) {
+  print("passStructAlignmentInt64(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("PassStructAlignmentInt64 throwing on purpuse!");
+  }
+
+  passStructAlignmentInt64_a0 = a0;
+
+  final result = passStructAlignmentInt64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passStructAlignmentInt64AfterCallback() {
+  final result = passStructAlignmentInt64CalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.equals(-2, result);
+}
+
+typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct1ByteInt_a0 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStruct1ByteIntResult = Struct1ByteInt();
+
+Struct1ByteInt returnStruct1ByteIntCalculateResult() {
+  Struct1ByteInt result = allocate<Struct1ByteInt>().ref;
+
+  result.a0 = returnStruct1ByteInt_a0;
+
+  returnStruct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Smallest struct with data.
+Struct1ByteInt returnStruct1ByteInt(int a0) {
+  print("returnStruct1ByteInt(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct1ByteInt throwing on purpuse!");
+  }
+
+  returnStruct1ByteInt_a0 = a0;
+
+  final result = returnStruct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct1ByteIntAfterCallback() {
+  free(returnStruct1ByteIntResult.addressOf);
+
+  final result = returnStruct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct1ByteIntResult.addressOf);
+}
+
+typedef ReturnStruct3BytesIntType = Struct3BytesInt Function(Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct3BytesInt_a0 = 0;
+int returnStruct3BytesInt_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct3BytesInt returnStruct3BytesIntResult = Struct3BytesInt();
+
+Struct3BytesInt returnStruct3BytesIntCalculateResult() {
+  Struct3BytesInt result = allocate<Struct3BytesInt>().ref;
+
+  result.a0 = returnStruct3BytesInt_a0;
+  result.a1 = returnStruct3BytesInt_a1;
+
+  returnStruct3BytesIntResult = result;
+
+  return result;
+}
+
+/// Smaller than word size return value on all architectures.
+Struct3BytesInt returnStruct3BytesInt(int a0, int a1) {
+  print("returnStruct3BytesInt(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct3BytesInt throwing on purpuse!");
+  }
+
+  returnStruct3BytesInt_a0 = a0;
+  returnStruct3BytesInt_a1 = a1;
+
+  final result = returnStruct3BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct3BytesIntAfterCallback() {
+  free(returnStruct3BytesIntResult.addressOf);
+
+  final result = returnStruct3BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct3BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct4BytesHomogeneousInt16Type = Struct4BytesHomogeneousInt16
+    Function(Int16, Int16);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct4BytesHomogeneousInt16_a0 = 0;
+int returnStruct4BytesHomogeneousInt16_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct4BytesHomogeneousInt16 returnStruct4BytesHomogeneousInt16Result =
+    Struct4BytesHomogeneousInt16();
+
+Struct4BytesHomogeneousInt16
+    returnStruct4BytesHomogeneousInt16CalculateResult() {
+  Struct4BytesHomogeneousInt16 result =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+
+  result.a0 = returnStruct4BytesHomogeneousInt16_a0;
+  result.a1 = returnStruct4BytesHomogeneousInt16_a1;
+
+  returnStruct4BytesHomogeneousInt16Result = result;
+
+  return result;
+}
+
+/// Word size return value on 32 bit architectures..
+Struct4BytesHomogeneousInt16 returnStruct4BytesHomogeneousInt16(
+    int a0, int a1) {
+  print("returnStruct4BytesHomogeneousInt16(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct4BytesHomogeneousInt16 throwing on purpuse!");
+  }
+
+  returnStruct4BytesHomogeneousInt16_a0 = a0;
+  returnStruct4BytesHomogeneousInt16_a1 = a1;
+
+  final result = returnStruct4BytesHomogeneousInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct4BytesHomogeneousInt16AfterCallback() {
+  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+
+  final result = returnStruct4BytesHomogeneousInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+}
+
+typedef ReturnStruct7BytesIntType = Struct7BytesInt Function(
+    Int32, Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct7BytesInt_a0 = 0;
+int returnStruct7BytesInt_a1 = 0;
+int returnStruct7BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct7BytesInt returnStruct7BytesIntResult = Struct7BytesInt();
+
+Struct7BytesInt returnStruct7BytesIntCalculateResult() {
+  Struct7BytesInt result = allocate<Struct7BytesInt>().ref;
+
+  result.a0 = returnStruct7BytesInt_a0;
+  result.a1 = returnStruct7BytesInt_a1;
+  result.a2 = returnStruct7BytesInt_a2;
+
+  returnStruct7BytesIntResult = result;
+
+  return result;
+}
+
+/// Non-wordsize return value.
+Struct7BytesInt returnStruct7BytesInt(int a0, int a1, int a2) {
+  print("returnStruct7BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct7BytesInt throwing on purpuse!");
+  }
+
+  returnStruct7BytesInt_a0 = a0;
+  returnStruct7BytesInt_a1 = a1;
+  returnStruct7BytesInt_a2 = a2;
+
+  final result = returnStruct7BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct7BytesIntAfterCallback() {
+  free(returnStruct7BytesIntResult.addressOf);
+
+  final result = returnStruct7BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct7BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct8BytesIntType = Struct8BytesInt Function(
+    Int16, Int16, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct8BytesInt_a0 = 0;
+int returnStruct8BytesInt_a1 = 0;
+int returnStruct8BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesInt returnStruct8BytesIntResult = Struct8BytesInt();
+
+Struct8BytesInt returnStruct8BytesIntCalculateResult() {
+  Struct8BytesInt result = allocate<Struct8BytesInt>().ref;
+
+  result.a0 = returnStruct8BytesInt_a0;
+  result.a1 = returnStruct8BytesInt_a1;
+  result.a2 = returnStruct8BytesInt_a2;
+
+  returnStruct8BytesIntResult = result;
+
+  return result;
+}
+
+/// Return value in integer registers on many architectures.
+Struct8BytesInt returnStruct8BytesInt(int a0, int a1, int a2) {
+  print("returnStruct8BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesInt throwing on purpuse!");
+  }
+
+  returnStruct8BytesInt_a0 = a0;
+  returnStruct8BytesInt_a1 = a1;
+  returnStruct8BytesInt_a2 = a2;
+
+  final result = returnStruct8BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesIntAfterCallback() {
+  free(returnStruct8BytesIntResult.addressOf);
+
+  final result = returnStruct8BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct8BytesHomogeneousFloatType = Struct8BytesHomogeneousFloat
+    Function(Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct8BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct8BytesHomogeneousFloat_a1 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesHomogeneousFloat returnStruct8BytesHomogeneousFloatResult =
+    Struct8BytesHomogeneousFloat();
+
+Struct8BytesHomogeneousFloat
+    returnStruct8BytesHomogeneousFloatCalculateResult() {
+  Struct8BytesHomogeneousFloat result =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct8BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct8BytesHomogeneousFloat_a1;
+
+  returnStruct8BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FP registers on many architectures.
+Struct8BytesHomogeneousFloat returnStruct8BytesHomogeneousFloat(
+    double a0, double a1) {
+  print("returnStruct8BytesHomogeneousFloat(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct8BytesHomogeneousFloat_a0 = a0;
+  returnStruct8BytesHomogeneousFloat_a1 = a1;
+
+  final result = returnStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct8BytesMixedType = Struct8BytesMixed Function(
+    Float, Int16, Int16);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct8BytesMixed_a0 = 0.0;
+int returnStruct8BytesMixed_a1 = 0;
+int returnStruct8BytesMixed_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesMixed returnStruct8BytesMixedResult = Struct8BytesMixed();
+
+Struct8BytesMixed returnStruct8BytesMixedCalculateResult() {
+  Struct8BytesMixed result = allocate<Struct8BytesMixed>().ref;
+
+  result.a0 = returnStruct8BytesMixed_a0;
+  result.a1 = returnStruct8BytesMixed_a1;
+  result.a2 = returnStruct8BytesMixed_a2;
+
+  returnStruct8BytesMixedResult = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+Struct8BytesMixed returnStruct8BytesMixed(double a0, int a1, int a2) {
+  print("returnStruct8BytesMixed(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct8BytesMixed throwing on purpuse!");
+  }
+
+  returnStruct8BytesMixed_a0 = a0;
+  returnStruct8BytesMixed_a1 = a1;
+  returnStruct8BytesMixed_a2 = a2;
+
+  final result = returnStruct8BytesMixedCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct8BytesMixedAfterCallback() {
+  free(returnStruct8BytesMixedResult.addressOf);
+
+  final result = returnStruct8BytesMixedCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct8BytesMixedResult.addressOf);
+}
+
+typedef ReturnStruct9BytesIntType = Struct9BytesInt Function(Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct9BytesInt_a0 = 0;
+int returnStruct9BytesInt_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct9BytesInt returnStruct9BytesIntResult = Struct9BytesInt();
+
+Struct9BytesInt returnStruct9BytesIntCalculateResult() {
+  Struct9BytesInt result = allocate<Struct9BytesInt>().ref;
+
+  result.a0 = returnStruct9BytesInt_a0;
+  result.a1 = returnStruct9BytesInt_a1;
+
+  returnStruct9BytesIntResult = result;
+
+  return result;
+}
+
+/// Return value in two integer registers on x64.
+/// The second register only contains a single byte.
+Struct9BytesInt returnStruct9BytesInt(int a0, int a1) {
+  print("returnStruct9BytesInt(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct9BytesInt throwing on purpuse!");
+  }
+
+  returnStruct9BytesInt_a0 = a0;
+  returnStruct9BytesInt_a1 = a1;
+
+  final result = returnStruct9BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct9BytesIntAfterCallback() {
+  free(returnStruct9BytesIntResult.addressOf);
+
+  final result = returnStruct9BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct9BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct9BytesHomogeneousUint82Type = Struct9BytesHomogeneousUint82
+    Function(Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct9BytesHomogeneousUint82_a0 = 0;
+int returnStruct9BytesHomogeneousUint82_a1 = 0;
+int returnStruct9BytesHomogeneousUint82_a2 = 0;
+int returnStruct9BytesHomogeneousUint82_a3 = 0;
+int returnStruct9BytesHomogeneousUint82_a4 = 0;
+int returnStruct9BytesHomogeneousUint82_a5 = 0;
+int returnStruct9BytesHomogeneousUint82_a6 = 0;
+int returnStruct9BytesHomogeneousUint82_a7 = 0;
+int returnStruct9BytesHomogeneousUint82_a8 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct9BytesHomogeneousUint82 returnStruct9BytesHomogeneousUint82Result =
+    Struct9BytesHomogeneousUint82();
+
+Struct9BytesHomogeneousUint82
+    returnStruct9BytesHomogeneousUint82CalculateResult() {
+  Struct9BytesHomogeneousUint82 result =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+
+  result.a0 = returnStruct9BytesHomogeneousUint82_a0;
+  result.a1 = returnStruct9BytesHomogeneousUint82_a1;
+  result.a2 = returnStruct9BytesHomogeneousUint82_a2;
+  result.a3 = returnStruct9BytesHomogeneousUint82_a3;
+  result.a4 = returnStruct9BytesHomogeneousUint82_a4;
+  result.a5 = returnStruct9BytesHomogeneousUint82_a5;
+  result.a6 = returnStruct9BytesHomogeneousUint82_a6;
+  result.a7 = returnStruct9BytesHomogeneousUint82_a7;
+  result.a8 = returnStruct9BytesHomogeneousUint82_a8;
+
+  returnStruct9BytesHomogeneousUint82Result = result;
+
+  return result;
+}
+
+/// 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.
+Struct9BytesHomogeneousUint82 returnStruct9BytesHomogeneousUint82(
+    int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
+  print(
+      "returnStruct9BytesHomogeneousUint82(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct9BytesHomogeneousUint82 throwing on purpuse!");
+  }
+
+  returnStruct9BytesHomogeneousUint82_a0 = a0;
+  returnStruct9BytesHomogeneousUint82_a1 = a1;
+  returnStruct9BytesHomogeneousUint82_a2 = a2;
+  returnStruct9BytesHomogeneousUint82_a3 = a3;
+  returnStruct9BytesHomogeneousUint82_a4 = a4;
+  returnStruct9BytesHomogeneousUint82_a5 = a5;
+  returnStruct9BytesHomogeneousUint82_a6 = a6;
+  returnStruct9BytesHomogeneousUint82_a7 = a7;
+  returnStruct9BytesHomogeneousUint82_a8 = a8;
+
+  final result = returnStruct9BytesHomogeneousUint82CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct9BytesHomogeneousUint82AfterCallback() {
+  free(returnStruct9BytesHomogeneousUint82Result.addressOf);
+
+  final result = returnStruct9BytesHomogeneousUint82CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct9BytesHomogeneousUint82Result.addressOf);
+}
+
+typedef ReturnStruct12BytesHomogeneousFloatType = Struct12BytesHomogeneousFloat
+    Function(Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct12BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct12BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct12BytesHomogeneousFloat_a2 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct12BytesHomogeneousFloat returnStruct12BytesHomogeneousFloatResult =
+    Struct12BytesHomogeneousFloat();
+
+Struct12BytesHomogeneousFloat
+    returnStruct12BytesHomogeneousFloatCalculateResult() {
+  Struct12BytesHomogeneousFloat result =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct12BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct12BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct12BytesHomogeneousFloat_a2;
+
+  returnStruct12BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+Struct12BytesHomogeneousFloat returnStruct12BytesHomogeneousFloat(
+    double a0, double a1, double a2) {
+  print("returnStruct12BytesHomogeneousFloat(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct12BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct12BytesHomogeneousFloat_a0 = a0;
+  returnStruct12BytesHomogeneousFloat_a1 = a1;
+  returnStruct12BytesHomogeneousFloat_a2 = a2;
+
+  final result = returnStruct12BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct12BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct12BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct16BytesHomogeneousFloatType = Struct16BytesHomogeneousFloat
+    Function(Float, Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a2 = 0.0;
+double returnStruct16BytesHomogeneousFloat_a3 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesHomogeneousFloat returnStruct16BytesHomogeneousFloatResult =
+    Struct16BytesHomogeneousFloat();
+
+Struct16BytesHomogeneousFloat
+    returnStruct16BytesHomogeneousFloatCalculateResult() {
+  Struct16BytesHomogeneousFloat result =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct16BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct16BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct16BytesHomogeneousFloat_a2;
+  result.a3 = returnStruct16BytesHomogeneousFloat_a3;
+
+  returnStruct16BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers on arm hardfp and arm64.
+Struct16BytesHomogeneousFloat returnStruct16BytesHomogeneousFloat(
+    double a0, double a1, double a2, double a3) {
+  print("returnStruct16BytesHomogeneousFloat(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct16BytesHomogeneousFloat_a0 = a0;
+  returnStruct16BytesHomogeneousFloat_a1 = a1;
+  returnStruct16BytesHomogeneousFloat_a2 = a2;
+  returnStruct16BytesHomogeneousFloat_a3 = a3;
+
+  final result = returnStruct16BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct16BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct16BytesMixedType = Struct16BytesMixed Function(
+    Double, Int64);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesMixed_a0 = 0.0;
+int returnStruct16BytesMixed_a1 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesMixed returnStruct16BytesMixedResult = Struct16BytesMixed();
+
+Struct16BytesMixed returnStruct16BytesMixedCalculateResult() {
+  Struct16BytesMixed result = allocate<Struct16BytesMixed>().ref;
+
+  result.a0 = returnStruct16BytesMixed_a0;
+  result.a1 = returnStruct16BytesMixed_a1;
+
+  returnStruct16BytesMixedResult = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+Struct16BytesMixed returnStruct16BytesMixed(double a0, int a1) {
+  print("returnStruct16BytesMixed(${a0}, ${a1})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesMixed throwing on purpuse!");
+  }
+
+  returnStruct16BytesMixed_a0 = a0;
+  returnStruct16BytesMixed_a1 = a1;
+
+  final result = returnStruct16BytesMixedCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesMixedAfterCallback() {
+  free(returnStruct16BytesMixedResult.addressOf);
+
+  final result = returnStruct16BytesMixedCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesMixedResult.addressOf);
+}
+
+typedef ReturnStruct16BytesMixed2Type = Struct16BytesMixed2 Function(
+    Float, Float, Float, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct16BytesMixed2_a0 = 0.0;
+double returnStruct16BytesMixed2_a1 = 0.0;
+double returnStruct16BytesMixed2_a2 = 0.0;
+int returnStruct16BytesMixed2_a3 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct16BytesMixed2 returnStruct16BytesMixed2Result = Struct16BytesMixed2();
+
+Struct16BytesMixed2 returnStruct16BytesMixed2CalculateResult() {
+  Struct16BytesMixed2 result = allocate<Struct16BytesMixed2>().ref;
+
+  result.a0 = returnStruct16BytesMixed2_a0;
+  result.a1 = returnStruct16BytesMixed2_a1;
+  result.a2 = returnStruct16BytesMixed2_a2;
+  result.a3 = returnStruct16BytesMixed2_a3;
+
+  returnStruct16BytesMixed2Result = result;
+
+  return result;
+}
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+Struct16BytesMixed2 returnStruct16BytesMixed2(
+    double a0, double a1, double a2, int a3) {
+  print("returnStruct16BytesMixed2(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct16BytesMixed2 throwing on purpuse!");
+  }
+
+  returnStruct16BytesMixed2_a0 = a0;
+  returnStruct16BytesMixed2_a1 = a1;
+  returnStruct16BytesMixed2_a2 = a2;
+  returnStruct16BytesMixed2_a3 = a3;
+
+  final result = returnStruct16BytesMixed2CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct16BytesMixed2AfterCallback() {
+  free(returnStruct16BytesMixed2Result.addressOf);
+
+  final result = returnStruct16BytesMixed2CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct16BytesMixed2Result.addressOf);
+}
+
+typedef ReturnStruct17BytesIntType = Struct17BytesInt Function(
+    Int64, Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct17BytesInt_a0 = 0;
+int returnStruct17BytesInt_a1 = 0;
+int returnStruct17BytesInt_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct17BytesInt returnStruct17BytesIntResult = Struct17BytesInt();
+
+Struct17BytesInt returnStruct17BytesIntCalculateResult() {
+  Struct17BytesInt result = allocate<Struct17BytesInt>().ref;
+
+  result.a0 = returnStruct17BytesInt_a0;
+  result.a1 = returnStruct17BytesInt_a1;
+  result.a2 = returnStruct17BytesInt_a2;
+
+  returnStruct17BytesIntResult = result;
+
+  return result;
+}
+
+/// 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.
+Struct17BytesInt returnStruct17BytesInt(int a0, int a1, int a2) {
+  print("returnStruct17BytesInt(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct17BytesInt throwing on purpuse!");
+  }
+
+  returnStruct17BytesInt_a0 = a0;
+  returnStruct17BytesInt_a1 = a1;
+  returnStruct17BytesInt_a2 = a2;
+
+  final result = returnStruct17BytesIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct17BytesIntAfterCallback() {
+  free(returnStruct17BytesIntResult.addressOf);
+
+  final result = returnStruct17BytesIntCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct17BytesIntResult.addressOf);
+}
+
+typedef ReturnStruct19BytesHomogeneousUint8Type
+    = Struct19BytesHomogeneousUint8 Function(
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8,
+        Uint8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct19BytesHomogeneousUint8_a0 = 0;
+int returnStruct19BytesHomogeneousUint8_a1 = 0;
+int returnStruct19BytesHomogeneousUint8_a2 = 0;
+int returnStruct19BytesHomogeneousUint8_a3 = 0;
+int returnStruct19BytesHomogeneousUint8_a4 = 0;
+int returnStruct19BytesHomogeneousUint8_a5 = 0;
+int returnStruct19BytesHomogeneousUint8_a6 = 0;
+int returnStruct19BytesHomogeneousUint8_a7 = 0;
+int returnStruct19BytesHomogeneousUint8_a8 = 0;
+int returnStruct19BytesHomogeneousUint8_a9 = 0;
+int returnStruct19BytesHomogeneousUint8_a10 = 0;
+int returnStruct19BytesHomogeneousUint8_a11 = 0;
+int returnStruct19BytesHomogeneousUint8_a12 = 0;
+int returnStruct19BytesHomogeneousUint8_a13 = 0;
+int returnStruct19BytesHomogeneousUint8_a14 = 0;
+int returnStruct19BytesHomogeneousUint8_a15 = 0;
+int returnStruct19BytesHomogeneousUint8_a16 = 0;
+int returnStruct19BytesHomogeneousUint8_a17 = 0;
+int returnStruct19BytesHomogeneousUint8_a18 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct19BytesHomogeneousUint8 returnStruct19BytesHomogeneousUint8Result =
+    Struct19BytesHomogeneousUint8();
+
+Struct19BytesHomogeneousUint8
+    returnStruct19BytesHomogeneousUint8CalculateResult() {
+  Struct19BytesHomogeneousUint8 result =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+
+  result.a0 = returnStruct19BytesHomogeneousUint8_a0;
+  result.a1 = returnStruct19BytesHomogeneousUint8_a1;
+  result.a2 = returnStruct19BytesHomogeneousUint8_a2;
+  result.a3 = returnStruct19BytesHomogeneousUint8_a3;
+  result.a4 = returnStruct19BytesHomogeneousUint8_a4;
+  result.a5 = returnStruct19BytesHomogeneousUint8_a5;
+  result.a6 = returnStruct19BytesHomogeneousUint8_a6;
+  result.a7 = returnStruct19BytesHomogeneousUint8_a7;
+  result.a8 = returnStruct19BytesHomogeneousUint8_a8;
+  result.a9 = returnStruct19BytesHomogeneousUint8_a9;
+  result.a10 = returnStruct19BytesHomogeneousUint8_a10;
+  result.a11 = returnStruct19BytesHomogeneousUint8_a11;
+  result.a12 = returnStruct19BytesHomogeneousUint8_a12;
+  result.a13 = returnStruct19BytesHomogeneousUint8_a13;
+  result.a14 = returnStruct19BytesHomogeneousUint8_a14;
+  result.a15 = returnStruct19BytesHomogeneousUint8_a15;
+  result.a16 = returnStruct19BytesHomogeneousUint8_a16;
+  result.a17 = returnStruct19BytesHomogeneousUint8_a17;
+  result.a18 = returnStruct19BytesHomogeneousUint8_a18;
+
+  returnStruct19BytesHomogeneousUint8Result = result;
+
+  return result;
+}
+
+/// 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.
+Struct19BytesHomogeneousUint8 returnStruct19BytesHomogeneousUint8(
+    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) {
+  print(
+      "returnStruct19BytesHomogeneousUint8(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12}, ${a13}, ${a14}, ${a15}, ${a16}, ${a17}, ${a18})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct19BytesHomogeneousUint8 throwing on purpuse!");
+  }
+
+  returnStruct19BytesHomogeneousUint8_a0 = a0;
+  returnStruct19BytesHomogeneousUint8_a1 = a1;
+  returnStruct19BytesHomogeneousUint8_a2 = a2;
+  returnStruct19BytesHomogeneousUint8_a3 = a3;
+  returnStruct19BytesHomogeneousUint8_a4 = a4;
+  returnStruct19BytesHomogeneousUint8_a5 = a5;
+  returnStruct19BytesHomogeneousUint8_a6 = a6;
+  returnStruct19BytesHomogeneousUint8_a7 = a7;
+  returnStruct19BytesHomogeneousUint8_a8 = a8;
+  returnStruct19BytesHomogeneousUint8_a9 = a9;
+  returnStruct19BytesHomogeneousUint8_a10 = a10;
+  returnStruct19BytesHomogeneousUint8_a11 = a11;
+  returnStruct19BytesHomogeneousUint8_a12 = a12;
+  returnStruct19BytesHomogeneousUint8_a13 = a13;
+  returnStruct19BytesHomogeneousUint8_a14 = a14;
+  returnStruct19BytesHomogeneousUint8_a15 = a15;
+  returnStruct19BytesHomogeneousUint8_a16 = a16;
+  returnStruct19BytesHomogeneousUint8_a17 = a17;
+  returnStruct19BytesHomogeneousUint8_a18 = a18;
+
+  final result = returnStruct19BytesHomogeneousUint8CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct19BytesHomogeneousUint8AfterCallback() {
+  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+
+  final result = returnStruct19BytesHomogeneousUint8CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+}
+
+typedef ReturnStruct20BytesHomogeneousInt32Type = Struct20BytesHomogeneousInt32
+    Function(Int32, Int32, Int32, Int32, Int32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct20BytesHomogeneousInt32_a0 = 0;
+int returnStruct20BytesHomogeneousInt32_a1 = 0;
+int returnStruct20BytesHomogeneousInt32_a2 = 0;
+int returnStruct20BytesHomogeneousInt32_a3 = 0;
+int returnStruct20BytesHomogeneousInt32_a4 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32 returnStruct20BytesHomogeneousInt32Result =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStruct20BytesHomogeneousInt32CalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+
+  result.a0 = returnStruct20BytesHomogeneousInt32_a0;
+  result.a1 = returnStruct20BytesHomogeneousInt32_a1;
+  result.a2 = returnStruct20BytesHomogeneousInt32_a2;
+  result.a3 = returnStruct20BytesHomogeneousInt32_a3;
+  result.a4 = returnStruct20BytesHomogeneousInt32_a4;
+
+  returnStruct20BytesHomogeneousInt32Result = result;
+
+  return result;
+}
+
+/// Return value too big to go in cpu registers on arm64.
+Struct20BytesHomogeneousInt32 returnStruct20BytesHomogeneousInt32(
+    int a0, int a1, int a2, int a3, int a4) {
+  print(
+      "returnStruct20BytesHomogeneousInt32(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct20BytesHomogeneousInt32 throwing on purpuse!");
+  }
+
+  returnStruct20BytesHomogeneousInt32_a0 = a0;
+  returnStruct20BytesHomogeneousInt32_a1 = a1;
+  returnStruct20BytesHomogeneousInt32_a2 = a2;
+  returnStruct20BytesHomogeneousInt32_a3 = a3;
+  returnStruct20BytesHomogeneousInt32_a4 = a4;
+
+  final result = returnStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct20BytesHomogeneousInt32AfterCallback() {
+  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+
+  final result = returnStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+}
+
+typedef ReturnStruct20BytesHomogeneousFloatType = Struct20BytesHomogeneousFloat
+    Function(Float, Float, Float, Float, Float);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct20BytesHomogeneousFloat_a0 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a1 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a2 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a3 = 0.0;
+double returnStruct20BytesHomogeneousFloat_a4 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousFloat returnStruct20BytesHomogeneousFloatResult =
+    Struct20BytesHomogeneousFloat();
+
+Struct20BytesHomogeneousFloat
+    returnStruct20BytesHomogeneousFloatCalculateResult() {
+  Struct20BytesHomogeneousFloat result =
+      allocate<Struct20BytesHomogeneousFloat>().ref;
+
+  result.a0 = returnStruct20BytesHomogeneousFloat_a0;
+  result.a1 = returnStruct20BytesHomogeneousFloat_a1;
+  result.a2 = returnStruct20BytesHomogeneousFloat_a2;
+  result.a3 = returnStruct20BytesHomogeneousFloat_a3;
+  result.a4 = returnStruct20BytesHomogeneousFloat_a4;
+
+  returnStruct20BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+Struct20BytesHomogeneousFloat returnStruct20BytesHomogeneousFloat(
+    double a0, double a1, double a2, double a3, double a4) {
+  print(
+      "returnStruct20BytesHomogeneousFloat(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStruct20BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStruct20BytesHomogeneousFloat_a0 = a0;
+  returnStruct20BytesHomogeneousFloat_a1 = a1;
+  returnStruct20BytesHomogeneousFloat_a2 = a2;
+  returnStruct20BytesHomogeneousFloat_a3 = a3;
+  returnStruct20BytesHomogeneousFloat_a4 = a4;
+
+  final result = returnStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct20BytesHomogeneousFloatAfterCallback() {
+  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+
+  final result = returnStruct20BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+}
+
+typedef ReturnStruct32BytesHomogeneousDoubleType
+    = Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct32BytesHomogeneousDouble_a0 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a1 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a2 = 0.0;
+double returnStruct32BytesHomogeneousDouble_a3 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct32BytesHomogeneousDouble returnStruct32BytesHomogeneousDoubleResult =
+    Struct32BytesHomogeneousDouble();
+
+Struct32BytesHomogeneousDouble
+    returnStruct32BytesHomogeneousDoubleCalculateResult() {
+  Struct32BytesHomogeneousDouble result =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+
+  result.a0 = returnStruct32BytesHomogeneousDouble_a0;
+  result.a1 = returnStruct32BytesHomogeneousDouble_a1;
+  result.a2 = returnStruct32BytesHomogeneousDouble_a2;
+  result.a3 = returnStruct32BytesHomogeneousDouble_a3;
+
+  returnStruct32BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Return value in FPU registers on arm64.
+Struct32BytesHomogeneousDouble returnStruct32BytesHomogeneousDouble(
+    double a0, double a1, double a2, double a3) {
+  print("returnStruct32BytesHomogeneousDouble(${a0}, ${a1}, ${a2}, ${a3})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct32BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  returnStruct32BytesHomogeneousDouble_a0 = a0;
+  returnStruct32BytesHomogeneousDouble_a1 = a1;
+  returnStruct32BytesHomogeneousDouble_a2 = a2;
+  returnStruct32BytesHomogeneousDouble_a3 = a3;
+
+  final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct32BytesHomogeneousDoubleAfterCallback() {
+  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+
+  final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+}
+
+typedef ReturnStruct40BytesHomogeneousDoubleType
+    = Struct40BytesHomogeneousDouble Function(
+        Double, Double, Double, Double, Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnStruct40BytesHomogeneousDouble_a0 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a1 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a2 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a3 = 0.0;
+double returnStruct40BytesHomogeneousDouble_a4 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct40BytesHomogeneousDouble returnStruct40BytesHomogeneousDoubleResult =
+    Struct40BytesHomogeneousDouble();
+
+Struct40BytesHomogeneousDouble
+    returnStruct40BytesHomogeneousDoubleCalculateResult() {
+  Struct40BytesHomogeneousDouble result =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+
+  result.a0 = returnStruct40BytesHomogeneousDouble_a0;
+  result.a1 = returnStruct40BytesHomogeneousDouble_a1;
+  result.a2 = returnStruct40BytesHomogeneousDouble_a2;
+  result.a3 = returnStruct40BytesHomogeneousDouble_a3;
+  result.a4 = returnStruct40BytesHomogeneousDouble_a4;
+
+  returnStruct40BytesHomogeneousDoubleResult = result;
+
+  return result;
+}
+
+/// Return value too big to go in FPU registers on arm64.
+Struct40BytesHomogeneousDouble returnStruct40BytesHomogeneousDouble(
+    double a0, double a1, double a2, double a3, double a4) {
+  print(
+      "returnStruct40BytesHomogeneousDouble(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct40BytesHomogeneousDouble throwing on purpuse!");
+  }
+
+  returnStruct40BytesHomogeneousDouble_a0 = a0;
+  returnStruct40BytesHomogeneousDouble_a1 = a1;
+  returnStruct40BytesHomogeneousDouble_a2 = a2;
+  returnStruct40BytesHomogeneousDouble_a3 = a3;
+  returnStruct40BytesHomogeneousDouble_a4 = a4;
+
+  final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct40BytesHomogeneousDoubleAfterCallback() {
+  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+
+  final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+}
+
+typedef ReturnStruct1024BytesHomogeneousUint64Type
+    = 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);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStruct1024BytesHomogeneousUint64_a0 = 0;
+int returnStruct1024BytesHomogeneousUint64_a1 = 0;
+int returnStruct1024BytesHomogeneousUint64_a2 = 0;
+int returnStruct1024BytesHomogeneousUint64_a3 = 0;
+int returnStruct1024BytesHomogeneousUint64_a4 = 0;
+int returnStruct1024BytesHomogeneousUint64_a5 = 0;
+int returnStruct1024BytesHomogeneousUint64_a6 = 0;
+int returnStruct1024BytesHomogeneousUint64_a7 = 0;
+int returnStruct1024BytesHomogeneousUint64_a8 = 0;
+int returnStruct1024BytesHomogeneousUint64_a9 = 0;
+int returnStruct1024BytesHomogeneousUint64_a10 = 0;
+int returnStruct1024BytesHomogeneousUint64_a11 = 0;
+int returnStruct1024BytesHomogeneousUint64_a12 = 0;
+int returnStruct1024BytesHomogeneousUint64_a13 = 0;
+int returnStruct1024BytesHomogeneousUint64_a14 = 0;
+int returnStruct1024BytesHomogeneousUint64_a15 = 0;
+int returnStruct1024BytesHomogeneousUint64_a16 = 0;
+int returnStruct1024BytesHomogeneousUint64_a17 = 0;
+int returnStruct1024BytesHomogeneousUint64_a18 = 0;
+int returnStruct1024BytesHomogeneousUint64_a19 = 0;
+int returnStruct1024BytesHomogeneousUint64_a20 = 0;
+int returnStruct1024BytesHomogeneousUint64_a21 = 0;
+int returnStruct1024BytesHomogeneousUint64_a22 = 0;
+int returnStruct1024BytesHomogeneousUint64_a23 = 0;
+int returnStruct1024BytesHomogeneousUint64_a24 = 0;
+int returnStruct1024BytesHomogeneousUint64_a25 = 0;
+int returnStruct1024BytesHomogeneousUint64_a26 = 0;
+int returnStruct1024BytesHomogeneousUint64_a27 = 0;
+int returnStruct1024BytesHomogeneousUint64_a28 = 0;
+int returnStruct1024BytesHomogeneousUint64_a29 = 0;
+int returnStruct1024BytesHomogeneousUint64_a30 = 0;
+int returnStruct1024BytesHomogeneousUint64_a31 = 0;
+int returnStruct1024BytesHomogeneousUint64_a32 = 0;
+int returnStruct1024BytesHomogeneousUint64_a33 = 0;
+int returnStruct1024BytesHomogeneousUint64_a34 = 0;
+int returnStruct1024BytesHomogeneousUint64_a35 = 0;
+int returnStruct1024BytesHomogeneousUint64_a36 = 0;
+int returnStruct1024BytesHomogeneousUint64_a37 = 0;
+int returnStruct1024BytesHomogeneousUint64_a38 = 0;
+int returnStruct1024BytesHomogeneousUint64_a39 = 0;
+int returnStruct1024BytesHomogeneousUint64_a40 = 0;
+int returnStruct1024BytesHomogeneousUint64_a41 = 0;
+int returnStruct1024BytesHomogeneousUint64_a42 = 0;
+int returnStruct1024BytesHomogeneousUint64_a43 = 0;
+int returnStruct1024BytesHomogeneousUint64_a44 = 0;
+int returnStruct1024BytesHomogeneousUint64_a45 = 0;
+int returnStruct1024BytesHomogeneousUint64_a46 = 0;
+int returnStruct1024BytesHomogeneousUint64_a47 = 0;
+int returnStruct1024BytesHomogeneousUint64_a48 = 0;
+int returnStruct1024BytesHomogeneousUint64_a49 = 0;
+int returnStruct1024BytesHomogeneousUint64_a50 = 0;
+int returnStruct1024BytesHomogeneousUint64_a51 = 0;
+int returnStruct1024BytesHomogeneousUint64_a52 = 0;
+int returnStruct1024BytesHomogeneousUint64_a53 = 0;
+int returnStruct1024BytesHomogeneousUint64_a54 = 0;
+int returnStruct1024BytesHomogeneousUint64_a55 = 0;
+int returnStruct1024BytesHomogeneousUint64_a56 = 0;
+int returnStruct1024BytesHomogeneousUint64_a57 = 0;
+int returnStruct1024BytesHomogeneousUint64_a58 = 0;
+int returnStruct1024BytesHomogeneousUint64_a59 = 0;
+int returnStruct1024BytesHomogeneousUint64_a60 = 0;
+int returnStruct1024BytesHomogeneousUint64_a61 = 0;
+int returnStruct1024BytesHomogeneousUint64_a62 = 0;
+int returnStruct1024BytesHomogeneousUint64_a63 = 0;
+int returnStruct1024BytesHomogeneousUint64_a64 = 0;
+int returnStruct1024BytesHomogeneousUint64_a65 = 0;
+int returnStruct1024BytesHomogeneousUint64_a66 = 0;
+int returnStruct1024BytesHomogeneousUint64_a67 = 0;
+int returnStruct1024BytesHomogeneousUint64_a68 = 0;
+int returnStruct1024BytesHomogeneousUint64_a69 = 0;
+int returnStruct1024BytesHomogeneousUint64_a70 = 0;
+int returnStruct1024BytesHomogeneousUint64_a71 = 0;
+int returnStruct1024BytesHomogeneousUint64_a72 = 0;
+int returnStruct1024BytesHomogeneousUint64_a73 = 0;
+int returnStruct1024BytesHomogeneousUint64_a74 = 0;
+int returnStruct1024BytesHomogeneousUint64_a75 = 0;
+int returnStruct1024BytesHomogeneousUint64_a76 = 0;
+int returnStruct1024BytesHomogeneousUint64_a77 = 0;
+int returnStruct1024BytesHomogeneousUint64_a78 = 0;
+int returnStruct1024BytesHomogeneousUint64_a79 = 0;
+int returnStruct1024BytesHomogeneousUint64_a80 = 0;
+int returnStruct1024BytesHomogeneousUint64_a81 = 0;
+int returnStruct1024BytesHomogeneousUint64_a82 = 0;
+int returnStruct1024BytesHomogeneousUint64_a83 = 0;
+int returnStruct1024BytesHomogeneousUint64_a84 = 0;
+int returnStruct1024BytesHomogeneousUint64_a85 = 0;
+int returnStruct1024BytesHomogeneousUint64_a86 = 0;
+int returnStruct1024BytesHomogeneousUint64_a87 = 0;
+int returnStruct1024BytesHomogeneousUint64_a88 = 0;
+int returnStruct1024BytesHomogeneousUint64_a89 = 0;
+int returnStruct1024BytesHomogeneousUint64_a90 = 0;
+int returnStruct1024BytesHomogeneousUint64_a91 = 0;
+int returnStruct1024BytesHomogeneousUint64_a92 = 0;
+int returnStruct1024BytesHomogeneousUint64_a93 = 0;
+int returnStruct1024BytesHomogeneousUint64_a94 = 0;
+int returnStruct1024BytesHomogeneousUint64_a95 = 0;
+int returnStruct1024BytesHomogeneousUint64_a96 = 0;
+int returnStruct1024BytesHomogeneousUint64_a97 = 0;
+int returnStruct1024BytesHomogeneousUint64_a98 = 0;
+int returnStruct1024BytesHomogeneousUint64_a99 = 0;
+int returnStruct1024BytesHomogeneousUint64_a100 = 0;
+int returnStruct1024BytesHomogeneousUint64_a101 = 0;
+int returnStruct1024BytesHomogeneousUint64_a102 = 0;
+int returnStruct1024BytesHomogeneousUint64_a103 = 0;
+int returnStruct1024BytesHomogeneousUint64_a104 = 0;
+int returnStruct1024BytesHomogeneousUint64_a105 = 0;
+int returnStruct1024BytesHomogeneousUint64_a106 = 0;
+int returnStruct1024BytesHomogeneousUint64_a107 = 0;
+int returnStruct1024BytesHomogeneousUint64_a108 = 0;
+int returnStruct1024BytesHomogeneousUint64_a109 = 0;
+int returnStruct1024BytesHomogeneousUint64_a110 = 0;
+int returnStruct1024BytesHomogeneousUint64_a111 = 0;
+int returnStruct1024BytesHomogeneousUint64_a112 = 0;
+int returnStruct1024BytesHomogeneousUint64_a113 = 0;
+int returnStruct1024BytesHomogeneousUint64_a114 = 0;
+int returnStruct1024BytesHomogeneousUint64_a115 = 0;
+int returnStruct1024BytesHomogeneousUint64_a116 = 0;
+int returnStruct1024BytesHomogeneousUint64_a117 = 0;
+int returnStruct1024BytesHomogeneousUint64_a118 = 0;
+int returnStruct1024BytesHomogeneousUint64_a119 = 0;
+int returnStruct1024BytesHomogeneousUint64_a120 = 0;
+int returnStruct1024BytesHomogeneousUint64_a121 = 0;
+int returnStruct1024BytesHomogeneousUint64_a122 = 0;
+int returnStruct1024BytesHomogeneousUint64_a123 = 0;
+int returnStruct1024BytesHomogeneousUint64_a124 = 0;
+int returnStruct1024BytesHomogeneousUint64_a125 = 0;
+int returnStruct1024BytesHomogeneousUint64_a126 = 0;
+int returnStruct1024BytesHomogeneousUint64_a127 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Struct1024BytesHomogeneousUint64 returnStruct1024BytesHomogeneousUint64Result =
+    Struct1024BytesHomogeneousUint64();
+
+Struct1024BytesHomogeneousUint64
+    returnStruct1024BytesHomogeneousUint64CalculateResult() {
+  Struct1024BytesHomogeneousUint64 result =
+      allocate<Struct1024BytesHomogeneousUint64>().ref;
+
+  result.a0 = returnStruct1024BytesHomogeneousUint64_a0;
+  result.a1 = returnStruct1024BytesHomogeneousUint64_a1;
+  result.a2 = returnStruct1024BytesHomogeneousUint64_a2;
+  result.a3 = returnStruct1024BytesHomogeneousUint64_a3;
+  result.a4 = returnStruct1024BytesHomogeneousUint64_a4;
+  result.a5 = returnStruct1024BytesHomogeneousUint64_a5;
+  result.a6 = returnStruct1024BytesHomogeneousUint64_a6;
+  result.a7 = returnStruct1024BytesHomogeneousUint64_a7;
+  result.a8 = returnStruct1024BytesHomogeneousUint64_a8;
+  result.a9 = returnStruct1024BytesHomogeneousUint64_a9;
+  result.a10 = returnStruct1024BytesHomogeneousUint64_a10;
+  result.a11 = returnStruct1024BytesHomogeneousUint64_a11;
+  result.a12 = returnStruct1024BytesHomogeneousUint64_a12;
+  result.a13 = returnStruct1024BytesHomogeneousUint64_a13;
+  result.a14 = returnStruct1024BytesHomogeneousUint64_a14;
+  result.a15 = returnStruct1024BytesHomogeneousUint64_a15;
+  result.a16 = returnStruct1024BytesHomogeneousUint64_a16;
+  result.a17 = returnStruct1024BytesHomogeneousUint64_a17;
+  result.a18 = returnStruct1024BytesHomogeneousUint64_a18;
+  result.a19 = returnStruct1024BytesHomogeneousUint64_a19;
+  result.a20 = returnStruct1024BytesHomogeneousUint64_a20;
+  result.a21 = returnStruct1024BytesHomogeneousUint64_a21;
+  result.a22 = returnStruct1024BytesHomogeneousUint64_a22;
+  result.a23 = returnStruct1024BytesHomogeneousUint64_a23;
+  result.a24 = returnStruct1024BytesHomogeneousUint64_a24;
+  result.a25 = returnStruct1024BytesHomogeneousUint64_a25;
+  result.a26 = returnStruct1024BytesHomogeneousUint64_a26;
+  result.a27 = returnStruct1024BytesHomogeneousUint64_a27;
+  result.a28 = returnStruct1024BytesHomogeneousUint64_a28;
+  result.a29 = returnStruct1024BytesHomogeneousUint64_a29;
+  result.a30 = returnStruct1024BytesHomogeneousUint64_a30;
+  result.a31 = returnStruct1024BytesHomogeneousUint64_a31;
+  result.a32 = returnStruct1024BytesHomogeneousUint64_a32;
+  result.a33 = returnStruct1024BytesHomogeneousUint64_a33;
+  result.a34 = returnStruct1024BytesHomogeneousUint64_a34;
+  result.a35 = returnStruct1024BytesHomogeneousUint64_a35;
+  result.a36 = returnStruct1024BytesHomogeneousUint64_a36;
+  result.a37 = returnStruct1024BytesHomogeneousUint64_a37;
+  result.a38 = returnStruct1024BytesHomogeneousUint64_a38;
+  result.a39 = returnStruct1024BytesHomogeneousUint64_a39;
+  result.a40 = returnStruct1024BytesHomogeneousUint64_a40;
+  result.a41 = returnStruct1024BytesHomogeneousUint64_a41;
+  result.a42 = returnStruct1024BytesHomogeneousUint64_a42;
+  result.a43 = returnStruct1024BytesHomogeneousUint64_a43;
+  result.a44 = returnStruct1024BytesHomogeneousUint64_a44;
+  result.a45 = returnStruct1024BytesHomogeneousUint64_a45;
+  result.a46 = returnStruct1024BytesHomogeneousUint64_a46;
+  result.a47 = returnStruct1024BytesHomogeneousUint64_a47;
+  result.a48 = returnStruct1024BytesHomogeneousUint64_a48;
+  result.a49 = returnStruct1024BytesHomogeneousUint64_a49;
+  result.a50 = returnStruct1024BytesHomogeneousUint64_a50;
+  result.a51 = returnStruct1024BytesHomogeneousUint64_a51;
+  result.a52 = returnStruct1024BytesHomogeneousUint64_a52;
+  result.a53 = returnStruct1024BytesHomogeneousUint64_a53;
+  result.a54 = returnStruct1024BytesHomogeneousUint64_a54;
+  result.a55 = returnStruct1024BytesHomogeneousUint64_a55;
+  result.a56 = returnStruct1024BytesHomogeneousUint64_a56;
+  result.a57 = returnStruct1024BytesHomogeneousUint64_a57;
+  result.a58 = returnStruct1024BytesHomogeneousUint64_a58;
+  result.a59 = returnStruct1024BytesHomogeneousUint64_a59;
+  result.a60 = returnStruct1024BytesHomogeneousUint64_a60;
+  result.a61 = returnStruct1024BytesHomogeneousUint64_a61;
+  result.a62 = returnStruct1024BytesHomogeneousUint64_a62;
+  result.a63 = returnStruct1024BytesHomogeneousUint64_a63;
+  result.a64 = returnStruct1024BytesHomogeneousUint64_a64;
+  result.a65 = returnStruct1024BytesHomogeneousUint64_a65;
+  result.a66 = returnStruct1024BytesHomogeneousUint64_a66;
+  result.a67 = returnStruct1024BytesHomogeneousUint64_a67;
+  result.a68 = returnStruct1024BytesHomogeneousUint64_a68;
+  result.a69 = returnStruct1024BytesHomogeneousUint64_a69;
+  result.a70 = returnStruct1024BytesHomogeneousUint64_a70;
+  result.a71 = returnStruct1024BytesHomogeneousUint64_a71;
+  result.a72 = returnStruct1024BytesHomogeneousUint64_a72;
+  result.a73 = returnStruct1024BytesHomogeneousUint64_a73;
+  result.a74 = returnStruct1024BytesHomogeneousUint64_a74;
+  result.a75 = returnStruct1024BytesHomogeneousUint64_a75;
+  result.a76 = returnStruct1024BytesHomogeneousUint64_a76;
+  result.a77 = returnStruct1024BytesHomogeneousUint64_a77;
+  result.a78 = returnStruct1024BytesHomogeneousUint64_a78;
+  result.a79 = returnStruct1024BytesHomogeneousUint64_a79;
+  result.a80 = returnStruct1024BytesHomogeneousUint64_a80;
+  result.a81 = returnStruct1024BytesHomogeneousUint64_a81;
+  result.a82 = returnStruct1024BytesHomogeneousUint64_a82;
+  result.a83 = returnStruct1024BytesHomogeneousUint64_a83;
+  result.a84 = returnStruct1024BytesHomogeneousUint64_a84;
+  result.a85 = returnStruct1024BytesHomogeneousUint64_a85;
+  result.a86 = returnStruct1024BytesHomogeneousUint64_a86;
+  result.a87 = returnStruct1024BytesHomogeneousUint64_a87;
+  result.a88 = returnStruct1024BytesHomogeneousUint64_a88;
+  result.a89 = returnStruct1024BytesHomogeneousUint64_a89;
+  result.a90 = returnStruct1024BytesHomogeneousUint64_a90;
+  result.a91 = returnStruct1024BytesHomogeneousUint64_a91;
+  result.a92 = returnStruct1024BytesHomogeneousUint64_a92;
+  result.a93 = returnStruct1024BytesHomogeneousUint64_a93;
+  result.a94 = returnStruct1024BytesHomogeneousUint64_a94;
+  result.a95 = returnStruct1024BytesHomogeneousUint64_a95;
+  result.a96 = returnStruct1024BytesHomogeneousUint64_a96;
+  result.a97 = returnStruct1024BytesHomogeneousUint64_a97;
+  result.a98 = returnStruct1024BytesHomogeneousUint64_a98;
+  result.a99 = returnStruct1024BytesHomogeneousUint64_a99;
+  result.a100 = returnStruct1024BytesHomogeneousUint64_a100;
+  result.a101 = returnStruct1024BytesHomogeneousUint64_a101;
+  result.a102 = returnStruct1024BytesHomogeneousUint64_a102;
+  result.a103 = returnStruct1024BytesHomogeneousUint64_a103;
+  result.a104 = returnStruct1024BytesHomogeneousUint64_a104;
+  result.a105 = returnStruct1024BytesHomogeneousUint64_a105;
+  result.a106 = returnStruct1024BytesHomogeneousUint64_a106;
+  result.a107 = returnStruct1024BytesHomogeneousUint64_a107;
+  result.a108 = returnStruct1024BytesHomogeneousUint64_a108;
+  result.a109 = returnStruct1024BytesHomogeneousUint64_a109;
+  result.a110 = returnStruct1024BytesHomogeneousUint64_a110;
+  result.a111 = returnStruct1024BytesHomogeneousUint64_a111;
+  result.a112 = returnStruct1024BytesHomogeneousUint64_a112;
+  result.a113 = returnStruct1024BytesHomogeneousUint64_a113;
+  result.a114 = returnStruct1024BytesHomogeneousUint64_a114;
+  result.a115 = returnStruct1024BytesHomogeneousUint64_a115;
+  result.a116 = returnStruct1024BytesHomogeneousUint64_a116;
+  result.a117 = returnStruct1024BytesHomogeneousUint64_a117;
+  result.a118 = returnStruct1024BytesHomogeneousUint64_a118;
+  result.a119 = returnStruct1024BytesHomogeneousUint64_a119;
+  result.a120 = returnStruct1024BytesHomogeneousUint64_a120;
+  result.a121 = returnStruct1024BytesHomogeneousUint64_a121;
+  result.a122 = returnStruct1024BytesHomogeneousUint64_a122;
+  result.a123 = returnStruct1024BytesHomogeneousUint64_a123;
+  result.a124 = returnStruct1024BytesHomogeneousUint64_a124;
+  result.a125 = returnStruct1024BytesHomogeneousUint64_a125;
+  result.a126 = returnStruct1024BytesHomogeneousUint64_a126;
+  result.a127 = returnStruct1024BytesHomogeneousUint64_a127;
+
+  returnStruct1024BytesHomogeneousUint64Result = result;
+
+  return result;
+}
+
+/// Test 1kb struct.
+Struct1024BytesHomogeneousUint64 returnStruct1024BytesHomogeneousUint64(
+    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) {
+  print(
+      "returnStruct1024BytesHomogeneousUint64(${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})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStruct1024BytesHomogeneousUint64 throwing on purpuse!");
+  }
+
+  returnStruct1024BytesHomogeneousUint64_a0 = a0;
+  returnStruct1024BytesHomogeneousUint64_a1 = a1;
+  returnStruct1024BytesHomogeneousUint64_a2 = a2;
+  returnStruct1024BytesHomogeneousUint64_a3 = a3;
+  returnStruct1024BytesHomogeneousUint64_a4 = a4;
+  returnStruct1024BytesHomogeneousUint64_a5 = a5;
+  returnStruct1024BytesHomogeneousUint64_a6 = a6;
+  returnStruct1024BytesHomogeneousUint64_a7 = a7;
+  returnStruct1024BytesHomogeneousUint64_a8 = a8;
+  returnStruct1024BytesHomogeneousUint64_a9 = a9;
+  returnStruct1024BytesHomogeneousUint64_a10 = a10;
+  returnStruct1024BytesHomogeneousUint64_a11 = a11;
+  returnStruct1024BytesHomogeneousUint64_a12 = a12;
+  returnStruct1024BytesHomogeneousUint64_a13 = a13;
+  returnStruct1024BytesHomogeneousUint64_a14 = a14;
+  returnStruct1024BytesHomogeneousUint64_a15 = a15;
+  returnStruct1024BytesHomogeneousUint64_a16 = a16;
+  returnStruct1024BytesHomogeneousUint64_a17 = a17;
+  returnStruct1024BytesHomogeneousUint64_a18 = a18;
+  returnStruct1024BytesHomogeneousUint64_a19 = a19;
+  returnStruct1024BytesHomogeneousUint64_a20 = a20;
+  returnStruct1024BytesHomogeneousUint64_a21 = a21;
+  returnStruct1024BytesHomogeneousUint64_a22 = a22;
+  returnStruct1024BytesHomogeneousUint64_a23 = a23;
+  returnStruct1024BytesHomogeneousUint64_a24 = a24;
+  returnStruct1024BytesHomogeneousUint64_a25 = a25;
+  returnStruct1024BytesHomogeneousUint64_a26 = a26;
+  returnStruct1024BytesHomogeneousUint64_a27 = a27;
+  returnStruct1024BytesHomogeneousUint64_a28 = a28;
+  returnStruct1024BytesHomogeneousUint64_a29 = a29;
+  returnStruct1024BytesHomogeneousUint64_a30 = a30;
+  returnStruct1024BytesHomogeneousUint64_a31 = a31;
+  returnStruct1024BytesHomogeneousUint64_a32 = a32;
+  returnStruct1024BytesHomogeneousUint64_a33 = a33;
+  returnStruct1024BytesHomogeneousUint64_a34 = a34;
+  returnStruct1024BytesHomogeneousUint64_a35 = a35;
+  returnStruct1024BytesHomogeneousUint64_a36 = a36;
+  returnStruct1024BytesHomogeneousUint64_a37 = a37;
+  returnStruct1024BytesHomogeneousUint64_a38 = a38;
+  returnStruct1024BytesHomogeneousUint64_a39 = a39;
+  returnStruct1024BytesHomogeneousUint64_a40 = a40;
+  returnStruct1024BytesHomogeneousUint64_a41 = a41;
+  returnStruct1024BytesHomogeneousUint64_a42 = a42;
+  returnStruct1024BytesHomogeneousUint64_a43 = a43;
+  returnStruct1024BytesHomogeneousUint64_a44 = a44;
+  returnStruct1024BytesHomogeneousUint64_a45 = a45;
+  returnStruct1024BytesHomogeneousUint64_a46 = a46;
+  returnStruct1024BytesHomogeneousUint64_a47 = a47;
+  returnStruct1024BytesHomogeneousUint64_a48 = a48;
+  returnStruct1024BytesHomogeneousUint64_a49 = a49;
+  returnStruct1024BytesHomogeneousUint64_a50 = a50;
+  returnStruct1024BytesHomogeneousUint64_a51 = a51;
+  returnStruct1024BytesHomogeneousUint64_a52 = a52;
+  returnStruct1024BytesHomogeneousUint64_a53 = a53;
+  returnStruct1024BytesHomogeneousUint64_a54 = a54;
+  returnStruct1024BytesHomogeneousUint64_a55 = a55;
+  returnStruct1024BytesHomogeneousUint64_a56 = a56;
+  returnStruct1024BytesHomogeneousUint64_a57 = a57;
+  returnStruct1024BytesHomogeneousUint64_a58 = a58;
+  returnStruct1024BytesHomogeneousUint64_a59 = a59;
+  returnStruct1024BytesHomogeneousUint64_a60 = a60;
+  returnStruct1024BytesHomogeneousUint64_a61 = a61;
+  returnStruct1024BytesHomogeneousUint64_a62 = a62;
+  returnStruct1024BytesHomogeneousUint64_a63 = a63;
+  returnStruct1024BytesHomogeneousUint64_a64 = a64;
+  returnStruct1024BytesHomogeneousUint64_a65 = a65;
+  returnStruct1024BytesHomogeneousUint64_a66 = a66;
+  returnStruct1024BytesHomogeneousUint64_a67 = a67;
+  returnStruct1024BytesHomogeneousUint64_a68 = a68;
+  returnStruct1024BytesHomogeneousUint64_a69 = a69;
+  returnStruct1024BytesHomogeneousUint64_a70 = a70;
+  returnStruct1024BytesHomogeneousUint64_a71 = a71;
+  returnStruct1024BytesHomogeneousUint64_a72 = a72;
+  returnStruct1024BytesHomogeneousUint64_a73 = a73;
+  returnStruct1024BytesHomogeneousUint64_a74 = a74;
+  returnStruct1024BytesHomogeneousUint64_a75 = a75;
+  returnStruct1024BytesHomogeneousUint64_a76 = a76;
+  returnStruct1024BytesHomogeneousUint64_a77 = a77;
+  returnStruct1024BytesHomogeneousUint64_a78 = a78;
+  returnStruct1024BytesHomogeneousUint64_a79 = a79;
+  returnStruct1024BytesHomogeneousUint64_a80 = a80;
+  returnStruct1024BytesHomogeneousUint64_a81 = a81;
+  returnStruct1024BytesHomogeneousUint64_a82 = a82;
+  returnStruct1024BytesHomogeneousUint64_a83 = a83;
+  returnStruct1024BytesHomogeneousUint64_a84 = a84;
+  returnStruct1024BytesHomogeneousUint64_a85 = a85;
+  returnStruct1024BytesHomogeneousUint64_a86 = a86;
+  returnStruct1024BytesHomogeneousUint64_a87 = a87;
+  returnStruct1024BytesHomogeneousUint64_a88 = a88;
+  returnStruct1024BytesHomogeneousUint64_a89 = a89;
+  returnStruct1024BytesHomogeneousUint64_a90 = a90;
+  returnStruct1024BytesHomogeneousUint64_a91 = a91;
+  returnStruct1024BytesHomogeneousUint64_a92 = a92;
+  returnStruct1024BytesHomogeneousUint64_a93 = a93;
+  returnStruct1024BytesHomogeneousUint64_a94 = a94;
+  returnStruct1024BytesHomogeneousUint64_a95 = a95;
+  returnStruct1024BytesHomogeneousUint64_a96 = a96;
+  returnStruct1024BytesHomogeneousUint64_a97 = a97;
+  returnStruct1024BytesHomogeneousUint64_a98 = a98;
+  returnStruct1024BytesHomogeneousUint64_a99 = a99;
+  returnStruct1024BytesHomogeneousUint64_a100 = a100;
+  returnStruct1024BytesHomogeneousUint64_a101 = a101;
+  returnStruct1024BytesHomogeneousUint64_a102 = a102;
+  returnStruct1024BytesHomogeneousUint64_a103 = a103;
+  returnStruct1024BytesHomogeneousUint64_a104 = a104;
+  returnStruct1024BytesHomogeneousUint64_a105 = a105;
+  returnStruct1024BytesHomogeneousUint64_a106 = a106;
+  returnStruct1024BytesHomogeneousUint64_a107 = a107;
+  returnStruct1024BytesHomogeneousUint64_a108 = a108;
+  returnStruct1024BytesHomogeneousUint64_a109 = a109;
+  returnStruct1024BytesHomogeneousUint64_a110 = a110;
+  returnStruct1024BytesHomogeneousUint64_a111 = a111;
+  returnStruct1024BytesHomogeneousUint64_a112 = a112;
+  returnStruct1024BytesHomogeneousUint64_a113 = a113;
+  returnStruct1024BytesHomogeneousUint64_a114 = a114;
+  returnStruct1024BytesHomogeneousUint64_a115 = a115;
+  returnStruct1024BytesHomogeneousUint64_a116 = a116;
+  returnStruct1024BytesHomogeneousUint64_a117 = a117;
+  returnStruct1024BytesHomogeneousUint64_a118 = a118;
+  returnStruct1024BytesHomogeneousUint64_a119 = a119;
+  returnStruct1024BytesHomogeneousUint64_a120 = a120;
+  returnStruct1024BytesHomogeneousUint64_a121 = a121;
+  returnStruct1024BytesHomogeneousUint64_a122 = a122;
+  returnStruct1024BytesHomogeneousUint64_a123 = a123;
+  returnStruct1024BytesHomogeneousUint64_a124 = a124;
+  returnStruct1024BytesHomogeneousUint64_a125 = a125;
+  returnStruct1024BytesHomogeneousUint64_a126 = a126;
+  returnStruct1024BytesHomogeneousUint64_a127 = a127;
+
+  final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStruct1024BytesHomogeneousUint64AfterCallback() {
+  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+
+  final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+}
+
+typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
+    Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct1ByteInt returnStructArgumentStruct1ByteInt_a0 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStructArgumentStruct1ByteIntResult = Struct1ByteInt();
+
+Struct1ByteInt returnStructArgumentStruct1ByteIntCalculateResult() {
+  Struct1ByteInt result = returnStructArgumentStruct1ByteInt_a0;
+
+  returnStructArgumentStruct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in int registers in most ABIs.
+Struct1ByteInt returnStructArgumentStruct1ByteInt(Struct1ByteInt a0) {
+  print("returnStructArgumentStruct1ByteInt(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructArgumentStruct1ByteInt throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct1ByteInt_a0 = a0;
+
+  final result = returnStructArgumentStruct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct1ByteIntAfterCallback() {
+  final result = returnStructArgumentStruct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentInt32x8Struct1ByteIntType = Struct1ByteInt Function(
+    Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Struct1ByteInt);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructArgumentInt32x8Struct1ByteInt_a0 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a1 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a2 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a3 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a4 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a5 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a6 = 0;
+int returnStructArgumentInt32x8Struct1ByteInt_a7 = 0;
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteInt_a8 = Struct1ByteInt();
+
+// Result variable also global, so we can delete it after the callback.
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteIntResult =
+    Struct1ByteInt();
+
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteIntCalculateResult() {
+  Struct1ByteInt result = returnStructArgumentInt32x8Struct1ByteInt_a8;
+
+  returnStructArgumentInt32x8Struct1ByteIntResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+Struct1ByteInt returnStructArgumentInt32x8Struct1ByteInt(int a0, int a1, int a2,
+    int a3, int a4, int a5, int a6, int a7, Struct1ByteInt a8) {
+  print(
+      "returnStructArgumentInt32x8Struct1ByteInt(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentInt32x8Struct1ByteInt throwing on purpuse!");
+  }
+
+  returnStructArgumentInt32x8Struct1ByteInt_a0 = a0;
+  returnStructArgumentInt32x8Struct1ByteInt_a1 = a1;
+  returnStructArgumentInt32x8Struct1ByteInt_a2 = a2;
+  returnStructArgumentInt32x8Struct1ByteInt_a3 = a3;
+  returnStructArgumentInt32x8Struct1ByteInt_a4 = a4;
+  returnStructArgumentInt32x8Struct1ByteInt_a5 = a5;
+  returnStructArgumentInt32x8Struct1ByteInt_a6 = a6;
+  returnStructArgumentInt32x8Struct1ByteInt_a7 = a7;
+  returnStructArgumentInt32x8Struct1ByteInt_a8 = a8;
+
+  final result = returnStructArgumentInt32x8Struct1ByteIntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentInt32x8Struct1ByteIntAfterCallback() {
+  final result = returnStructArgumentInt32x8Struct1ByteIntCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentStruct8BytesHomogeneousFloatType
+    = Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloat_a0 =
+    Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloatResult =
+    Struct8BytesHomogeneousFloat();
+
+Struct8BytesHomogeneousFloat
+    returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult() {
+  Struct8BytesHomogeneousFloat result =
+      returnStructArgumentStruct8BytesHomogeneousFloat_a0;
+
+  returnStructArgumentStruct8BytesHomogeneousFloatResult = result;
+
+  return result;
+}
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed in float registers in most ABIs.
+Struct8BytesHomogeneousFloat returnStructArgumentStruct8BytesHomogeneousFloat(
+    Struct8BytesHomogeneousFloat a0) {
+  print("returnStructArgumentStruct8BytesHomogeneousFloat(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentStruct8BytesHomogeneousFloat throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct8BytesHomogeneousFloat_a0 = a0;
+
+  final result =
+      returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct8BytesHomogeneousFloatAfterCallback() {
+  final result =
+      returnStructArgumentStruct8BytesHomogeneousFloatCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentStruct20BytesHomogeneousInt32Type
+    = Struct20BytesHomogeneousInt32 Function(Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32_a0 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32Result =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      returnStructArgumentStruct20BytesHomogeneousInt32_a0;
+
+  returnStructArgumentStruct20BytesHomogeneousInt32Result = result;
+
+  return result;
+}
+
+/// On arm64, both argument and return value are passed in by pointer.
+Struct20BytesHomogeneousInt32 returnStructArgumentStruct20BytesHomogeneousInt32(
+    Struct20BytesHomogeneousInt32 a0) {
+  print("returnStructArgumentStruct20BytesHomogeneousInt32(${a0})");
+
+  // In legacy mode, possibly return null.
+  if (a0.a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0.a0 == 42 || a0.a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentStruct20BytesHomogeneousInt32 throwing on purpuse!");
+  }
+
+  returnStructArgumentStruct20BytesHomogeneousInt32_a0 = a0;
+
+  final result =
+      returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentStruct20BytesHomogeneousInt32AfterCallback() {
+  final result =
+      returnStructArgumentStruct20BytesHomogeneousInt32CalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructArgumentInt32x8Struct20BytesHomogeneouType
+    = Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32,
+        Int32, Int32, Int32, Struct20BytesHomogeneousInt32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a0 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a1 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a2 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a3 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a4 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a5 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a6 = 0;
+int returnStructArgumentInt32x8Struct20BytesHomogeneou_a7 = 0;
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneou_a8 =
+    Struct20BytesHomogeneousInt32();
+
+// Result variable also global, so we can delete it after the callback.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneouResult =
+    Struct20BytesHomogeneousInt32();
+
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult() {
+  Struct20BytesHomogeneousInt32 result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneou_a8;
+
+  returnStructArgumentInt32x8Struct20BytesHomogeneouResult = result;
+
+  return result;
+}
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+Struct20BytesHomogeneousInt32
+    returnStructArgumentInt32x8Struct20BytesHomogeneou(
+        int a0,
+        int a1,
+        int a2,
+        int a3,
+        int a4,
+        int a5,
+        int a6,
+        int a7,
+        Struct20BytesHomogeneousInt32 a8) {
+  print(
+      "returnStructArgumentInt32x8Struct20BytesHomogeneou(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "ReturnStructArgumentInt32x8Struct20BytesHomogeneou throwing on purpuse!");
+  }
+
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a0 = a0;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a1 = a1;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a2 = a2;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a3 = a3;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a4 = a4;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a5 = a5;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a6 = a6;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a7 = a7;
+  returnStructArgumentInt32x8Struct20BytesHomogeneou_a8 = a8;
+
+  final result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructArgumentInt32x8Struct20BytesHomogeneouAfterCallback() {
+  final result =
+      returnStructArgumentInt32x8Struct20BytesHomogeneouCalculateResult();
+
+  print("after callback result = $result");
+}
+
+typedef ReturnStructAlignmentInt16Type = StructAlignmentInt16 Function(
+    Int8, Int16, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt16_a0 = 0;
+int returnStructAlignmentInt16_a1 = 0;
+int returnStructAlignmentInt16_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt16 returnStructAlignmentInt16Result = StructAlignmentInt16();
+
+StructAlignmentInt16 returnStructAlignmentInt16CalculateResult() {
+  StructAlignmentInt16 result = allocate<StructAlignmentInt16>().ref;
+
+  result.a0 = returnStructAlignmentInt16_a0;
+  result.a1 = returnStructAlignmentInt16_a1;
+  result.a2 = returnStructAlignmentInt16_a2;
+
+  returnStructAlignmentInt16Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+StructAlignmentInt16 returnStructAlignmentInt16(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt16(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt16 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt16_a0 = a0;
+  returnStructAlignmentInt16_a1 = a1;
+  returnStructAlignmentInt16_a2 = a2;
+
+  final result = returnStructAlignmentInt16CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt16AfterCallback() {
+  free(returnStructAlignmentInt16Result.addressOf);
+
+  final result = returnStructAlignmentInt16CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt16Result.addressOf);
+}
+
+typedef ReturnStructAlignmentInt32Type = StructAlignmentInt32 Function(
+    Int8, Int32, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt32_a0 = 0;
+int returnStructAlignmentInt32_a1 = 0;
+int returnStructAlignmentInt32_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt32 returnStructAlignmentInt32Result = StructAlignmentInt32();
+
+StructAlignmentInt32 returnStructAlignmentInt32CalculateResult() {
+  StructAlignmentInt32 result = allocate<StructAlignmentInt32>().ref;
+
+  result.a0 = returnStructAlignmentInt32_a0;
+  result.a1 = returnStructAlignmentInt32_a1;
+  result.a2 = returnStructAlignmentInt32_a2;
+
+  returnStructAlignmentInt32Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 32 byte int within struct.
+StructAlignmentInt32 returnStructAlignmentInt32(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt32(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt32 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt32_a0 = a0;
+  returnStructAlignmentInt32_a1 = a1;
+  returnStructAlignmentInt32_a2 = a2;
+
+  final result = returnStructAlignmentInt32CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt32AfterCallback() {
+  free(returnStructAlignmentInt32Result.addressOf);
+
+  final result = returnStructAlignmentInt32CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt32Result.addressOf);
+}
+
+typedef ReturnStructAlignmentInt64Type = StructAlignmentInt64 Function(
+    Int8, Int64, Int8);
+
+// Global variables to be able to test inputs after callback returned.
+int returnStructAlignmentInt64_a0 = 0;
+int returnStructAlignmentInt64_a1 = 0;
+int returnStructAlignmentInt64_a2 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+StructAlignmentInt64 returnStructAlignmentInt64Result = StructAlignmentInt64();
+
+StructAlignmentInt64 returnStructAlignmentInt64CalculateResult() {
+  StructAlignmentInt64 result = allocate<StructAlignmentInt64>().ref;
+
+  result.a0 = returnStructAlignmentInt64_a0;
+  result.a1 = returnStructAlignmentInt64_a1;
+  result.a2 = returnStructAlignmentInt64_a2;
+
+  returnStructAlignmentInt64Result = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 64 byte int within struct.
+StructAlignmentInt64 returnStructAlignmentInt64(int a0, int a1, int a2) {
+  print("returnStructAlignmentInt64(${a0}, ${a1}, ${a2})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception("ReturnStructAlignmentInt64 throwing on purpuse!");
+  }
+
+  returnStructAlignmentInt64_a0 = a0;
+  returnStructAlignmentInt64_a1 = a1;
+  returnStructAlignmentInt64_a2 = a2;
+
+  final result = returnStructAlignmentInt64CalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void returnStructAlignmentInt64AfterCallback() {
+  free(returnStructAlignmentInt64Result.addressOf);
+
+  final result = returnStructAlignmentInt64CalculateResult();
+
+  print("after callback result = $result");
+
+  free(returnStructAlignmentInt64Result.addressOf);
+}
diff --git a/tests/ffi_2/function_callbacks_structs_by_value_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_test.dart
new file mode 100644
index 0000000..98ab518
--- /dev/null
+++ b/tests/ffi_2/function_callbacks_structs_by_value_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2020, 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
+//
+// VMOptions=--deterministic --optimization-counter-threshold=5 --use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+void main() {
+  for (int i = 0; i < 10; i++) {
+    recursiveTest(10);
+    recursiveTest(11);
+  }
+}
+
+void recursiveTest(int recursionCounter) {
+  final struct = allocate<Struct20BytesHomogeneousInt32>().ref;
+  struct.a0 = 1;
+  struct.a1 = 2;
+  struct.a2 = 3;
+  struct.a3 = 4;
+  struct.a4 = 5;
+  final result = dartPassStructRecursive(recursionCounter, struct);
+  Expect.equals(struct.a0 + recursionCounter * 2, result.a0);
+  Expect.equals(struct.a1, result.a1);
+  Expect.equals(struct.a2, result.a2);
+  Expect.equals(struct.a3, result.a3);
+  Expect.equals(struct.a4, result.a4);
+  free(struct.addressOf);
+}
+
+Struct20BytesHomogeneousInt32 dartPassStructRecursive(
+    int recursionCounter, Struct20BytesHomogeneousInt32 struct) {
+  print("callbackPassStructRecurisive($recursionCounter, $struct)");
+  struct.a0++;
+  final structA0Saved = struct.a0;
+  if (recursionCounter <= 0) {
+    print("returning");
+    return struct;
+  }
+
+  final result =
+      cPassStructRecursive(recursionCounter - 1, struct, functionPointer);
+  result.a0++;
+
+  // Check struct.a0 is not modified by Dart->C call.
+  Expect.equals(structA0Saved, struct.a0);
+
+  // Check struct.a0 is not modified by C->Dart callback, if so struct.a4 == 0.
+  Expect.notEquals(0, struct.a4);
+
+  return result;
+}
+
+final functionPointer = Pointer.fromFunction<
+    Struct20BytesHomogeneousInt32 Function(
+        Int64, Struct20BytesHomogeneousInt32)>(dartPassStructRecursive);
+
+final cPassStructRecursive = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousInt32 Function(Int64 recursionCounter,
+        Struct20BytesHomogeneousInt32 struct, Pointer callbackAddress),
+    Struct20BytesHomogeneousInt32 Function(int recursionCounter,
+        Struct20BytesHomogeneousInt32, Pointer)>("PassStructRecursive");
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
new file mode 100644
index 0000000..d2c34dd
--- /dev/null
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -0,0 +1,4720 @@
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=5
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'dylib_utils.dart';
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+void main() {
+  for (int i = 0; i < 10; ++i) {
+    testPassStruct1ByteIntx10();
+    testPassStruct3BytesIntx10();
+    testPassStruct4BytesHomogeneousInt16x10();
+    testPassStruct7BytesIntx10();
+    testPassStruct8BytesIntx10();
+    testPassStruct8BytesHomogeneousFloatx10();
+    testPassStruct8BytesMixedx10();
+    testPassStruct9BytesIntx10();
+    testPassStruct9BytesHomogeneousUint82x10();
+    testPassStruct12BytesHomogeneousFloatx6();
+    testPassStruct16BytesHomogeneousFloatx5();
+    testPassStruct16BytesMixedx10();
+    testPassStruct16BytesMixed2x10();
+    testPassStruct17BytesIntx10();
+    testPassStruct19BytesHomogeneousUint8x10();
+    testPassStruct20BytesHomogeneousInt32x10();
+    testPassStruct20BytesHomogeneousFloat();
+    testPassStruct32BytesHomogeneousDoublex5();
+    testPassStruct40BytesHomogeneousDouble();
+    testPassStruct1024BytesHomogeneousUint64();
+    testPassFloatStruct16BytesHomogeneousFloatFloatStruct1();
+    testPassFloatStruct32BytesHomogeneousDoubleFloatStruct();
+    testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn();
+    testPassDoublex6Struct16BytesMixedx4Int32();
+    testPassInt32x4Struct16BytesMixedx4Double();
+    testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo();
+    testPassStructAlignmentInt16();
+    testPassStructAlignmentInt32();
+    testPassStructAlignmentInt64();
+    testReturnStruct1ByteInt();
+    testReturnStruct3BytesInt();
+    testReturnStruct4BytesHomogeneousInt16();
+    testReturnStruct7BytesInt();
+    testReturnStruct8BytesInt();
+    testReturnStruct8BytesHomogeneousFloat();
+    testReturnStruct8BytesMixed();
+    testReturnStruct9BytesInt();
+    testReturnStruct9BytesHomogeneousUint82();
+    testReturnStruct12BytesHomogeneousFloat();
+    testReturnStruct16BytesHomogeneousFloat();
+    testReturnStruct16BytesMixed();
+    testReturnStruct16BytesMixed2();
+    testReturnStruct17BytesInt();
+    testReturnStruct19BytesHomogeneousUint8();
+    testReturnStruct20BytesHomogeneousInt32();
+    testReturnStruct20BytesHomogeneousFloat();
+    testReturnStruct32BytesHomogeneousDouble();
+    testReturnStruct40BytesHomogeneousDouble();
+    testReturnStruct1024BytesHomogeneousUint64();
+    testReturnStructArgumentStruct1ByteInt();
+    testReturnStructArgumentInt32x8Struct1ByteInt();
+    testReturnStructArgumentStruct8BytesHomogeneousFloat();
+    testReturnStructArgumentStruct20BytesHomogeneousInt32();
+    testReturnStructArgumentInt32x8Struct20BytesHomogeneou();
+    testReturnStructAlignmentInt16();
+    testReturnStructAlignmentInt32();
+    testReturnStructAlignmentInt64();
+  }
+}
+
+class Struct0Bytes extends Struct {
+  String toString() => "()";
+}
+
+class Struct1ByteInt extends Struct {
+  @Int8()
+  int a0;
+
+  String toString() => "(${a0})";
+}
+
+class Struct3BytesInt extends Struct {
+  @Int16()
+  int a0;
+
+  @Int8()
+  int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct4BytesHomogeneousInt16 extends Struct {
+  @Int16()
+  int a0;
+
+  @Int16()
+  int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct7BytesInt extends Struct {
+  @Int32()
+  int a0;
+
+  @Int16()
+  int a1;
+
+  @Int8()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct8BytesInt extends Struct {
+  @Int16()
+  int a0;
+
+  @Int16()
+  int a1;
+
+  @Int32()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct8BytesHomogeneousFloat extends Struct {
+  @Float()
+  double a0;
+
+  @Float()
+  double a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct8BytesMixed extends Struct {
+  @Float()
+  double a0;
+
+  @Int16()
+  int a1;
+
+  @Int16()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct9BytesInt extends Struct {
+  @Int64()
+  int a0;
+
+  @Int8()
+  int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct9BytesHomogeneousUint82 extends Struct {
+  @Uint8()
+  int a0;
+
+  @Uint8()
+  int a1;
+
+  @Uint8()
+  int a2;
+
+  @Uint8()
+  int a3;
+
+  @Uint8()
+  int a4;
+
+  @Uint8()
+  int a5;
+
+  @Uint8()
+  int a6;
+
+  @Uint8()
+  int a7;
+
+  @Uint8()
+  int a8;
+
+  String toString() =>
+      "(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8})";
+}
+
+class Struct12BytesHomogeneousFloat extends Struct {
+  @Float()
+  double a0;
+
+  @Float()
+  double a1;
+
+  @Float()
+  double a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct16BytesHomogeneousFloat extends Struct {
+  @Float()
+  double a0;
+
+  @Float()
+  double a1;
+
+  @Float()
+  double a2;
+
+  @Float()
+  double a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct16BytesMixed extends Struct {
+  @Double()
+  double a0;
+
+  @Int64()
+  int a1;
+
+  String toString() => "(${a0}, ${a1})";
+}
+
+class Struct16BytesMixed2 extends Struct {
+  @Float()
+  double a0;
+
+  @Float()
+  double a1;
+
+  @Float()
+  double a2;
+
+  @Int32()
+  int a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct17BytesInt extends Struct {
+  @Int64()
+  int a0;
+
+  @Int64()
+  int a1;
+
+  @Int8()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class Struct19BytesHomogeneousUint8 extends Struct {
+  @Uint8()
+  int a0;
+
+  @Uint8()
+  int a1;
+
+  @Uint8()
+  int a2;
+
+  @Uint8()
+  int a3;
+
+  @Uint8()
+  int a4;
+
+  @Uint8()
+  int a5;
+
+  @Uint8()
+  int a6;
+
+  @Uint8()
+  int a7;
+
+  @Uint8()
+  int a8;
+
+  @Uint8()
+  int a9;
+
+  @Uint8()
+  int a10;
+
+  @Uint8()
+  int a11;
+
+  @Uint8()
+  int a12;
+
+  @Uint8()
+  int a13;
+
+  @Uint8()
+  int a14;
+
+  @Uint8()
+  int a15;
+
+  @Uint8()
+  int a16;
+
+  @Uint8()
+  int a17;
+
+  @Uint8()
+  int a18;
+
+  String toString() =>
+      "(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9}, ${a10}, ${a11}, ${a12}, ${a13}, ${a14}, ${a15}, ${a16}, ${a17}, ${a18})";
+}
+
+class Struct20BytesHomogeneousInt32 extends Struct {
+  @Int32()
+  int a0;
+
+  @Int32()
+  int a1;
+
+  @Int32()
+  int a2;
+
+  @Int32()
+  int a3;
+
+  @Int32()
+  int a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct20BytesHomogeneousFloat extends Struct {
+  @Float()
+  double a0;
+
+  @Float()
+  double a1;
+
+  @Float()
+  double a2;
+
+  @Float()
+  double a3;
+
+  @Float()
+  double a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct32BytesHomogeneousDouble extends Struct {
+  @Double()
+  double a0;
+
+  @Double()
+  double a1;
+
+  @Double()
+  double a2;
+
+  @Double()
+  double a3;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3})";
+}
+
+class Struct40BytesHomogeneousDouble extends Struct {
+  @Double()
+  double a0;
+
+  @Double()
+  double a1;
+
+  @Double()
+  double a2;
+
+  @Double()
+  double a3;
+
+  @Double()
+  double a4;
+
+  String toString() => "(${a0}, ${a1}, ${a2}, ${a3}, ${a4})";
+}
+
+class Struct1024BytesHomogeneousUint64 extends Struct {
+  @Uint64()
+  int a0;
+
+  @Uint64()
+  int a1;
+
+  @Uint64()
+  int a2;
+
+  @Uint64()
+  int a3;
+
+  @Uint64()
+  int a4;
+
+  @Uint64()
+  int a5;
+
+  @Uint64()
+  int a6;
+
+  @Uint64()
+  int a7;
+
+  @Uint64()
+  int a8;
+
+  @Uint64()
+  int a9;
+
+  @Uint64()
+  int a10;
+
+  @Uint64()
+  int a11;
+
+  @Uint64()
+  int a12;
+
+  @Uint64()
+  int a13;
+
+  @Uint64()
+  int a14;
+
+  @Uint64()
+  int a15;
+
+  @Uint64()
+  int a16;
+
+  @Uint64()
+  int a17;
+
+  @Uint64()
+  int a18;
+
+  @Uint64()
+  int a19;
+
+  @Uint64()
+  int a20;
+
+  @Uint64()
+  int a21;
+
+  @Uint64()
+  int a22;
+
+  @Uint64()
+  int a23;
+
+  @Uint64()
+  int a24;
+
+  @Uint64()
+  int a25;
+
+  @Uint64()
+  int a26;
+
+  @Uint64()
+  int a27;
+
+  @Uint64()
+  int a28;
+
+  @Uint64()
+  int a29;
+
+  @Uint64()
+  int a30;
+
+  @Uint64()
+  int a31;
+
+  @Uint64()
+  int a32;
+
+  @Uint64()
+  int a33;
+
+  @Uint64()
+  int a34;
+
+  @Uint64()
+  int a35;
+
+  @Uint64()
+  int a36;
+
+  @Uint64()
+  int a37;
+
+  @Uint64()
+  int a38;
+
+  @Uint64()
+  int a39;
+
+  @Uint64()
+  int a40;
+
+  @Uint64()
+  int a41;
+
+  @Uint64()
+  int a42;
+
+  @Uint64()
+  int a43;
+
+  @Uint64()
+  int a44;
+
+  @Uint64()
+  int a45;
+
+  @Uint64()
+  int a46;
+
+  @Uint64()
+  int a47;
+
+  @Uint64()
+  int a48;
+
+  @Uint64()
+  int a49;
+
+  @Uint64()
+  int a50;
+
+  @Uint64()
+  int a51;
+
+  @Uint64()
+  int a52;
+
+  @Uint64()
+  int a53;
+
+  @Uint64()
+  int a54;
+
+  @Uint64()
+  int a55;
+
+  @Uint64()
+  int a56;
+
+  @Uint64()
+  int a57;
+
+  @Uint64()
+  int a58;
+
+  @Uint64()
+  int a59;
+
+  @Uint64()
+  int a60;
+
+  @Uint64()
+  int a61;
+
+  @Uint64()
+  int a62;
+
+  @Uint64()
+  int a63;
+
+  @Uint64()
+  int a64;
+
+  @Uint64()
+  int a65;
+
+  @Uint64()
+  int a66;
+
+  @Uint64()
+  int a67;
+
+  @Uint64()
+  int a68;
+
+  @Uint64()
+  int a69;
+
+  @Uint64()
+  int a70;
+
+  @Uint64()
+  int a71;
+
+  @Uint64()
+  int a72;
+
+  @Uint64()
+  int a73;
+
+  @Uint64()
+  int a74;
+
+  @Uint64()
+  int a75;
+
+  @Uint64()
+  int a76;
+
+  @Uint64()
+  int a77;
+
+  @Uint64()
+  int a78;
+
+  @Uint64()
+  int a79;
+
+  @Uint64()
+  int a80;
+
+  @Uint64()
+  int a81;
+
+  @Uint64()
+  int a82;
+
+  @Uint64()
+  int a83;
+
+  @Uint64()
+  int a84;
+
+  @Uint64()
+  int a85;
+
+  @Uint64()
+  int a86;
+
+  @Uint64()
+  int a87;
+
+  @Uint64()
+  int a88;
+
+  @Uint64()
+  int a89;
+
+  @Uint64()
+  int a90;
+
+  @Uint64()
+  int a91;
+
+  @Uint64()
+  int a92;
+
+  @Uint64()
+  int a93;
+
+  @Uint64()
+  int a94;
+
+  @Uint64()
+  int a95;
+
+  @Uint64()
+  int a96;
+
+  @Uint64()
+  int a97;
+
+  @Uint64()
+  int a98;
+
+  @Uint64()
+  int a99;
+
+  @Uint64()
+  int a100;
+
+  @Uint64()
+  int a101;
+
+  @Uint64()
+  int a102;
+
+  @Uint64()
+  int a103;
+
+  @Uint64()
+  int a104;
+
+  @Uint64()
+  int a105;
+
+  @Uint64()
+  int a106;
+
+  @Uint64()
+  int a107;
+
+  @Uint64()
+  int a108;
+
+  @Uint64()
+  int a109;
+
+  @Uint64()
+  int a110;
+
+  @Uint64()
+  int a111;
+
+  @Uint64()
+  int a112;
+
+  @Uint64()
+  int a113;
+
+  @Uint64()
+  int a114;
+
+  @Uint64()
+  int a115;
+
+  @Uint64()
+  int a116;
+
+  @Uint64()
+  int a117;
+
+  @Uint64()
+  int a118;
+
+  @Uint64()
+  int a119;
+
+  @Uint64()
+  int a120;
+
+  @Uint64()
+  int a121;
+
+  @Uint64()
+  int a122;
+
+  @Uint64()
+  int a123;
+
+  @Uint64()
+  int a124;
+
+  @Uint64()
+  int a125;
+
+  @Uint64()
+  int a126;
+
+  @Uint64()
+  int a127;
+
+  String toString() =>
+      "(${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})";
+}
+
+class StructAlignmentInt16 extends Struct {
+  @Int8()
+  int a0;
+
+  @Int16()
+  int a1;
+
+  @Int8()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class StructAlignmentInt32 extends Struct {
+  @Int8()
+  int a0;
+
+  @Int32()
+  int a1;
+
+  @Int8()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+class StructAlignmentInt64 extends Struct {
+  @Int8()
+  int a0;
+
+  @Int64()
+  int a1;
+
+  @Int8()
+  int a2;
+
+  String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
+final passStruct1ByteIntx10 = 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");
+
+/// Smallest struct with data.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct1ByteIntx10() {
+  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a1 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a2 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a3 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a4 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a5 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a6 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a7 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a9 = allocate<Struct1ByteInt>().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 = passStruct1ByteIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(5, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct3BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt),
+    int Function(
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt,
+        Struct3BytesInt)>("PassStruct3BytesIntx10");
+
+/// Not a multiple of word size, not a power of two.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct3BytesIntx10() {
+  Struct3BytesInt a0 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a1 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a2 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a3 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a4 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a5 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a6 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a7 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a8 = allocate<Struct3BytesInt>().ref;
+  Struct3BytesInt a9 = allocate<Struct3BytesInt>().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 = passStruct3BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct4BytesHomogeneousInt16x10 = 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");
+
+/// Exactly word size on 32-bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct4BytesHomogeneousInt16x10() {
+  Struct4BytesHomogeneousInt16 a0 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a2 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a3 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a4 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a5 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a6 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a7 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a8 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a9 =
+      allocate<Struct4BytesHomogeneousInt16>().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 = passStruct4BytesHomogeneousInt16x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct7BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt),
+    int Function(
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt,
+        Struct7BytesInt)>("PassStruct7BytesIntx10");
+
+/// Sub word size on 64 bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct7BytesIntx10() {
+  Struct7BytesInt a0 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a1 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a2 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a3 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a4 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a5 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a6 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a7 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a8 = allocate<Struct7BytesInt>().ref;
+  Struct7BytesInt a9 = allocate<Struct7BytesInt>().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 = passStruct7BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesIntx10 = 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");
+
+/// Exactly word size struct on 64bit architectures.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesIntx10() {
+  Struct8BytesInt a0 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a1 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a2 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a3 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a4 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a5 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a6 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a7 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a8 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a9 = allocate<Struct8BytesInt>().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 = passStruct8BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesHomogeneousFloatx10 = 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");
+
+/// Arguments passed in FP registers as long as they fit.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesHomogeneousFloatx10() {
+  Struct8BytesHomogeneousFloat a0 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a1 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a2 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a3 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a4 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a5 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a6 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a7 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a8 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a9 =
+      allocate<Struct8BytesHomogeneousFloat>().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 = passStruct8BytesHomogeneousFloatx10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct8BytesMixedx10 = 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");
+
+/// On x64, arguments go in int registers because it is not only float.
+/// 10 struct arguments will exhaust available registers.
+void testPassStruct8BytesMixedx10() {
+  Struct8BytesMixed a0 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a1 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a2 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a3 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a4 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a5 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a6 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a7 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a8 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a9 = allocate<Struct8BytesMixed>().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 =
+      passStruct8BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(15.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct9BytesIntx10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt),
+    int Function(
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt,
+        Struct9BytesInt)>("PassStruct9BytesIntx10");
+
+/// Argument is a single byte over a multiple of word size.
+/// 10 struct arguments will exhaust available registers.
+/// Tests upper bytes in the integer registers that are partly filled.
+/// Tests stack alignment of non word size stack arguments.
+void testPassStruct9BytesIntx10() {
+  Struct9BytesInt a0 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a1 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a2 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a3 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a4 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a5 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a6 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a7 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a8 = allocate<Struct9BytesInt>().ref;
+  Struct9BytesInt a9 = allocate<Struct9BytesInt>().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 = passStruct9BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(10, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct9BytesHomogeneousUint82x10 = ffiTestFunctions.lookupFunction<
+    Int64 Function(
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82),
+    int Function(
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82,
+        Struct9BytesHomogeneousUint82)>("PassStruct9BytesHomogeneousUint82x10");
+
+/// 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.
+///
+void testPassStruct9BytesHomogeneousUint82x10() {
+  Struct9BytesHomogeneousUint82 a0 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a1 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a2 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a3 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a4 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a5 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a6 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a7 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a8 =
+      allocate<Struct9BytesHomogeneousUint82>().ref;
+  Struct9BytesHomogeneousUint82 a9 =
+      allocate<Struct9BytesHomogeneousUint82>().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 = passStruct9BytesHomogeneousUint82x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(4095, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct12BytesHomogeneousFloatx6 = ffiTestFunctions.lookupFunction<
+    Float Function(
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat),
+    double Function(
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat,
+        Struct12BytesHomogeneousFloat)>("PassStruct12BytesHomogeneousFloatx6");
+
+/// 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 testPassStruct12BytesHomogeneousFloatx6() {
+  Struct12BytesHomogeneousFloat a0 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a1 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a2 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a3 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a4 =
+      allocate<Struct12BytesHomogeneousFloat>().ref;
+  Struct12BytesHomogeneousFloat a5 =
+      allocate<Struct12BytesHomogeneousFloat>().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 = passStruct12BytesHomogeneousFloatx6(a0, a1, a2, a3, a4, a5);
+
+  print("result = $result");
+
+  Expect.approxEquals(9.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+}
+
+final passStruct16BytesHomogeneousFloatx5 = ffiTestFunctions.lookupFunction<
+    Float Function(
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat),
+    double Function(
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat,
+        Struct16BytesHomogeneousFloat)>("PassStruct16BytesHomogeneousFloatx5");
+
+/// 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 testPassStruct16BytesHomogeneousFloatx5() {
+  Struct16BytesHomogeneousFloat a0 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a1 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a2 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a3 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  Struct16BytesHomogeneousFloat a4 =
+      allocate<Struct16BytesHomogeneousFloat>().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 = passStruct16BytesHomogeneousFloatx5(a0, a1, a2, a3, a4);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+}
+
+final passStruct16BytesMixedx10 = 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");
+
+/// 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 testPassStruct16BytesMixedx10() {
+  Struct16BytesMixed a0 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a2 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().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 =
+      passStruct16BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct16BytesMixed2x10 = 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");
+
+/// 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 testPassStruct16BytesMixed2x10() {
+  Struct16BytesMixed2 a0 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a1 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a2 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a3 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a4 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a5 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a6 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a7 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a8 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a9 = allocate<Struct16BytesMixed2>().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 =
+      passStruct16BytesMixed2x10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.approxEquals(20.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct17BytesIntx10 = 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");
+
+/// Arguments are passed as pointer to copy on arm64.
+/// Tests that the memory allocated for copies are rounded up to word size.
+void testPassStruct17BytesIntx10() {
+  Struct17BytesInt a0 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a1 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a2 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a3 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a4 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a5 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a6 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a7 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a8 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a9 = allocate<Struct17BytesInt>().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 =
+      passStruct17BytesIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(15, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct19BytesHomogeneousUint8x10 = 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");
+
+/// 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 testPassStruct19BytesHomogeneousUint8x10() {
+  Struct19BytesHomogeneousUint8 a0 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a1 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a2 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a3 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a4 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a5 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a6 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a7 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a8 =
+      allocate<Struct19BytesHomogeneousUint8>().ref;
+  Struct19BytesHomogeneousUint8 a9 =
+      allocate<Struct19BytesHomogeneousUint8>().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 = passStruct19BytesHomogeneousUint8x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(18145, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct20BytesHomogeneousInt32x10 = 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");
+
+/// 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 testPassStruct20BytesHomogeneousInt32x10() {
+  Struct20BytesHomogeneousInt32 a0 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a1 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a2 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a3 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a4 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a5 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a6 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a7 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a8 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+  Struct20BytesHomogeneousInt32 a9 =
+      allocate<Struct20BytesHomogeneousInt32>().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 = passStruct20BytesHomogeneousInt32x10(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+  print("result = $result");
+
+  Expect.equals(25, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Float Function(Struct20BytesHomogeneousFloat),
+    double Function(
+        Struct20BytesHomogeneousFloat)>("PassStruct20BytesHomogeneousFloat");
+
+/// Argument too big to go into FPU registers in hardfp and arm64.
+void testPassStruct20BytesHomogeneousFloat() {
+  Struct20BytesHomogeneousFloat a0 =
+      allocate<Struct20BytesHomogeneousFloat>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  final result = passStruct20BytesHomogeneousFloat(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(-3.0, result);
+
+  free(a0.addressOf);
+}
+
+final passStruct32BytesHomogeneousDoublex5 = ffiTestFunctions.lookupFunction<
+        Double Function(
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble),
+        double Function(
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble,
+            Struct32BytesHomogeneousDouble)>(
+    "PassStruct32BytesHomogeneousDoublex5");
+
+/// Arguments in FPU registers on arm64.
+/// 5 struct arguments will exhaust available registers.
+void testPassStruct32BytesHomogeneousDoublex5() {
+  Struct32BytesHomogeneousDouble a0 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a1 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a2 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a3 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  Struct32BytesHomogeneousDouble a4 =
+      allocate<Struct32BytesHomogeneousDouble>().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 = passStruct32BytesHomogeneousDoublex5(a0, a1, a2, a3, a4);
+
+  print("result = $result");
+
+  Expect.approxEquals(10.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+  free(a3.addressOf);
+  free(a4.addressOf);
+}
+
+final passStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Double Function(Struct40BytesHomogeneousDouble),
+    double Function(
+        Struct40BytesHomogeneousDouble)>("PassStruct40BytesHomogeneousDouble");
+
+/// Argument too big to go into FPU registers in arm64.
+void testPassStruct40BytesHomogeneousDouble() {
+  Struct40BytesHomogeneousDouble a0 =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+  a0.a2 = -3.0;
+  a0.a3 = 4.0;
+  a0.a4 = -5.0;
+
+  final result = passStruct40BytesHomogeneousDouble(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(-3.0, result);
+
+  free(a0.addressOf);
+}
+
+final passStruct1024BytesHomogeneousUint64 = ffiTestFunctions.lookupFunction<
+        Uint64 Function(Struct1024BytesHomogeneousUint64),
+        int Function(Struct1024BytesHomogeneousUint64)>(
+    "PassStruct1024BytesHomogeneousUint64");
+
+/// Test 1kb struct.
+void testPassStruct1024BytesHomogeneousUint64() {
+  Struct1024BytesHomogeneousUint64 a0 =
+      allocate<Struct1024BytesHomogeneousUint64>().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 = passStruct1024BytesHomogeneousUint64(a0);
+
+  print("result = $result");
+
+  Expect.equals(8256, result);
+
+  free(a0.addressOf);
+}
+
+final passFloatStruct16BytesHomogeneousFloatFloatStruct1 =
+    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");
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1() {
+  double a0;
+  Struct16BytesHomogeneousFloat a1 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a2;
+  Struct16BytesHomogeneousFloat a3 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a4;
+  Struct16BytesHomogeneousFloat a5 =
+      allocate<Struct16BytesHomogeneousFloat>().ref;
+  double a6;
+  Struct16BytesHomogeneousFloat a7 =
+      allocate<Struct16BytesHomogeneousFloat>().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 = passFloatStruct16BytesHomogeneousFloatFloatStruct1(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-11.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passFloatStruct32BytesHomogeneousDoubleFloatStruct =
+    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");
+
+/// Tests the alignment of structs in FPU registers and backfilling.
+void testPassFloatStruct32BytesHomogeneousDoubleFloatStruct() {
+  double a0;
+  Struct32BytesHomogeneousDouble a1 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a2;
+  Struct32BytesHomogeneousDouble a3 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a4;
+  Struct32BytesHomogeneousDouble a5 =
+      allocate<Struct32BytesHomogeneousDouble>().ref;
+  double a6;
+  Struct32BytesHomogeneousDouble a7 =
+      allocate<Struct32BytesHomogeneousDouble>().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 = passFloatStruct32BytesHomogeneousDoubleFloatStruct(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-11.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passInt8Struct16BytesMixedInt8Struct16BytesMixedIn =
+    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");
+
+/// 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 testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn() {
+  int a0;
+  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  int a2;
+  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  int a4;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  int a6;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().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 = passInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-7.0, result);
+
+  free(a1.addressOf);
+  free(a3.addressOf);
+  free(a5.addressOf);
+  free(a7.addressOf);
+}
+
+final passDoublex6Struct16BytesMixedx4Int32 = 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");
+
+/// 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 testPassDoublex6Struct16BytesMixedx4Int32() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+  double a4;
+  double a5;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().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 = passDoublex6Struct16BytesMixedx4Int32(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+
+  print("result = $result");
+
+  Expect.approxEquals(-8.0, result);
+
+  free(a6.addressOf);
+  free(a7.addressOf);
+  free(a8.addressOf);
+  free(a9.addressOf);
+}
+
+final passInt32x4Struct16BytesMixedx4Double = 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");
+
+/// 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 testPassInt32x4Struct16BytesMixedx4Double() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().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 =
+      passInt32x4Struct16BytesMixedx4Double(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.approxEquals(-7.0, result);
+
+  free(a4.addressOf);
+  free(a5.addressOf);
+  free(a6.addressOf);
+  free(a7.addressOf);
+}
+
+final passStruct40BytesHomogeneousDoubleStruct4BytesHomo =
+    ffiTestFunctions.lookupFunction<
+            Double Function(Struct40BytesHomogeneousDouble,
+                Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat),
+            double Function(Struct40BytesHomogeneousDouble,
+                Struct4BytesHomogeneousInt16, Struct8BytesHomogeneousFloat)>(
+        "PassStruct40BytesHomogeneousDoubleStruct4BytesHomo");
+
+/// On various architectures, first struct is allocated on stack.
+/// Check that the other two arguments are allocated on registers.
+void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo() {
+  Struct40BytesHomogeneousDouble a0 =
+      allocate<Struct40BytesHomogeneousDouble>().ref;
+  Struct4BytesHomogeneousInt16 a1 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct8BytesHomogeneousFloat a2 =
+      allocate<Struct8BytesHomogeneousFloat>().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 = passStruct40BytesHomogeneousDoubleStruct4BytesHomo(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(-5.0, result);
+
+  free(a0.addressOf);
+  free(a1.addressOf);
+  free(a2.addressOf);
+}
+
+final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt16),
+    int Function(StructAlignmentInt16)>("PassStructAlignmentInt16");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassStructAlignmentInt16() {
+  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt16(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final passStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt32),
+    int Function(StructAlignmentInt32)>("PassStructAlignmentInt32");
+
+/// Test alignment and padding of 32 byte int within struct.
+void testPassStructAlignmentInt32() {
+  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt32(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final passStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
+    Int64 Function(StructAlignmentInt64),
+    int Function(StructAlignmentInt64)>("PassStructAlignmentInt64");
+
+/// Test alignment and padding of 64 byte int within struct.
+void testPassStructAlignmentInt64() {
+  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+
+  final result = passStructAlignmentInt64(a0);
+
+  print("result = $result");
+
+  Expect.equals(-2, result);
+
+  free(a0.addressOf);
+}
+
+final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
+    Struct1ByteInt Function(Int8),
+    Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
+
+/// Smallest struct with data.
+void testReturnStruct1ByteInt() {
+  int a0;
+
+  a0 = -1;
+
+  final result = returnStruct1ByteInt(a0);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+}
+
+final returnStruct3BytesInt = ffiTestFunctions.lookupFunction<
+    Struct3BytesInt Function(Int16, Int8),
+    Struct3BytesInt Function(int, int)>("ReturnStruct3BytesInt");
+
+/// Smaller than word size return value on all architectures.
+void testReturnStruct3BytesInt() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct3BytesInt(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct4BytesHomogeneousInt16 = ffiTestFunctions.lookupFunction<
+    Struct4BytesHomogeneousInt16 Function(Int16, Int16),
+    Struct4BytesHomogeneousInt16 Function(
+        int, int)>("ReturnStruct4BytesHomogeneousInt16");
+
+/// Word size return value on 32 bit architectures..
+void testReturnStruct4BytesHomogeneousInt16() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct4BytesHomogeneousInt16(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct7BytesInt = ffiTestFunctions.lookupFunction<
+    Struct7BytesInt Function(Int32, Int16, Int8),
+    Struct7BytesInt Function(int, int, int)>("ReturnStruct7BytesInt");
+
+/// Non-wordsize return value.
+void testReturnStruct7BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct7BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesInt = ffiTestFunctions.lookupFunction<
+    Struct8BytesInt Function(Int16, Int16, Int32),
+    Struct8BytesInt Function(int, int, int)>("ReturnStruct8BytesInt");
+
+/// Return value in integer registers on many architectures.
+void testReturnStruct8BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct8BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct8BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct8BytesHomogeneousFloat Function(Float, Float),
+    Struct8BytesHomogeneousFloat Function(
+        double, double)>("ReturnStruct8BytesHomogeneousFloat");
+
+/// Return value in FP registers on many architectures.
+void testReturnStruct8BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+
+  a0 = -1.0;
+  a1 = 2.0;
+
+  final result = returnStruct8BytesHomogeneousFloat(a0, a1);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.approxEquals(a1, result.a1);
+}
+
+final returnStruct8BytesMixed = ffiTestFunctions.lookupFunction<
+    Struct8BytesMixed Function(Float, Int16, Int16),
+    Struct8BytesMixed Function(double, int, int)>("ReturnStruct8BytesMixed");
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct8BytesMixed() {
+  double a0;
+  int a1;
+  int a2;
+
+  a0 = -1.0;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct8BytesMixed(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct9BytesInt = ffiTestFunctions.lookupFunction<
+    Struct9BytesInt Function(Int64, Int8),
+    Struct9BytesInt Function(int, int)>("ReturnStruct9BytesInt");
+
+/// Return value in two integer registers on x64.
+/// The second register only contains a single byte.
+void testReturnStruct9BytesInt() {
+  int a0;
+  int a1;
+
+  a0 = -1;
+  a1 = 2;
+
+  final result = returnStruct9BytesInt(a0, a1);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct9BytesHomogeneousUint82 = ffiTestFunctions.lookupFunction<
+    Struct9BytesHomogeneousUint82 Function(
+        Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8, Uint8),
+    Struct9BytesHomogeneousUint82 Function(int, int, int, int, int, int, int,
+        int, int)>("ReturnStruct9BytesHomogeneousUint82");
+
+/// 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 testReturnStruct9BytesHomogeneousUint82() {
+  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 =
+      returnStruct9BytesHomogeneousUint82(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 returnStruct12BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct12BytesHomogeneousFloat Function(Float, Float, Float),
+    Struct12BytesHomogeneousFloat Function(
+        double, double, double)>("ReturnStruct12BytesHomogeneousFloat");
+
+/// Return value in FPU registers, but does not use all registers on arm hardfp
+/// and arm64.
+void testReturnStruct12BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+  double a2;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+
+  final result = returnStruct12BytesHomogeneousFloat(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.approxEquals(a1, result.a1);
+  Expect.approxEquals(a2, result.a2);
+}
+
+final returnStruct16BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct16BytesHomogeneousFloat Function(Float, Float, Float, Float),
+    Struct16BytesHomogeneousFloat Function(
+        double, double, double, double)>("ReturnStruct16BytesHomogeneousFloat");
+
+/// Return value in FPU registers on arm hardfp and arm64.
+void testReturnStruct16BytesHomogeneousFloat() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  final result = returnStruct16BytesHomogeneousFloat(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 returnStruct16BytesMixed = ffiTestFunctions.lookupFunction<
+    Struct16BytesMixed Function(Double, Int64),
+    Struct16BytesMixed Function(double, int)>("ReturnStruct16BytesMixed");
+
+/// Return value split over FP and integer register in x64.
+void testReturnStruct16BytesMixed() {
+  double a0;
+  int a1;
+
+  a0 = -1.0;
+  a1 = 2;
+
+  final result = returnStruct16BytesMixed(a0, a1);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+}
+
+final returnStruct16BytesMixed2 = ffiTestFunctions.lookupFunction<
+    Struct16BytesMixed2 Function(Float, Float, Float, Int32),
+    Struct16BytesMixed2 Function(
+        double, double, double, int)>("ReturnStruct16BytesMixed2");
+
+/// Return value split over FP and integer register in x64.
+/// The integer register contains half float half int.
+void testReturnStruct16BytesMixed2() {
+  double a0;
+  double a1;
+  double a2;
+  int a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4;
+
+  final result = returnStruct16BytesMixed2(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 returnStruct17BytesInt = ffiTestFunctions.lookupFunction<
+    Struct17BytesInt Function(Int64, Int64, Int8),
+    Struct17BytesInt Function(int, int, int)>("ReturnStruct17BytesInt");
+
+/// 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 testReturnStruct17BytesInt() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStruct17BytesInt(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStruct19BytesHomogeneousUint8 = 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");
+
+/// 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 testReturnStruct19BytesHomogeneousUint8() {
+  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 = returnStruct19BytesHomogeneousUint8(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 returnStruct20BytesHomogeneousInt32 = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousInt32 Function(Int32, Int32, Int32, Int32, Int32),
+    Struct20BytesHomogeneousInt32 Function(
+        int, int, int, int, int)>("ReturnStruct20BytesHomogeneousInt32");
+
+/// Return value too big to go in cpu registers on arm64.
+void testReturnStruct20BytesHomogeneousInt32() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+
+  final result = returnStruct20BytesHomogeneousInt32(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 returnStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
+    Struct20BytesHomogeneousFloat Function(Float, Float, Float, Float, Float),
+    Struct20BytesHomogeneousFloat Function(double, double, double, double,
+        double)>("ReturnStruct20BytesHomogeneousFloat");
+
+/// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
+void testReturnStruct20BytesHomogeneousFloat() {
+  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 = returnStruct20BytesHomogeneousFloat(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 returnStruct32BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Struct32BytesHomogeneousDouble Function(Double, Double, Double, Double),
+    Struct32BytesHomogeneousDouble Function(double, double, double,
+        double)>("ReturnStruct32BytesHomogeneousDouble");
+
+/// Return value in FPU registers on arm64.
+void testReturnStruct32BytesHomogeneousDouble() {
+  double a0;
+  double a1;
+  double a2;
+  double a3;
+
+  a0 = -1.0;
+  a1 = 2.0;
+  a2 = -3.0;
+  a3 = 4.0;
+
+  final result = returnStruct32BytesHomogeneousDouble(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 returnStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
+    Struct40BytesHomogeneousDouble Function(
+        Double, Double, Double, Double, Double),
+    Struct40BytesHomogeneousDouble Function(double, double, double, double,
+        double)>("ReturnStruct40BytesHomogeneousDouble");
+
+/// Return value too big to go in FPU registers on arm64.
+void testReturnStruct40BytesHomogeneousDouble() {
+  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 = returnStruct40BytesHomogeneousDouble(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 returnStruct1024BytesHomogeneousUint64 = 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");
+
+/// Test 1kb struct.
+void testReturnStruct1024BytesHomogeneousUint64() {
+  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 = returnStruct1024BytesHomogeneousUint64(
+      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 returnStructArgumentStruct1ByteInt = ffiTestFunctions.lookupFunction<
+    Struct1ByteInt Function(Struct1ByteInt),
+    Struct1ByteInt Function(
+        Struct1ByteInt)>("ReturnStructArgumentStruct1ByteInt");
+
+/// 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 testReturnStructArgumentStruct1ByteInt() {
+  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+
+  a0.a0 = -1;
+
+  final result = returnStructArgumentStruct1ByteInt(a0);
+
+  print("result = $result");
+
+  Expect.equals(a0.a0, result.a0);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentInt32x8Struct1ByteInt =
+    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");
+
+/// Test that a struct passed in as argument can be returned.
+/// Especially for ffi callbacks.
+/// Struct is passed on stack on all ABIs.
+void testReturnStructArgumentInt32x8Struct1ByteInt() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+  a5 = 6;
+  a6 = -7;
+  a7 = 8;
+  a8.a0 = -9;
+
+  final result = returnStructArgumentInt32x8Struct1ByteInt(
+      a0, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  print("result = $result");
+
+  Expect.equals(a8.a0, result.a0);
+
+  free(a8.addressOf);
+}
+
+final returnStructArgumentStruct8BytesHomogeneousFloat =
+    ffiTestFunctions.lookupFunction<
+            Struct8BytesHomogeneousFloat Function(Struct8BytesHomogeneousFloat),
+            Struct8BytesHomogeneousFloat Function(
+                Struct8BytesHomogeneousFloat)>(
+        "ReturnStructArgumentStruct8BytesHomogeneousFloat");
+
+/// 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 testReturnStructArgumentStruct8BytesHomogeneousFloat() {
+  Struct8BytesHomogeneousFloat a0 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+
+  a0.a0 = -1.0;
+  a0.a1 = 2.0;
+
+  final result = returnStructArgumentStruct8BytesHomogeneousFloat(a0);
+
+  print("result = $result");
+
+  Expect.approxEquals(a0.a0, result.a0);
+  Expect.approxEquals(a0.a1, result.a1);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentStruct20BytesHomogeneousInt32 =
+    ffiTestFunctions
+        .lookupFunction<
+                Struct20BytesHomogeneousInt32 Function(
+                    Struct20BytesHomogeneousInt32),
+                Struct20BytesHomogeneousInt32 Function(
+                    Struct20BytesHomogeneousInt32)>(
+            "ReturnStructArgumentStruct20BytesHomogeneousInt32");
+
+/// On arm64, both argument and return value are passed in by pointer.
+void testReturnStructArgumentStruct20BytesHomogeneousInt32() {
+  Struct20BytesHomogeneousInt32 a0 =
+      allocate<Struct20BytesHomogeneousInt32>().ref;
+
+  a0.a0 = -1;
+  a0.a1 = 2;
+  a0.a2 = -3;
+  a0.a3 = 4;
+  a0.a4 = -5;
+
+  final result = returnStructArgumentStruct20BytesHomogeneousInt32(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);
+
+  free(a0.addressOf);
+}
+
+final returnStructArgumentInt32x8Struct20BytesHomogeneou =
+    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");
+
+/// On arm64, both argument and return value are passed in by pointer.
+/// Ints exhaust registers, so that pointer is passed on stack.
+void testReturnStructArgumentInt32x8Struct20BytesHomogeneou() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  Struct20BytesHomogeneousInt32 a8 =
+      allocate<Struct20BytesHomogeneousInt32>().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 = returnStructArgumentInt32x8Struct20BytesHomogeneou(
+      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);
+
+  free(a8.addressOf);
+}
+
+final returnStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt16 Function(Int8, Int16, Int8),
+    StructAlignmentInt16 Function(int, int, int)>("ReturnStructAlignmentInt16");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testReturnStructAlignmentInt16() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt16(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt32 Function(Int8, Int32, Int8),
+    StructAlignmentInt32 Function(int, int, int)>("ReturnStructAlignmentInt32");
+
+/// Test alignment and padding of 32 byte int within struct.
+void testReturnStructAlignmentInt32() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt32(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
+
+final returnStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
+    StructAlignmentInt64 Function(Int8, Int64, Int8),
+    StructAlignmentInt64 Function(int, int, int)>("ReturnStructAlignmentInt64");
+
+/// Test alignment and padding of 64 byte int within struct.
+void testReturnStructAlignmentInt64() {
+  int a0;
+  int a1;
+  int a2;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+
+  final result = returnStructAlignmentInt64(a0, a1, a2);
+
+  print("result = $result");
+
+  Expect.equals(a0, result.a0);
+  Expect.equals(a1, result.a1);
+  Expect.equals(a2, result.a2);
+}
diff --git a/tests/ffi_2/generator/c_types.dart b/tests/ffi_2/generator/c_types.dart
new file mode 100644
index 0000000..f2948fa
--- /dev/null
+++ b/tests/ffi_2/generator/c_types.dart
@@ -0,0 +1,299 @@
+// Copyright (c) 2020, 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 'utils.dart';
+
+const int8 = FundamentalType(PrimitiveType.int8);
+const int16 = FundamentalType(PrimitiveType.int16);
+const int32 = FundamentalType(PrimitiveType.int32);
+const int64 = FundamentalType(PrimitiveType.int64);
+const uint8 = FundamentalType(PrimitiveType.uint8);
+const uint16 = FundamentalType(PrimitiveType.uint16);
+const uint32 = FundamentalType(PrimitiveType.uint32);
+const uint64 = FundamentalType(PrimitiveType.uint64);
+const intptr = FundamentalType(PrimitiveType.intptr);
+const float = FundamentalType(PrimitiveType.float);
+const double_ = FundamentalType(PrimitiveType.double_);
+
+enum PrimitiveType {
+  int8,
+  int16,
+  int32,
+  int64,
+  uint8,
+  uint16,
+  uint32,
+  uint64,
+  intptr,
+  float,
+  double_,
+}
+
+const primitiveNames = [
+  "int8",
+  "int16",
+  "int32",
+  "int64",
+  "uint8",
+  "uint16",
+  "uint32",
+  "uint64",
+  "intptr",
+  "float",
+  "double",
+];
+
+const intptrSize = -1;
+const primitiveSizesInBytes = [1, 2, 4, 8, 1, 2, 4, 8, intptrSize, 4, 8];
+
+abstract class CType {
+  String get cType;
+  String get dartCType;
+  String get dartType;
+  String get dartStructFieldAnnotation;
+
+  /// Has a known [size] that is the same for all architectures.
+  bool get hasSize;
+
+  /// Get a size in bytes that is the same on all architectures.
+  int get size;
+
+  String toString() => dartCType;
+
+  const CType();
+}
+
+class FundamentalType extends CType {
+  final PrimitiveType primitive;
+
+  const FundamentalType(this.primitive);
+
+  bool get isFloatingPoint =>
+      primitive == PrimitiveType.float || primitive == PrimitiveType.double_;
+  bool get isInteger => !isFloatingPoint;
+  bool get isUnsigned =>
+      primitive == PrimitiveType.uint8 ||
+      primitive == PrimitiveType.uint16 ||
+      primitive == PrimitiveType.uint32 ||
+      primitive == PrimitiveType.uint64;
+  bool get isSigned => !isUnsigned;
+
+  String get name => primitiveNames[primitive.index];
+
+  String get cType => "${name}${isInteger ? "_t" : ""}";
+  String get dartCType => name.upperCaseFirst();
+  String get dartType => isInteger ? "int" : "double";
+  String get dartStructFieldAnnotation => "@${dartCType}()";
+  bool get hasSize => primitive != PrimitiveType.intptr;
+  int get size {
+    if (!hasSize) {
+      throw "Size unknown.";
+    }
+    return primitiveSizesInBytes[primitive.index];
+  }
+}
+
+class PointerType extends CType {
+  final CType pointerTo;
+
+  PointerType(this.pointerTo);
+
+  String get cType => "${pointerTo.cType}*";
+  String get dartCType => "Pointer<${pointerTo.dartCType}>";
+  String get dartType => "Pointer<${pointerTo.dartType}>";
+  String get dartStructFieldAnnotation => "";
+  bool get hasSize => false;
+  int get size => throw "Size unknown";
+}
+
+/// Used to give [StructType] fields and [FunctionType] arguments names.
+class Member {
+  final CType type;
+  final String name;
+
+  Member(this.type, this.name);
+
+  String dartStructField(bool nnbd) {
+    final modifier = nnbd ? "external" : "";
+    return "${type.dartStructFieldAnnotation} $modifier ${type.dartType} $name;";
+  }
+
+  String get cStructField => "${type.cType} $name;";
+
+  String toString() => "$type $name";
+}
+
+List<Member> generateMemberNames(List<CType> memberTypes) {
+  int index = 0;
+  List<Member> result = [];
+  for (final type in memberTypes) {
+    result.add(Member(type, "a$index"));
+    index++;
+  }
+  return result;
+}
+
+class StructType extends CType {
+  final List<Member> members;
+
+  /// To disambiguate same size structs.
+  final String suffix;
+
+  StructType(List<CType> memberTypes)
+      : this.members = generateMemberNames(memberTypes),
+        this.suffix = "";
+  StructType.disambiguate(List<CType> memberTypes, this.suffix)
+      : this.members = generateMemberNames(memberTypes);
+
+  List<CType> get memberTypes => members.map((a) => a.type).toList();
+
+  String get cType => name;
+  String get dartCType => name;
+  String get dartType => name;
+  String get dartStructFieldAnnotation => "";
+
+  bool get hasSize =>
+      !memberTypes.map((e) => e.hasSize).contains(false) && !hasPadding;
+  int get size => memberTypes.fold(0, (int acc, e) => acc + e.size);
+
+  /// Rough approximation, to not redo all ABI logic here.
+  bool get hasPadding =>
+      members.length < 2 ? false : members[0].type.size < members[1].type.size;
+
+  bool get hasNestedStructs =>
+      members.map((e) => e.type is StructType).contains(true);
+
+  /// All members have the same type.
+  bool get isHomogeneous => memberTypes.toSet().length == 1;
+
+  /// All members have a floating point type.
+  bool get isOnlyFloatingPoint => !memberTypes.map((e) {
+        if (e is FundamentalType) {
+          return e.isFloatingPoint;
+        }
+        if (e is StructType) {
+          return e.isOnlyFloatingPoint;
+        }
+      }).contains(false);
+
+  /// All members have a integer type.
+  bool get isOnlyInteger => !memberTypes.map((e) {
+        if (e is FundamentalType) {
+          return e.isInteger;
+        }
+        if (e is StructType) {
+          return e.isOnlyInteger;
+        }
+      }).contains(false);
+
+  bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
+
+  String get name {
+    String result = "Struct";
+    if (hasSize) {
+      result += "${size}Byte" + (size != 1 ? "s" : "");
+    }
+    if (hasNestedStructs) {
+      result += "Nested";
+    }
+    if (members.length == 0) {
+      // No suffix.
+    } else if (hasPadding) {
+      result += "Alignment${memberTypes[1].dartCType}";
+    } else if (isHomogeneous && members.length > 1 && !hasNestedStructs) {
+      result += "Homogeneous${memberTypes.first.dartCType}";
+    } else if (isOnlyFloatingPoint) {
+      result += "Float";
+    } else if (isOnlyInteger) {
+      result += "Int";
+    } else {
+      result += "Mixed";
+    }
+    result += suffix;
+    return result;
+  }
+}
+
+class FunctionType extends CType {
+  final List<Member> arguments;
+  final CType returnValue;
+  final String reason;
+
+  List<CType> get argumentTypes => arguments.map((a) => a.type).toList();
+
+  FunctionType(List<CType> argumentTypes, this.returnValue, this.reason)
+      : this.arguments = generateMemberNames(argumentTypes);
+
+  String get cType =>
+      throw "Are not represented without function or variable name in C.";
+
+  String get dartCType {
+    final argumentsDartCType = argumentTypes.map((e) => e.dartCType).join(", ");
+    return "${returnValue.dartCType} Function($argumentsDartCType)";
+  }
+
+  String get dartType {
+    final argumentsDartType = argumentTypes.map((e) => e.dartType).join(", ");
+    return "${returnValue.dartType} Function($argumentsDartType)";
+  }
+
+  String get dartStructFieldAnnotation => throw "No nested function pointers.";
+
+  bool get hasSize => false;
+  int get size => throw "Unknown size.";
+
+  /// Group consecutive [arguments] by same type.
+  ///
+  /// Used for naming.
+  List<List<Member>> get argumentsGrouped {
+    List<List<Member>> result = [];
+    for (final a in arguments) {
+      if (result.isEmpty) {
+        result.add([a]);
+      } else if (result.last.first.type.dartCType == a.type.dartCType) {
+        result.last.add(a);
+      } else {
+        result.add([a]);
+      }
+    }
+    return result;
+  }
+
+  /// A suitable name based on the signature.
+  String get cName {
+    String result = "";
+    if (arguments.containsStructs && returnValue is FundamentalType) {
+      result = "Pass";
+    } else if (returnValue is StructType &&
+        argumentTypes.contains(returnValue)) {
+      result = "ReturnStructArgument";
+    } else if (returnValue is StructType) {
+      if (arguments.length == (returnValue as StructType).members.length) {
+        return "Return${returnValue.dartCType}";
+      }
+    } else {
+      result = "Uncategorized";
+    }
+
+    for (final group in argumentsGrouped) {
+      result += group.first.type.dartCType;
+      if (group.length > 1) {
+        result += "x${group.length}";
+      }
+    }
+    return result.limitTo(50);
+  }
+
+  String get dartTestName => "test$cName";
+
+  String get dartName => cName.lowerCaseFirst();
+
+  /// Only valid for [TestType.structReturnArgument].
+  Member get structReturnArgument =>
+      arguments.firstWhere((a) => a.type == returnValue);
+}
+
+extension MemberList on List<Member> {
+  bool get containsStructs => map((m) => m.type is StructType).contains(true);
+}
diff --git a/tests/ffi_2/generator/structs_by_value_tests_confguration.dart b/tests/ffi_2/generator/structs_by_value_tests_confguration.dart
new file mode 100644
index 0000000..487a68e
--- /dev/null
+++ b/tests/ffi_2/generator/structs_by_value_tests_confguration.dart
@@ -0,0 +1,373 @@
+// Copyright (c) 2020, 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 'c_types.dart';
+
+final functions = [
+  FunctionType(List.filled(10, struct1byteInt), int64, """
+Smallest struct with data.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct3bytesInt), int64, """
+Not a multiple of word size, not a power of two.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct4bytesInt), int64, """
+Exactly word size on 32-bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct7bytesInt), int64, """
+Sub word size on 64 bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8bytesInt), int64, """
+Exactly word size struct on 64bit architectures.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8bytesFloat), float, """
+Arguments passed in FP registers as long as they fit.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct8BytesMixed), float, """
+On x64, arguments go in int registers because it is not only float.
+10 struct arguments will exhaust available registers."""),
+  FunctionType(List.filled(10, struct9bytesInt), int64, """
+Argument is a single byte over a multiple of word size.
+10 struct arguments will exhaust available registers.
+Tests upper bytes in the integer registers that are partly filled.
+Tests stack alignment of non word size stack arguments."""),
+  FunctionType(List.filled(10, struct9bytesInt2), int64, """
+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.
+"""),
+  FunctionType(List.filled(6, struct12bytesFloat), float, """
+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."""),
+  FunctionType(List.filled(5, struct16bytesFloat), float, """
+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."""),
+  FunctionType(List.filled(10, struct16bytesMixed), double_, """
+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."""),
+  FunctionType(List.filled(10, struct16bytesMixed2), float, """
+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."""),
+  FunctionType(List.filled(10, struct17bytesInt), int64, """
+Arguments are passed as pointer to copy on arm64.
+Tests that the memory allocated for copies are rounded up to word size."""),
+  FunctionType(List.filled(10, struct19bytesInt), int64, """
+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.
+"""),
+  FunctionType(List.filled(10, struct20bytesInt), int32, """
+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."""),
+  FunctionType(
+      [struct20bytesFloat],
+      float,
+      """
+Argument too big to go into FPU registers in hardfp and arm64."""),
+  FunctionType(List.filled(5, struct32bytesDouble), double_, """
+Arguments in FPU registers on arm64.
+5 struct arguments will exhaust available registers."""),
+  FunctionType(
+      [struct40bytesDouble],
+      double_,
+      """
+Argument too big to go into FPU registers in arm64."""),
+  FunctionType(
+      [struct1024bytesInt],
+      uint64,
+      """
+Test 1kb struct."""),
+  FunctionType(
+      [
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float,
+        struct16bytesFloat,
+        float
+      ],
+      float,
+      """
+Tests the alignment of structs in FPU registers and backfilling."""),
+  FunctionType(
+      [
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float,
+        struct32bytesDouble,
+        float
+      ],
+      double_,
+      """
+Tests the alignment of structs in FPU registers and backfilling."""),
+  FunctionType(
+      [
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8,
+        struct16bytesMixed,
+        int8
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        int32,
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        int32,
+        int32,
+        int32,
+        int32,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        struct16bytesMixed,
+        double_,
+      ],
+      double_,
+      """
+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."""),
+  FunctionType(
+      [
+        struct40bytesDouble,
+        struct4bytesInt,
+        struct8bytesFloat,
+      ],
+      double_,
+      """
+On various architectures, first struct is allocated on stack.
+Check that the other two arguments are allocated on registers."""),
+  FunctionType(
+      [structAlignmentInt16],
+      int64,
+      """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(
+      [structAlignmentInt32],
+      int64,
+      """
+Test alignment and padding of 32 byte int within struct."""),
+  FunctionType(
+      [structAlignmentInt64],
+      int64,
+      """
+Test alignment and padding of 64 byte int within struct."""),
+  FunctionType(struct1byteInt.memberTypes, struct1byteInt, """
+Smallest struct with data."""),
+  FunctionType(struct3bytesInt.memberTypes, struct3bytesInt, """
+Smaller than word size return value on all architectures."""),
+  FunctionType(struct4bytesInt.memberTypes, struct4bytesInt, """
+Word size return value on 32 bit architectures.."""),
+  FunctionType(struct7bytesInt.memberTypes, struct7bytesInt, """
+Non-wordsize return value."""),
+  FunctionType(struct8bytesInt.memberTypes, struct8bytesInt, """
+Return value in integer registers on many architectures."""),
+  FunctionType(struct8bytesFloat.memberTypes, struct8bytesFloat, """
+Return value in FP registers on many architectures."""),
+  FunctionType(struct8BytesMixed.memberTypes, struct8BytesMixed, """
+Return value split over FP and integer register in x64."""),
+  FunctionType(struct9bytesInt.memberTypes, struct9bytesInt, """
+Return value in two integer registers on x64.
+The second register only contains a single byte."""),
+  FunctionType(struct9bytesInt2.memberTypes, struct9bytesInt2, """
+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."""),
+  FunctionType(struct12bytesFloat.memberTypes, struct12bytesFloat, """
+Return value in FPU registers, but does not use all registers on arm hardfp
+and arm64."""),
+  FunctionType(struct16bytesFloat.memberTypes, struct16bytesFloat, """
+Return value in FPU registers on arm hardfp and arm64."""),
+  FunctionType(struct16bytesMixed.memberTypes, struct16bytesMixed, """
+Return value split over FP and integer register in x64."""),
+  FunctionType(struct16bytesMixed2.memberTypes, struct16bytesMixed2, """
+Return value split over FP and integer register in x64.
+The integer register contains half float half int."""),
+  FunctionType(struct17bytesInt.memberTypes, struct17bytesInt, """
+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."""),
+  FunctionType(struct19bytesInt.memberTypes, struct19bytesInt, """
+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."""),
+  FunctionType(struct20bytesInt.memberTypes, struct20bytesInt, """
+Return value too big to go in cpu registers on arm64."""),
+  FunctionType(struct20bytesFloat.memberTypes, struct20bytesFloat, """
+Return value too big to go in FPU registers on x64, arm hardfp and arm64."""),
+  FunctionType(struct32bytesDouble.memberTypes, struct32bytesDouble, """
+Return value in FPU registers on arm64."""),
+  FunctionType(struct40bytesDouble.memberTypes, struct40bytesDouble, """
+Return value too big to go in FPU registers on arm64."""),
+  FunctionType(struct1024bytesInt.memberTypes, struct1024bytesInt, """
+Test 1kb struct."""),
+  FunctionType(
+      [struct1byteInt],
+      struct1byteInt,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed in int registers in most ABIs."""),
+  FunctionType(
+      [int32, int32, int32, int32, int32, int32, int32, int32, struct1byteInt],
+      struct1byteInt,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed on stack on all ABIs."""),
+  FunctionType(
+      [struct8bytesFloat],
+      struct8bytesFloat,
+      """
+Test that a struct passed in as argument can be returned.
+Especially for ffi callbacks.
+Struct is passed in float registers in most ABIs."""),
+  FunctionType(
+      [struct20bytesInt],
+      struct20bytesInt,
+      """
+On arm64, both argument and return value are passed in by pointer."""),
+  FunctionType(
+      [
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        struct20bytesInt
+      ],
+      struct20bytesInt,
+      """
+On arm64, both argument and return value are passed in by pointer.
+Ints exhaust registers, so that pointer is passed on stack."""),
+  FunctionType(structAlignmentInt16.memberTypes, structAlignmentInt16, """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(structAlignmentInt32.memberTypes, structAlignmentInt32, """
+Test alignment and padding of 32 byte int within struct."""),
+  FunctionType(structAlignmentInt64.memberTypes, structAlignmentInt64, """
+Test alignment and padding of 64 byte int within struct."""),
+];
+
+final structs = [
+  struct0bytes,
+  struct1byteInt,
+  struct3bytesInt,
+  struct4bytesInt,
+  struct7bytesInt,
+  struct8bytesInt,
+  struct8bytesFloat,
+  struct8BytesMixed,
+  struct9bytesInt,
+  struct9bytesInt2,
+  struct12bytesFloat,
+  struct16bytesFloat,
+  struct16bytesMixed,
+  struct16bytesMixed2,
+  struct17bytesInt,
+  struct19bytesInt,
+  struct20bytesInt,
+  struct20bytesFloat,
+  struct32bytesDouble,
+  struct40bytesDouble,
+  struct1024bytesInt,
+  structAlignmentInt16,
+  structAlignmentInt32,
+  structAlignmentInt64,
+];
+
+/// Using empty structs is undefined behavior in C.
+final struct0bytes = StructType([]);
+
+final struct1byteInt = StructType([int8]);
+final struct3bytesInt = StructType([int16, int8]);
+final struct4bytesInt = StructType([int16, int16]);
+final struct7bytesInt = StructType([int32, int16, int8]);
+final struct8bytesInt = StructType([int16, int16, int32]);
+final struct8bytesFloat = StructType([float, float]);
+final struct8BytesMixed = StructType([float, int16, int16]);
+final struct9bytesInt = StructType([int64, int8]);
+final struct9bytesInt2 = StructType.disambiguate(List.filled(9, uint8), "2");
+final struct12bytesFloat = StructType([float, float, float]);
+
+/// The largest homogenous float that goes into FPU registers on softfp and
+/// arm64.
+final struct16bytesFloat = StructType([float, float, float, float]);
+
+/// This struct will be 8 byte aligned on arm.
+final struct16bytesMixed = StructType([double_, int64]);
+
+/// This struct will be 4 byte aligned on arm.
+final struct16bytesMixed2 =
+    StructType.disambiguate([float, float, float, int32], "2");
+
+final struct17bytesInt = StructType([int64, int64, int8]);
+
+/// This struct has only 1 byte field-alignmnent requirements.
+final struct19bytesInt = StructType(List.filled(19, uint8));
+
+/// The first homogenous integer struct that does not go into registers
+/// anymore on arm64.
+final struct20bytesInt = StructType([int32, int32, int32, int32, int32]);
+
+/// The first homogenous float that does not go into FPU registers anymore on
+/// softfp and arm64.
+final struct20bytesFloat = StructType([float, float, float, float, float]);
+
+/// Largest homogenous doubles in arm64 that goes into FPU registers.
+final struct32bytesDouble = StructType([double_, double_, double_, double_]);
+
+/// The first homogenous doubles that does not go into FPU registers anymore on
+/// arm64.
+final struct40bytesDouble =
+    StructType([double_, double_, double_, double_, double_]);
+
+final struct1024bytesInt = StructType(List.filled(128, uint64));
+
+final structAlignmentInt16 = StructType([int8, int16, int8]);
+final structAlignmentInt32 = StructType([int8, int32, int8]);
+final structAlignmentInt64 = StructType([int8, int64, int8]);
diff --git a/tests/ffi_2/generator/structs_by_value_tests_generator.dart b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
new file mode 100644
index 0000000..e233753
--- /dev/null
+++ b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
@@ -0,0 +1,930 @@
+// Copyright (c) 2020, 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 'dart:io';
+
+import 'c_types.dart';
+import 'structs_by_value_tests_confguration.dart';
+import 'utils.dart';
+
+/// The test type determines how to convert the arguments into return values
+/// such that the caller knows what to check.
+enum TestType {
+  /// Tested by getting all the individual fields out of the structs and
+  /// summing their values.
+  structArguments,
+
+  /// Tested by passing assigning the arguments to the struct fields.
+  structReturn,
+
+  /// Tested by returning the struct passed in.
+  structReturnArgument,
+}
+
+extension on FunctionType {
+  TestType get testType {
+    if (arguments.containsStructs && returnValue is FundamentalType) {
+      return TestType.structArguments;
+    }
+    if (returnValue is StructType && argumentTypes.contains(returnValue)) {
+      return TestType.structReturnArgument;
+    }
+    if (returnValue is StructType) {
+      if (arguments.length == (returnValue as StructType).members.length) {
+        return TestType.structReturn;
+      }
+    }
+    throw Exception("Unknown test type: $this");
+  }
+}
+
+/// We use the class structure as an algebraic data type in order to keep the
+/// relevant parts of the code generation closer together.
+extension on CType {
+  /// The part of the cout expression after `std::cout` and before the `;`.
+  String coutExpression(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        if (this == uint8 || this == int8) {
+          return "<< static_cast<int>($variableName)";
+        }
+        return "<< $variableName";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.coutExpression("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A statement recursively outputting all members.
+  String coutStatement(String variableName) {
+    final coutExpr = this.coutExpression(variableName);
+    return 'std::cout << "$variableName = " $coutExpr << "\\n";';
+  }
+}
+
+extension on List<Member> {
+  /// The part of the cout expression after `std::cout` and before the `;`.
+  String coutExpression([String namePrefix = ""]) {
+    String result = '<< "("';
+    result += this
+        .map((m) => m.type.coutExpression("$namePrefix${m.name}"))
+        .join('<< ", "');
+    result += '<< ")"';
+    return result.trimCouts();
+  }
+}
+
+extension on CType {
+  /// A list of statements adding all members recurisvely to `result`.
+  ///
+  /// Both valid in Dart and C.
+  String addToResultStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "result += $variableName;\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.addToResultStatements("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of statements adding all members recurisvely to `result`.
+  ///
+  /// Both valid in Dart and C.
+  String addToResultStatements([String namePrefix = ""]) {
+    return map((m) => m.type.addToResultStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of statements recursively assigning all members with [a].
+  ///
+  /// Both valid in Dart and C.
+  String assignValueStatements(ArgumentValueAssigner a, String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        return "$variableName = ${a.nextValue(this_)};\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.assignValueStatements(a, "$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of statements recursively coping all members from [source].
+  ///
+  /// Both valid in Dart and C.
+  String copyValueStatements(String source, String destination) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "$destination = $source;\n";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.copyValueStatements("$source.", "$destination.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of statements recursively assigning all members with [a].
+  ///
+  /// Both valid in Dart and C.
+  String assignValueStatements(ArgumentValueAssigner a,
+      [String namePrefix = ""]) {
+    return map((m) => m.type.assignValueStatements(a, "$namePrefix${m.name}"))
+        .join();
+  }
+
+  /// A list of statements recursively coping all members from [source].
+  ///
+  /// Both valid in Dart and C.
+  String copyValueStatements([sourcePrefix = "", destinationPrefix = ""]) {
+    return map((m) => m.type.copyValueStatements(
+        "$sourcePrefix${m.name}", "$destinationPrefix${m.name}")).join();
+  }
+}
+
+/// A helper class that assigns values to fundamental types.
+///
+/// Also keeps track of a sum of all values, to be used for testing the result.
+class ArgumentValueAssigner {
+  int i = 1;
+  int sum = 0;
+  String nextValue(FundamentalType type) {
+    int argumentValue = i;
+    i++;
+    if (type.isSigned && i % 2 == 0) {
+      argumentValue = -argumentValue;
+    }
+    sum += argumentValue;
+    if (type.isFloatingPoint) {
+      return argumentValue.toDouble().toString();
+    } else {
+      return argumentValue.toString();
+    }
+  }
+
+  String sumValue(FundamentalType type) {
+    if (type.isFloatingPoint) {
+      return sum.toDouble().toString();
+    } else {
+      return sum.toString();
+    }
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively allocating all members.
+  String dartAllocateStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "${dartType} ${variableName};\n";
+
+      case StructType:
+        return "${dartType} ${variableName} = allocate<$dartType>().ref;\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of Dart statements allocating as zero or nullptr.
+  String dartAllocateZeroStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "${dartType} ${variableName} = 0;\n";
+        }
+        return "${dartType} ${variableName} = 0.0;\n";
+
+      case StructType:
+        return "${dartType} ${variableName} = ${dartType}();\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively allocating all members.
+  String dartAllocateStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartAllocateStatements("$namePrefix${m.name}"))
+        .join();
+  }
+
+  /// A list of Dart statements as zero or nullptr.
+  String dartAllocateZeroStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartAllocateZeroStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively freeing all members.
+  String dartFreeStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return "";
+
+      case StructType:
+        return "free($variableName.addressOf);\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively freeing all members.
+  String dartFreeStatements([String namePrefix = ""]) {
+    return map((m) => m.type.dartFreeStatements("$namePrefix${m.name}")).join();
+  }
+}
+
+extension on CType {
+  /// A list of C statements recursively allocating all members.
+  String cAllocateStatements(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+      case StructType:
+        return "${cType} ${variableName};\n";
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of C statements recursively allocating all members.
+  String cAllocateStatements([String namePrefix = ""]) {
+    return map((m) => m.type.cAllocateStatements("$namePrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// A list of Dart statements recursively checking all members.
+  String dartExpectsStatements(String expected, String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "Expect.equals(${expected}, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "Expect.approxEquals(${expected}, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.dartExpectsStatements("$expected.", "$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of Dart statements recursively checking all members.
+  String dartExpectsStatements(
+      [String expectedPrefix = "", String actualPrefix = ""]) {
+    return map((m) => m.type.dartExpectsStatements(
+        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
+  }
+}
+
+extension on CType {
+  /// A list of C statements recursively checking all members.
+  String cExpectsStatements(String expected, String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "CHECK_EQ(${expected}, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "CHECK_APPROX(${expected}, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.cExpectsStatements("$expected.", "$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+
+  /// A list of C statements recursively checking all members for zero.
+  String cExpectsZeroStatements(String actual) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        final this_ = this as FundamentalType;
+        if (this_.isInteger) {
+          return "CHECK_EQ(0, ${actual});";
+        }
+        assert(this_.isFloatingPoint);
+        return "CHECK_APPROX(0.0, ${actual});";
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.cExpectsZeroStatements("$actual.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// A list of C statements recursively checking all members.
+  String cExpectsStatements(
+      [String expectedPrefix = "", String actualPrefix = ""]) {
+    return map((m) => m.type.cExpectsStatements(
+        "$expectedPrefix${m.name}", "$actualPrefix${m.name}")).join();
+  }
+
+  /// A list of C statements recursively checking all members for zero.
+  String cExpectsZeroStatements([String actualPrefix = ""]) {
+    return map((m) => m.type.cExpectsZeroStatements("$actualPrefix${m.name}"))
+        .join();
+  }
+}
+
+extension on CType {
+  /// Expression denoting the first FundamentalType field.
+  ///
+  /// Both valid in Dart and C.
+  String firstArgumentName(String variableName) {
+    switch (this.runtimeType) {
+      case FundamentalType:
+        return variableName;
+
+      case StructType:
+        final this_ = this as StructType;
+        return this_.members.firstArgumentName("$variableName.");
+    }
+
+    throw Exception("Not implemented for ${this.runtimeType}");
+  }
+}
+
+extension on List<Member> {
+  /// Expression denoting the first FundamentalType field.
+  ///
+  /// Both valid in Dart and C.
+  String firstArgumentName([String prefix = ""]) {
+    return this[0].type.firstArgumentName("$prefix${this[0].name}");
+  }
+}
+
+extension on StructType {
+  String dartClass(bool nnbd) {
+    String dartFields = "";
+    for (final member in members) {
+      dartFields += "${member.dartStructField(nnbd)}\n\n";
+    }
+    String toStringBody = members.map((m) => "\$\{${m.name}\}").join(", ");
+    return """
+    class $name extends Struct {
+      $dartFields
+
+      String toString() => "($toStringBody)";
+    }
+    """;
+  }
+
+  String get cDefinition {
+    String cFields = "";
+    for (final member in members) {
+      cFields += "  ${member.cStructField}\n";
+    }
+    return """
+    struct $name {
+      $cFields
+    };
+
+    """;
+  }
+}
+
+extension on FunctionType {
+  String get dartCallCode {
+    final a = ArgumentValueAssigner();
+    final assignValues = arguments.assignValueStatements(a);
+    final argumentFrees = arguments.dartFreeStatements();
+
+    final argumentNames = arguments.map((e) => e.name).join(", ");
+
+    String expects;
+    switch (testType) {
+      case TestType.structArguments:
+        // Check against sum value.
+        final expectedResult = a.sumValue(returnValue as FundamentalType);
+        expects = returnValue.dartExpectsStatements(expectedResult, "result");
+        break;
+      case TestType.structReturn:
+        // Check against input arguments.
+        expects = arguments.dartExpectsStatements("", "result.");
+        break;
+      case TestType.structReturnArgument:
+        expects = returnValue.dartExpectsStatements(
+            structReturnArgument.name, "result");
+        break;
+    }
+
+    return """
+    final $dartName =
+      ffiTestFunctions.lookupFunction<$dartCType, $dartType>("$cName");
+
+    ${reason.makeDartDocComment()}
+    void $dartTestName() {
+      ${arguments.dartAllocateStatements()}
+
+      ${assignValues}
+
+      final result = $dartName($argumentNames);
+
+      print("result = \$result");
+
+      $expects
+
+      $argumentFrees
+    }
+    """;
+  }
+
+  String dartCallbackCode(bool nnbd) {
+    final argumentss =
+        arguments.map((a) => "${a.type.dartType} ${a.name}").join(", ");
+
+    final prints = arguments.map((a) => "\$\{${a.name}\}").join(", ");
+
+    String buildReturnValue = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Sum all input values.
+        buildReturnValue = """
+        ${returnValue.dartType} result = 0;
+
+        ${arguments.addToResultStatements('${dartName}_')}
+        """;
+        break;
+      case TestType.structReturn:
+        // Allocate a struct.
+        buildReturnValue = """
+        ${returnValue.dartType} result = allocate<${returnValue.dartType}>().ref;
+
+        ${arguments.copyValueStatements("${dartName}_", "result.")}
+        """;
+        break;
+      case TestType.structReturnArgument:
+        buildReturnValue = """
+        ${returnValue.cType} result = ${dartName}_${structReturnArgument.name};
+        """;
+        break;
+    }
+
+    final globals = arguments.dartAllocateZeroStatements("${dartName}_");
+
+    final copyToGlobals =
+        arguments.map((a) => '${dartName}_${a.name} = ${a.name};').join("\n");
+
+    // Simulate assigning values the same way as in C, so that we know what the
+    // final return value should be.
+    final a = ArgumentValueAssigner();
+    arguments.assignValueStatements(a);
+    String afterCallbackExpects = "";
+    String afterCallbackFrees = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Check that the input structs are still available.
+        // Check against sum value.
+        final expectedResult = a.sumValue(returnValue as FundamentalType);
+        afterCallbackExpects =
+            returnValue.dartExpectsStatements(expectedResult, "result");
+        break;
+      case TestType.structReturn:
+        // We're passing allocating structs in [buildReturnValue].
+        afterCallbackFrees =
+            returnValue.dartFreeStatements("${dartName}Result");
+        break;
+      case TestType.structReturnArgument:
+        break;
+    }
+
+    String returnNull = "";
+    if (!nnbd) {
+      returnNull = """
+      if (${arguments.firstArgumentName()} == $returnNullValue) {
+        print("returning null!");
+        return null;
+      }
+      """;
+    }
+
+    return """
+    typedef ${cName}Type = $dartCType;
+
+    // Global variables to be able to test inputs after callback returned.
+    $globals
+
+    // Result variable also global, so we can delete it after the callback.
+    ${returnValue.dartAllocateZeroStatements("${dartName}Result")}
+
+    ${returnValue.dartType} ${dartName}CalculateResult() {
+      $buildReturnValue
+
+      ${dartName}Result = result;
+
+      return result;
+    }
+
+    ${reason.makeDartDocComment()}
+    ${returnValue.dartType} $dartName($argumentss) {
+      print("$dartName($prints)");
+
+      // In legacy mode, possibly return null.
+      $returnNull
+
+      // In both nnbd and legacy mode, possibly throw.
+      if (${arguments.firstArgumentName()} == $throwExceptionValue ||
+          ${arguments.firstArgumentName()} == $returnNullValue) {
+        print("throwing!");
+        throw Exception("$cName throwing on purpuse!");
+      }
+
+      $copyToGlobals
+
+      final result = ${dartName}CalculateResult();
+
+      print(\"result = \$result\");
+
+      return result;
+    }
+
+    void ${dartName}AfterCallback() {
+      $afterCallbackFrees
+
+      final result = ${dartName}CalculateResult();
+
+      print(\"after callback result = \$result\");
+
+      $afterCallbackExpects
+
+      $afterCallbackFrees
+    }
+
+    """;
+  }
+
+  String get dartCallbackTestConstructor {
+    String exceptionalReturn = "";
+    if (returnValue is FundamentalType) {
+      if ((returnValue as FundamentalType).isFloatingPoint) {
+        exceptionalReturn = ", 0.0";
+      } else {
+        exceptionalReturn = ", 0";
+      }
+    }
+    return """
+    CallbackTest.withCheck("$cName",
+      Pointer.fromFunction<${cName}Type>($dartName$exceptionalReturn),
+      ${dartName}AfterCallback),
+    """;
+  }
+
+  String get cCallCode {
+    String body = "";
+    switch (testType) {
+      case TestType.structArguments:
+        body = """
+        ${returnValue.cType} result = 0;
+
+        ${arguments.addToResultStatements()}
+        """;
+        break;
+      case TestType.structReturn:
+        body = """
+        ${returnValue.cType} result;
+
+        ${arguments.copyValueStatements("", "result.")}
+        """;
+        break;
+      case TestType.structReturnArgument:
+        body = """
+        ${returnValue.cType} result = ${structReturnArgument.name};
+        """;
+        break;
+    }
+
+    final argumentss =
+        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
+
+    return """
+    // Used for testing structs by value.
+    ${reason.makeCComment()}
+    DART_EXPORT ${returnValue.cType} $cName($argumentss) {
+      std::cout << \"$cName\" ${arguments.coutExpression()} << \"\\n\";
+
+      $body
+
+      ${returnValue.coutStatement("result")}
+
+      return result;
+    }
+
+    """;
+  }
+
+  String get cCallbackCode {
+    final a = ArgumentValueAssigner();
+    final argumentAllocations = arguments.cAllocateStatements();
+    final assignValues = arguments.assignValueStatements(a);
+
+    final argumentss =
+        arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
+
+    final argumentNames = arguments.map((e) => e.name).join(", ");
+
+    String expects = "";
+    String expectsZero = "";
+    switch (testType) {
+      case TestType.structArguments:
+        // Check against sum value.
+        final returnValue_ = returnValue as FundamentalType;
+        final expectedResult = a.sumValue(returnValue_);
+        expects = returnValue.cExpectsStatements(expectedResult, "result");
+
+        expectsZero = returnValue.cExpectsZeroStatements("result");
+        break;
+      case TestType.structReturn:
+        // Check against input statements.
+        expects = arguments.cExpectsStatements("", "result.");
+
+        expectsZero = arguments.cExpectsZeroStatements("result.");
+        break;
+      case TestType.structReturnArgument:
+        // Check against input struct fields.
+        expects =
+            returnValue.cExpectsStatements(structReturnArgument.name, "result");
+
+        expectsZero = returnValue.cExpectsZeroStatements("result");
+        break;
+    }
+
+    return """
+    // Used for testing structs by value.
+    ${reason.makeCComment()}
+    DART_EXPORT intptr_t
+    Test$cName(
+        // NOLINTNEXTLINE(whitespace/parens)
+        ${returnValue.cType} (*f)($argumentss)) {
+      $argumentAllocations
+
+      $assignValues
+
+      std::cout << \"Calling Test$cName(\" ${arguments.coutExpression()} << \")\\n\";
+
+      ${returnValue.cType} result = f($argumentNames);
+
+      ${returnValue.coutStatement("result")}
+
+      $expects
+
+      // Pass argument that will make the Dart callback throw.
+      ${arguments.firstArgumentName()} = $throwExceptionValue;
+
+      result = f($argumentNames);
+
+      $expectsZero
+
+      // Pass argument that will make the Dart callback return null.
+      ${arguments.firstArgumentName()} = $returnNullValue;
+
+      result = f($argumentNames);
+
+      $expectsZero
+
+      return 0;
+    }
+
+    """;
+  }
+}
+
+/// Some value between 0 and 127 (works in every native type).
+const throwExceptionValue = 42;
+
+/// Some value between 0 and 127 (works in every native type).
+const returnNullValue = 84;
+
+const headerDartCallTest = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=5
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'dylib_utils.dart';
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+""";
+
+void writeDartCallTest() {
+  for (bool nnbd in [true, false]) {
+    final StringBuffer buffer = StringBuffer();
+    buffer.write(headerDartCallTest);
+
+    buffer.write("""
+    void main() {
+      for (int i = 0; i < 10; ++i) {
+        ${functions.map((e) => "${e.dartTestName}();").join("\n")}
+      }
+    }
+    """);
+    buffer.writeAll(structs.map((e) => e.dartClass(nnbd)));
+    buffer.writeAll(functions.map((e) => e.dartCallCode));
+
+    final path = callTestPath(nnbd);
+    File(path).writeAsStringSync(buffer.toString());
+    Process.runSync("dartfmt", ["-w", path]);
+  }
+}
+
+String callTestPath(bool nnbd) {
+  final folder = nnbd ? "ffi" : "ffi_2";
+  return Platform.script
+      .resolve("../../$folder/function_structs_by_value_generated_test.dart")
+      .path;
+}
+
+const headerDartCallbackTest = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+//
+// SharedObjects=ffi_test_functions
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=10
+// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'callback_tests_utils.dart';
+
+// Reuse the struct classes.
+import 'function_structs_by_value_generated_test.dart';
+
+
+void main() {
+  testCases.forEach((t) {
+    print("==== Running " + t.name);
+    t.run();
+  });
+}
+
+
+""";
+
+void writeDartCallbackTest() {
+  for (bool nnbd in [true, false]) {
+    final StringBuffer buffer = StringBuffer();
+    buffer.write(headerDartCallbackTest);
+
+    buffer.write("""
+  final testCases = [
+    ${functions.map((e) => e.dartCallbackTestConstructor).join("\n")}
+  ];
+  """);
+
+    buffer.writeAll(functions.map((e) => e.dartCallbackCode(nnbd)));
+
+    final path = callbackTestPath(nnbd);
+    File(path).writeAsStringSync(buffer.toString());
+    Process.runSync("dartfmt", ["-w", path]);
+  }
+}
+
+String callbackTestPath(bool nnbd) {
+  final folder = nnbd ? "ffi" : "ffi_2";
+  return Platform.script
+      .resolve(
+          "../../$folder/function_callbacks_structs_by_value_generated_test.dart")
+      .path;
+}
+
+const headerC = """
+// Copyright (c) 2020, 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+#if defined(_WIN32)
+#define DART_EXPORT extern "C" __declspec(dllexport)
+#else
+#define DART_EXPORT                                                            \\
+  extern "C" __attribute__((visibility("default"))) __attribute((used))
+#endif
+
+namespace dart {
+
+#define CHECK(X)                                                               \\
+  if (!(X)) {                                                                  \\
+    fprintf(stderr, "%s\\n", "Check failed: " #X);                              \\
+    return 1;                                                                  \\
+  }
+
+#define CHECK_EQ(X, Y) CHECK((X) == (Y))
+
+// Works for positive, negative and zero.
+#define CHECK_APPROX(EXPECTED, ACTUAL)                                         \\
+  CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \\
+        ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
+
+""";
+
+const footerC = """
+
+}  // namespace dart
+""";
+
+void writeC() {
+  final StringBuffer buffer = StringBuffer();
+  buffer.write(headerC);
+
+  buffer.writeAll(structs.map((e) => e.cDefinition));
+  buffer.writeAll(functions.map((e) => e.cCallCode));
+  buffer.writeAll(functions.map((e) => e.cCallbackCode));
+
+  buffer.write(footerC);
+
+  File(ccPath).writeAsStringSync(buffer.toString());
+  Process.runSync("clang-format", ["-i", ccPath]);
+}
+
+final ccPath = Platform.script
+    .resolve("../../../runtime/bin/ffi_test/ffi_test_functions_generated.cc")
+    .path;
+
+void printUsage() {
+  print("""
+Generates structs by value tests.
+
+Generates:
+- $ccPath
+- ${callbackTestPath(true)}
+- ${callTestPath(true)}
+- ${callbackTestPath(false)}
+- ${callTestPath(false)}
+""");
+}
+
+void main(List<String> arguments) {
+  if (arguments.length != 0) {
+    printUsage();
+    return;
+  }
+
+  writeDartCallTest();
+  writeDartCallbackTest();
+  writeC();
+}
diff --git a/tests/ffi_2/generator/utils.dart b/tests/ffi_2/generator/utils.dart
new file mode 100644
index 0000000..735e769
--- /dev/null
+++ b/tests/ffi_2/generator/utils.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, 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.
+
+extension TestGeneratorStringExtension on String {
+  String upperCaseFirst() => "${this[0].toUpperCase()}${this.substring(1)}";
+
+  String lowerCaseFirst() => "${this[0].toLowerCase()}${this.substring(1)}";
+
+  String makeCComment() => "// " + split("\n").join("\n// ");
+
+  String makeDartDocComment() => "/// " + split("\n").join("\n/// ");
+
+  String limitTo(int lenght) {
+    if (this.length > lenght) {
+      return substring(0, lenght);
+    }
+    return this;
+  }
+
+  String trimCouts() => replaceAll('" << "', '').replaceAll('"<< "', '');
+}