// 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.
// Generated by tests/ffi/generator/structs_by_value_tests_generator.dart.

#include <stdarg.h>
#include <stddef.h>
#include <stdint.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 Struct1ByteBool {
  bool a0;
};

struct Struct1ByteInt {
  int8_t a0;
};

struct Struct3BytesHomogeneousUint8 {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;
};

struct Struct3BytesInt2ByteAligned {
  int16_t a0;
  int8_t a1;
};

struct Struct4BytesHomogeneousInt16 {
  int16_t a0;
  int16_t a1;
};

struct Struct4BytesFloat {
  float a0;
};

struct Struct7BytesHomogeneousUint8 {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;
  uint8_t a5;
  uint8_t a6;
};

struct Struct7BytesInt4ByteAligned {
  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 Struct8BytesFloat {
  double a0;
};

struct Struct8BytesMixed {
  float a0;
  int16_t a1;
  int16_t a2;
};

struct Struct9BytesHomogeneousUint8 {
  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 Struct9BytesInt4Or8ByteAligned {
  int64_t a0;
  int8_t a1;
};

struct Struct10BytesHomogeneousBool {
  bool a0;
  bool a1;
  bool a2;
  bool a3;
  bool a4;
  bool a5;
  bool a6;
  bool a7;
  bool a8;
  bool a9;
};

struct Struct12BytesHomogeneousFloat {
  float a0;
  float a1;
  float a2;
};

struct Struct12BytesHomogeneousInt32 {
  int32_t a0;
  int32_t a1;
  int32_t 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;
};

struct Struct8BytesNestedInt {
  Struct4BytesHomogeneousInt16 a0;
  Struct4BytesHomogeneousInt16 a1;
};

struct Struct8BytesNestedFloat {
  Struct4BytesFloat a0;
  Struct4BytesFloat a1;
};

struct Struct8BytesNestedFloat2 {
  Struct4BytesFloat a0;
  float a1;
};

struct Struct8BytesNestedMixed {
  Struct4BytesHomogeneousInt16 a0;
  Struct4BytesFloat a1;
};

struct Struct16BytesNestedInt {
  Struct8BytesNestedInt a0;
  Struct8BytesNestedInt a1;
};

struct Struct32BytesNestedInt {
  Struct16BytesNestedInt a0;
  Struct16BytesNestedInt a1;
};

struct StructNestedIntStructAlignmentInt16 {
  StructAlignmentInt16 a0;
  StructAlignmentInt16 a1;
};

struct StructNestedIntStructAlignmentInt32 {
  StructAlignmentInt32 a0;
  StructAlignmentInt32 a1;
};

struct StructNestedIntStructAlignmentInt64 {
  StructAlignmentInt64 a0;
  StructAlignmentInt64 a1;
};

struct StructNestedIrregularBig {
  uint16_t a0;
  Struct8BytesNestedMixed a1;
  uint16_t a2;
  Struct8BytesNestedFloat2 a3;
  uint16_t a4;
  Struct8BytesNestedFloat a5;
  uint16_t a6;
};

struct StructNestedIrregularBigger {
  StructNestedIrregularBig a0;
  Struct8BytesNestedMixed a1;
  float a2;
  double a3;
};

struct StructNestedIrregularEvenBigger {
  uint64_t a0;
  StructNestedIrregularBigger a1;
  StructNestedIrregularBigger a2;
  double a3;
};

struct Struct8BytesInlineArrayInt {
  uint8_t a0[8];
};

struct Struct10BytesInlineArrayBool {
  bool a0[10];
};

struct StructInlineArrayIrregular {
  Struct3BytesInt2ByteAligned a0[2];
  uint8_t a1;
};

struct StructInlineArray100Bytes {
  uint8_t a0[100];
};

struct StructInlineArrayBig {
  uint32_t a0;
  uint32_t a1;
  uint8_t a2[4000];
};

struct StructStruct16BytesHomogeneousFloat2 {
  Struct4BytesFloat a0;
  Struct4BytesFloat a1[2];
  float a2;
};

struct StructStruct32BytesHomogeneousDouble2 {
  Struct8BytesFloat a0;
  Struct8BytesFloat a1[2];
  double a2;
};

struct StructStruct16BytesMixed3 {
  Struct4BytesFloat a0;
  Struct8BytesMixed a1[1];
  int16_t a2[2];
};

struct Struct8BytesInlineArrayMultiDimensionalInt {
  uint8_t a0[2][2][2];
};

struct Struct32BytesInlineArrayMultiDimensionalInt {
  uint8_t a0[2][2][2][2][2];
};

struct Struct64BytesInlineArrayMultiDimensionalInt {
  uint8_t a0[2][2][2][2][2][2];
};

struct Struct4BytesInlineArrayMultiDimensionalInt {
  Struct1ByteInt a0[2][2];
};

#pragma pack(push, 1)
struct Struct3BytesPackedInt {
  int8_t a0;
  int16_t a1;
};
#pragma pack(pop)

#pragma pack(push, 1)
struct Struct3BytesPackedIntMembersAligned {
  int8_t a0;
  int16_t a1;
};
#pragma pack(pop)

#pragma pack(push, 1)
struct Struct5BytesPackedMixed {
  float a0;
  uint8_t a1;
};
#pragma pack(pop)

struct StructNestedAlignmentStruct5BytesPackedMixed {
  uint8_t a0;
  Struct5BytesPackedMixed a1;
};

struct Struct6BytesInlineArrayInt {
  Struct3BytesPackedIntMembersAligned a0[2];
};

#pragma pack(push, 1)
struct Struct8BytesPackedInt {
  uint8_t a0;
  uint32_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;
};
#pragma pack(pop)

#pragma pack(push, 1)
struct Struct9BytesPackedMixed {
  uint8_t a0;
  double a1;
};
#pragma pack(pop)

struct Struct15BytesInlineArrayMixed {
  Struct5BytesPackedMixed a0[3];
};

union Union4BytesMixed {
  uint32_t a0;
  float a1;
};

union Union8BytesNestedFloat {
  double a0;
  Struct8BytesHomogeneousFloat a1;
};

union Union9BytesNestedInt {
  Struct8BytesInt a0;
  Struct9BytesHomogeneousUint8 a1;
};

union Union16BytesNestedInlineArrayFloat {
  float a0[4];
  Struct16BytesHomogeneousFloat a1;
};

union Union16BytesNestedFloat {
  Struct8BytesHomogeneousFloat a0;
  Struct12BytesHomogeneousFloat a1;
  Struct16BytesHomogeneousFloat a2;
};

struct StructInlineArrayInt {
  wchar_t a0[10];
};

struct StructInlineArrayVariable {
  uint32_t a0;
  uint8_t a1[];
};

struct StructInlineArrayVariableNested {
  uint32_t a0;
  uint8_t a1[][2][2];
};

struct StructInlineArrayVariableNestedDeep {
  uint32_t a0;
  uint8_t a1[][2][2][2][2][2][2];
};

struct StructInlineArrayVariableAlign {
  uint8_t a0;
  uint32_t a1[];
};

struct StructInlineArrayVariable2 {
  uint32_t a0;
  uint8_t a1[1];
};

struct StructInlineArrayVariableNested2 {
  uint32_t a0;
  uint8_t a1[1][2][2];
};

struct StructInlineArrayVariableNestedDeep2 {
  uint32_t a0;
  uint8_t a1[1][2][2][2][2][2][2];
};

// Used for testing the size of Struct1ByteBool.
DART_EXPORT uint64_t SizeOfStruct1ByteBool() {
  std::cout << "SizeOfStruct1ByteBool"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct1ByteBool);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct1ByteInt.
DART_EXPORT uint64_t SizeOfStruct1ByteInt() {
  std::cout << "SizeOfStruct1ByteInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct1ByteInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct3BytesHomogeneousUint8.
DART_EXPORT uint64_t SizeOfStruct3BytesHomogeneousUint8() {
  std::cout << "SizeOfStruct3BytesHomogeneousUint8"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct3BytesHomogeneousUint8);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct3BytesInt2ByteAligned.
DART_EXPORT uint64_t SizeOfStruct3BytesInt2ByteAligned() {
  std::cout << "SizeOfStruct3BytesInt2ByteAligned"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct3BytesInt2ByteAligned);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct4BytesHomogeneousInt16.
DART_EXPORT uint64_t SizeOfStruct4BytesHomogeneousInt16() {
  std::cout << "SizeOfStruct4BytesHomogeneousInt16"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct4BytesHomogeneousInt16);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct4BytesFloat.
DART_EXPORT uint64_t SizeOfStruct4BytesFloat() {
  std::cout << "SizeOfStruct4BytesFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct4BytesFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct7BytesHomogeneousUint8.
DART_EXPORT uint64_t SizeOfStruct7BytesHomogeneousUint8() {
  std::cout << "SizeOfStruct7BytesHomogeneousUint8"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct7BytesHomogeneousUint8);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct7BytesInt4ByteAligned.
DART_EXPORT uint64_t SizeOfStruct7BytesInt4ByteAligned() {
  std::cout << "SizeOfStruct7BytesInt4ByteAligned"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct7BytesInt4ByteAligned);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesInt.
DART_EXPORT uint64_t SizeOfStruct8BytesInt() {
  std::cout << "SizeOfStruct8BytesInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesHomogeneousFloat.
DART_EXPORT uint64_t SizeOfStruct8BytesHomogeneousFloat() {
  std::cout << "SizeOfStruct8BytesHomogeneousFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesHomogeneousFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesFloat.
DART_EXPORT uint64_t SizeOfStruct8BytesFloat() {
  std::cout << "SizeOfStruct8BytesFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesMixed.
DART_EXPORT uint64_t SizeOfStruct8BytesMixed() {
  std::cout << "SizeOfStruct8BytesMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct9BytesHomogeneousUint8.
DART_EXPORT uint64_t SizeOfStruct9BytesHomogeneousUint8() {
  std::cout << "SizeOfStruct9BytesHomogeneousUint8"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct9BytesHomogeneousUint8);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct9BytesInt4Or8ByteAligned.
DART_EXPORT uint64_t SizeOfStruct9BytesInt4Or8ByteAligned() {
  std::cout << "SizeOfStruct9BytesInt4Or8ByteAligned"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct9BytesInt4Or8ByteAligned);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct10BytesHomogeneousBool.
DART_EXPORT uint64_t SizeOfStruct10BytesHomogeneousBool() {
  std::cout << "SizeOfStruct10BytesHomogeneousBool"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct10BytesHomogeneousBool);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct12BytesHomogeneousFloat.
DART_EXPORT uint64_t SizeOfStruct12BytesHomogeneousFloat() {
  std::cout << "SizeOfStruct12BytesHomogeneousFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct12BytesHomogeneousFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct12BytesHomogeneousInt32.
DART_EXPORT uint64_t SizeOfStruct12BytesHomogeneousInt32() {
  std::cout << "SizeOfStruct12BytesHomogeneousInt32"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct12BytesHomogeneousInt32);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct16BytesHomogeneousFloat.
DART_EXPORT uint64_t SizeOfStruct16BytesHomogeneousFloat() {
  std::cout << "SizeOfStruct16BytesHomogeneousFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct16BytesHomogeneousFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct16BytesMixed.
DART_EXPORT uint64_t SizeOfStruct16BytesMixed() {
  std::cout << "SizeOfStruct16BytesMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct16BytesMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct16BytesMixed2.
DART_EXPORT uint64_t SizeOfStruct16BytesMixed2() {
  std::cout << "SizeOfStruct16BytesMixed2"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct16BytesMixed2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct17BytesInt.
DART_EXPORT uint64_t SizeOfStruct17BytesInt() {
  std::cout << "SizeOfStruct17BytesInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct17BytesInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct19BytesHomogeneousUint8.
DART_EXPORT uint64_t SizeOfStruct19BytesHomogeneousUint8() {
  std::cout << "SizeOfStruct19BytesHomogeneousUint8"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct19BytesHomogeneousUint8);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct20BytesHomogeneousInt32.
DART_EXPORT uint64_t SizeOfStruct20BytesHomogeneousInt32() {
  std::cout << "SizeOfStruct20BytesHomogeneousInt32"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct20BytesHomogeneousInt32);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct20BytesHomogeneousFloat.
DART_EXPORT uint64_t SizeOfStruct20BytesHomogeneousFloat() {
  std::cout << "SizeOfStruct20BytesHomogeneousFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct20BytesHomogeneousFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct32BytesHomogeneousDouble.
DART_EXPORT uint64_t SizeOfStruct32BytesHomogeneousDouble() {
  std::cout << "SizeOfStruct32BytesHomogeneousDouble"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct32BytesHomogeneousDouble);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct40BytesHomogeneousDouble.
DART_EXPORT uint64_t SizeOfStruct40BytesHomogeneousDouble() {
  std::cout << "SizeOfStruct40BytesHomogeneousDouble"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct40BytesHomogeneousDouble);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct1024BytesHomogeneousUint64.
DART_EXPORT uint64_t SizeOfStruct1024BytesHomogeneousUint64() {
  std::cout << "SizeOfStruct1024BytesHomogeneousUint64"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct1024BytesHomogeneousUint64);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructAlignmentInt16.
DART_EXPORT uint64_t SizeOfStructAlignmentInt16() {
  std::cout << "SizeOfStructAlignmentInt16"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructAlignmentInt16);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructAlignmentInt32.
DART_EXPORT uint64_t SizeOfStructAlignmentInt32() {
  std::cout << "SizeOfStructAlignmentInt32"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructAlignmentInt32);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructAlignmentInt64.
DART_EXPORT uint64_t SizeOfStructAlignmentInt64() {
  std::cout << "SizeOfStructAlignmentInt64"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructAlignmentInt64);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesNestedInt.
DART_EXPORT uint64_t SizeOfStruct8BytesNestedInt() {
  std::cout << "SizeOfStruct8BytesNestedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesNestedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesNestedFloat.
DART_EXPORT uint64_t SizeOfStruct8BytesNestedFloat() {
  std::cout << "SizeOfStruct8BytesNestedFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesNestedFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesNestedFloat2.
DART_EXPORT uint64_t SizeOfStruct8BytesNestedFloat2() {
  std::cout << "SizeOfStruct8BytesNestedFloat2"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesNestedFloat2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesNestedMixed.
DART_EXPORT uint64_t SizeOfStruct8BytesNestedMixed() {
  std::cout << "SizeOfStruct8BytesNestedMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesNestedMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct16BytesNestedInt.
DART_EXPORT uint64_t SizeOfStruct16BytesNestedInt() {
  std::cout << "SizeOfStruct16BytesNestedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct16BytesNestedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct32BytesNestedInt.
DART_EXPORT uint64_t SizeOfStruct32BytesNestedInt() {
  std::cout << "SizeOfStruct32BytesNestedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct32BytesNestedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIntStructAlignmentInt16.
DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt16() {
  std::cout << "SizeOfStructNestedIntStructAlignmentInt16"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIntStructAlignmentInt16);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIntStructAlignmentInt32.
DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt32() {
  std::cout << "SizeOfStructNestedIntStructAlignmentInt32"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIntStructAlignmentInt32);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIntStructAlignmentInt64.
DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt64() {
  std::cout << "SizeOfStructNestedIntStructAlignmentInt64"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIntStructAlignmentInt64);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIrregularBig.
DART_EXPORT uint64_t SizeOfStructNestedIrregularBig() {
  std::cout << "SizeOfStructNestedIrregularBig"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIrregularBig);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIrregularBigger.
DART_EXPORT uint64_t SizeOfStructNestedIrregularBigger() {
  std::cout << "SizeOfStructNestedIrregularBigger"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIrregularBigger);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedIrregularEvenBigger.
DART_EXPORT uint64_t SizeOfStructNestedIrregularEvenBigger() {
  std::cout << "SizeOfStructNestedIrregularEvenBigger"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedIrregularEvenBigger);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesInlineArrayInt.
DART_EXPORT uint64_t SizeOfStruct8BytesInlineArrayInt() {
  std::cout << "SizeOfStruct8BytesInlineArrayInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesInlineArrayInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct10BytesInlineArrayBool.
DART_EXPORT uint64_t SizeOfStruct10BytesInlineArrayBool() {
  std::cout << "SizeOfStruct10BytesInlineArrayBool"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct10BytesInlineArrayBool);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayIrregular.
DART_EXPORT uint64_t SizeOfStructInlineArrayIrregular() {
  std::cout << "SizeOfStructInlineArrayIrregular"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayIrregular);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArray100Bytes.
DART_EXPORT uint64_t SizeOfStructInlineArray100Bytes() {
  std::cout << "SizeOfStructInlineArray100Bytes"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArray100Bytes);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayBig.
DART_EXPORT uint64_t SizeOfStructInlineArrayBig() {
  std::cout << "SizeOfStructInlineArrayBig"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayBig);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructStruct16BytesHomogeneousFloat2.
DART_EXPORT uint64_t SizeOfStructStruct16BytesHomogeneousFloat2() {
  std::cout << "SizeOfStructStruct16BytesHomogeneousFloat2"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructStruct16BytesHomogeneousFloat2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructStruct32BytesHomogeneousDouble2.
DART_EXPORT uint64_t SizeOfStructStruct32BytesHomogeneousDouble2() {
  std::cout << "SizeOfStructStruct32BytesHomogeneousDouble2"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructStruct32BytesHomogeneousDouble2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructStruct16BytesMixed3.
DART_EXPORT uint64_t SizeOfStructStruct16BytesMixed3() {
  std::cout << "SizeOfStructStruct16BytesMixed3"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructStruct16BytesMixed3);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesInlineArrayMultiDimensionalInt.
DART_EXPORT uint64_t SizeOfStruct8BytesInlineArrayMultiDimensionalInt() {
  std::cout << "SizeOfStruct8BytesInlineArrayMultiDimensionalInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesInlineArrayMultiDimensionalInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct32BytesInlineArrayMultiDimensionalInt.
DART_EXPORT uint64_t SizeOfStruct32BytesInlineArrayMultiDimensionalInt() {
  std::cout << "SizeOfStruct32BytesInlineArrayMultiDimensionalInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct32BytesInlineArrayMultiDimensionalInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct64BytesInlineArrayMultiDimensionalInt.
DART_EXPORT uint64_t SizeOfStruct64BytesInlineArrayMultiDimensionalInt() {
  std::cout << "SizeOfStruct64BytesInlineArrayMultiDimensionalInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct64BytesInlineArrayMultiDimensionalInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct4BytesInlineArrayMultiDimensionalInt.
DART_EXPORT uint64_t SizeOfStruct4BytesInlineArrayMultiDimensionalInt() {
  std::cout << "SizeOfStruct4BytesInlineArrayMultiDimensionalInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct4BytesInlineArrayMultiDimensionalInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct3BytesPackedInt.
DART_EXPORT uint64_t SizeOfStruct3BytesPackedInt() {
  std::cout << "SizeOfStruct3BytesPackedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct3BytesPackedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct3BytesPackedIntMembersAligned.
DART_EXPORT uint64_t SizeOfStruct3BytesPackedIntMembersAligned() {
  std::cout << "SizeOfStruct3BytesPackedIntMembersAligned"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct3BytesPackedIntMembersAligned);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct5BytesPackedMixed.
DART_EXPORT uint64_t SizeOfStruct5BytesPackedMixed() {
  std::cout << "SizeOfStruct5BytesPackedMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct5BytesPackedMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructNestedAlignmentStruct5BytesPackedMixed.
DART_EXPORT uint64_t SizeOfStructNestedAlignmentStruct5BytesPackedMixed() {
  std::cout << "SizeOfStructNestedAlignmentStruct5BytesPackedMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructNestedAlignmentStruct5BytesPackedMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct6BytesInlineArrayInt.
DART_EXPORT uint64_t SizeOfStruct6BytesInlineArrayInt() {
  std::cout << "SizeOfStruct6BytesInlineArrayInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct6BytesInlineArrayInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct8BytesPackedInt.
DART_EXPORT uint64_t SizeOfStruct8BytesPackedInt() {
  std::cout << "SizeOfStruct8BytesPackedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct8BytesPackedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct9BytesPackedMixed.
DART_EXPORT uint64_t SizeOfStruct9BytesPackedMixed() {
  std::cout << "SizeOfStruct9BytesPackedMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct9BytesPackedMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Struct15BytesInlineArrayMixed.
DART_EXPORT uint64_t SizeOfStruct15BytesInlineArrayMixed() {
  std::cout << "SizeOfStruct15BytesInlineArrayMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Struct15BytesInlineArrayMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Union4BytesMixed.
DART_EXPORT uint64_t SizeOfUnion4BytesMixed() {
  std::cout << "SizeOfUnion4BytesMixed"
            << "()"
            << "\n";

  uint64_t result = sizeof(Union4BytesMixed);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Union8BytesNestedFloat.
DART_EXPORT uint64_t SizeOfUnion8BytesNestedFloat() {
  std::cout << "SizeOfUnion8BytesNestedFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Union8BytesNestedFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Union9BytesNestedInt.
DART_EXPORT uint64_t SizeOfUnion9BytesNestedInt() {
  std::cout << "SizeOfUnion9BytesNestedInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(Union9BytesNestedInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Union16BytesNestedInlineArrayFloat.
DART_EXPORT uint64_t SizeOfUnion16BytesNestedInlineArrayFloat() {
  std::cout << "SizeOfUnion16BytesNestedInlineArrayFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Union16BytesNestedInlineArrayFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of Union16BytesNestedFloat.
DART_EXPORT uint64_t SizeOfUnion16BytesNestedFloat() {
  std::cout << "SizeOfUnion16BytesNestedFloat"
            << "()"
            << "\n";

  uint64_t result = sizeof(Union16BytesNestedFloat);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayInt.
DART_EXPORT uint64_t SizeOfStructInlineArrayInt() {
  std::cout << "SizeOfStructInlineArrayInt"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayInt);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariable.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariable() {
  std::cout << "SizeOfStructInlineArrayVariable"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariable);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariableNested.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNested() {
  std::cout << "SizeOfStructInlineArrayVariableNested"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariableNested);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariableNestedDeep.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNestedDeep() {
  std::cout << "SizeOfStructInlineArrayVariableNestedDeep"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariableNestedDeep);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariableAlign.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariableAlign() {
  std::cout << "SizeOfStructInlineArrayVariableAlign"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariableAlign);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariable2.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariable2() {
  std::cout << "SizeOfStructInlineArrayVariable2"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariable2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariableNested2.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNested2() {
  std::cout << "SizeOfStructInlineArrayVariableNested2"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariableNested2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing the size of StructInlineArrayVariableNestedDeep2.
DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNestedDeep2() {
  std::cout << "SizeOfStructInlineArrayVariableNestedDeep2"
            << "()"
            << "\n";

  uint64_t result = sizeof(StructInlineArrayVariableNestedDeep2);

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions by value.
// Not a multiple of word size, not a power of two.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
PassStruct3BytesHomogeneousUint8x10(Struct3BytesHomogeneousUint8 a0,
                                    Struct3BytesHomogeneousUint8 a1,
                                    Struct3BytesHomogeneousUint8 a2,
                                    Struct3BytesHomogeneousUint8 a3,
                                    Struct3BytesHomogeneousUint8 a4,
                                    Struct3BytesHomogeneousUint8 a5,
                                    Struct3BytesHomogeneousUint8 a6,
                                    Struct3BytesHomogeneousUint8 a7,
                                    Struct3BytesHomogeneousUint8 a8,
                                    Struct3BytesHomogeneousUint8 a9) {
  std::cout << "PassStruct3BytesHomogeneousUint8x10" << "(("
            << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
            << ", " << static_cast<int>(a0.a2) << "), ("
            << static_cast<int>(a1.a0) << ", " << static_cast<int>(a1.a1)
            << ", " << static_cast<int>(a1.a2) << "), ("
            << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
            << ", " << static_cast<int>(a2.a2) << "), ("
            << static_cast<int>(a3.a0) << ", " << static_cast<int>(a3.a1)
            << ", " << static_cast<int>(a3.a2) << "), ("
            << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
            << ", " << static_cast<int>(a4.a2) << "), ("
            << static_cast<int>(a5.a0) << ", " << static_cast<int>(a5.a1)
            << ", " << static_cast<int>(a5.a2) << "), ("
            << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
            << ", " << static_cast<int>(a6.a2) << "), ("
            << static_cast<int>(a7.a0) << ", " << static_cast<int>(a7.a1)
            << ", " << static_cast<int>(a7.a2) << "), ("
            << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
            << ", " << static_cast<int>(a8.a2) << "), ("
            << static_cast<int>(a9.a0) << ", " << static_cast<int>(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 and unions by value.
// Not a multiple of word size, not a power of two.
// With alignment rules taken into account size is 4 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
PassStruct3BytesInt2ByteAlignedx10(Struct3BytesInt2ByteAligned a0,
                                   Struct3BytesInt2ByteAligned a1,
                                   Struct3BytesInt2ByteAligned a2,
                                   Struct3BytesInt2ByteAligned a3,
                                   Struct3BytesInt2ByteAligned a4,
                                   Struct3BytesInt2ByteAligned a5,
                                   Struct3BytesInt2ByteAligned a6,
                                   Struct3BytesInt2ByteAligned a7,
                                   Struct3BytesInt2ByteAligned a8,
                                   Struct3BytesInt2ByteAligned a9) {
  std::cout << "PassStruct3BytesInt2ByteAlignedx10" << "((" << 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 and unions 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 and unions by value.
// Sub word size on 64 bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
PassStruct7BytesHomogeneousUint8x10(Struct7BytesHomogeneousUint8 a0,
                                    Struct7BytesHomogeneousUint8 a1,
                                    Struct7BytesHomogeneousUint8 a2,
                                    Struct7BytesHomogeneousUint8 a3,
                                    Struct7BytesHomogeneousUint8 a4,
                                    Struct7BytesHomogeneousUint8 a5,
                                    Struct7BytesHomogeneousUint8 a6,
                                    Struct7BytesHomogeneousUint8 a7,
                                    Struct7BytesHomogeneousUint8 a8,
                                    Struct7BytesHomogeneousUint8 a9) {
  std::cout
      << "PassStruct7BytesHomogeneousUint8x10" << "(("
      << 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>(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>(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>(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>(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>(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>(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>(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>(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>(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) << "))"
      << "\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 += a1.a0;
  result += a1.a1;
  result += a1.a2;
  result += a1.a3;
  result += a1.a4;
  result += a1.a5;
  result += a1.a6;
  result += a2.a0;
  result += a2.a1;
  result += a2.a2;
  result += a2.a3;
  result += a2.a4;
  result += a2.a5;
  result += a2.a6;
  result += a3.a0;
  result += a3.a1;
  result += a3.a2;
  result += a3.a3;
  result += a3.a4;
  result += a3.a5;
  result += a3.a6;
  result += a4.a0;
  result += a4.a1;
  result += a4.a2;
  result += a4.a3;
  result += a4.a4;
  result += a4.a5;
  result += a4.a6;
  result += a5.a0;
  result += a5.a1;
  result += a5.a2;
  result += a5.a3;
  result += a5.a4;
  result += a5.a5;
  result += a5.a6;
  result += a6.a0;
  result += a6.a1;
  result += a6.a2;
  result += a6.a3;
  result += a6.a4;
  result += a6.a5;
  result += a6.a6;
  result += a7.a0;
  result += a7.a1;
  result += a7.a2;
  result += a7.a3;
  result += a7.a4;
  result += a7.a5;
  result += a7.a6;
  result += a8.a0;
  result += a8.a1;
  result += a8.a2;
  result += a8.a3;
  result += a8.a4;
  result += a8.a5;
  result += a8.a6;
  result += a9.a0;
  result += a9.a1;
  result += a9.a2;
  result += a9.a3;
  result += a9.a4;
  result += a9.a5;
  result += a9.a6;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// With alignment rules taken into account size is 8 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
PassStruct7BytesInt4ByteAlignedx10(Struct7BytesInt4ByteAligned a0,
                                   Struct7BytesInt4ByteAligned a1,
                                   Struct7BytesInt4ByteAligned a2,
                                   Struct7BytesInt4ByteAligned a3,
                                   Struct7BytesInt4ByteAligned a4,
                                   Struct7BytesInt4ByteAligned a5,
                                   Struct7BytesInt4ByteAligned a6,
                                   Struct7BytesInt4ByteAligned a7,
                                   Struct7BytesInt4ByteAligned a8,
                                   Struct7BytesInt4ByteAligned a9) {
  std::cout << "PassStruct7BytesInt4ByteAlignedx10" << "((" << 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 and unions 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 and unions 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 and unions 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 and unions 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.
// Tests upper bytes in the integer registers that are partly filled.
// Tests stack alignment of non word size stack arguments.
DART_EXPORT int64_t
PassStruct9BytesHomogeneousUint8x10(Struct9BytesHomogeneousUint8 a0,
                                    Struct9BytesHomogeneousUint8 a1,
                                    Struct9BytesHomogeneousUint8 a2,
                                    Struct9BytesHomogeneousUint8 a3,
                                    Struct9BytesHomogeneousUint8 a4,
                                    Struct9BytesHomogeneousUint8 a5,
                                    Struct9BytesHomogeneousUint8 a6,
                                    Struct9BytesHomogeneousUint8 a7,
                                    Struct9BytesHomogeneousUint8 a8,
                                    Struct9BytesHomogeneousUint8 a9) {
  std::cout
      << "PassStruct9BytesHomogeneousUint8x10" << "(("
      << 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 and unions by value.
// Argument is a single byte over a multiple of word size.
// With alignment rules taken into account size is 12 or 16 bytes.
// 10 struct arguments will exhaust available registers.
//
DART_EXPORT int64_t
PassStruct9BytesInt4Or8ByteAlignedx10(Struct9BytesInt4Or8ByteAligned a0,
                                      Struct9BytesInt4Or8ByteAligned a1,
                                      Struct9BytesInt4Or8ByteAligned a2,
                                      Struct9BytesInt4Or8ByteAligned a3,
                                      Struct9BytesInt4Or8ByteAligned a4,
                                      Struct9BytesInt4Or8ByteAligned a5,
                                      Struct9BytesInt4Or8ByteAligned a6,
                                      Struct9BytesInt4Or8ByteAligned a7,
                                      Struct9BytesInt4Or8ByteAligned a8,
                                      Struct9BytesInt4Or8ByteAligned a9) {
  std::cout << "PassStruct9BytesInt4Or8ByteAlignedx10" << "((" << 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT double PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
    int32_t a0,
    int32_t a1,
    int32_t a2,
    int32_t a3,
    int32_t a4,
    int32_t a5,
    int32_t a6,
    int32_t a7,
    double a8,
    double a9,
    double a10,
    double a11,
    double a12,
    double a13,
    double a14,
    double a15,
    int64_t a16,
    int8_t a17,
    Struct1ByteInt a18,
    int64_t a19,
    int8_t a20,
    Struct4BytesHomogeneousInt16 a21,
    int64_t a22,
    int8_t a23,
    Struct8BytesInt a24,
    int64_t a25,
    int8_t a26,
    Struct8BytesHomogeneousFloat a27,
    int64_t a28,
    int8_t a29,
    Struct8BytesMixed a30,
    int64_t a31,
    int8_t a32,
    StructAlignmentInt16 a33,
    int64_t a34,
    int8_t a35,
    StructAlignmentInt32 a36,
    int64_t a37,
    int8_t a38,
    StructAlignmentInt64 a39) {
  std::cout << "PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int" << "(" << a0
            << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ", "
            << a5 << ", " << a6 << ", " << a7 << ", " << a8 << ", " << a9
            << ", " << a10 << ", " << a11 << ", " << a12 << ", " << a13 << ", "
            << a14 << ", " << a15 << ", " << a16 << ", "
            << static_cast<int>(a17) << ", (" << static_cast<int>(a18.a0)
            << "), " << a19 << ", " << static_cast<int>(a20) << ", (" << a21.a0
            << ", " << a21.a1 << "), " << a22 << ", " << static_cast<int>(a23)
            << ", (" << a24.a0 << ", " << a24.a1 << ", " << a24.a2 << "), "
            << a25 << ", " << static_cast<int>(a26) << ", (" << a27.a0 << ", "
            << a27.a1 << "), " << a28 << ", " << static_cast<int>(a29) << ", ("
            << a30.a0 << ", " << a30.a1 << ", " << a30.a2 << "), " << a31
            << ", " << static_cast<int>(a32) << ", ("
            << static_cast<int>(a33.a0) << ", " << a33.a1 << ", "
            << static_cast<int>(a33.a2) << "), " << a34 << ", "
            << static_cast<int>(a35) << ", (" << static_cast<int>(a36.a0)
            << ", " << a36.a1 << ", " << static_cast<int>(a36.a2) << "), "
            << a37 << ", " << static_cast<int>(a38) << ", ("
            << static_cast<int>(a39.a0) << ", " << a39.a1 << ", "
            << static_cast<int>(a39.a2) << "))" << "\n";

  double result = 0;

  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.a0;
  result += a19;
  result += a20;
  result += a21.a0;
  result += a21.a1;
  result += a22;
  result += a23;
  result += a24.a0;
  result += a24.a1;
  result += a24.a2;
  result += a25;
  result += a26;
  result += a27.a0;
  result += a27.a1;
  result += a28;
  result += a29;
  result += a30.a0;
  result += a30.a1;
  result += a30.a2;
  result += a31;
  result += a32;
  result += a33.a0;
  result += a33.a1;
  result += a33.a2;
  result += a34;
  result += a35;
  result += a36.a0;
  result += a36.a1;
  result += a36.a2;
  result += a37;
  result += a38;
  result += a39.a0;
  result += a39.a1;
  result += a39.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust registers on all platforms.
DART_EXPORT int64_t PassStruct8BytesNestedIntx10(Struct8BytesNestedInt a0,
                                                 Struct8BytesNestedInt a1,
                                                 Struct8BytesNestedInt a2,
                                                 Struct8BytesNestedInt a3,
                                                 Struct8BytesNestedInt a4,
                                                 Struct8BytesNestedInt a5,
                                                 Struct8BytesNestedInt a6,
                                                 Struct8BytesNestedInt a7,
                                                 Struct8BytesNestedInt a8,
                                                 Struct8BytesNestedInt a9) {
  std::cout << "PassStruct8BytesNestedIntx10" << "(((" << a0.a0.a0 << ", "
            << a0.a0.a1 << "), (" << a0.a1.a0 << ", " << a0.a1.a1 << ")), (("
            << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0 << ", "
            << a1.a1.a1 << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << "), ("
            << a2.a1.a0 << ", " << a2.a1.a1 << ")), ((" << a3.a0.a0 << ", "
            << a3.a0.a1 << "), (" << a3.a1.a0 << ", " << a3.a1.a1 << ")), (("
            << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0 << ", "
            << a4.a1.a1 << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << "), ("
            << a5.a1.a0 << ", " << a5.a1.a1 << ")), ((" << a6.a0.a0 << ", "
            << a6.a0.a1 << "), (" << a6.a1.a0 << ", " << a6.a1.a1 << ")), (("
            << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0 << ", "
            << a7.a1.a1 << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << "), ("
            << a8.a1.a0 << ", " << a8.a1.a1 << ")), ((" << a9.a0.a0 << ", "
            << a9.a0.a1 << "), (" << a9.a1.a0 << ", " << a9.a1.a1 << ")))"
            << "\n";

  int64_t result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a1.a0;
  result += a0.a1.a1;
  result += a1.a0.a0;
  result += a1.a0.a1;
  result += a1.a1.a0;
  result += a1.a1.a1;
  result += a2.a0.a0;
  result += a2.a0.a1;
  result += a2.a1.a0;
  result += a2.a1.a1;
  result += a3.a0.a0;
  result += a3.a0.a1;
  result += a3.a1.a0;
  result += a3.a1.a1;
  result += a4.a0.a0;
  result += a4.a0.a1;
  result += a4.a1.a0;
  result += a4.a1.a1;
  result += a5.a0.a0;
  result += a5.a0.a1;
  result += a5.a1.a0;
  result += a5.a1.a1;
  result += a6.a0.a0;
  result += a6.a0.a1;
  result += a6.a1.a0;
  result += a6.a1.a1;
  result += a7.a0.a0;
  result += a7.a0.a1;
  result += a7.a1.a0;
  result += a7.a1.a1;
  result += a8.a0.a0;
  result += a8.a0.a1;
  result += a8.a1.a0;
  result += a8.a1.a1;
  result += a9.a0.a0;
  result += a9.a0.a1;
  result += a9.a1.a0;
  result += a9.a1.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
DART_EXPORT float PassStruct8BytesNestedFloatx10(Struct8BytesNestedFloat a0,
                                                 Struct8BytesNestedFloat a1,
                                                 Struct8BytesNestedFloat a2,
                                                 Struct8BytesNestedFloat a3,
                                                 Struct8BytesNestedFloat a4,
                                                 Struct8BytesNestedFloat a5,
                                                 Struct8BytesNestedFloat a6,
                                                 Struct8BytesNestedFloat a7,
                                                 Struct8BytesNestedFloat a8,
                                                 Struct8BytesNestedFloat a9) {
  std::cout << "PassStruct8BytesNestedFloatx10" << "(((" << a0.a0.a0 << "), ("
            << a0.a1.a0 << ")), ((" << a1.a0.a0 << "), (" << a1.a1.a0
            << ")), ((" << a2.a0.a0 << "), (" << a2.a1.a0 << ")), (("
            << a3.a0.a0 << "), (" << a3.a1.a0 << ")), ((" << a4.a0.a0 << "), ("
            << a4.a1.a0 << ")), ((" << a5.a0.a0 << "), (" << a5.a1.a0
            << ")), ((" << a6.a0.a0 << "), (" << a6.a1.a0 << ")), (("
            << a7.a0.a0 << "), (" << a7.a1.a0 << ")), ((" << a8.a0.a0 << "), ("
            << a8.a1.a0 << ")), ((" << a9.a0.a0 << "), (" << a9.a1.a0 << ")))"
            << "\n";

  float result = 0;

  result += a0.a0.a0;
  result += a0.a1.a0;
  result += a1.a0.a0;
  result += a1.a1.a0;
  result += a2.a0.a0;
  result += a2.a1.a0;
  result += a3.a0.a0;
  result += a3.a1.a0;
  result += a4.a0.a0;
  result += a4.a1.a0;
  result += a5.a0.a0;
  result += a5.a1.a0;
  result += a6.a0.a0;
  result += a6.a1.a0;
  result += a7.a0.a0;
  result += a7.a1.a0;
  result += a8.a0.a0;
  result += a8.a1.a0;
  result += a9.a0.a0;
  result += a9.a1.a0;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT float PassStruct8BytesNestedFloat2x10(Struct8BytesNestedFloat2 a0,
                                                  Struct8BytesNestedFloat2 a1,
                                                  Struct8BytesNestedFloat2 a2,
                                                  Struct8BytesNestedFloat2 a3,
                                                  Struct8BytesNestedFloat2 a4,
                                                  Struct8BytesNestedFloat2 a5,
                                                  Struct8BytesNestedFloat2 a6,
                                                  Struct8BytesNestedFloat2 a7,
                                                  Struct8BytesNestedFloat2 a8,
                                                  Struct8BytesNestedFloat2 a9) {
  std::cout << "PassStruct8BytesNestedFloat2x10" << "(((" << a0.a0.a0 << "), "
            << a0.a1 << "), ((" << a1.a0.a0 << "), " << a1.a1 << "), (("
            << a2.a0.a0 << "), " << a2.a1 << "), ((" << a3.a0.a0 << "), "
            << a3.a1 << "), ((" << a4.a0.a0 << "), " << a4.a1 << "), (("
            << a5.a0.a0 << "), " << a5.a1 << "), ((" << a6.a0.a0 << "), "
            << a6.a1 << "), ((" << a7.a0.a0 << "), " << a7.a1 << "), (("
            << a8.a0.a0 << "), " << a8.a1 << "), ((" << a9.a0.a0 << "), "
            << a9.a1 << "))" << "\n";

  float result = 0;

  result += a0.a0.a0;
  result += a0.a1;
  result += a1.a0.a0;
  result += a1.a1;
  result += a2.a0.a0;
  result += a2.a1;
  result += a3.a0.a0;
  result += a3.a1;
  result += a4.a0.a0;
  result += a4.a1;
  result += a5.a0.a0;
  result += a5.a1;
  result += a6.a0.a0;
  result += a6.a1;
  result += a7.a0.a0;
  result += a7.a1;
  result += a8.a0.a0;
  result += a8.a1;
  result += a9.a0.a0;
  result += a9.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust all registers on all platforms.
DART_EXPORT double PassStruct8BytesNestedMixedx10(Struct8BytesNestedMixed a0,
                                                  Struct8BytesNestedMixed a1,
                                                  Struct8BytesNestedMixed a2,
                                                  Struct8BytesNestedMixed a3,
                                                  Struct8BytesNestedMixed a4,
                                                  Struct8BytesNestedMixed a5,
                                                  Struct8BytesNestedMixed a6,
                                                  Struct8BytesNestedMixed a7,
                                                  Struct8BytesNestedMixed a8,
                                                  Struct8BytesNestedMixed a9) {
  std::cout << "PassStruct8BytesNestedMixedx10" << "(((" << a0.a0.a0 << ", "
            << a0.a0.a1 << "), (" << a0.a1.a0 << ")), ((" << a1.a0.a0 << ", "
            << a1.a0.a1 << "), (" << a1.a1.a0 << ")), ((" << a2.a0.a0 << ", "
            << a2.a0.a1 << "), (" << a2.a1.a0 << ")), ((" << a3.a0.a0 << ", "
            << a3.a0.a1 << "), (" << a3.a1.a0 << ")), ((" << a4.a0.a0 << ", "
            << a4.a0.a1 << "), (" << a4.a1.a0 << ")), ((" << a5.a0.a0 << ", "
            << a5.a0.a1 << "), (" << a5.a1.a0 << ")), ((" << a6.a0.a0 << ", "
            << a6.a0.a1 << "), (" << a6.a1.a0 << ")), ((" << a7.a0.a0 << ", "
            << a7.a0.a1 << "), (" << a7.a1.a0 << ")), ((" << a8.a0.a0 << ", "
            << a8.a0.a1 << "), (" << a8.a1.a0 << ")), ((" << a9.a0.a0 << ", "
            << a9.a0.a1 << "), (" << a9.a1.a0 << ")))" << "\n";

  double result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a1.a0;
  result += a1.a0.a0;
  result += a1.a0.a1;
  result += a1.a1.a0;
  result += a2.a0.a0;
  result += a2.a0.a1;
  result += a2.a1.a0;
  result += a3.a0.a0;
  result += a3.a0.a1;
  result += a3.a1.a0;
  result += a4.a0.a0;
  result += a4.a0.a1;
  result += a4.a1.a0;
  result += a5.a0.a0;
  result += a5.a0.a1;
  result += a5.a1.a0;
  result += a6.a0.a0;
  result += a6.a0.a1;
  result += a6.a1.a0;
  result += a7.a0.a0;
  result += a7.a0.a1;
  result += a7.a1.a0;
  result += a8.a0.a0;
  result += a8.a0.a1;
  result += a8.a1.a0;
  result += a9.a0.a0;
  result += a9.a0.a1;
  result += a9.a1.a0;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT int64_t PassStruct16BytesNestedIntx2(Struct16BytesNestedInt a0,
                                                 Struct16BytesNestedInt a1) {
  std::cout << "PassStruct16BytesNestedIntx2" << "((((" << a0.a0.a0.a0 << ", "
            << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0 << ", " << a0.a0.a1.a1
            << ")), ((" << a0.a1.a0.a0 << ", " << a0.a1.a0.a1 << "), ("
            << a0.a1.a1.a0 << ", " << a0.a1.a1.a1 << "))), (((" << a1.a0.a0.a0
            << ", " << a1.a0.a0.a1 << "), (" << a1.a0.a1.a0 << ", "
            << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0 << ", " << a1.a1.a0.a1
            << "), (" << a1.a1.a1.a0 << ", " << a1.a1.a1.a1 << "))))" << "\n";

  int64_t result = 0;

  result += a0.a0.a0.a0;
  result += a0.a0.a0.a1;
  result += a0.a0.a1.a0;
  result += a0.a0.a1.a1;
  result += a0.a1.a0.a0;
  result += a0.a1.a0.a1;
  result += a0.a1.a1.a0;
  result += a0.a1.a1.a1;
  result += a1.a0.a0.a0;
  result += a1.a0.a0.a1;
  result += a1.a0.a1.a0;
  result += a1.a0.a1.a1;
  result += a1.a1.a0.a0;
  result += a1.a1.a0.a1;
  result += a1.a1.a1.a0;
  result += a1.a1.a1.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT int64_t PassStruct32BytesNestedIntx2(Struct32BytesNestedInt a0,
                                                 Struct32BytesNestedInt a1) {
  std::cout << "PassStruct32BytesNestedIntx2" << "(((((" << a0.a0.a0.a0.a0
            << ", " << a0.a0.a0.a0.a1 << "), (" << a0.a0.a0.a1.a0 << ", "
            << a0.a0.a0.a1.a1 << ")), ((" << a0.a0.a1.a0.a0 << ", "
            << a0.a0.a1.a0.a1 << "), (" << a0.a0.a1.a1.a0 << ", "
            << a0.a0.a1.a1.a1 << "))), (((" << a0.a1.a0.a0.a0 << ", "
            << a0.a1.a0.a0.a1 << "), (" << a0.a1.a0.a1.a0 << ", "
            << a0.a1.a0.a1.a1 << ")), ((" << a0.a1.a1.a0.a0 << ", "
            << a0.a1.a1.a0.a1 << "), (" << a0.a1.a1.a1.a0 << ", "
            << a0.a1.a1.a1.a1 << ")))), ((((" << a1.a0.a0.a0.a0 << ", "
            << a1.a0.a0.a0.a1 << "), (" << a1.a0.a0.a1.a0 << ", "
            << a1.a0.a0.a1.a1 << ")), ((" << a1.a0.a1.a0.a0 << ", "
            << a1.a0.a1.a0.a1 << "), (" << a1.a0.a1.a1.a0 << ", "
            << a1.a0.a1.a1.a1 << "))), (((" << a1.a1.a0.a0.a0 << ", "
            << a1.a1.a0.a0.a1 << "), (" << a1.a1.a0.a1.a0 << ", "
            << a1.a1.a0.a1.a1 << ")), ((" << a1.a1.a1.a0.a0 << ", "
            << a1.a1.a1.a0.a1 << "), (" << a1.a1.a1.a1.a0 << ", "
            << a1.a1.a1.a1.a1 << ")))))" << "\n";

  int64_t result = 0;

  result += a0.a0.a0.a0.a0;
  result += a0.a0.a0.a0.a1;
  result += a0.a0.a0.a1.a0;
  result += a0.a0.a0.a1.a1;
  result += a0.a0.a1.a0.a0;
  result += a0.a0.a1.a0.a1;
  result += a0.a0.a1.a1.a0;
  result += a0.a0.a1.a1.a1;
  result += a0.a1.a0.a0.a0;
  result += a0.a1.a0.a0.a1;
  result += a0.a1.a0.a1.a0;
  result += a0.a1.a0.a1.a1;
  result += a0.a1.a1.a0.a0;
  result += a0.a1.a1.a0.a1;
  result += a0.a1.a1.a1.a0;
  result += a0.a1.a1.a1.a1;
  result += a1.a0.a0.a0.a0;
  result += a1.a0.a0.a0.a1;
  result += a1.a0.a0.a1.a0;
  result += a1.a0.a0.a1.a1;
  result += a1.a0.a1.a0.a0;
  result += a1.a0.a1.a0.a1;
  result += a1.a0.a1.a1.a0;
  result += a1.a0.a1.a1.a1;
  result += a1.a1.a0.a0.a0;
  result += a1.a1.a0.a0.a1;
  result += a1.a1.a0.a1.a0;
  result += a1.a1.a0.a1.a1;
  result += a1.a1.a1.a0.a0;
  result += a1.a1.a1.a0.a1;
  result += a1.a1.a1.a1.a0;
  result += a1.a1.a1.a1.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt16(
    StructNestedIntStructAlignmentInt16 a0) {
  std::cout << "PassStructNestedIntStructAlignmentInt16" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << "\n";

  int64_t result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a0.a2;
  result += a0.a1.a0;
  result += a0.a1.a1;
  result += a0.a1.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt32(
    StructNestedIntStructAlignmentInt32 a0) {
  std::cout << "PassStructNestedIntStructAlignmentInt32" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << "\n";

  int64_t result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a0.a2;
  result += a0.a1.a0;
  result += a0.a1.a1;
  result += a0.a1.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt64(
    StructNestedIntStructAlignmentInt64 a0) {
  std::cout << "PassStructNestedIntStructAlignmentInt64" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << "\n";

  int64_t result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a0.a2;
  result += a0.a1.a0;
  result += a0.a1.a1;
  result += a0.a1.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT double PassStructNestedIrregularEvenBiggerx4(
    StructNestedIrregularEvenBigger a0,
    StructNestedIrregularEvenBigger a1,
    StructNestedIrregularEvenBigger a2,
    StructNestedIrregularEvenBigger a3) {
  std::cout
      << "PassStructNestedIrregularEvenBiggerx4" << "((" << a0.a0 << ", (("
      << a0.a1.a0.a0 << ", ((" << a0.a1.a0.a1.a0.a0 << ", " << a0.a1.a0.a1.a0.a1
      << "), (" << a0.a1.a0.a1.a1.a0 << ")), " << a0.a1.a0.a2 << ", (("
      << a0.a1.a0.a3.a0.a0 << "), " << a0.a1.a0.a3.a1 << "), " << a0.a1.a0.a4
      << ", ((" << a0.a1.a0.a5.a0.a0 << "), (" << a0.a1.a0.a5.a1.a0 << ")), "
      << a0.a1.a0.a6 << "), ((" << a0.a1.a1.a0.a0 << ", " << a0.a1.a1.a0.a1
      << "), (" << a0.a1.a1.a1.a0 << ")), " << a0.a1.a2 << ", " << a0.a1.a3
      << "), ((" << a0.a2.a0.a0 << ", ((" << a0.a2.a0.a1.a0.a0 << ", "
      << a0.a2.a0.a1.a0.a1 << "), (" << a0.a2.a0.a1.a1.a0 << ")), "
      << a0.a2.a0.a2 << ", ((" << a0.a2.a0.a3.a0.a0 << "), " << a0.a2.a0.a3.a1
      << "), " << a0.a2.a0.a4 << ", ((" << a0.a2.a0.a5.a0.a0 << "), ("
      << a0.a2.a0.a5.a1.a0 << ")), " << a0.a2.a0.a6 << "), ((" << a0.a2.a1.a0.a0
      << ", " << a0.a2.a1.a0.a1 << "), (" << a0.a2.a1.a1.a0 << ")), "
      << a0.a2.a2 << ", " << a0.a2.a3 << "), " << a0.a3 << "), (" << a1.a0
      << ", ((" << a1.a1.a0.a0 << ", ((" << a1.a1.a0.a1.a0.a0 << ", "
      << a1.a1.a0.a1.a0.a1 << "), (" << a1.a1.a0.a1.a1.a0 << ")), "
      << a1.a1.a0.a2 << ", ((" << a1.a1.a0.a3.a0.a0 << "), " << a1.a1.a0.a3.a1
      << "), " << a1.a1.a0.a4 << ", ((" << a1.a1.a0.a5.a0.a0 << "), ("
      << a1.a1.a0.a5.a1.a0 << ")), " << a1.a1.a0.a6 << "), ((" << a1.a1.a1.a0.a0
      << ", " << a1.a1.a1.a0.a1 << "), (" << a1.a1.a1.a1.a0 << ")), "
      << a1.a1.a2 << ", " << a1.a1.a3 << "), ((" << a1.a2.a0.a0 << ", (("
      << a1.a2.a0.a1.a0.a0 << ", " << a1.a2.a0.a1.a0.a1 << "), ("
      << a1.a2.a0.a1.a1.a0 << ")), " << a1.a2.a0.a2 << ", (("
      << a1.a2.a0.a3.a0.a0 << "), " << a1.a2.a0.a3.a1 << "), " << a1.a2.a0.a4
      << ", ((" << a1.a2.a0.a5.a0.a0 << "), (" << a1.a2.a0.a5.a1.a0 << ")), "
      << a1.a2.a0.a6 << "), ((" << a1.a2.a1.a0.a0 << ", " << a1.a2.a1.a0.a1
      << "), (" << a1.a2.a1.a1.a0 << ")), " << a1.a2.a2 << ", " << a1.a2.a3
      << "), " << a1.a3 << "), (" << a2.a0 << ", ((" << a2.a1.a0.a0 << ", (("
      << a2.a1.a0.a1.a0.a0 << ", " << a2.a1.a0.a1.a0.a1 << "), ("
      << a2.a1.a0.a1.a1.a0 << ")), " << a2.a1.a0.a2 << ", (("
      << a2.a1.a0.a3.a0.a0 << "), " << a2.a1.a0.a3.a1 << "), " << a2.a1.a0.a4
      << ", ((" << a2.a1.a0.a5.a0.a0 << "), (" << a2.a1.a0.a5.a1.a0 << ")), "
      << a2.a1.a0.a6 << "), ((" << a2.a1.a1.a0.a0 << ", " << a2.a1.a1.a0.a1
      << "), (" << a2.a1.a1.a1.a0 << ")), " << a2.a1.a2 << ", " << a2.a1.a3
      << "), ((" << a2.a2.a0.a0 << ", ((" << a2.a2.a0.a1.a0.a0 << ", "
      << a2.a2.a0.a1.a0.a1 << "), (" << a2.a2.a0.a1.a1.a0 << ")), "
      << a2.a2.a0.a2 << ", ((" << a2.a2.a0.a3.a0.a0 << "), " << a2.a2.a0.a3.a1
      << "), " << a2.a2.a0.a4 << ", ((" << a2.a2.a0.a5.a0.a0 << "), ("
      << a2.a2.a0.a5.a1.a0 << ")), " << a2.a2.a0.a6 << "), ((" << a2.a2.a1.a0.a0
      << ", " << a2.a2.a1.a0.a1 << "), (" << a2.a2.a1.a1.a0 << ")), "
      << a2.a2.a2 << ", " << a2.a2.a3 << "), " << a2.a3 << "), (" << a3.a0
      << ", ((" << a3.a1.a0.a0 << ", ((" << a3.a1.a0.a1.a0.a0 << ", "
      << a3.a1.a0.a1.a0.a1 << "), (" << a3.a1.a0.a1.a1.a0 << ")), "
      << a3.a1.a0.a2 << ", ((" << a3.a1.a0.a3.a0.a0 << "), " << a3.a1.a0.a3.a1
      << "), " << a3.a1.a0.a4 << ", ((" << a3.a1.a0.a5.a0.a0 << "), ("
      << a3.a1.a0.a5.a1.a0 << ")), " << a3.a1.a0.a6 << "), ((" << a3.a1.a1.a0.a0
      << ", " << a3.a1.a1.a0.a1 << "), (" << a3.a1.a1.a1.a0 << ")), "
      << a3.a1.a2 << ", " << a3.a1.a3 << "), ((" << a3.a2.a0.a0 << ", (("
      << a3.a2.a0.a1.a0.a0 << ", " << a3.a2.a0.a1.a0.a1 << "), ("
      << a3.a2.a0.a1.a1.a0 << ")), " << a3.a2.a0.a2 << ", (("
      << a3.a2.a0.a3.a0.a0 << "), " << a3.a2.a0.a3.a1 << "), " << a3.a2.a0.a4
      << ", ((" << a3.a2.a0.a5.a0.a0 << "), (" << a3.a2.a0.a5.a1.a0 << ")), "
      << a3.a2.a0.a6 << "), ((" << a3.a2.a1.a0.a0 << ", " << a3.a2.a1.a0.a1
      << "), (" << a3.a2.a1.a1.a0 << ")), " << a3.a2.a2 << ", " << a3.a2.a3
      << "), " << a3.a3 << "))" << "\n";

  double result = 0;

  result += a0.a0;
  result += a0.a1.a0.a0;
  result += a0.a1.a0.a1.a0.a0;
  result += a0.a1.a0.a1.a0.a1;
  result += a0.a1.a0.a1.a1.a0;
  result += a0.a1.a0.a2;
  result += a0.a1.a0.a3.a0.a0;
  result += a0.a1.a0.a3.a1;
  result += a0.a1.a0.a4;
  result += a0.a1.a0.a5.a0.a0;
  result += a0.a1.a0.a5.a1.a0;
  result += a0.a1.a0.a6;
  result += a0.a1.a1.a0.a0;
  result += a0.a1.a1.a0.a1;
  result += a0.a1.a1.a1.a0;
  result += a0.a1.a2;
  result += a0.a1.a3;
  result += a0.a2.a0.a0;
  result += a0.a2.a0.a1.a0.a0;
  result += a0.a2.a0.a1.a0.a1;
  result += a0.a2.a0.a1.a1.a0;
  result += a0.a2.a0.a2;
  result += a0.a2.a0.a3.a0.a0;
  result += a0.a2.a0.a3.a1;
  result += a0.a2.a0.a4;
  result += a0.a2.a0.a5.a0.a0;
  result += a0.a2.a0.a5.a1.a0;
  result += a0.a2.a0.a6;
  result += a0.a2.a1.a0.a0;
  result += a0.a2.a1.a0.a1;
  result += a0.a2.a1.a1.a0;
  result += a0.a2.a2;
  result += a0.a2.a3;
  result += a0.a3;
  result += a1.a0;
  result += a1.a1.a0.a0;
  result += a1.a1.a0.a1.a0.a0;
  result += a1.a1.a0.a1.a0.a1;
  result += a1.a1.a0.a1.a1.a0;
  result += a1.a1.a0.a2;
  result += a1.a1.a0.a3.a0.a0;
  result += a1.a1.a0.a3.a1;
  result += a1.a1.a0.a4;
  result += a1.a1.a0.a5.a0.a0;
  result += a1.a1.a0.a5.a1.a0;
  result += a1.a1.a0.a6;
  result += a1.a1.a1.a0.a0;
  result += a1.a1.a1.a0.a1;
  result += a1.a1.a1.a1.a0;
  result += a1.a1.a2;
  result += a1.a1.a3;
  result += a1.a2.a0.a0;
  result += a1.a2.a0.a1.a0.a0;
  result += a1.a2.a0.a1.a0.a1;
  result += a1.a2.a0.a1.a1.a0;
  result += a1.a2.a0.a2;
  result += a1.a2.a0.a3.a0.a0;
  result += a1.a2.a0.a3.a1;
  result += a1.a2.a0.a4;
  result += a1.a2.a0.a5.a0.a0;
  result += a1.a2.a0.a5.a1.a0;
  result += a1.a2.a0.a6;
  result += a1.a2.a1.a0.a0;
  result += a1.a2.a1.a0.a1;
  result += a1.a2.a1.a1.a0;
  result += a1.a2.a2;
  result += a1.a2.a3;
  result += a1.a3;
  result += a2.a0;
  result += a2.a1.a0.a0;
  result += a2.a1.a0.a1.a0.a0;
  result += a2.a1.a0.a1.a0.a1;
  result += a2.a1.a0.a1.a1.a0;
  result += a2.a1.a0.a2;
  result += a2.a1.a0.a3.a0.a0;
  result += a2.a1.a0.a3.a1;
  result += a2.a1.a0.a4;
  result += a2.a1.a0.a5.a0.a0;
  result += a2.a1.a0.a5.a1.a0;
  result += a2.a1.a0.a6;
  result += a2.a1.a1.a0.a0;
  result += a2.a1.a1.a0.a1;
  result += a2.a1.a1.a1.a0;
  result += a2.a1.a2;
  result += a2.a1.a3;
  result += a2.a2.a0.a0;
  result += a2.a2.a0.a1.a0.a0;
  result += a2.a2.a0.a1.a0.a1;
  result += a2.a2.a0.a1.a1.a0;
  result += a2.a2.a0.a2;
  result += a2.a2.a0.a3.a0.a0;
  result += a2.a2.a0.a3.a1;
  result += a2.a2.a0.a4;
  result += a2.a2.a0.a5.a0.a0;
  result += a2.a2.a0.a5.a1.a0;
  result += a2.a2.a0.a6;
  result += a2.a2.a1.a0.a0;
  result += a2.a2.a1.a0.a1;
  result += a2.a2.a1.a1.a0;
  result += a2.a2.a2;
  result += a2.a2.a3;
  result += a2.a3;
  result += a3.a0;
  result += a3.a1.a0.a0;
  result += a3.a1.a0.a1.a0.a0;
  result += a3.a1.a0.a1.a0.a1;
  result += a3.a1.a0.a1.a1.a0;
  result += a3.a1.a0.a2;
  result += a3.a1.a0.a3.a0.a0;
  result += a3.a1.a0.a3.a1;
  result += a3.a1.a0.a4;
  result += a3.a1.a0.a5.a0.a0;
  result += a3.a1.a0.a5.a1.a0;
  result += a3.a1.a0.a6;
  result += a3.a1.a1.a0.a0;
  result += a3.a1.a1.a0.a1;
  result += a3.a1.a1.a1.a0;
  result += a3.a1.a2;
  result += a3.a1.a3;
  result += a3.a2.a0.a0;
  result += a3.a2.a0.a1.a0.a0;
  result += a3.a2.a0.a1.a0.a1;
  result += a3.a2.a0.a1.a1.a0;
  result += a3.a2.a0.a2;
  result += a3.a2.a0.a3.a0.a0;
  result += a3.a2.a0.a3.a1;
  result += a3.a2.a0.a4;
  result += a3.a2.a0.a5.a0.a0;
  result += a3.a2.a0.a5.a1.a0;
  result += a3.a2.a0.a6;
  result += a3.a2.a1.a0.a0;
  result += a3.a2.a1.a0.a1;
  result += a3.a2.a1.a1.a0;
  result += a3.a2.a2;
  result += a3.a2.a3;
  result += a3.a3;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple struct with inline array.
DART_EXPORT int32_t
PassStruct8BytesInlineArrayIntx4(Struct8BytesInlineArrayInt a0,
                                 Struct8BytesInlineArrayInt a1,
                                 Struct8BytesInlineArrayInt a2,
                                 Struct8BytesInlineArrayInt a3) {
  std::cout << "PassStruct8BytesInlineArrayIntx4" << "((["
            << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
            << ", " << static_cast<int>(a0.a0[2]) << ", "
            << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
            << ", " << static_cast<int>(a0.a0[5]) << ", "
            << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
            << "]), ([" << static_cast<int>(a1.a0[0]) << ", "
            << static_cast<int>(a1.a0[1]) << ", " << static_cast<int>(a1.a0[2])
            << ", " << static_cast<int>(a1.a0[3]) << ", "
            << static_cast<int>(a1.a0[4]) << ", " << static_cast<int>(a1.a0[5])
            << ", " << static_cast<int>(a1.a0[6]) << ", "
            << static_cast<int>(a1.a0[7]) << "]), (["
            << static_cast<int>(a2.a0[0]) << ", " << static_cast<int>(a2.a0[1])
            << ", " << static_cast<int>(a2.a0[2]) << ", "
            << static_cast<int>(a2.a0[3]) << ", " << static_cast<int>(a2.a0[4])
            << ", " << static_cast<int>(a2.a0[5]) << ", "
            << static_cast<int>(a2.a0[6]) << ", " << static_cast<int>(a2.a0[7])
            << "]), ([" << static_cast<int>(a3.a0[0]) << ", "
            << static_cast<int>(a3.a0[1]) << ", " << static_cast<int>(a3.a0[2])
            << ", " << static_cast<int>(a3.a0[3]) << ", "
            << static_cast<int>(a3.a0[4]) << ", " << static_cast<int>(a3.a0[5])
            << ", " << static_cast<int>(a3.a0[6]) << ", "
            << static_cast<int>(a3.a0[7]) << "]))" << "\n";

  int32_t result = 0;

  result += a0.a0[0];
  result += a0.a0[1];
  result += a0.a0[2];
  result += a0.a0[3];
  result += a0.a0[4];
  result += a0.a0[5];
  result += a0.a0[6];
  result += a0.a0[7];
  result += a1.a0[0];
  result += a1.a0[1];
  result += a1.a0[2];
  result += a1.a0[3];
  result += a1.a0[4];
  result += a1.a0[5];
  result += a1.a0[6];
  result += a1.a0[7];
  result += a2.a0[0];
  result += a2.a0[1];
  result += a2.a0[2];
  result += a2.a0[3];
  result += a2.a0[4];
  result += a2.a0[5];
  result += a2.a0[6];
  result += a2.a0[7];
  result += a3.a0[0];
  result += a3.a0[1];
  result += a3.a0[2];
  result += a3.a0[3];
  result += a3.a0[4];
  result += a3.a0[5];
  result += a3.a0[6];
  result += a3.a0[7];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Irregular struct with inline array.
DART_EXPORT int32_t
PassStructInlineArrayIrregularx4(StructInlineArrayIrregular a0,
                                 StructInlineArrayIrregular a1,
                                 StructInlineArrayIrregular a2,
                                 StructInlineArrayIrregular a3) {
  std::cout << "PassStructInlineArrayIrregularx4" << "(([(" << a0.a0[0].a0
            << ", " << static_cast<int>(a0.a0[0].a1) << "), (" << a0.a0[1].a0
            << ", " << static_cast<int>(a0.a0[1].a1) << ")], "
            << static_cast<int>(a0.a1) << "), ([(" << a1.a0[0].a0 << ", "
            << static_cast<int>(a1.a0[0].a1) << "), (" << a1.a0[1].a0 << ", "
            << static_cast<int>(a1.a0[1].a1) << ")], "
            << static_cast<int>(a1.a1) << "), ([(" << a2.a0[0].a0 << ", "
            << static_cast<int>(a2.a0[0].a1) << "), (" << a2.a0[1].a0 << ", "
            << static_cast<int>(a2.a0[1].a1) << ")], "
            << static_cast<int>(a2.a1) << "), ([(" << a3.a0[0].a0 << ", "
            << static_cast<int>(a3.a0[0].a1) << "), (" << a3.a0[1].a0 << ", "
            << static_cast<int>(a3.a0[1].a1) << ")], "
            << static_cast<int>(a3.a1) << "))" << "\n";

  int32_t result = 0;

  result += a0.a0[0].a0;
  result += a0.a0[0].a1;
  result += a0.a0[1].a0;
  result += a0.a0[1].a1;
  result += a0.a1;
  result += a1.a0[0].a0;
  result += a1.a0[0].a1;
  result += a1.a0[1].a0;
  result += a1.a0[1].a1;
  result += a1.a1;
  result += a2.a0[0].a0;
  result += a2.a0[0].a1;
  result += a2.a0[1].a0;
  result += a2.a0[1].a1;
  result += a2.a1;
  result += a3.a0[0].a0;
  result += a3.a0[0].a1;
  result += a3.a0[1].a0;
  result += a3.a0[1].a1;
  result += a3.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Regular larger struct with inline array.
DART_EXPORT int32_t
PassStructInlineArray100Bytes(StructInlineArray100Bytes a0) {
  std::cout
      << "PassStructInlineArray100Bytes" << "(([" << static_cast<int>(a0.a0[0])
      << ", " << static_cast<int>(a0.a0[1]) << ", "
      << static_cast<int>(a0.a0[2]) << ", " << static_cast<int>(a0.a0[3])
      << ", " << static_cast<int>(a0.a0[4]) << ", "
      << static_cast<int>(a0.a0[5]) << ", " << static_cast<int>(a0.a0[6])
      << ", " << static_cast<int>(a0.a0[7]) << ", "
      << static_cast<int>(a0.a0[8]) << ", " << static_cast<int>(a0.a0[9])
      << ", " << static_cast<int>(a0.a0[10]) << ", "
      << static_cast<int>(a0.a0[11]) << ", " << static_cast<int>(a0.a0[12])
      << ", " << static_cast<int>(a0.a0[13]) << ", "
      << static_cast<int>(a0.a0[14]) << ", " << static_cast<int>(a0.a0[15])
      << ", " << static_cast<int>(a0.a0[16]) << ", "
      << static_cast<int>(a0.a0[17]) << ", " << static_cast<int>(a0.a0[18])
      << ", " << static_cast<int>(a0.a0[19]) << ", "
      << static_cast<int>(a0.a0[20]) << ", " << static_cast<int>(a0.a0[21])
      << ", " << static_cast<int>(a0.a0[22]) << ", "
      << static_cast<int>(a0.a0[23]) << ", " << static_cast<int>(a0.a0[24])
      << ", " << static_cast<int>(a0.a0[25]) << ", "
      << static_cast<int>(a0.a0[26]) << ", " << static_cast<int>(a0.a0[27])
      << ", " << static_cast<int>(a0.a0[28]) << ", "
      << static_cast<int>(a0.a0[29]) << ", " << static_cast<int>(a0.a0[30])
      << ", " << static_cast<int>(a0.a0[31]) << ", "
      << static_cast<int>(a0.a0[32]) << ", " << static_cast<int>(a0.a0[33])
      << ", " << static_cast<int>(a0.a0[34]) << ", "
      << static_cast<int>(a0.a0[35]) << ", " << static_cast<int>(a0.a0[36])
      << ", " << static_cast<int>(a0.a0[37]) << ", "
      << static_cast<int>(a0.a0[38]) << ", " << static_cast<int>(a0.a0[39])
      << ", " << static_cast<int>(a0.a0[40]) << ", "
      << static_cast<int>(a0.a0[41]) << ", " << static_cast<int>(a0.a0[42])
      << ", " << static_cast<int>(a0.a0[43]) << ", "
      << static_cast<int>(a0.a0[44]) << ", " << static_cast<int>(a0.a0[45])
      << ", " << static_cast<int>(a0.a0[46]) << ", "
      << static_cast<int>(a0.a0[47]) << ", " << static_cast<int>(a0.a0[48])
      << ", " << static_cast<int>(a0.a0[49]) << ", "
      << static_cast<int>(a0.a0[50]) << ", " << static_cast<int>(a0.a0[51])
      << ", " << static_cast<int>(a0.a0[52]) << ", "
      << static_cast<int>(a0.a0[53]) << ", " << static_cast<int>(a0.a0[54])
      << ", " << static_cast<int>(a0.a0[55]) << ", "
      << static_cast<int>(a0.a0[56]) << ", " << static_cast<int>(a0.a0[57])
      << ", " << static_cast<int>(a0.a0[58]) << ", "
      << static_cast<int>(a0.a0[59]) << ", " << static_cast<int>(a0.a0[60])
      << ", " << static_cast<int>(a0.a0[61]) << ", "
      << static_cast<int>(a0.a0[62]) << ", " << static_cast<int>(a0.a0[63])
      << ", " << static_cast<int>(a0.a0[64]) << ", "
      << static_cast<int>(a0.a0[65]) << ", " << static_cast<int>(a0.a0[66])
      << ", " << static_cast<int>(a0.a0[67]) << ", "
      << static_cast<int>(a0.a0[68]) << ", " << static_cast<int>(a0.a0[69])
      << ", " << static_cast<int>(a0.a0[70]) << ", "
      << static_cast<int>(a0.a0[71]) << ", " << static_cast<int>(a0.a0[72])
      << ", " << static_cast<int>(a0.a0[73]) << ", "
      << static_cast<int>(a0.a0[74]) << ", " << static_cast<int>(a0.a0[75])
      << ", " << static_cast<int>(a0.a0[76]) << ", "
      << static_cast<int>(a0.a0[77]) << ", " << static_cast<int>(a0.a0[78])
      << ", " << static_cast<int>(a0.a0[79]) << ", "
      << static_cast<int>(a0.a0[80]) << ", " << static_cast<int>(a0.a0[81])
      << ", " << static_cast<int>(a0.a0[82]) << ", "
      << static_cast<int>(a0.a0[83]) << ", " << static_cast<int>(a0.a0[84])
      << ", " << static_cast<int>(a0.a0[85]) << ", "
      << static_cast<int>(a0.a0[86]) << ", " << static_cast<int>(a0.a0[87])
      << ", " << static_cast<int>(a0.a0[88]) << ", "
      << static_cast<int>(a0.a0[89]) << ", " << static_cast<int>(a0.a0[90])
      << ", " << static_cast<int>(a0.a0[91]) << ", "
      << static_cast<int>(a0.a0[92]) << ", " << static_cast<int>(a0.a0[93])
      << ", " << static_cast<int>(a0.a0[94]) << ", "
      << static_cast<int>(a0.a0[95]) << ", " << static_cast<int>(a0.a0[96])
      << ", " << static_cast<int>(a0.a0[97]) << ", "
      << static_cast<int>(a0.a0[98]) << ", " << static_cast<int>(a0.a0[99])
      << "]))" << "\n";

  int32_t result = 0;

  result += a0.a0[0];
  result += a0.a0[1];
  result += a0.a0[2];
  result += a0.a0[3];
  result += a0.a0[4];
  result += a0.a0[5];
  result += a0.a0[6];
  result += a0.a0[7];
  result += a0.a0[8];
  result += a0.a0[9];
  result += a0.a0[10];
  result += a0.a0[11];
  result += a0.a0[12];
  result += a0.a0[13];
  result += a0.a0[14];
  result += a0.a0[15];
  result += a0.a0[16];
  result += a0.a0[17];
  result += a0.a0[18];
  result += a0.a0[19];
  result += a0.a0[20];
  result += a0.a0[21];
  result += a0.a0[22];
  result += a0.a0[23];
  result += a0.a0[24];
  result += a0.a0[25];
  result += a0.a0[26];
  result += a0.a0[27];
  result += a0.a0[28];
  result += a0.a0[29];
  result += a0.a0[30];
  result += a0.a0[31];
  result += a0.a0[32];
  result += a0.a0[33];
  result += a0.a0[34];
  result += a0.a0[35];
  result += a0.a0[36];
  result += a0.a0[37];
  result += a0.a0[38];
  result += a0.a0[39];
  result += a0.a0[40];
  result += a0.a0[41];
  result += a0.a0[42];
  result += a0.a0[43];
  result += a0.a0[44];
  result += a0.a0[45];
  result += a0.a0[46];
  result += a0.a0[47];
  result += a0.a0[48];
  result += a0.a0[49];
  result += a0.a0[50];
  result += a0.a0[51];
  result += a0.a0[52];
  result += a0.a0[53];
  result += a0.a0[54];
  result += a0.a0[55];
  result += a0.a0[56];
  result += a0.a0[57];
  result += a0.a0[58];
  result += a0.a0[59];
  result += a0.a0[60];
  result += a0.a0[61];
  result += a0.a0[62];
  result += a0.a0[63];
  result += a0.a0[64];
  result += a0.a0[65];
  result += a0.a0[66];
  result += a0.a0[67];
  result += a0.a0[68];
  result += a0.a0[69];
  result += a0.a0[70];
  result += a0.a0[71];
  result += a0.a0[72];
  result += a0.a0[73];
  result += a0.a0[74];
  result += a0.a0[75];
  result += a0.a0[76];
  result += a0.a0[77];
  result += a0.a0[78];
  result += a0.a0[79];
  result += a0.a0[80];
  result += a0.a0[81];
  result += a0.a0[82];
  result += a0.a0[83];
  result += a0.a0[84];
  result += a0.a0[85];
  result += a0.a0[86];
  result += a0.a0[87];
  result += a0.a0[88];
  result += a0.a0[89];
  result += a0.a0[90];
  result += a0.a0[91];
  result += a0.a0[92];
  result += a0.a0[93];
  result += a0.a0[94];
  result += a0.a0[95];
  result += a0.a0[96];
  result += a0.a0[97];
  result += a0.a0[98];
  result += a0.a0[99];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT float PassStructStruct16BytesHomogeneousFloat2x5(
    StructStruct16BytesHomogeneousFloat2 a0,
    StructStruct16BytesHomogeneousFloat2 a1,
    StructStruct16BytesHomogeneousFloat2 a2,
    StructStruct16BytesHomogeneousFloat2 a3,
    StructStruct16BytesHomogeneousFloat2 a4) {
  std::cout << "PassStructStruct16BytesHomogeneousFloat2x5" << "(((" << a0.a0.a0
            << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0 << ")], "
            << a0.a2 << "), ((" << a1.a0.a0 << "), [(" << a1.a1[0].a0 << "), ("
            << a1.a1[1].a0 << ")], " << a1.a2 << "), ((" << a2.a0.a0 << "), [("
            << a2.a1[0].a0 << "), (" << a2.a1[1].a0 << ")], " << a2.a2
            << "), ((" << a3.a0.a0 << "), [(" << a3.a1[0].a0 << "), ("
            << a3.a1[1].a0 << ")], " << a3.a2 << "), ((" << a4.a0.a0 << "), [("
            << a4.a1[0].a0 << "), (" << a4.a1[1].a0 << ")], " << a4.a2 << "))"
            << "\n";

  float result = 0;

  result += a0.a0.a0;
  result += a0.a1[0].a0;
  result += a0.a1[1].a0;
  result += a0.a2;
  result += a1.a0.a0;
  result += a1.a1[0].a0;
  result += a1.a1[1].a0;
  result += a1.a2;
  result += a2.a0.a0;
  result += a2.a1[0].a0;
  result += a2.a1[1].a0;
  result += a2.a2;
  result += a3.a0.a0;
  result += a3.a1[0].a0;
  result += a3.a1[1].a0;
  result += a3.a2;
  result += a4.a0.a0;
  result += a4.a1[0].a0;
  result += a4.a1[1].a0;
  result += a4.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT double PassStructStruct32BytesHomogeneousDouble2x5(
    StructStruct32BytesHomogeneousDouble2 a0,
    StructStruct32BytesHomogeneousDouble2 a1,
    StructStruct32BytesHomogeneousDouble2 a2,
    StructStruct32BytesHomogeneousDouble2 a3,
    StructStruct32BytesHomogeneousDouble2 a4) {
  std::cout << "PassStructStruct32BytesHomogeneousDouble2x5" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0
            << ")], " << a0.a2 << "), ((" << a1.a0.a0 << "), [(" << a1.a1[0].a0
            << "), (" << a1.a1[1].a0 << ")], " << a1.a2 << "), ((" << a2.a0.a0
            << "), [(" << a2.a1[0].a0 << "), (" << a2.a1[1].a0 << ")], "
            << a2.a2 << "), ((" << a3.a0.a0 << "), [(" << a3.a1[0].a0 << "), ("
            << a3.a1[1].a0 << ")], " << a3.a2 << "), ((" << a4.a0.a0 << "), [("
            << a4.a1[0].a0 << "), (" << a4.a1[1].a0 << ")], " << a4.a2 << "))"
            << "\n";

  double result = 0;

  result += a0.a0.a0;
  result += a0.a1[0].a0;
  result += a0.a1[1].a0;
  result += a0.a2;
  result += a1.a0.a0;
  result += a1.a1[0].a0;
  result += a1.a1[1].a0;
  result += a1.a2;
  result += a2.a0.a0;
  result += a2.a1[0].a0;
  result += a2.a1[1].a0;
  result += a2.a2;
  result += a3.a0.a0;
  result += a3.a1[0].a0;
  result += a3.a1[1].a0;
  result += a3.a2;
  result += a4.a0.a0;
  result += a4.a1[0].a0;
  result += a4.a1[1].a0;
  result += a4.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions 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 PassStructStruct16BytesMixed3x10(
    StructStruct16BytesMixed3 a0,
    StructStruct16BytesMixed3 a1,
    StructStruct16BytesMixed3 a2,
    StructStruct16BytesMixed3 a3,
    StructStruct16BytesMixed3 a4,
    StructStruct16BytesMixed3 a5,
    StructStruct16BytesMixed3 a6,
    StructStruct16BytesMixed3 a7,
    StructStruct16BytesMixed3 a8,
    StructStruct16BytesMixed3 a9) {
  std::cout << "PassStructStruct16BytesMixed3x10" << "(((" << a0.a0.a0
            << "), [(" << a0.a1[0].a0 << ", " << a0.a1[0].a1 << ", "
            << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", " << a0.a2[1]
            << "]), ((" << a1.a0.a0 << "), [(" << a1.a1[0].a0 << ", "
            << a1.a1[0].a1 << ", " << a1.a1[0].a2 << ")], [" << a1.a2[0] << ", "
            << a1.a2[1] << "]), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0
            << ", " << a2.a1[0].a1 << ", " << a2.a1[0].a2 << ")], [" << a2.a2[0]
            << ", " << a2.a2[1] << "]), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << ", " << a3.a1[0].a1 << ", " << a3.a1[0].a2
            << ")], [" << a3.a2[0] << ", " << a3.a2[1] << "]), ((" << a4.a0.a0
            << "), [(" << a4.a1[0].a0 << ", " << a4.a1[0].a1 << ", "
            << a4.a1[0].a2 << ")], [" << a4.a2[0] << ", " << a4.a2[1]
            << "]), ((" << a5.a0.a0 << "), [(" << a5.a1[0].a0 << ", "
            << a5.a1[0].a1 << ", " << a5.a1[0].a2 << ")], [" << a5.a2[0] << ", "
            << a5.a2[1] << "]), ((" << a6.a0.a0 << "), [(" << a6.a1[0].a0
            << ", " << a6.a1[0].a1 << ", " << a6.a1[0].a2 << ")], [" << a6.a2[0]
            << ", " << a6.a2[1] << "]), ((" << a7.a0.a0 << "), [("
            << a7.a1[0].a0 << ", " << a7.a1[0].a1 << ", " << a7.a1[0].a2
            << ")], [" << a7.a2[0] << ", " << a7.a2[1] << "]), ((" << a8.a0.a0
            << "), [(" << a8.a1[0].a0 << ", " << a8.a1[0].a1 << ", "
            << a8.a1[0].a2 << ")], [" << a8.a2[0] << ", " << a8.a2[1]
            << "]), ((" << a9.a0.a0 << "), [(" << a9.a1[0].a0 << ", "
            << a9.a1[0].a1 << ", " << a9.a1[0].a2 << ")], [" << a9.a2[0] << ", "
            << a9.a2[1] << "]))" << "\n";

  float result = 0;

  result += a0.a0.a0;
  result += a0.a1[0].a0;
  result += a0.a1[0].a1;
  result += a0.a1[0].a2;
  result += a0.a2[0];
  result += a0.a2[1];
  result += a1.a0.a0;
  result += a1.a1[0].a0;
  result += a1.a1[0].a1;
  result += a1.a1[0].a2;
  result += a1.a2[0];
  result += a1.a2[1];
  result += a2.a0.a0;
  result += a2.a1[0].a0;
  result += a2.a1[0].a1;
  result += a2.a1[0].a2;
  result += a2.a2[0];
  result += a2.a2[1];
  result += a3.a0.a0;
  result += a3.a1[0].a0;
  result += a3.a1[0].a1;
  result += a3.a1[0].a2;
  result += a3.a2[0];
  result += a3.a2[1];
  result += a4.a0.a0;
  result += a4.a1[0].a0;
  result += a4.a1[0].a1;
  result += a4.a1[0].a2;
  result += a4.a2[0];
  result += a4.a2[1];
  result += a5.a0.a0;
  result += a5.a1[0].a0;
  result += a5.a1[0].a1;
  result += a5.a1[0].a2;
  result += a5.a2[0];
  result += a5.a2[1];
  result += a6.a0.a0;
  result += a6.a1[0].a0;
  result += a6.a1[0].a1;
  result += a6.a1[0].a2;
  result += a6.a2[0];
  result += a6.a2[1];
  result += a7.a0.a0;
  result += a7.a1[0].a0;
  result += a7.a1[0].a1;
  result += a7.a1[0].a2;
  result += a7.a2[0];
  result += a7.a2[1];
  result += a8.a0.a0;
  result += a8.a1[0].a0;
  result += a8.a1[0].a1;
  result += a8.a1[0].a2;
  result += a8.a2[0];
  result += a8.a2[1];
  result += a9.a0.a0;
  result += a9.a1[0].a0;
  result += a9.a1[0].a1;
  result += a9.a1[0].a2;
  result += a9.a2[0];
  result += a9.a2[1];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test multi dimensional inline array struct as argument.
DART_EXPORT uint32_t PassUint8Struct32BytesInlineArrayMultiDimensionalI(
    uint8_t a0,
    Struct32BytesInlineArrayMultiDimensionalInt a1,
    uint8_t a2,
    Struct8BytesInlineArrayMultiDimensionalInt a3,
    uint8_t a4,
    Struct8BytesInlineArrayMultiDimensionalInt a5,
    uint8_t a6) {
  std::cout << "PassUint8Struct32BytesInlineArrayMultiDimensionalI" << "("
            << static_cast<int>(a0) << ", ([[[[["
            << static_cast<int>(a1.a0[0][0][0][0][0]) << ", "
            << static_cast<int>(a1.a0[0][0][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][0][0][1][0]) << ", "
            << static_cast<int>(a1.a0[0][0][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[0][0][1][0][0]) << ", "
            << static_cast<int>(a1.a0[0][0][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][0][1][1][0]) << ", "
            << static_cast<int>(a1.a0[0][0][1][1][1]) << "]]], [[["
            << static_cast<int>(a1.a0[0][1][0][0][0]) << ", "
            << static_cast<int>(a1.a0[0][1][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][1][0][1][0]) << ", "
            << static_cast<int>(a1.a0[0][1][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[0][1][1][0][0]) << ", "
            << static_cast<int>(a1.a0[0][1][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][1][1][1][0]) << ", "
            << static_cast<int>(a1.a0[0][1][1][1][1]) << "]]]], [[[["
            << static_cast<int>(a1.a0[1][0][0][0][0]) << ", "
            << static_cast<int>(a1.a0[1][0][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][0][0][1][0]) << ", "
            << static_cast<int>(a1.a0[1][0][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[1][0][1][0][0]) << ", "
            << static_cast<int>(a1.a0[1][0][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][0][1][1][0]) << ", "
            << static_cast<int>(a1.a0[1][0][1][1][1]) << "]]], [[["
            << static_cast<int>(a1.a0[1][1][0][0][0]) << ", "
            << static_cast<int>(a1.a0[1][1][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][1][0][1][0]) << ", "
            << static_cast<int>(a1.a0[1][1][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[1][1][1][0][0]) << ", "
            << static_cast<int>(a1.a0[1][1][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][1][1][1][0]) << ", "
            << static_cast<int>(a1.a0[1][1][1][1][1]) << "]]]]]), "
            << static_cast<int>(a2) << ", ([[["
            << static_cast<int>(a3.a0[0][0][0]) << ", "
            << static_cast<int>(a3.a0[0][0][1]) << "], ["
            << static_cast<int>(a3.a0[0][1][0]) << ", "
            << static_cast<int>(a3.a0[0][1][1]) << "]], [["
            << static_cast<int>(a3.a0[1][0][0]) << ", "
            << static_cast<int>(a3.a0[1][0][1]) << "], ["
            << static_cast<int>(a3.a0[1][1][0]) << ", "
            << static_cast<int>(a3.a0[1][1][1]) << "]]]), "
            << static_cast<int>(a4) << ", ([[["
            << static_cast<int>(a5.a0[0][0][0]) << ", "
            << static_cast<int>(a5.a0[0][0][1]) << "], ["
            << static_cast<int>(a5.a0[0][1][0]) << ", "
            << static_cast<int>(a5.a0[0][1][1]) << "]], [["
            << static_cast<int>(a5.a0[1][0][0]) << ", "
            << static_cast<int>(a5.a0[1][0][1]) << "], ["
            << static_cast<int>(a5.a0[1][1][0]) << ", "
            << static_cast<int>(a5.a0[1][1][1]) << "]]]), "
            << static_cast<int>(a6) << ")" << "\n";

  uint32_t result = 0;

  result += a0;
  result += a1.a0[0][0][0][0][0];
  result += a1.a0[0][0][0][0][1];
  result += a1.a0[0][0][0][1][0];
  result += a1.a0[0][0][0][1][1];
  result += a1.a0[0][0][1][0][0];
  result += a1.a0[0][0][1][0][1];
  result += a1.a0[0][0][1][1][0];
  result += a1.a0[0][0][1][1][1];
  result += a1.a0[0][1][0][0][0];
  result += a1.a0[0][1][0][0][1];
  result += a1.a0[0][1][0][1][0];
  result += a1.a0[0][1][0][1][1];
  result += a1.a0[0][1][1][0][0];
  result += a1.a0[0][1][1][0][1];
  result += a1.a0[0][1][1][1][0];
  result += a1.a0[0][1][1][1][1];
  result += a1.a0[1][0][0][0][0];
  result += a1.a0[1][0][0][0][1];
  result += a1.a0[1][0][0][1][0];
  result += a1.a0[1][0][0][1][1];
  result += a1.a0[1][0][1][0][0];
  result += a1.a0[1][0][1][0][1];
  result += a1.a0[1][0][1][1][0];
  result += a1.a0[1][0][1][1][1];
  result += a1.a0[1][1][0][0][0];
  result += a1.a0[1][1][0][0][1];
  result += a1.a0[1][1][0][1][0];
  result += a1.a0[1][1][0][1][1];
  result += a1.a0[1][1][1][0][0];
  result += a1.a0[1][1][1][0][1];
  result += a1.a0[1][1][1][1][0];
  result += a1.a0[1][1][1][1][1];
  result += a2;
  result += a3.a0[0][0][0];
  result += a3.a0[0][0][1];
  result += a3.a0[0][1][0];
  result += a3.a0[0][1][1];
  result += a3.a0[1][0][0];
  result += a3.a0[1][0][1];
  result += a3.a0[1][1][0];
  result += a3.a0[1][1][1];
  result += a4;
  result += a5.a0[0][0][0];
  result += a5.a0[0][0][1];
  result += a5.a0[0][1][0];
  result += a5.a0[0][1][1];
  result += a5.a0[1][0][0];
  result += a5.a0[1][0][1];
  result += a5.a0[1][1][0];
  result += a5.a0[1][1][1];
  result += a6;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test struct in multi dimensional inline array.
DART_EXPORT uint32_t PassUint8Struct4BytesInlineArrayMultiDimensionalIn(
    uint8_t a0,
    Struct4BytesInlineArrayMultiDimensionalInt a1,
    uint8_t a2) {
  std::cout << "PassUint8Struct4BytesInlineArrayMultiDimensionalIn" << "("
            << static_cast<int>(a0) << ", ([[("
            << static_cast<int>(a1.a0[0][0].a0) << "), ("
            << static_cast<int>(a1.a0[0][1].a0) << ")], [("
            << static_cast<int>(a1.a0[1][0].a0) << "), ("
            << static_cast<int>(a1.a0[1][1].a0) << ")]]), "
            << static_cast<int>(a2) << ")" << "\n";

  uint32_t result = 0;

  result += a0;
  result += a1.a0[0][0].a0;
  result += a1.a0[0][1].a0;
  result += a1.a0[1][0].a0;
  result += a1.a0[1][1].a0;
  result += a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT int64_t PassStruct3BytesPackedIntx10(Struct3BytesPackedInt a0,
                                                 Struct3BytesPackedInt a1,
                                                 Struct3BytesPackedInt a2,
                                                 Struct3BytesPackedInt a3,
                                                 Struct3BytesPackedInt a4,
                                                 Struct3BytesPackedInt a5,
                                                 Struct3BytesPackedInt a6,
                                                 Struct3BytesPackedInt a7,
                                                 Struct3BytesPackedInt a8,
                                                 Struct3BytesPackedInt a9) {
  std::cout << "PassStruct3BytesPackedIntx10" << "((" << static_cast<int>(a0.a0)
            << ", " << a0.a1 << "), (" << static_cast<int>(a1.a0) << ", "
            << a1.a1 << "), (" << static_cast<int>(a2.a0) << ", " << a2.a1
            << "), (" << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(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 and unions by value.
// Struct with mis-aligned member.
DART_EXPORT int64_t PassStruct8BytesPackedIntx10(Struct8BytesPackedInt a0,
                                                 Struct8BytesPackedInt a1,
                                                 Struct8BytesPackedInt a2,
                                                 Struct8BytesPackedInt a3,
                                                 Struct8BytesPackedInt a4,
                                                 Struct8BytesPackedInt a5,
                                                 Struct8BytesPackedInt a6,
                                                 Struct8BytesPackedInt a7,
                                                 Struct8BytesPackedInt a8,
                                                 Struct8BytesPackedInt a9) {
  std::cout << "PassStruct8BytesPackedIntx10" << "((" << static_cast<int>(a0.a0)
            << ", " << a0.a1 << ", " << static_cast<int>(a0.a2) << ", "
            << static_cast<int>(a0.a3) << ", " << static_cast<int>(a0.a4)
            << "), (" << static_cast<int>(a1.a0) << ", " << a1.a1 << ", "
            << static_cast<int>(a1.a2) << ", " << static_cast<int>(a1.a3)
            << ", " << static_cast<int>(a1.a4) << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << ", "
            << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
            << ", " << static_cast<int>(a2.a4) << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << ", "
            << static_cast<int>(a3.a2) << ", " << static_cast<int>(a3.a3)
            << ", " << static_cast<int>(a3.a4) << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << ", "
            << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
            << ", " << static_cast<int>(a4.a4) << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << ", "
            << static_cast<int>(a5.a2) << ", " << static_cast<int>(a5.a3)
            << ", " << static_cast<int>(a5.a4) << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << ", "
            << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
            << ", " << static_cast<int>(a6.a4) << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << ", "
            << static_cast<int>(a7.a2) << ", " << static_cast<int>(a7.a3)
            << ", " << static_cast<int>(a7.a4) << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << ", "
            << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
            << ", " << static_cast<int>(a8.a4) << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << ", "
            << static_cast<int>(a9.a2) << ", " << static_cast<int>(a9.a3)
            << ", " << static_cast<int>(a9.a4) << "))" << "\n";

  int64_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 and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT double PassStruct9BytesPackedMixedx10DoubleInt32x2(
    Struct9BytesPackedMixed a0,
    Struct9BytesPackedMixed a1,
    Struct9BytesPackedMixed a2,
    Struct9BytesPackedMixed a3,
    Struct9BytesPackedMixed a4,
    Struct9BytesPackedMixed a5,
    Struct9BytesPackedMixed a6,
    Struct9BytesPackedMixed a7,
    Struct9BytesPackedMixed a8,
    Struct9BytesPackedMixed a9,
    double a10,
    int32_t a11,
    int32_t a12) {
  std::cout << "PassStruct9BytesPackedMixedx10DoubleInt32x2" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << "), " << a10 << ", "
            << a11 << ", " << a12 << ")" << "\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;
  result += a10;
  result += a11;
  result += a12;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// This packed struct happens to have only aligned members.
DART_EXPORT double PassStruct5BytesPackedMixed(Struct5BytesPackedMixed a0) {
  std::cout << "PassStruct5BytesPackedMixed" << "((" << a0.a0 << ", "
            << static_cast<int>(a0.a1) << "))" << "\n";

  double result = 0;

  result += a0.a0;
  result += a0.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Check alignment of packed struct in non-packed struct.
DART_EXPORT double PassStructNestedAlignmentStruct5BytesPackedMixed(
    StructNestedAlignmentStruct5BytesPackedMixed a0) {
  std::cout << "PassStructNestedAlignmentStruct5BytesPackedMixed" << "(("
            << static_cast<int>(a0.a0) << ", (" << a0.a1.a0 << ", "
            << static_cast<int>(a0.a1.a1) << ")))" << "\n";

  double result = 0;

  result += a0.a0;
  result += a0.a1.a0;
  result += a0.a1.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT double PassStruct6BytesInlineArrayInt(
    Struct6BytesInlineArrayInt a0) {
  std::cout << "PassStruct6BytesInlineArrayInt" << "(([("
            << static_cast<int>(a0.a0[0].a0) << ", " << a0.a0[0].a1 << "), ("
            << static_cast<int>(a0.a0[1].a0) << ", " << a0.a0[1].a1 << ")]))"
            << "\n";

  double result = 0;

  result += a0.a0[0].a0;
  result += a0.a0[0].a1;
  result += a0.a0[1].a0;
  result += a0.a0[1].a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT double PassStruct15BytesInlineArrayMixed(
    Struct15BytesInlineArrayMixed a0) {
  std::cout << "PassStruct15BytesInlineArrayMixed" << "(([(" << a0.a0[0].a0
            << ", " << static_cast<int>(a0.a0[0].a1) << "), (" << a0.a0[1].a0
            << ", " << static_cast<int>(a0.a0[1].a1) << "), (" << a0.a0[2].a0
            << ", " << static_cast<int>(a0.a0[2].a1) << ")]))" << "\n";

  double result = 0;

  result += a0.a0[0].a0;
  result += a0.a0[0].a1;
  result += a0.a0[1].a0;
  result += a0.a0[1].a1;
  result += a0.a0[2].a0;
  result += a0.a0[2].a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Check placement of mixed integer/float union.
DART_EXPORT double PassUnion4BytesMixedx10(Union4BytesMixed a0,
                                           Union4BytesMixed a1,
                                           Union4BytesMixed a2,
                                           Union4BytesMixed a3,
                                           Union4BytesMixed a4,
                                           Union4BytesMixed a5,
                                           Union4BytesMixed a6,
                                           Union4BytesMixed a7,
                                           Union4BytesMixed a8,
                                           Union4BytesMixed a9) {
  std::cout << "PassUnion4BytesMixedx10" << "((" << a0.a0 << "), (" << a1.a0
            << "), (" << a2.a0 << "), (" << a3.a0 << "), (" << a4.a0 << "), ("
            << a5.a0 << "), (" << a6.a0 << "), (" << a7.a0 << "), (" << a8.a0
            << "), (" << a9.a0 << "))" << "\n";

  double 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 and unions by value.
// Check placement of mixed floats union.
DART_EXPORT double PassUnion8BytesNestedFloatx10(Union8BytesNestedFloat a0,
                                                 Union8BytesNestedFloat a1,
                                                 Union8BytesNestedFloat a2,
                                                 Union8BytesNestedFloat a3,
                                                 Union8BytesNestedFloat a4,
                                                 Union8BytesNestedFloat a5,
                                                 Union8BytesNestedFloat a6,
                                                 Union8BytesNestedFloat a7,
                                                 Union8BytesNestedFloat a8,
                                                 Union8BytesNestedFloat a9) {
  std::cout << "PassUnion8BytesNestedFloatx10" << "((" << a0.a0 << "), ("
            << a1.a0 << "), (" << a2.a0 << "), (" << a3.a0 << "), (" << a4.a0
            << "), (" << a5.a0 << "), (" << a6.a0 << "), (" << a7.a0 << "), ("
            << a8.a0 << "), (" << a9.a0 << "))" << "\n";

  double 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 and unions by value.
// Mixed-size union argument.
DART_EXPORT double PassUnion9BytesNestedIntx10(Union9BytesNestedInt a0,
                                               Union9BytesNestedInt a1,
                                               Union9BytesNestedInt a2,
                                               Union9BytesNestedInt a3,
                                               Union9BytesNestedInt a4,
                                               Union9BytesNestedInt a5,
                                               Union9BytesNestedInt a6,
                                               Union9BytesNestedInt a7,
                                               Union9BytesNestedInt a8,
                                               Union9BytesNestedInt a9) {
  std::cout << "PassUnion9BytesNestedIntx10" << "(((" << a0.a0.a0 << ", "
            << a0.a0.a1 << ", " << a0.a0.a2 << ")), ((" << a1.a0.a0 << ", "
            << a1.a0.a1 << ", " << a1.a0.a2 << ")), ((" << a2.a0.a0 << ", "
            << a2.a0.a1 << ", " << a2.a0.a2 << ")), ((" << a3.a0.a0 << ", "
            << a3.a0.a1 << ", " << a3.a0.a2 << ")), ((" << a4.a0.a0 << ", "
            << a4.a0.a1 << ", " << a4.a0.a2 << ")), ((" << a5.a0.a0 << ", "
            << a5.a0.a1 << ", " << a5.a0.a2 << ")), ((" << a6.a0.a0 << ", "
            << a6.a0.a1 << ", " << a6.a0.a2 << ")), ((" << a7.a0.a0 << ", "
            << a7.a0.a1 << ", " << a7.a0.a2 << ")), ((" << a8.a0.a0 << ", "
            << a8.a0.a1 << ", " << a8.a0.a2 << ")), ((" << a9.a0.a0 << ", "
            << a9.a0.a1 << ", " << a9.a0.a2 << ")))" << "\n";

  double result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a0.a0.a2;
  result += a1.a0.a0;
  result += a1.a0.a1;
  result += a1.a0.a2;
  result += a2.a0.a0;
  result += a2.a0.a1;
  result += a2.a0.a2;
  result += a3.a0.a0;
  result += a3.a0.a1;
  result += a3.a0.a2;
  result += a4.a0.a0;
  result += a4.a0.a1;
  result += a4.a0.a2;
  result += a5.a0.a0;
  result += a5.a0.a1;
  result += a5.a0.a2;
  result += a6.a0.a0;
  result += a6.a0.a1;
  result += a6.a0.a2;
  result += a7.a0.a0;
  result += a7.a0.a1;
  result += a7.a0.a2;
  result += a8.a0.a0;
  result += a8.a0.a1;
  result += a8.a0.a2;
  result += a9.a0.a0;
  result += a9.a0.a1;
  result += a9.a0.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Union with homogenous floats.
DART_EXPORT double PassUnion16BytesNestedInlineArrayFloatx10(
    Union16BytesNestedInlineArrayFloat a0,
    Union16BytesNestedInlineArrayFloat a1,
    Union16BytesNestedInlineArrayFloat a2,
    Union16BytesNestedInlineArrayFloat a3,
    Union16BytesNestedInlineArrayFloat a4,
    Union16BytesNestedInlineArrayFloat a5,
    Union16BytesNestedInlineArrayFloat a6,
    Union16BytesNestedInlineArrayFloat a7,
    Union16BytesNestedInlineArrayFloat a8,
    Union16BytesNestedInlineArrayFloat a9) {
  std::cout << "PassUnion16BytesNestedInlineArrayFloatx10" << "(([" << a0.a0[0]
            << ", " << a0.a0[1] << ", " << a0.a0[2] << ", " << a0.a0[3]
            << "]), ([" << a1.a0[0] << ", " << a1.a0[1] << ", " << a1.a0[2]
            << ", " << a1.a0[3] << "]), ([" << a2.a0[0] << ", " << a2.a0[1]
            << ", " << a2.a0[2] << ", " << a2.a0[3] << "]), ([" << a3.a0[0]
            << ", " << a3.a0[1] << ", " << a3.a0[2] << ", " << a3.a0[3]
            << "]), ([" << a4.a0[0] << ", " << a4.a0[1] << ", " << a4.a0[2]
            << ", " << a4.a0[3] << "]), ([" << a5.a0[0] << ", " << a5.a0[1]
            << ", " << a5.a0[2] << ", " << a5.a0[3] << "]), ([" << a6.a0[0]
            << ", " << a6.a0[1] << ", " << a6.a0[2] << ", " << a6.a0[3]
            << "]), ([" << a7.a0[0] << ", " << a7.a0[1] << ", " << a7.a0[2]
            << ", " << a7.a0[3] << "]), ([" << a8.a0[0] << ", " << a8.a0[1]
            << ", " << a8.a0[2] << ", " << a8.a0[3] << "]), ([" << a9.a0[0]
            << ", " << a9.a0[1] << ", " << a9.a0[2] << ", " << a9.a0[3] << "]))"
            << "\n";

  double result = 0;

  result += a0.a0[0];
  result += a0.a0[1];
  result += a0.a0[2];
  result += a0.a0[3];
  result += a1.a0[0];
  result += a1.a0[1];
  result += a1.a0[2];
  result += a1.a0[3];
  result += a2.a0[0];
  result += a2.a0[1];
  result += a2.a0[2];
  result += a2.a0[3];
  result += a3.a0[0];
  result += a3.a0[1];
  result += a3.a0[2];
  result += a3.a0[3];
  result += a4.a0[0];
  result += a4.a0[1];
  result += a4.a0[2];
  result += a4.a0[3];
  result += a5.a0[0];
  result += a5.a0[1];
  result += a5.a0[2];
  result += a5.a0[3];
  result += a6.a0[0];
  result += a6.a0[1];
  result += a6.a0[2];
  result += a6.a0[3];
  result += a7.a0[0];
  result += a7.a0[1];
  result += a7.a0[2];
  result += a7.a0[3];
  result += a8.a0[0];
  result += a8.a0[1];
  result += a8.a0[2];
  result += a8.a0[3];
  result += a9.a0[0];
  result += a9.a0[1];
  result += a9.a0[2];
  result += a9.a0[3];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Union with homogenous floats.
DART_EXPORT double PassUnion16BytesNestedFloatx10(Union16BytesNestedFloat a0,
                                                  Union16BytesNestedFloat a1,
                                                  Union16BytesNestedFloat a2,
                                                  Union16BytesNestedFloat a3,
                                                  Union16BytesNestedFloat a4,
                                                  Union16BytesNestedFloat a5,
                                                  Union16BytesNestedFloat a6,
                                                  Union16BytesNestedFloat a7,
                                                  Union16BytesNestedFloat a8,
                                                  Union16BytesNestedFloat a9) {
  std::cout << "PassUnion16BytesNestedFloatx10" << "(((" << a0.a0.a0 << ", "
            << a0.a0.a1 << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << ")), (("
            << a2.a0.a0 << ", " << a2.a0.a1 << ")), ((" << a3.a0.a0 << ", "
            << a3.a0.a1 << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << ")), (("
            << a5.a0.a0 << ", " << a5.a0.a1 << ")), ((" << a6.a0.a0 << ", "
            << a6.a0.a1 << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << ")), (("
            << a8.a0.a0 << ", " << a8.a0.a1 << ")), ((" << a9.a0.a0 << ", "
            << a9.a0.a1 << ")))" << "\n";

  double result = 0;

  result += a0.a0.a0;
  result += a0.a0.a1;
  result += a1.a0.a0;
  result += a1.a0.a1;
  result += a2.a0.a0;
  result += a2.a0.a1;
  result += a3.a0.a0;
  result += a3.a0.a1;
  result += a4.a0.a0;
  result += a4.a0.a1;
  result += a5.a0.a0;
  result += a5.a0.a1;
  result += a6.a0.a0;
  result += a6.a0.a1;
  result += a7.a0.a0;
  result += a7.a0.a1;
  result += a8.a0.a0;
  result += a8.a0.a1;
  result += a9.a0.a0;
  result += a9.a0.a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT int32_t PassUint8Boolx9Struct10BytesHomogeneousBoolBool(
    uint8_t a0,
    bool a1,
    bool a2,
    bool a3,
    bool a4,
    bool a5,
    bool a6,
    bool a7,
    bool a8,
    bool a9,
    Struct10BytesHomogeneousBool a10,
    bool a11) {
  std::cout << "PassUint8Boolx9Struct10BytesHomogeneousBoolBool" << "("
            << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", " << a3
            << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7 << ", "
            << a8 << ", " << a9 << ", (" << a10.a0 << ", " << a10.a1 << ", "
            << a10.a2 << ", " << a10.a3 << ", " << a10.a4 << ", " << a10.a5
            << ", " << a10.a6 << ", " << a10.a7 << ", " << a10.a8 << ", "
            << a10.a9 << "), " << a11 << ")" << "\n";

  int32_t result = 0;

  result += a0;
  result += a1 ? 1 : 0;
  result += a2 ? 1 : 0;
  result += a3 ? 1 : 0;
  result += a4 ? 1 : 0;
  result += a5 ? 1 : 0;
  result += a6 ? 1 : 0;
  result += a7 ? 1 : 0;
  result += a8 ? 1 : 0;
  result += a9 ? 1 : 0;
  result += a10.a0 ? 1 : 0;
  result += a10.a1 ? 1 : 0;
  result += a10.a2 ? 1 : 0;
  result += a10.a3 ? 1 : 0;
  result += a10.a4 ? 1 : 0;
  result += a10.a5 ? 1 : 0;
  result += a10.a6 ? 1 : 0;
  result += a10.a7 ? 1 : 0;
  result += a10.a8 ? 1 : 0;
  result += a10.a9 ? 1 : 0;
  result += a11 ? 1 : 0;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT int32_t PassUint8Boolx9Struct10BytesInlineArrayBoolBool(
    uint8_t a0,
    bool a1,
    bool a2,
    bool a3,
    bool a4,
    bool a5,
    bool a6,
    bool a7,
    bool a8,
    bool a9,
    Struct10BytesInlineArrayBool a10,
    bool a11) {
  std::cout << "PassUint8Boolx9Struct10BytesInlineArrayBoolBool" << "("
            << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", " << a3
            << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7 << ", "
            << a8 << ", " << a9 << ", ([" << a10.a0[0] << ", " << a10.a0[1]
            << ", " << a10.a0[2] << ", " << a10.a0[3] << ", " << a10.a0[4]
            << ", " << a10.a0[5] << ", " << a10.a0[6] << ", " << a10.a0[7]
            << ", " << a10.a0[8] << ", " << a10.a0[9] << "]), " << a11 << ")"
            << "\n";

  int32_t result = 0;

  result += a0;
  result += a1 ? 1 : 0;
  result += a2 ? 1 : 0;
  result += a3 ? 1 : 0;
  result += a4 ? 1 : 0;
  result += a5 ? 1 : 0;
  result += a6 ? 1 : 0;
  result += a7 ? 1 : 0;
  result += a8 ? 1 : 0;
  result += a9 ? 1 : 0;
  result += a10.a0[0] ? 1 : 0;
  result += a10.a0[1] ? 1 : 0;
  result += a10.a0[2] ? 1 : 0;
  result += a10.a0[3] ? 1 : 0;
  result += a10.a0[4] ? 1 : 0;
  result += a10.a0[5] ? 1 : 0;
  result += a10.a0[6] ? 1 : 0;
  result += a10.a0[7] ? 1 : 0;
  result += a10.a0[8] ? 1 : 0;
  result += a10.a0[9] ? 1 : 0;
  result += a11 ? 1 : 0;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Returning a bool.
DART_EXPORT bool PassUint8Struct1ByteBool(uint8_t a0, Struct1ByteBool a1) {
  std::cout << "PassUint8Struct1ByteBool" << "(" << static_cast<int>(a0)
            << ", (" << a1.a0 << "))" << "\n";

  uint64_t result = 0;

  result += a0;
  result += a1.a0 ? 1 : 0;

  std::cout << "result = " << result << "\n";

  return result % 2 != 0;
}

// Used for testing structs and unions by value.
// Returning a wchar.
DART_EXPORT wchar_t PassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
    wchar_t a0,
    StructInlineArrayInt a1,
    uintptr_t a2,
    uintptr_t a3,
    /* NOLINT(runtime/int) */ long a4,
    /* NOLINT(runtime/int) */ unsigned long a5) {
  std::cout << "PassWCharStructInlineArrayIntUintPtrx2LongUnsigned" << "("
            << static_cast<int>(a0) << ", ([" << static_cast<int>(a1.a0[0])
            << ", " << static_cast<int>(a1.a0[1]) << ", "
            << static_cast<int>(a1.a0[2]) << ", " << static_cast<int>(a1.a0[3])
            << ", " << static_cast<int>(a1.a0[4]) << ", "
            << static_cast<int>(a1.a0[5]) << ", " << static_cast<int>(a1.a0[6])
            << ", " << static_cast<int>(a1.a0[7]) << ", "
            << static_cast<int>(a1.a0[8]) << ", " << static_cast<int>(a1.a0[9])
            << "]), " << a2 << ", " << a3 << ", " << a4 << ", " << a5 << ")"
            << "\n";

  wchar_t result = 0;

  result += a0;
  result += a1.a0[0];
  result += a1.a0[1];
  result += a1.a0[2];
  result += a1.a0[3];
  result += a1.a0[4];
  result += a1.a0[5];
  result += a1.a0[6];
  result += a1.a0[7];
  result += a1.a0[8];
  result += a1.a0[9];
  result += a2;
  result += a3;
  result += a4;
  result += a5;

  std::cout << "result = " << static_cast<int>(result) << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Struct stradles last argument register
DART_EXPORT int64_t
PassInt64x7Struct12BytesHomogeneousInt32(int64_t a0,
                                         int64_t a1,
                                         int64_t a2,
                                         int64_t a3,
                                         int64_t a4,
                                         int64_t a5,
                                         int64_t a6,
                                         Struct12BytesHomogeneousInt32 a7) {
  std::cout << "PassInt64x7Struct12BytesHomogeneousInt32" << "(" << a0 << ", "
            << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ", " << a5
            << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1 << ", " << a7.a2
            << "))" << "\n";

  int64_t result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;
  result += a5;
  result += a6;
  result += a7.a0;
  result += a7.a1;
  result += a7.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Passing a pointer to a struct
DART_EXPORT int64_t
PassPointerStruct12BytesHomogeneousInt32(Struct12BytesHomogeneousInt32* a0) {
  std::cout << "PassPointerStruct12BytesHomogeneousInt32" << "((" << a0->a0
            << ", " << a0->a1 << ", " << 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 and unions by value.
// Variable length array
DART_EXPORT int64_t
PassPointerStructInlineArrayVariable(StructInlineArrayVariable* a0) {
  std::cout << "PassPointerStructInlineArrayVariable" << "((" << a0->a0 << ", ["
            << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))" << "\n";

  int64_t result = 0;

  result += a0->a0;
  result += a0->a1[0];
  result += a0->a1[1];
  result += a0->a1[2];
  result += a0->a1[3];
  result += a0->a1[4];
  result += a0->a1[5];
  result += a0->a1[6];
  result += a0->a1[7];
  result += a0->a1[8];
  result += a0->a1[9];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variable length array with variable length element having more alignment than
// the rest of the struct.
DART_EXPORT int64_t
PassPointerStructInlineArrayVariableAlign(StructInlineArrayVariableAlign* a0) {
  std::cout << "PassPointerStructInlineArrayVariableAlign" << "(("
            << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
            << a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
            << a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
            << a0->a1[7] << ", " << a0->a1[8] << ", " << a0->a1[9] << "]))"
            << "\n";

  int64_t result = 0;

  result += a0->a0;
  result += a0->a1[0];
  result += a0->a1[1];
  result += a0->a1[2];
  result += a0->a1[3];
  result += a0->a1[4];
  result += a0->a1[5];
  result += a0->a1[6];
  result += a0->a1[7];
  result += a0->a1[8];
  result += a0->a1[9];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variable length array with variable dimension of 1.
DART_EXPORT int64_t
PassPointerStructInlineArrayVariable2(StructInlineArrayVariable2* a0) {
  std::cout << "PassPointerStructInlineArrayVariable2"
            << "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))"
            << "\n";

  int64_t result = 0;

  result += a0->a0;
  result += a0->a1[0];
  result += a0->a1[1];
  result += a0->a1[2];
  result += a0->a1[3];
  result += a0->a1[4];
  result += a0->a1[5];
  result += a0->a1[6];
  result += a0->a1[7];
  result += a0->a1[8];
  result += a0->a1[9];

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions by value.
// Smaller than word size return value on all architectures.
DART_EXPORT Struct3BytesHomogeneousUint8
ReturnStruct3BytesHomogeneousUint8(uint8_t a0, uint8_t a1, uint8_t a2) {
  std::cout << "ReturnStruct3BytesHomogeneousUint8" << "("
            << static_cast<int>(a0) << ", " << static_cast<int>(a1) << ", "
            << static_cast<int>(a2) << ")" << "\n";

  Struct3BytesHomogeneousUint8 result = {};

  result.a0 = a0;
  result.a1 = a1;
  result.a2 = a2;

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << static_cast<int>(result.a1) << ", "
            << static_cast<int>(result.a2) << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
// With alignment rules taken into account size is 4 bytes.
DART_EXPORT Struct3BytesInt2ByteAligned
ReturnStruct3BytesInt2ByteAligned(int16_t a0, int8_t a1) {
  std::cout << "ReturnStruct3BytesInt2ByteAligned" << "(" << a0 << ", "
            << static_cast<int>(a1) << ")" << "\n";

  Struct3BytesInt2ByteAligned result = {};

  result.a0 = a0;
  result.a1 = a1;

  std::cout << "result = " << "(" << result.a0 << ", "
            << static_cast<int>(result.a1) << ")" << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions by value.
// Non-wordsize return value.
DART_EXPORT Struct7BytesHomogeneousUint8
ReturnStruct7BytesHomogeneousUint8(uint8_t a0,
                                   uint8_t a1,
                                   uint8_t a2,
                                   uint8_t a3,
                                   uint8_t a4,
                                   uint8_t a5,
                                   uint8_t a6) {
  std::cout << "ReturnStruct7BytesHomogeneousUint8" << "("
            << 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) << ")" << "\n";

  Struct7BytesHomogeneousUint8 result = {};

  result.a0 = a0;
  result.a1 = a1;
  result.a2 = a2;
  result.a3 = a3;
  result.a4 = a4;
  result.a5 = a5;
  result.a6 = a6;

  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) << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Non-wordsize return value.
// With alignment rules taken into account size is 8 bytes.
DART_EXPORT Struct7BytesInt4ByteAligned
ReturnStruct7BytesInt4ByteAligned(int32_t a0, int16_t a1, int8_t a2) {
  std::cout << "ReturnStruct7BytesInt4ByteAligned" << "(" << a0 << ", " << a1
            << ", " << static_cast<int>(a2) << ")" << "\n";

  Struct7BytesInt4ByteAligned 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 and unions 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 and unions 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 and unions 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 and unions 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 Struct9BytesHomogeneousUint8
ReturnStruct9BytesHomogeneousUint8(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 << "ReturnStruct9BytesHomogeneousUint8" << "("
            << 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";

  Struct9BytesHomogeneousUint8 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 and unions by value.
// Return value in two integer registers on x64.
// With alignment rules taken into account size is 12 or 16 bytes.
DART_EXPORT Struct9BytesInt4Or8ByteAligned
ReturnStruct9BytesInt4Or8ByteAligned(int64_t a0, int8_t a1) {
  std::cout << "ReturnStruct9BytesInt4Or8ByteAligned" << "(" << a0 << ", "
            << static_cast<int>(a1) << ")" << "\n";

  Struct9BytesInt4Or8ByteAligned result = {};

  result.a0 = a0;
  result.a1 = a1;

  std::cout << "result = " << "(" << result.a0 << ", "
            << static_cast<int>(result.a1) << ")" << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Return 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT Struct3BytesPackedInt ReturnStruct3BytesPackedInt(int8_t a0,
                                                              int16_t a1) {
  std::cout << "ReturnStruct3BytesPackedInt" << "(" << static_cast<int>(a0)
            << ", " << a1 << ")" << "\n";

  Struct3BytesPackedInt result = {};

  result.a0 = a0;
  result.a1 = a1;

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << result.a1 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT Struct8BytesPackedInt ReturnStruct8BytesPackedInt(uint8_t a0,
                                                              uint32_t a1,
                                                              uint8_t a2,
                                                              uint8_t a3,
                                                              uint8_t a4) {
  std::cout << "ReturnStruct8BytesPackedInt" << "(" << static_cast<int>(a0)
            << ", " << a1 << ", " << static_cast<int>(a2) << ", "
            << static_cast<int>(a3) << ", " << static_cast<int>(a4) << ")"
            << "\n";

  Struct8BytesPackedInt result = {};

  result.a0 = a0;
  result.a1 = a1;
  result.a2 = a2;
  result.a3 = a3;
  result.a4 = a4;

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << result.a1 << ", " << static_cast<int>(result.a2) << ", "
            << static_cast<int>(result.a3) << ", "
            << static_cast<int>(result.a4) << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT Struct9BytesPackedMixed ReturnStruct9BytesPackedMixed(uint8_t a0,
                                                                  double a1) {
  std::cout << "ReturnStruct9BytesPackedMixed" << "(" << static_cast<int>(a0)
            << ", " << a1 << ")" << "\n";

  Struct9BytesPackedMixed result = {};

  result.a0 = a0;
  result.a1 = a1;

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << result.a1 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Returning a mixed integer/float union.
DART_EXPORT Union4BytesMixed ReturnUnion4BytesMixed(uint32_t a0) {
  std::cout << "ReturnUnion4BytesMixed" << "(" << a0 << ")" << "\n";

  Union4BytesMixed result = {};

  result.a0 = a0;

  std::cout << "result = " << "(" << result.a0 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Returning a floating point only union.
DART_EXPORT Union8BytesNestedFloat ReturnUnion8BytesNestedFloat(double a0) {
  std::cout << "ReturnUnion8BytesNestedFloat" << "(" << a0 << ")" << "\n";

  Union8BytesNestedFloat result = {};

  result.a0 = a0;

  std::cout << "result = " << "(" << result.a0 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Returning a mixed-size union.
DART_EXPORT Union9BytesNestedInt
ReturnUnion9BytesNestedInt(Struct8BytesInt a0) {
  std::cout << "ReturnUnion9BytesNestedInt" << "((" << a0.a0 << ", " << a0.a1
            << ", " << a0.a2 << "))" << "\n";

  Union9BytesNestedInt result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a0.a2 = a0.a2;

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << ", " << result.a0.a2 << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Returning union with homogenous floats.
DART_EXPORT Union16BytesNestedFloat
ReturnUnion16BytesNestedFloat(Struct8BytesHomogeneousFloat a0) {
  std::cout << "ReturnUnion16BytesNestedFloat" << "((" << a0.a0 << ", " << a0.a1
            << "))" << "\n";

  Union16BytesNestedFloat result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "))" << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Test returning struct with inline array.
DART_EXPORT Struct8BytesInlineArrayInt
ReturnStructArgumentStruct8BytesInlineArrayInt(Struct8BytesInlineArrayInt a0) {
  std::cout << "ReturnStructArgumentStruct8BytesInlineArrayInt" << "((["
            << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
            << ", " << static_cast<int>(a0.a0[2]) << ", "
            << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
            << ", " << static_cast<int>(a0.a0[5]) << ", "
            << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
            << "]))" << "\n";

  Struct8BytesInlineArrayInt result = a0;

  std::cout << "result = " << "([" << static_cast<int>(result.a0[0]) << ", "
            << static_cast<int>(result.a0[1]) << ", "
            << static_cast<int>(result.a0[2]) << ", "
            << static_cast<int>(result.a0[3]) << ", "
            << static_cast<int>(result.a0[4]) << ", "
            << static_cast<int>(result.a0[5]) << ", "
            << static_cast<int>(result.a0[6]) << ", "
            << static_cast<int>(result.a0[7]) << "])" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT StructStruct16BytesHomogeneousFloat2
ReturnStructArgumentStructStruct16BytesHomogeneous(
    StructStruct16BytesHomogeneousFloat2 a0) {
  std::cout << "ReturnStructArgumentStructStruct16BytesHomogeneous" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0
            << ")], " << a0.a2 << "))" << "\n";

  StructStruct16BytesHomogeneousFloat2 result = a0;

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << "), (" << result.a1[1].a0 << ")], " << result.a2 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT StructStruct32BytesHomogeneousDouble2
ReturnStructArgumentStructStruct32BytesHomogeneous(
    StructStruct32BytesHomogeneousDouble2 a0) {
  std::cout << "ReturnStructArgumentStructStruct32BytesHomogeneous" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0
            << ")], " << a0.a2 << "))" << "\n";

  StructStruct32BytesHomogeneousDouble2 result = a0;

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << "), (" << result.a1[1].a0 << ")], " << result.a2 << ")" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// On x64 Linux, return value is split over FP and int registers.
DART_EXPORT StructStruct16BytesMixed3
ReturnStructArgumentStructStruct16BytesMixed3(StructStruct16BytesMixed3 a0) {
  std::cout << "ReturnStructArgumentStructStruct16BytesMixed3" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << ", " << a0.a1[0].a1 << ", "
            << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", " << a0.a2[1] << "]))"
            << "\n";

  StructStruct16BytesMixed3 result = a0;

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << ", " << result.a1[0].a1 << ", " << result.a1[0].a2 << ")], ["
            << result.a2[0] << ", " << result.a2[1] << "])" << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions by value.
// Simple nested struct.
DART_EXPORT Struct8BytesNestedInt
ReturnStruct8BytesNestedInt(Struct4BytesHomogeneousInt16 a0,
                            Struct4BytesHomogeneousInt16 a1) {
  std::cout << "ReturnStruct8BytesNestedInt" << "((" << a0.a0 << ", " << a0.a1
            << "), (" << a1.a0 << ", " << a1.a1 << "))" << "\n";

  Struct8BytesNestedInt result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a1.a0 = a1.a0;
  result.a1.a1 = a1.a1;

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "), (" << result.a1.a0 << ", " << result.a1.a1 << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple nested struct with floats.
DART_EXPORT Struct8BytesNestedFloat
ReturnStruct8BytesNestedFloat(Struct4BytesFloat a0, Struct4BytesFloat a1) {
  std::cout << "ReturnStruct8BytesNestedFloat" << "((" << a0.a0 << "), ("
            << a1.a0 << "))" << "\n";

  Struct8BytesNestedFloat result = {};

  result.a0.a0 = a0.a0;
  result.a1.a0 = a1.a0;

  std::cout << "result = " << "((" << result.a0.a0 << "), (" << result.a1.a0
            << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT Struct8BytesNestedFloat2
ReturnStruct8BytesNestedFloat2(Struct4BytesFloat a0, float a1) {
  std::cout << "ReturnStruct8BytesNestedFloat2" << "((" << a0.a0 << "), " << a1
            << ")" << "\n";

  Struct8BytesNestedFloat2 result = {};

  result.a0.a0 = a0.a0;
  result.a1 = a1;

  std::cout << "result = " << "((" << result.a0.a0 << "), " << result.a1 << ")"
            << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Simple nested struct with mixed members.
DART_EXPORT Struct8BytesNestedMixed
ReturnStruct8BytesNestedMixed(Struct4BytesHomogeneousInt16 a0,
                              Struct4BytesFloat a1) {
  std::cout << "ReturnStruct8BytesNestedMixed" << "((" << a0.a0 << ", " << a0.a1
            << "), (" << a1.a0 << "))" << "\n";

  Struct8BytesNestedMixed result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a1.a0 = a1.a0;

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "), (" << result.a1.a0 << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT Struct16BytesNestedInt
ReturnStruct16BytesNestedInt(Struct8BytesNestedInt a0,
                             Struct8BytesNestedInt a1) {
  std::cout << "ReturnStruct16BytesNestedInt" << "(((" << a0.a0.a0 << ", "
            << a0.a0.a1 << "), (" << a0.a1.a0 << ", " << a0.a1.a1 << ")), (("
            << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0 << ", "
            << a1.a1.a1 << ")))" << "\n";

  Struct16BytesNestedInt result = {};

  result.a0.a0.a0 = a0.a0.a0;
  result.a0.a0.a1 = a0.a0.a1;
  result.a0.a1.a0 = a0.a1.a0;
  result.a0.a1.a1 = a0.a1.a1;
  result.a1.a0.a0 = a1.a0.a0;
  result.a1.a0.a1 = a1.a0.a1;
  result.a1.a1.a0 = a1.a1.a0;
  result.a1.a1.a1 = a1.a1.a1;

  std::cout << "result = " << "(((" << result.a0.a0.a0 << ", "
            << result.a0.a0.a1 << "), (" << result.a0.a1.a0 << ", "
            << result.a0.a1.a1 << ")), ((" << result.a1.a0.a0 << ", "
            << result.a1.a0.a1 << "), (" << result.a1.a1.a0 << ", "
            << result.a1.a1.a1 << ")))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT Struct32BytesNestedInt
ReturnStruct32BytesNestedInt(Struct16BytesNestedInt a0,
                             Struct16BytesNestedInt a1) {
  std::cout << "ReturnStruct32BytesNestedInt" << "((((" << a0.a0.a0.a0 << ", "
            << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0 << ", " << a0.a0.a1.a1
            << ")), ((" << a0.a1.a0.a0 << ", " << a0.a1.a0.a1 << "), ("
            << a0.a1.a1.a0 << ", " << a0.a1.a1.a1 << "))), (((" << a1.a0.a0.a0
            << ", " << a1.a0.a0.a1 << "), (" << a1.a0.a1.a0 << ", "
            << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0 << ", " << a1.a1.a0.a1
            << "), (" << a1.a1.a1.a0 << ", " << a1.a1.a1.a1 << "))))" << "\n";

  Struct32BytesNestedInt result = {};

  result.a0.a0.a0.a0 = a0.a0.a0.a0;
  result.a0.a0.a0.a1 = a0.a0.a0.a1;
  result.a0.a0.a1.a0 = a0.a0.a1.a0;
  result.a0.a0.a1.a1 = a0.a0.a1.a1;
  result.a0.a1.a0.a0 = a0.a1.a0.a0;
  result.a0.a1.a0.a1 = a0.a1.a0.a1;
  result.a0.a1.a1.a0 = a0.a1.a1.a0;
  result.a0.a1.a1.a1 = a0.a1.a1.a1;
  result.a1.a0.a0.a0 = a1.a0.a0.a0;
  result.a1.a0.a0.a1 = a1.a0.a0.a1;
  result.a1.a0.a1.a0 = a1.a0.a1.a0;
  result.a1.a0.a1.a1 = a1.a0.a1.a1;
  result.a1.a1.a0.a0 = a1.a1.a0.a0;
  result.a1.a1.a0.a1 = a1.a1.a0.a1;
  result.a1.a1.a1.a0 = a1.a1.a1.a0;
  result.a1.a1.a1.a1 = a1.a1.a1.a1;

  std::cout << "result = " << "((((" << result.a0.a0.a0.a0 << ", "
            << result.a0.a0.a0.a1 << "), (" << result.a0.a0.a1.a0 << ", "
            << result.a0.a0.a1.a1 << ")), ((" << result.a0.a1.a0.a0 << ", "
            << result.a0.a1.a0.a1 << "), (" << result.a0.a1.a1.a0 << ", "
            << result.a0.a1.a1.a1 << "))), (((" << result.a1.a0.a0.a0 << ", "
            << result.a1.a0.a0.a1 << "), (" << result.a1.a0.a1.a0 << ", "
            << result.a1.a0.a1.a1 << ")), ((" << result.a1.a1.a0.a0 << ", "
            << result.a1.a1.a0.a1 << "), (" << result.a1.a1.a1.a0 << ", "
            << result.a1.a1.a1.a1 << "))))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt16
ReturnStructNestedIntStructAlignmentInt16(StructAlignmentInt16 a0,
                                          StructAlignmentInt16 a1) {
  std::cout << "ReturnStructNestedIntStructAlignmentInt16" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))" << "\n";

  StructNestedIntStructAlignmentInt16 result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a0.a2 = a0.a2;
  result.a1.a0 = a1.a0;
  result.a1.a1 = a1.a1;
  result.a1.a2 = a1.a2;

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt32
ReturnStructNestedIntStructAlignmentInt32(StructAlignmentInt32 a0,
                                          StructAlignmentInt32 a1) {
  std::cout << "ReturnStructNestedIntStructAlignmentInt32" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))" << "\n";

  StructNestedIntStructAlignmentInt32 result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a0.a2 = a0.a2;
  result.a1.a0 = a1.a0;
  result.a1.a1 = a1.a1;
  result.a1.a2 = a1.a2;

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt64
ReturnStructNestedIntStructAlignmentInt64(StructAlignmentInt64 a0,
                                          StructAlignmentInt64 a1) {
  std::cout << "ReturnStructNestedIntStructAlignmentInt64" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))" << "\n";

  StructNestedIntStructAlignmentInt64 result = {};

  result.a0.a0 = a0.a0;
  result.a0.a1 = a0.a1;
  result.a0.a2 = a0.a2;
  result.a1.a0 = a1.a0;
  result.a1.a1 = a1.a1;
  result.a1.a2 = a1.a2;

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT StructNestedIrregularEvenBigger
ReturnStructNestedIrregularEvenBigger(uint64_t a0,
                                      StructNestedIrregularBigger a1,
                                      StructNestedIrregularBigger a2,
                                      double a3) {
  std::cout << "ReturnStructNestedIrregularEvenBigger" << "(" << a0 << ", (("
            << a1.a0.a0 << ", ((" << a1.a0.a1.a0.a0 << ", " << a1.a0.a1.a0.a1
            << "), (" << a1.a0.a1.a1.a0 << ")), " << a1.a0.a2 << ", (("
            << a1.a0.a3.a0.a0 << "), " << a1.a0.a3.a1 << "), " << a1.a0.a4
            << ", ((" << a1.a0.a5.a0.a0 << "), (" << a1.a0.a5.a1.a0 << ")), "
            << a1.a0.a6 << "), ((" << a1.a1.a0.a0 << ", " << a1.a1.a0.a1
            << "), (" << a1.a1.a1.a0 << ")), " << a1.a2 << ", " << a1.a3
            << "), ((" << a2.a0.a0 << ", ((" << a2.a0.a1.a0.a0 << ", "
            << a2.a0.a1.a0.a1 << "), (" << a2.a0.a1.a1.a0 << ")), " << a2.a0.a2
            << ", ((" << a2.a0.a3.a0.a0 << "), " << a2.a0.a3.a1 << "), "
            << a2.a0.a4 << ", ((" << a2.a0.a5.a0.a0 << "), (" << a2.a0.a5.a1.a0
            << ")), " << a2.a0.a6 << "), ((" << a2.a1.a0.a0 << ", "
            << a2.a1.a0.a1 << "), (" << a2.a1.a1.a0 << ")), " << a2.a2 << ", "
            << a2.a3 << "), " << a3 << ")" << "\n";

  StructNestedIrregularEvenBigger result = {};

  result.a0 = a0;
  result.a1.a0.a0 = a1.a0.a0;
  result.a1.a0.a1.a0.a0 = a1.a0.a1.a0.a0;
  result.a1.a0.a1.a0.a1 = a1.a0.a1.a0.a1;
  result.a1.a0.a1.a1.a0 = a1.a0.a1.a1.a0;
  result.a1.a0.a2 = a1.a0.a2;
  result.a1.a0.a3.a0.a0 = a1.a0.a3.a0.a0;
  result.a1.a0.a3.a1 = a1.a0.a3.a1;
  result.a1.a0.a4 = a1.a0.a4;
  result.a1.a0.a5.a0.a0 = a1.a0.a5.a0.a0;
  result.a1.a0.a5.a1.a0 = a1.a0.a5.a1.a0;
  result.a1.a0.a6 = a1.a0.a6;
  result.a1.a1.a0.a0 = a1.a1.a0.a0;
  result.a1.a1.a0.a1 = a1.a1.a0.a1;
  result.a1.a1.a1.a0 = a1.a1.a1.a0;
  result.a1.a2 = a1.a2;
  result.a1.a3 = a1.a3;
  result.a2.a0.a0 = a2.a0.a0;
  result.a2.a0.a1.a0.a0 = a2.a0.a1.a0.a0;
  result.a2.a0.a1.a0.a1 = a2.a0.a1.a0.a1;
  result.a2.a0.a1.a1.a0 = a2.a0.a1.a1.a0;
  result.a2.a0.a2 = a2.a0.a2;
  result.a2.a0.a3.a0.a0 = a2.a0.a3.a0.a0;
  result.a2.a0.a3.a1 = a2.a0.a3.a1;
  result.a2.a0.a4 = a2.a0.a4;
  result.a2.a0.a5.a0.a0 = a2.a0.a5.a0.a0;
  result.a2.a0.a5.a1.a0 = a2.a0.a5.a1.a0;
  result.a2.a0.a6 = a2.a0.a6;
  result.a2.a1.a0.a0 = a2.a1.a0.a0;
  result.a2.a1.a0.a1 = a2.a1.a0.a1;
  result.a2.a1.a1.a0 = a2.a1.a1.a0;
  result.a2.a2 = a2.a2;
  result.a2.a3 = a2.a3;
  result.a3 = a3;

  std::cout << "result = " << "(" << result.a0 << ", ((" << result.a1.a0.a0
            << ", ((" << result.a1.a0.a1.a0.a0 << ", " << result.a1.a0.a1.a0.a1
            << "), (" << result.a1.a0.a1.a1.a0 << ")), " << result.a1.a0.a2
            << ", ((" << result.a1.a0.a3.a0.a0 << "), " << result.a1.a0.a3.a1
            << "), " << result.a1.a0.a4 << ", ((" << result.a1.a0.a5.a0.a0
            << "), (" << result.a1.a0.a5.a1.a0 << ")), " << result.a1.a0.a6
            << "), ((" << result.a1.a1.a0.a0 << ", " << result.a1.a1.a0.a1
            << "), (" << result.a1.a1.a1.a0 << ")), " << result.a1.a2 << ", "
            << result.a1.a3 << "), ((" << result.a2.a0.a0 << ", (("
            << result.a2.a0.a1.a0.a0 << ", " << result.a2.a0.a1.a0.a1 << "), ("
            << result.a2.a0.a1.a1.a0 << ")), " << result.a2.a0.a2 << ", (("
            << result.a2.a0.a3.a0.a0 << "), " << result.a2.a0.a3.a1 << "), "
            << result.a2.a0.a4 << ", ((" << result.a2.a0.a5.a0.a0 << "), ("
            << result.a2.a0.a5.a1.a0 << ")), " << result.a2.a0.a6 << "), (("
            << result.a2.a1.a0.a0 << ", " << result.a2.a1.a0.a1 << "), ("
            << result.a2.a1.a1.a0 << ")), " << result.a2.a2 << ", "
            << result.a2.a3 << "), " << result.a3 << ")" << "\n";

  return result;
}

// Used for testing structs and unions 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 and unions by value.
// Not a multiple of word size, not a power of two.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct3BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct3BytesHomogeneousUint8 a0,
                 Struct3BytesHomogeneousUint8 a1,
                 Struct3BytesHomogeneousUint8 a2,
                 Struct3BytesHomogeneousUint8 a3,
                 Struct3BytesHomogeneousUint8 a4,
                 Struct3BytesHomogeneousUint8 a5,
                 Struct3BytesHomogeneousUint8 a6,
                 Struct3BytesHomogeneousUint8 a7,
                 Struct3BytesHomogeneousUint8 a8,
                 Struct3BytesHomogeneousUint8 a9)) {
  Struct3BytesHomogeneousUint8 a0 = {};
  Struct3BytesHomogeneousUint8 a1 = {};
  Struct3BytesHomogeneousUint8 a2 = {};
  Struct3BytesHomogeneousUint8 a3 = {};
  Struct3BytesHomogeneousUint8 a4 = {};
  Struct3BytesHomogeneousUint8 a5 = {};
  Struct3BytesHomogeneousUint8 a6 = {};
  Struct3BytesHomogeneousUint8 a7 = {};
  Struct3BytesHomogeneousUint8 a8 = {};
  Struct3BytesHomogeneousUint8 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 TestPassStruct3BytesHomogeneousUint8x10(" << "(("
            << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
            << ", " << static_cast<int>(a0.a2) << "), ("
            << static_cast<int>(a1.a0) << ", " << static_cast<int>(a1.a1)
            << ", " << static_cast<int>(a1.a2) << "), ("
            << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
            << ", " << static_cast<int>(a2.a2) << "), ("
            << static_cast<int>(a3.a0) << ", " << static_cast<int>(a3.a1)
            << ", " << static_cast<int>(a3.a2) << "), ("
            << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
            << ", " << static_cast<int>(a4.a2) << "), ("
            << static_cast<int>(a5.a0) << ", " << static_cast<int>(a5.a1)
            << ", " << static_cast<int>(a5.a2) << "), ("
            << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
            << ", " << static_cast<int>(a6.a2) << "), ("
            << static_cast<int>(a7.a0) << ", " << static_cast<int>(a7.a1)
            << ", " << static_cast<int>(a7.a2) << "), ("
            << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
            << ", " << static_cast<int>(a8.a2) << "), ("
            << static_cast<int>(a9.a0) << ", " << static_cast<int>(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(465, 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 and unions by value.
// Not a multiple of word size, not a power of two.
// With alignment rules taken into account size is 4 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct3BytesInt2ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct3BytesInt2ByteAligned a0,
                 Struct3BytesInt2ByteAligned a1,
                 Struct3BytesInt2ByteAligned a2,
                 Struct3BytesInt2ByteAligned a3,
                 Struct3BytesInt2ByteAligned a4,
                 Struct3BytesInt2ByteAligned a5,
                 Struct3BytesInt2ByteAligned a6,
                 Struct3BytesInt2ByteAligned a7,
                 Struct3BytesInt2ByteAligned a8,
                 Struct3BytesInt2ByteAligned a9)) {
  Struct3BytesInt2ByteAligned a0 = {};
  Struct3BytesInt2ByteAligned a1 = {};
  Struct3BytesInt2ByteAligned a2 = {};
  Struct3BytesInt2ByteAligned a3 = {};
  Struct3BytesInt2ByteAligned a4 = {};
  Struct3BytesInt2ByteAligned a5 = {};
  Struct3BytesInt2ByteAligned a6 = {};
  Struct3BytesInt2ByteAligned a7 = {};
  Struct3BytesInt2ByteAligned a8 = {};
  Struct3BytesInt2ByteAligned 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 TestPassStruct3BytesInt2ByteAlignedx10(" << "(("
            << 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 and unions 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 and unions by value.
// Sub word size on 64 bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct7BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct7BytesHomogeneousUint8 a0,
                 Struct7BytesHomogeneousUint8 a1,
                 Struct7BytesHomogeneousUint8 a2,
                 Struct7BytesHomogeneousUint8 a3,
                 Struct7BytesHomogeneousUint8 a4,
                 Struct7BytesHomogeneousUint8 a5,
                 Struct7BytesHomogeneousUint8 a6,
                 Struct7BytesHomogeneousUint8 a7,
                 Struct7BytesHomogeneousUint8 a8,
                 Struct7BytesHomogeneousUint8 a9)) {
  Struct7BytesHomogeneousUint8 a0 = {};
  Struct7BytesHomogeneousUint8 a1 = {};
  Struct7BytesHomogeneousUint8 a2 = {};
  Struct7BytesHomogeneousUint8 a3 = {};
  Struct7BytesHomogeneousUint8 a4 = {};
  Struct7BytesHomogeneousUint8 a5 = {};
  Struct7BytesHomogeneousUint8 a6 = {};
  Struct7BytesHomogeneousUint8 a7 = {};
  Struct7BytesHomogeneousUint8 a8 = {};
  Struct7BytesHomogeneousUint8 a9 = {};

  a0.a0 = 1;
  a0.a1 = 2;
  a0.a2 = 3;
  a0.a3 = 4;
  a0.a4 = 5;
  a0.a5 = 6;
  a0.a6 = 7;
  a1.a0 = 8;
  a1.a1 = 9;
  a1.a2 = 10;
  a1.a3 = 11;
  a1.a4 = 12;
  a1.a5 = 13;
  a1.a6 = 14;
  a2.a0 = 15;
  a2.a1 = 16;
  a2.a2 = 17;
  a2.a3 = 18;
  a2.a4 = 19;
  a2.a5 = 20;
  a2.a6 = 21;
  a3.a0 = 22;
  a3.a1 = 23;
  a3.a2 = 24;
  a3.a3 = 25;
  a3.a4 = 26;
  a3.a5 = 27;
  a3.a6 = 28;
  a4.a0 = 29;
  a4.a1 = 30;
  a4.a2 = 31;
  a4.a3 = 32;
  a4.a4 = 33;
  a4.a5 = 34;
  a4.a6 = 35;
  a5.a0 = 36;
  a5.a1 = 37;
  a5.a2 = 38;
  a5.a3 = 39;
  a5.a4 = 40;
  a5.a5 = 41;
  a5.a6 = 42;
  a6.a0 = 43;
  a6.a1 = 44;
  a6.a2 = 45;
  a6.a3 = 46;
  a6.a4 = 47;
  a6.a5 = 48;
  a6.a6 = 49;
  a7.a0 = 50;
  a7.a1 = 51;
  a7.a2 = 52;
  a7.a3 = 53;
  a7.a4 = 54;
  a7.a5 = 55;
  a7.a6 = 56;
  a8.a0 = 57;
  a8.a1 = 58;
  a8.a2 = 59;
  a8.a3 = 60;
  a8.a4 = 61;
  a8.a5 = 62;
  a8.a6 = 63;
  a9.a0 = 64;
  a9.a1 = 65;
  a9.a2 = 66;
  a9.a3 = 67;
  a9.a4 = 68;
  a9.a5 = 69;
  a9.a6 = 70;

  std::cout
      << "Calling TestPassStruct7BytesHomogeneousUint8x10(" << "(("
      << 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>(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>(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>(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>(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>(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>(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>(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>(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>(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) << "))"
      << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(2485, 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 and unions by value.
// Sub word size on 64 bit architectures.
// With alignment rules taken into account size is 8 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct7BytesInt4ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct7BytesInt4ByteAligned a0,
                 Struct7BytesInt4ByteAligned a1,
                 Struct7BytesInt4ByteAligned a2,
                 Struct7BytesInt4ByteAligned a3,
                 Struct7BytesInt4ByteAligned a4,
                 Struct7BytesInt4ByteAligned a5,
                 Struct7BytesInt4ByteAligned a6,
                 Struct7BytesInt4ByteAligned a7,
                 Struct7BytesInt4ByteAligned a8,
                 Struct7BytesInt4ByteAligned a9)) {
  Struct7BytesInt4ByteAligned a0 = {};
  Struct7BytesInt4ByteAligned a1 = {};
  Struct7BytesInt4ByteAligned a2 = {};
  Struct7BytesInt4ByteAligned a3 = {};
  Struct7BytesInt4ByteAligned a4 = {};
  Struct7BytesInt4ByteAligned a5 = {};
  Struct7BytesInt4ByteAligned a6 = {};
  Struct7BytesInt4ByteAligned a7 = {};
  Struct7BytesInt4ByteAligned a8 = {};
  Struct7BytesInt4ByteAligned 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 TestPassStruct7BytesInt4ByteAlignedx10(" << "(("
            << 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 and unions 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 and unions 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 and unions 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 and unions 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.
// Tests upper bytes in the integer registers that are partly filled.
// Tests stack alignment of non word size stack arguments.
DART_EXPORT intptr_t TestPassStruct9BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct9BytesHomogeneousUint8 a0,
                 Struct9BytesHomogeneousUint8 a1,
                 Struct9BytesHomogeneousUint8 a2,
                 Struct9BytesHomogeneousUint8 a3,
                 Struct9BytesHomogeneousUint8 a4,
                 Struct9BytesHomogeneousUint8 a5,
                 Struct9BytesHomogeneousUint8 a6,
                 Struct9BytesHomogeneousUint8 a7,
                 Struct9BytesHomogeneousUint8 a8,
                 Struct9BytesHomogeneousUint8 a9)) {
  Struct9BytesHomogeneousUint8 a0 = {};
  Struct9BytesHomogeneousUint8 a1 = {};
  Struct9BytesHomogeneousUint8 a2 = {};
  Struct9BytesHomogeneousUint8 a3 = {};
  Struct9BytesHomogeneousUint8 a4 = {};
  Struct9BytesHomogeneousUint8 a5 = {};
  Struct9BytesHomogeneousUint8 a6 = {};
  Struct9BytesHomogeneousUint8 a7 = {};
  Struct9BytesHomogeneousUint8 a8 = {};
  Struct9BytesHomogeneousUint8 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 TestPassStruct9BytesHomogeneousUint8x10(" << "(("
      << 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 and unions by value.
// Argument is a single byte over a multiple of word size.
// With alignment rules taken into account size is 12 or 16 bytes.
// 10 struct arguments will exhaust available registers.
//
DART_EXPORT intptr_t TestPassStruct9BytesInt4Or8ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct9BytesInt4Or8ByteAligned a0,
                 Struct9BytesInt4Or8ByteAligned a1,
                 Struct9BytesInt4Or8ByteAligned a2,
                 Struct9BytesInt4Or8ByteAligned a3,
                 Struct9BytesInt4Or8ByteAligned a4,
                 Struct9BytesInt4Or8ByteAligned a5,
                 Struct9BytesInt4Or8ByteAligned a6,
                 Struct9BytesInt4Or8ByteAligned a7,
                 Struct9BytesInt4Or8ByteAligned a8,
                 Struct9BytesInt4Or8ByteAligned a9)) {
  Struct9BytesInt4Or8ByteAligned a0 = {};
  Struct9BytesInt4Or8ByteAligned a1 = {};
  Struct9BytesInt4Or8ByteAligned a2 = {};
  Struct9BytesInt4Or8ByteAligned a3 = {};
  Struct9BytesInt4Or8ByteAligned a4 = {};
  Struct9BytesInt4Or8ByteAligned a5 = {};
  Struct9BytesInt4Or8ByteAligned a6 = {};
  Struct9BytesInt4Or8ByteAligned a7 = {};
  Struct9BytesInt4Or8ByteAligned a8 = {};
  Struct9BytesInt4Or8ByteAligned 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 TestPassStruct9BytesInt4Or8ByteAlignedx10(" << "(("
            << 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT intptr_t TestPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*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,
                double a8,
                double a9,
                double a10,
                double a11,
                double a12,
                double a13,
                double a14,
                double a15,
                int64_t a16,
                int8_t a17,
                Struct1ByteInt a18,
                int64_t a19,
                int8_t a20,
                Struct4BytesHomogeneousInt16 a21,
                int64_t a22,
                int8_t a23,
                Struct8BytesInt a24,
                int64_t a25,
                int8_t a26,
                Struct8BytesHomogeneousFloat a27,
                int64_t a28,
                int8_t a29,
                Struct8BytesMixed a30,
                int64_t a31,
                int8_t a32,
                StructAlignmentInt16 a33,
                int64_t a34,
                int8_t a35,
                StructAlignmentInt32 a36,
                int64_t a37,
                int8_t a38,
                StructAlignmentInt64 a39)) {
  int32_t a0;
  int32_t a1;
  int32_t a2;
  int32_t a3;
  int32_t a4;
  int32_t a5;
  int32_t a6;
  int32_t a7;
  double a8;
  double a9;
  double a10;
  double a11;
  double a12;
  double a13;
  double a14;
  double a15;
  int64_t a16;
  int8_t a17;
  Struct1ByteInt a18 = {};
  int64_t a19;
  int8_t a20;
  Struct4BytesHomogeneousInt16 a21 = {};
  int64_t a22;
  int8_t a23;
  Struct8BytesInt a24 = {};
  int64_t a25;
  int8_t a26;
  Struct8BytesHomogeneousFloat a27 = {};
  int64_t a28;
  int8_t a29;
  Struct8BytesMixed a30 = {};
  int64_t a31;
  int8_t a32;
  StructAlignmentInt16 a33 = {};
  int64_t a34;
  int8_t a35;
  StructAlignmentInt32 a36 = {};
  int64_t a37;
  int8_t a38;
  StructAlignmentInt64 a39 = {};

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;
  a5 = 6;
  a6 = -7;
  a7 = 8;
  a8 = -9.0;
  a9 = 10.0;
  a10 = -11.0;
  a11 = 12.0;
  a12 = -13.0;
  a13 = 14.0;
  a14 = -15.0;
  a15 = 16.0;
  a16 = -17;
  a17 = 18;
  a18.a0 = -19;
  a19 = 20;
  a20 = -21;
  a21.a0 = 22;
  a21.a1 = -23;
  a22 = 24;
  a23 = -25;
  a24.a0 = 26;
  a24.a1 = -27;
  a24.a2 = 28;
  a25 = -29;
  a26 = 30;
  a27.a0 = -31.0;
  a27.a1 = 32.0;
  a28 = -33;
  a29 = 34;
  a30.a0 = -35.0;
  a30.a1 = 36;
  a30.a2 = -37;
  a31 = 38;
  a32 = -39;
  a33.a0 = 40;
  a33.a1 = -41;
  a33.a2 = 42;
  a34 = -43;
  a35 = 44;
  a36.a0 = -45;
  a36.a1 = 46;
  a36.a2 = -47;
  a37 = 48;
  a38 = -49;
  a39.a0 = 50;
  a39.a1 = -51;
  a39.a2 = 52;

  std::cout << "Calling TestPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", " << a7 << ", " << a8 << ", "
            << a9 << ", " << a10 << ", " << a11 << ", " << a12 << ", " << a13
            << ", " << a14 << ", " << a15 << ", " << a16 << ", "
            << static_cast<int>(a17) << ", (" << static_cast<int>(a18.a0)
            << "), " << a19 << ", " << static_cast<int>(a20) << ", (" << a21.a0
            << ", " << a21.a1 << "), " << a22 << ", " << static_cast<int>(a23)
            << ", (" << a24.a0 << ", " << a24.a1 << ", " << a24.a2 << "), "
            << a25 << ", " << static_cast<int>(a26) << ", (" << a27.a0 << ", "
            << a27.a1 << "), " << a28 << ", " << static_cast<int>(a29) << ", ("
            << a30.a0 << ", " << a30.a1 << ", " << a30.a2 << "), " << a31
            << ", " << static_cast<int>(a32) << ", ("
            << static_cast<int>(a33.a0) << ", " << a33.a1 << ", "
            << static_cast<int>(a33.a2) << "), " << a34 << ", "
            << static_cast<int>(a35) << ", (" << static_cast<int>(a36.a0)
            << ", " << a36.a1 << ", " << static_cast<int>(a36.a2) << "), "
            << a37 << ", " << static_cast<int>(a38) << ", ("
            << static_cast<int>(a39.a0) << ", " << a39.a1 << ", "
            << static_cast<int>(a39.a2) << "))" << ")\n";

  double 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);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(26.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, 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);

  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, 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);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct8BytesNestedInt a0,
                 Struct8BytesNestedInt a1,
                 Struct8BytesNestedInt a2,
                 Struct8BytesNestedInt a3,
                 Struct8BytesNestedInt a4,
                 Struct8BytesNestedInt a5,
                 Struct8BytesNestedInt a6,
                 Struct8BytesNestedInt a7,
                 Struct8BytesNestedInt a8,
                 Struct8BytesNestedInt a9)) {
  Struct8BytesNestedInt a0 = {};
  Struct8BytesNestedInt a1 = {};
  Struct8BytesNestedInt a2 = {};
  Struct8BytesNestedInt a3 = {};
  Struct8BytesNestedInt a4 = {};
  Struct8BytesNestedInt a5 = {};
  Struct8BytesNestedInt a6 = {};
  Struct8BytesNestedInt a7 = {};
  Struct8BytesNestedInt a8 = {};
  Struct8BytesNestedInt a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3;
  a0.a1.a1 = 4;
  a1.a0.a0 = -5;
  a1.a0.a1 = 6;
  a1.a1.a0 = -7;
  a1.a1.a1 = 8;
  a2.a0.a0 = -9;
  a2.a0.a1 = 10;
  a2.a1.a0 = -11;
  a2.a1.a1 = 12;
  a3.a0.a0 = -13;
  a3.a0.a1 = 14;
  a3.a1.a0 = -15;
  a3.a1.a1 = 16;
  a4.a0.a0 = -17;
  a4.a0.a1 = 18;
  a4.a1.a0 = -19;
  a4.a1.a1 = 20;
  a5.a0.a0 = -21;
  a5.a0.a1 = 22;
  a5.a1.a0 = -23;
  a5.a1.a1 = 24;
  a6.a0.a0 = -25;
  a6.a0.a1 = 26;
  a6.a1.a0 = -27;
  a6.a1.a1 = 28;
  a7.a0.a0 = -29;
  a7.a0.a1 = 30;
  a7.a1.a0 = -31;
  a7.a1.a1 = 32;
  a8.a0.a0 = -33;
  a8.a0.a1 = 34;
  a8.a1.a0 = -35;
  a8.a1.a1 = 36;
  a9.a0.a0 = -37;
  a9.a0.a1 = 38;
  a9.a1.a0 = -39;
  a9.a1.a1 = 40;

  std::cout << "Calling TestPassStruct8BytesNestedIntx10(" << "(((" << a0.a0.a0
            << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ", " << a0.a1.a1
            << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0
            << ", " << a1.a1.a1 << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1
            << "), (" << a2.a1.a0 << ", " << a2.a1.a1 << ")), ((" << a3.a0.a0
            << ", " << a3.a0.a1 << "), (" << a3.a1.a0 << ", " << a3.a1.a1
            << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0
            << ", " << a4.a1.a1 << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1
            << "), (" << a5.a1.a0 << ", " << a5.a1.a1 << ")), ((" << a6.a0.a0
            << ", " << a6.a0.a1 << "), (" << a6.a1.a0 << ", " << a6.a1.a1
            << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0
            << ", " << a7.a1.a1 << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1
            << "), (" << a8.a1.a0 << ", " << a8.a1.a1 << ")), ((" << a9.a0.a0
            << ", " << a9.a0.a1 << "), (" << a9.a1.a0 << ", " << a9.a1.a1
            << ")))" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(20, result);

  // Pass argument that will make the Dart callback throw.
  a0.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.a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    float (*f)(Struct8BytesNestedFloat a0,
               Struct8BytesNestedFloat a1,
               Struct8BytesNestedFloat a2,
               Struct8BytesNestedFloat a3,
               Struct8BytesNestedFloat a4,
               Struct8BytesNestedFloat a5,
               Struct8BytesNestedFloat a6,
               Struct8BytesNestedFloat a7,
               Struct8BytesNestedFloat a8,
               Struct8BytesNestedFloat a9)) {
  Struct8BytesNestedFloat a0 = {};
  Struct8BytesNestedFloat a1 = {};
  Struct8BytesNestedFloat a2 = {};
  Struct8BytesNestedFloat a3 = {};
  Struct8BytesNestedFloat a4 = {};
  Struct8BytesNestedFloat a5 = {};
  Struct8BytesNestedFloat a6 = {};
  Struct8BytesNestedFloat a7 = {};
  Struct8BytesNestedFloat a8 = {};
  Struct8BytesNestedFloat a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1.a0 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a1.a0 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a1.a0 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a1.a0 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a1.a0 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a1.a0 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a1.a0 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a1.a0 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a1.a0 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a1.a0 = 20.0;

  std::cout << "Calling TestPassStruct8BytesNestedFloatx10(" << "((("
            << a0.a0.a0 << "), (" << a0.a1.a0 << ")), ((" << a1.a0.a0 << "), ("
            << a1.a1.a0 << ")), ((" << a2.a0.a0 << "), (" << a2.a1.a0
            << ")), ((" << a3.a0.a0 << "), (" << a3.a1.a0 << ")), (("
            << a4.a0.a0 << "), (" << a4.a1.a0 << ")), ((" << a5.a0.a0 << "), ("
            << a5.a1.a0 << ")), ((" << a6.a0.a0 << "), (" << a6.a1.a0
            << ")), ((" << a7.a0.a0 << "), (" << a7.a1.a0 << ")), (("
            << a8.a0.a0 << "), (" << a8.a1.a0 << ")), ((" << a9.a0.a0 << "), ("
            << a9.a1.a0 << ")))" << ")\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.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.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 and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT intptr_t TestPassStruct8BytesNestedFloat2x10(
    // NOLINTNEXTLINE(whitespace/parens)
    float (*f)(Struct8BytesNestedFloat2 a0,
               Struct8BytesNestedFloat2 a1,
               Struct8BytesNestedFloat2 a2,
               Struct8BytesNestedFloat2 a3,
               Struct8BytesNestedFloat2 a4,
               Struct8BytesNestedFloat2 a5,
               Struct8BytesNestedFloat2 a6,
               Struct8BytesNestedFloat2 a7,
               Struct8BytesNestedFloat2 a8,
               Struct8BytesNestedFloat2 a9)) {
  Struct8BytesNestedFloat2 a0 = {};
  Struct8BytesNestedFloat2 a1 = {};
  Struct8BytesNestedFloat2 a2 = {};
  Struct8BytesNestedFloat2 a3 = {};
  Struct8BytesNestedFloat2 a4 = {};
  Struct8BytesNestedFloat2 a5 = {};
  Struct8BytesNestedFloat2 a6 = {};
  Struct8BytesNestedFloat2 a7 = {};
  Struct8BytesNestedFloat2 a8 = {};
  Struct8BytesNestedFloat2 a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a1 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a1 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a1 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a1 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a1 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a1 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a1 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a1 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a1 = 20.0;

  std::cout << "Calling TestPassStruct8BytesNestedFloat2x10(" << "((("
            << a0.a0.a0 << "), " << a0.a1 << "), ((" << a1.a0.a0 << "), "
            << a1.a1 << "), ((" << a2.a0.a0 << "), " << a2.a1 << "), (("
            << a3.a0.a0 << "), " << a3.a1 << "), ((" << a4.a0.a0 << "), "
            << a4.a1 << "), ((" << a5.a0.a0 << "), " << a5.a1 << "), (("
            << a6.a0.a0 << "), " << a6.a1 << "), ((" << a7.a0.a0 << "), "
            << a7.a1 << "), ((" << a8.a0.a0 << "), " << a8.a1 << "), (("
            << a9.a0.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.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.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 and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust all registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Struct8BytesNestedMixed a0,
                Struct8BytesNestedMixed a1,
                Struct8BytesNestedMixed a2,
                Struct8BytesNestedMixed a3,
                Struct8BytesNestedMixed a4,
                Struct8BytesNestedMixed a5,
                Struct8BytesNestedMixed a6,
                Struct8BytesNestedMixed a7,
                Struct8BytesNestedMixed a8,
                Struct8BytesNestedMixed a9)) {
  Struct8BytesNestedMixed a0 = {};
  Struct8BytesNestedMixed a1 = {};
  Struct8BytesNestedMixed a2 = {};
  Struct8BytesNestedMixed a3 = {};
  Struct8BytesNestedMixed a4 = {};
  Struct8BytesNestedMixed a5 = {};
  Struct8BytesNestedMixed a6 = {};
  Struct8BytesNestedMixed a7 = {};
  Struct8BytesNestedMixed a8 = {};
  Struct8BytesNestedMixed a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3.0;
  a1.a0.a0 = 4;
  a1.a0.a1 = -5;
  a1.a1.a0 = 6.0;
  a2.a0.a0 = -7;
  a2.a0.a1 = 8;
  a2.a1.a0 = -9.0;
  a3.a0.a0 = 10;
  a3.a0.a1 = -11;
  a3.a1.a0 = 12.0;
  a4.a0.a0 = -13;
  a4.a0.a1 = 14;
  a4.a1.a0 = -15.0;
  a5.a0.a0 = 16;
  a5.a0.a1 = -17;
  a5.a1.a0 = 18.0;
  a6.a0.a0 = -19;
  a6.a0.a1 = 20;
  a6.a1.a0 = -21.0;
  a7.a0.a0 = 22;
  a7.a0.a1 = -23;
  a7.a1.a0 = 24.0;
  a8.a0.a0 = -25;
  a8.a0.a1 = 26;
  a8.a1.a0 = -27.0;
  a9.a0.a0 = 28;
  a9.a0.a1 = -29;
  a9.a1.a0 = 30.0;

  std::cout << "Calling TestPassStruct8BytesNestedMixedx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ")), (("
            << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0 << ")), (("
            << a2.a0.a0 << ", " << a2.a0.a1 << "), (" << a2.a1.a0 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << "), (" << a3.a1.a0 << ")), (("
            << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0 << ")), (("
            << a5.a0.a0 << ", " << a5.a0.a1 << "), (" << a5.a1.a0 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << "), (" << a6.a1.a0 << ")), (("
            << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0 << ")), (("
            << a8.a0.a0 << ", " << a8.a0.a1 << "), (" << a8.a1.a0 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.a1 << "), (" << a9.a1.a0 << ")))"
            << ")\n";

  double 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.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.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 and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestPassStruct16BytesNestedIntx2(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct16BytesNestedInt a0, Struct16BytesNestedInt a1)) {
  Struct16BytesNestedInt a0 = {};
  Struct16BytesNestedInt a1 = {};

  a0.a0.a0.a0 = -1;
  a0.a0.a0.a1 = 2;
  a0.a0.a1.a0 = -3;
  a0.a0.a1.a1 = 4;
  a0.a1.a0.a0 = -5;
  a0.a1.a0.a1 = 6;
  a0.a1.a1.a0 = -7;
  a0.a1.a1.a1 = 8;
  a1.a0.a0.a0 = -9;
  a1.a0.a0.a1 = 10;
  a1.a0.a1.a0 = -11;
  a1.a0.a1.a1 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15;
  a1.a1.a1.a1 = 16;

  std::cout << "Calling TestPassStruct16BytesNestedIntx2(" << "(((("
            << a0.a0.a0.a0 << ", " << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0
            << ", " << a0.a0.a1.a1 << ")), ((" << a0.a1.a0.a0 << ", "
            << a0.a1.a0.a1 << "), (" << a0.a1.a1.a0 << ", " << a0.a1.a1.a1
            << "))), (((" << a1.a0.a0.a0 << ", " << a1.a0.a0.a1 << "), ("
            << a1.a0.a1.a0 << ", " << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0
            << ", " << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ", "
            << a1.a1.a1.a1 << "))))" << ")\n";

  int64_t result = f(a0, a1);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(8, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestPassStruct32BytesNestedIntx2(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct32BytesNestedInt a0, Struct32BytesNestedInt a1)) {
  Struct32BytesNestedInt a0 = {};
  Struct32BytesNestedInt a1 = {};

  a0.a0.a0.a0.a0 = -1;
  a0.a0.a0.a0.a1 = 2;
  a0.a0.a0.a1.a0 = -3;
  a0.a0.a0.a1.a1 = 4;
  a0.a0.a1.a0.a0 = -5;
  a0.a0.a1.a0.a1 = 6;
  a0.a0.a1.a1.a0 = -7;
  a0.a0.a1.a1.a1 = 8;
  a0.a1.a0.a0.a0 = -9;
  a0.a1.a0.a0.a1 = 10;
  a0.a1.a0.a1.a0 = -11;
  a0.a1.a0.a1.a1 = 12;
  a0.a1.a1.a0.a0 = -13;
  a0.a1.a1.a0.a1 = 14;
  a0.a1.a1.a1.a0 = -15;
  a0.a1.a1.a1.a1 = 16;
  a1.a0.a0.a0.a0 = -17;
  a1.a0.a0.a0.a1 = 18;
  a1.a0.a0.a1.a0 = -19;
  a1.a0.a0.a1.a1 = 20;
  a1.a0.a1.a0.a0 = -21;
  a1.a0.a1.a0.a1 = 22;
  a1.a0.a1.a1.a0 = -23;
  a1.a0.a1.a1.a1 = 24;
  a1.a1.a0.a0.a0 = -25;
  a1.a1.a0.a0.a1 = 26;
  a1.a1.a0.a1.a0 = -27;
  a1.a1.a0.a1.a1 = 28;
  a1.a1.a1.a0.a0 = -29;
  a1.a1.a1.a0.a1 = 30;
  a1.a1.a1.a1.a0 = -31;
  a1.a1.a1.a1.a1 = 32;

  std::cout << "Calling TestPassStruct32BytesNestedIntx2(" << "((((("
            << a0.a0.a0.a0.a0 << ", " << a0.a0.a0.a0.a1 << "), ("
            << a0.a0.a0.a1.a0 << ", " << a0.a0.a0.a1.a1 << ")), (("
            << a0.a0.a1.a0.a0 << ", " << a0.a0.a1.a0.a1 << "), ("
            << a0.a0.a1.a1.a0 << ", " << a0.a0.a1.a1.a1 << "))), ((("
            << a0.a1.a0.a0.a0 << ", " << a0.a1.a0.a0.a1 << "), ("
            << a0.a1.a0.a1.a0 << ", " << a0.a1.a0.a1.a1 << ")), (("
            << a0.a1.a1.a0.a0 << ", " << a0.a1.a1.a0.a1 << "), ("
            << a0.a1.a1.a1.a0 << ", " << a0.a1.a1.a1.a1 << ")))), (((("
            << a1.a0.a0.a0.a0 << ", " << a1.a0.a0.a0.a1 << "), ("
            << a1.a0.a0.a1.a0 << ", " << a1.a0.a0.a1.a1 << ")), (("
            << a1.a0.a1.a0.a0 << ", " << a1.a0.a1.a0.a1 << "), ("
            << a1.a0.a1.a1.a0 << ", " << a1.a0.a1.a1.a1 << "))), ((("
            << a1.a1.a0.a0.a0 << ", " << a1.a1.a0.a0.a1 << "), ("
            << a1.a1.a0.a1.a0 << ", " << a1.a1.a0.a1.a1 << ")), (("
            << a1.a1.a1.a0.a0 << ", " << a1.a1.a1.a0.a1 << "), ("
            << a1.a1.a1.a1.a0 << ", " << a1.a1.a1.a1.a1 << ")))))" << ")\n";

  int64_t result = f(a0, a1);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(16, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0.a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0.a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructNestedIntStructAlignmentInt16 a0)) {
  StructNestedIntStructAlignmentInt16 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestPassStructNestedIntStructAlignmentInt16(" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(3, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructNestedIntStructAlignmentInt32 a0)) {
  StructNestedIntStructAlignmentInt32 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestPassStructNestedIntStructAlignmentInt32(" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(3, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructNestedIntStructAlignmentInt64 a0)) {
  StructNestedIntStructAlignmentInt64 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestPassStructNestedIntStructAlignmentInt64(" << "((("
            << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(3, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT intptr_t TestPassStructNestedIrregularEvenBiggerx4(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(StructNestedIrregularEvenBigger a0,
                StructNestedIrregularEvenBigger a1,
                StructNestedIrregularEvenBigger a2,
                StructNestedIrregularEvenBigger a3)) {
  StructNestedIrregularEvenBigger a0 = {};
  StructNestedIrregularEvenBigger a1 = {};
  StructNestedIrregularEvenBigger a2 = {};
  StructNestedIrregularEvenBigger a3 = {};

  a0.a0 = 1;
  a0.a1.a0.a0 = 2;
  a0.a1.a0.a1.a0.a0 = -3;
  a0.a1.a0.a1.a0.a1 = 4;
  a0.a1.a0.a1.a1.a0 = -5.0;
  a0.a1.a0.a2 = 6;
  a0.a1.a0.a3.a0.a0 = -7.0;
  a0.a1.a0.a3.a1 = 8.0;
  a0.a1.a0.a4 = 9;
  a0.a1.a0.a5.a0.a0 = 10.0;
  a0.a1.a0.a5.a1.a0 = -11.0;
  a0.a1.a0.a6 = 12;
  a0.a1.a1.a0.a0 = -13;
  a0.a1.a1.a0.a1 = 14;
  a0.a1.a1.a1.a0 = -15.0;
  a0.a1.a2 = 16.0;
  a0.a1.a3 = -17.0;
  a0.a2.a0.a0 = 18;
  a0.a2.a0.a1.a0.a0 = -19;
  a0.a2.a0.a1.a0.a1 = 20;
  a0.a2.a0.a1.a1.a0 = -21.0;
  a0.a2.a0.a2 = 22;
  a0.a2.a0.a3.a0.a0 = -23.0;
  a0.a2.a0.a3.a1 = 24.0;
  a0.a2.a0.a4 = 25;
  a0.a2.a0.a5.a0.a0 = 26.0;
  a0.a2.a0.a5.a1.a0 = -27.0;
  a0.a2.a0.a6 = 28;
  a0.a2.a1.a0.a0 = -29;
  a0.a2.a1.a0.a1 = 30;
  a0.a2.a1.a1.a0 = -31.0;
  a0.a2.a2 = 32.0;
  a0.a2.a3 = -33.0;
  a0.a3 = 34.0;
  a1.a0 = 35;
  a1.a1.a0.a0 = 36;
  a1.a1.a0.a1.a0.a0 = -37;
  a1.a1.a0.a1.a0.a1 = 38;
  a1.a1.a0.a1.a1.a0 = -39.0;
  a1.a1.a0.a2 = 40;
  a1.a1.a0.a3.a0.a0 = -41.0;
  a1.a1.a0.a3.a1 = 42.0;
  a1.a1.a0.a4 = 43;
  a1.a1.a0.a5.a0.a0 = 44.0;
  a1.a1.a0.a5.a1.a0 = -45.0;
  a1.a1.a0.a6 = 46;
  a1.a1.a1.a0.a0 = -47;
  a1.a1.a1.a0.a1 = 48;
  a1.a1.a1.a1.a0 = -49.0;
  a1.a1.a2 = 50.0;
  a1.a1.a3 = -51.0;
  a1.a2.a0.a0 = 52;
  a1.a2.a0.a1.a0.a0 = -53;
  a1.a2.a0.a1.a0.a1 = 54;
  a1.a2.a0.a1.a1.a0 = -55.0;
  a1.a2.a0.a2 = 56;
  a1.a2.a0.a3.a0.a0 = -57.0;
  a1.a2.a0.a3.a1 = 58.0;
  a1.a2.a0.a4 = 59;
  a1.a2.a0.a5.a0.a0 = 60.0;
  a1.a2.a0.a5.a1.a0 = -61.0;
  a1.a2.a0.a6 = 62;
  a1.a2.a1.a0.a0 = -63;
  a1.a2.a1.a0.a1 = 64;
  a1.a2.a1.a1.a0 = -65.0;
  a1.a2.a2 = 66.0;
  a1.a2.a3 = -67.0;
  a1.a3 = 68.0;
  a2.a0 = 69;
  a2.a1.a0.a0 = 70;
  a2.a1.a0.a1.a0.a0 = -71;
  a2.a1.a0.a1.a0.a1 = 72;
  a2.a1.a0.a1.a1.a0 = -73.0;
  a2.a1.a0.a2 = 74;
  a2.a1.a0.a3.a0.a0 = -75.0;
  a2.a1.a0.a3.a1 = 76.0;
  a2.a1.a0.a4 = 77;
  a2.a1.a0.a5.a0.a0 = 78.0;
  a2.a1.a0.a5.a1.a0 = -79.0;
  a2.a1.a0.a6 = 80;
  a2.a1.a1.a0.a0 = -81;
  a2.a1.a1.a0.a1 = 82;
  a2.a1.a1.a1.a0 = -83.0;
  a2.a1.a2 = 84.0;
  a2.a1.a3 = -85.0;
  a2.a2.a0.a0 = 86;
  a2.a2.a0.a1.a0.a0 = -87;
  a2.a2.a0.a1.a0.a1 = 88;
  a2.a2.a0.a1.a1.a0 = -89.0;
  a2.a2.a0.a2 = 90;
  a2.a2.a0.a3.a0.a0 = -91.0;
  a2.a2.a0.a3.a1 = 92.0;
  a2.a2.a0.a4 = 93;
  a2.a2.a0.a5.a0.a0 = 94.0;
  a2.a2.a0.a5.a1.a0 = -95.0;
  a2.a2.a0.a6 = 96;
  a2.a2.a1.a0.a0 = -97;
  a2.a2.a1.a0.a1 = 98;
  a2.a2.a1.a1.a0 = -99.0;
  a2.a2.a2 = 100.0;
  a2.a2.a3 = -101.0;
  a2.a3 = 102.0;
  a3.a0 = 103;
  a3.a1.a0.a0 = 104;
  a3.a1.a0.a1.a0.a0 = -105;
  a3.a1.a0.a1.a0.a1 = 106;
  a3.a1.a0.a1.a1.a0 = -107.0;
  a3.a1.a0.a2 = 108;
  a3.a1.a0.a3.a0.a0 = -109.0;
  a3.a1.a0.a3.a1 = 110.0;
  a3.a1.a0.a4 = 111;
  a3.a1.a0.a5.a0.a0 = 112.0;
  a3.a1.a0.a5.a1.a0 = -113.0;
  a3.a1.a0.a6 = 114;
  a3.a1.a1.a0.a0 = -115;
  a3.a1.a1.a0.a1 = 116;
  a3.a1.a1.a1.a0 = -117.0;
  a3.a1.a2 = 118.0;
  a3.a1.a3 = -119.0;
  a3.a2.a0.a0 = 120;
  a3.a2.a0.a1.a0.a0 = -121;
  a3.a2.a0.a1.a0.a1 = 122;
  a3.a2.a0.a1.a1.a0 = -123.0;
  a3.a2.a0.a2 = 124;
  a3.a2.a0.a3.a0.a0 = -125.0;
  a3.a2.a0.a3.a1 = 126.0;
  a3.a2.a0.a4 = 127;
  a3.a2.a0.a5.a0.a0 = 128.0;
  a3.a2.a0.a5.a1.a0 = -129.0;
  a3.a2.a0.a6 = 130;
  a3.a2.a1.a0.a0 = -131;
  a3.a2.a1.a0.a1 = 132;
  a3.a2.a1.a1.a0 = -133.0;
  a3.a2.a2 = 134.0;
  a3.a2.a3 = -135.0;
  a3.a3 = 136.0;

  std::cout
      << "Calling TestPassStructNestedIrregularEvenBiggerx4(" << "((" << a0.a0
      << ", ((" << a0.a1.a0.a0 << ", ((" << a0.a1.a0.a1.a0.a0 << ", "
      << a0.a1.a0.a1.a0.a1 << "), (" << a0.a1.a0.a1.a1.a0 << ")), "
      << a0.a1.a0.a2 << ", ((" << a0.a1.a0.a3.a0.a0 << "), " << a0.a1.a0.a3.a1
      << "), " << a0.a1.a0.a4 << ", ((" << a0.a1.a0.a5.a0.a0 << "), ("
      << a0.a1.a0.a5.a1.a0 << ")), " << a0.a1.a0.a6 << "), ((" << a0.a1.a1.a0.a0
      << ", " << a0.a1.a1.a0.a1 << "), (" << a0.a1.a1.a1.a0 << ")), "
      << a0.a1.a2 << ", " << a0.a1.a3 << "), ((" << a0.a2.a0.a0 << ", (("
      << a0.a2.a0.a1.a0.a0 << ", " << a0.a2.a0.a1.a0.a1 << "), ("
      << a0.a2.a0.a1.a1.a0 << ")), " << a0.a2.a0.a2 << ", (("
      << a0.a2.a0.a3.a0.a0 << "), " << a0.a2.a0.a3.a1 << "), " << a0.a2.a0.a4
      << ", ((" << a0.a2.a0.a5.a0.a0 << "), (" << a0.a2.a0.a5.a1.a0 << ")), "
      << a0.a2.a0.a6 << "), ((" << a0.a2.a1.a0.a0 << ", " << a0.a2.a1.a0.a1
      << "), (" << a0.a2.a1.a1.a0 << ")), " << a0.a2.a2 << ", " << a0.a2.a3
      << "), " << a0.a3 << "), (" << a1.a0 << ", ((" << a1.a1.a0.a0 << ", (("
      << a1.a1.a0.a1.a0.a0 << ", " << a1.a1.a0.a1.a0.a1 << "), ("
      << a1.a1.a0.a1.a1.a0 << ")), " << a1.a1.a0.a2 << ", (("
      << a1.a1.a0.a3.a0.a0 << "), " << a1.a1.a0.a3.a1 << "), " << a1.a1.a0.a4
      << ", ((" << a1.a1.a0.a5.a0.a0 << "), (" << a1.a1.a0.a5.a1.a0 << ")), "
      << a1.a1.a0.a6 << "), ((" << a1.a1.a1.a0.a0 << ", " << a1.a1.a1.a0.a1
      << "), (" << a1.a1.a1.a1.a0 << ")), " << a1.a1.a2 << ", " << a1.a1.a3
      << "), ((" << a1.a2.a0.a0 << ", ((" << a1.a2.a0.a1.a0.a0 << ", "
      << a1.a2.a0.a1.a0.a1 << "), (" << a1.a2.a0.a1.a1.a0 << ")), "
      << a1.a2.a0.a2 << ", ((" << a1.a2.a0.a3.a0.a0 << "), " << a1.a2.a0.a3.a1
      << "), " << a1.a2.a0.a4 << ", ((" << a1.a2.a0.a5.a0.a0 << "), ("
      << a1.a2.a0.a5.a1.a0 << ")), " << a1.a2.a0.a6 << "), ((" << a1.a2.a1.a0.a0
      << ", " << a1.a2.a1.a0.a1 << "), (" << a1.a2.a1.a1.a0 << ")), "
      << a1.a2.a2 << ", " << a1.a2.a3 << "), " << a1.a3 << "), (" << a2.a0
      << ", ((" << a2.a1.a0.a0 << ", ((" << a2.a1.a0.a1.a0.a0 << ", "
      << a2.a1.a0.a1.a0.a1 << "), (" << a2.a1.a0.a1.a1.a0 << ")), "
      << a2.a1.a0.a2 << ", ((" << a2.a1.a0.a3.a0.a0 << "), " << a2.a1.a0.a3.a1
      << "), " << a2.a1.a0.a4 << ", ((" << a2.a1.a0.a5.a0.a0 << "), ("
      << a2.a1.a0.a5.a1.a0 << ")), " << a2.a1.a0.a6 << "), ((" << a2.a1.a1.a0.a0
      << ", " << a2.a1.a1.a0.a1 << "), (" << a2.a1.a1.a1.a0 << ")), "
      << a2.a1.a2 << ", " << a2.a1.a3 << "), ((" << a2.a2.a0.a0 << ", (("
      << a2.a2.a0.a1.a0.a0 << ", " << a2.a2.a0.a1.a0.a1 << "), ("
      << a2.a2.a0.a1.a1.a0 << ")), " << a2.a2.a0.a2 << ", (("
      << a2.a2.a0.a3.a0.a0 << "), " << a2.a2.a0.a3.a1 << "), " << a2.a2.a0.a4
      << ", ((" << a2.a2.a0.a5.a0.a0 << "), (" << a2.a2.a0.a5.a1.a0 << ")), "
      << a2.a2.a0.a6 << "), ((" << a2.a2.a1.a0.a0 << ", " << a2.a2.a1.a0.a1
      << "), (" << a2.a2.a1.a1.a0 << ")), " << a2.a2.a2 << ", " << a2.a2.a3
      << "), " << a2.a3 << "), (" << a3.a0 << ", ((" << a3.a1.a0.a0 << ", (("
      << a3.a1.a0.a1.a0.a0 << ", " << a3.a1.a0.a1.a0.a1 << "), ("
      << a3.a1.a0.a1.a1.a0 << ")), " << a3.a1.a0.a2 << ", (("
      << a3.a1.a0.a3.a0.a0 << "), " << a3.a1.a0.a3.a1 << "), " << a3.a1.a0.a4
      << ", ((" << a3.a1.a0.a5.a0.a0 << "), (" << a3.a1.a0.a5.a1.a0 << ")), "
      << a3.a1.a0.a6 << "), ((" << a3.a1.a1.a0.a0 << ", " << a3.a1.a1.a0.a1
      << "), (" << a3.a1.a1.a1.a0 << ")), " << a3.a1.a2 << ", " << a3.a1.a3
      << "), ((" << a3.a2.a0.a0 << ", ((" << a3.a2.a0.a1.a0.a0 << ", "
      << a3.a2.a0.a1.a0.a1 << "), (" << a3.a2.a0.a1.a1.a0 << ")), "
      << a3.a2.a0.a2 << ", ((" << a3.a2.a0.a3.a0.a0 << "), " << a3.a2.a0.a3.a1
      << "), " << a3.a2.a0.a4 << ", ((" << a3.a2.a0.a5.a0.a0 << "), ("
      << a3.a2.a0.a5.a1.a0 << ")), " << a3.a2.a0.a6 << "), ((" << a3.a2.a1.a0.a0
      << ", " << a3.a2.a1.a0.a1 << "), (" << a3.a2.a1.a1.a0 << ")), "
      << a3.a2.a2 << ", " << a3.a2.a3 << "), " << a3.a3 << "))" << ")\n";

  double result = f(a0, a1, a2, a3);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(1572.0, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1, a2, a3);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1, a2, a3);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Simple struct with inline array.
DART_EXPORT intptr_t TestPassStruct8BytesInlineArrayIntx4(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(Struct8BytesInlineArrayInt a0,
                 Struct8BytesInlineArrayInt a1,
                 Struct8BytesInlineArrayInt a2,
                 Struct8BytesInlineArrayInt a3)) {
  Struct8BytesInlineArrayInt a0 = {};
  Struct8BytesInlineArrayInt a1 = {};
  Struct8BytesInlineArrayInt a2 = {};
  Struct8BytesInlineArrayInt a3 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;
  a1.a0[0] = 9;
  a1.a0[1] = 10;
  a1.a0[2] = 11;
  a1.a0[3] = 12;
  a1.a0[4] = 13;
  a1.a0[5] = 14;
  a1.a0[6] = 15;
  a1.a0[7] = 16;
  a2.a0[0] = 17;
  a2.a0[1] = 18;
  a2.a0[2] = 19;
  a2.a0[3] = 20;
  a2.a0[4] = 21;
  a2.a0[5] = 22;
  a2.a0[6] = 23;
  a2.a0[7] = 24;
  a3.a0[0] = 25;
  a3.a0[1] = 26;
  a3.a0[2] = 27;
  a3.a0[3] = 28;
  a3.a0[4] = 29;
  a3.a0[5] = 30;
  a3.a0[6] = 31;
  a3.a0[7] = 32;

  std::cout << "Calling TestPassStruct8BytesInlineArrayIntx4(" << "((["
            << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
            << ", " << static_cast<int>(a0.a0[2]) << ", "
            << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
            << ", " << static_cast<int>(a0.a0[5]) << ", "
            << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
            << "]), ([" << static_cast<int>(a1.a0[0]) << ", "
            << static_cast<int>(a1.a0[1]) << ", " << static_cast<int>(a1.a0[2])
            << ", " << static_cast<int>(a1.a0[3]) << ", "
            << static_cast<int>(a1.a0[4]) << ", " << static_cast<int>(a1.a0[5])
            << ", " << static_cast<int>(a1.a0[6]) << ", "
            << static_cast<int>(a1.a0[7]) << "]), (["
            << static_cast<int>(a2.a0[0]) << ", " << static_cast<int>(a2.a0[1])
            << ", " << static_cast<int>(a2.a0[2]) << ", "
            << static_cast<int>(a2.a0[3]) << ", " << static_cast<int>(a2.a0[4])
            << ", " << static_cast<int>(a2.a0[5]) << ", "
            << static_cast<int>(a2.a0[6]) << ", " << static_cast<int>(a2.a0[7])
            << "]), ([" << static_cast<int>(a3.a0[0]) << ", "
            << static_cast<int>(a3.a0[1]) << ", " << static_cast<int>(a3.a0[2])
            << ", " << static_cast<int>(a3.a0[3]) << ", "
            << static_cast<int>(a3.a0[4]) << ", " << static_cast<int>(a3.a0[5])
            << ", " << static_cast<int>(a3.a0[6]) << ", "
            << static_cast<int>(a3.a0[7]) << "]))" << ")\n";

  int32_t result = f(a0, a1, a2, a3);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(528, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0[0] = 42;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0[0] = 84;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Irregular struct with inline array.
DART_EXPORT intptr_t TestPassStructInlineArrayIrregularx4(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(StructInlineArrayIrregular a0,
                 StructInlineArrayIrregular a1,
                 StructInlineArrayIrregular a2,
                 StructInlineArrayIrregular a3)) {
  StructInlineArrayIrregular a0 = {};
  StructInlineArrayIrregular a1 = {};
  StructInlineArrayIrregular a2 = {};
  StructInlineArrayIrregular a3 = {};

  a0.a0[0].a0 = -1;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3;
  a0.a0[1].a1 = 4;
  a0.a1 = 5;
  a1.a0[0].a0 = 6;
  a1.a0[0].a1 = -7;
  a1.a0[1].a0 = 8;
  a1.a0[1].a1 = -9;
  a1.a1 = 10;
  a2.a0[0].a0 = -11;
  a2.a0[0].a1 = 12;
  a2.a0[1].a0 = -13;
  a2.a0[1].a1 = 14;
  a2.a1 = 15;
  a3.a0[0].a0 = 16;
  a3.a0[0].a1 = -17;
  a3.a0[1].a0 = 18;
  a3.a0[1].a1 = -19;
  a3.a1 = 20;

  std::cout << "Calling TestPassStructInlineArrayIrregularx4(" << "(([("
            << a0.a0[0].a0 << ", " << static_cast<int>(a0.a0[0].a1) << "), ("
            << a0.a0[1].a0 << ", " << static_cast<int>(a0.a0[1].a1) << ")], "
            << static_cast<int>(a0.a1) << "), ([(" << a1.a0[0].a0 << ", "
            << static_cast<int>(a1.a0[0].a1) << "), (" << a1.a0[1].a0 << ", "
            << static_cast<int>(a1.a0[1].a1) << ")], "
            << static_cast<int>(a1.a1) << "), ([(" << a2.a0[0].a0 << ", "
            << static_cast<int>(a2.a0[0].a1) << "), (" << a2.a0[1].a0 << ", "
            << static_cast<int>(a2.a0[1].a1) << ")], "
            << static_cast<int>(a2.a1) << "), ([(" << a3.a0[0].a0 << ", "
            << static_cast<int>(a3.a0[0].a1) << "), (" << a3.a0[1].a0 << ", "
            << static_cast<int>(a3.a0[1].a1) << ")], "
            << static_cast<int>(a3.a1) << "))" << ")\n";

  int32_t result = f(a0, a1, a2, a3);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(50, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0[0].a0 = 42;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0[0].a0 = 84;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Regular larger struct with inline array.
DART_EXPORT intptr_t TestPassStructInlineArray100Bytes(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(StructInlineArray100Bytes a0)) {
  StructInlineArray100Bytes a0 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;
  a0.a0[8] = 9;
  a0.a0[9] = 10;
  a0.a0[10] = 11;
  a0.a0[11] = 12;
  a0.a0[12] = 13;
  a0.a0[13] = 14;
  a0.a0[14] = 15;
  a0.a0[15] = 16;
  a0.a0[16] = 17;
  a0.a0[17] = 18;
  a0.a0[18] = 19;
  a0.a0[19] = 20;
  a0.a0[20] = 21;
  a0.a0[21] = 22;
  a0.a0[22] = 23;
  a0.a0[23] = 24;
  a0.a0[24] = 25;
  a0.a0[25] = 26;
  a0.a0[26] = 27;
  a0.a0[27] = 28;
  a0.a0[28] = 29;
  a0.a0[29] = 30;
  a0.a0[30] = 31;
  a0.a0[31] = 32;
  a0.a0[32] = 33;
  a0.a0[33] = 34;
  a0.a0[34] = 35;
  a0.a0[35] = 36;
  a0.a0[36] = 37;
  a0.a0[37] = 38;
  a0.a0[38] = 39;
  a0.a0[39] = 40;
  a0.a0[40] = 41;
  a0.a0[41] = 42;
  a0.a0[42] = 43;
  a0.a0[43] = 44;
  a0.a0[44] = 45;
  a0.a0[45] = 46;
  a0.a0[46] = 47;
  a0.a0[47] = 48;
  a0.a0[48] = 49;
  a0.a0[49] = 50;
  a0.a0[50] = 51;
  a0.a0[51] = 52;
  a0.a0[52] = 53;
  a0.a0[53] = 54;
  a0.a0[54] = 55;
  a0.a0[55] = 56;
  a0.a0[56] = 57;
  a0.a0[57] = 58;
  a0.a0[58] = 59;
  a0.a0[59] = 60;
  a0.a0[60] = 61;
  a0.a0[61] = 62;
  a0.a0[62] = 63;
  a0.a0[63] = 64;
  a0.a0[64] = 65;
  a0.a0[65] = 66;
  a0.a0[66] = 67;
  a0.a0[67] = 68;
  a0.a0[68] = 69;
  a0.a0[69] = 70;
  a0.a0[70] = 71;
  a0.a0[71] = 72;
  a0.a0[72] = 73;
  a0.a0[73] = 74;
  a0.a0[74] = 75;
  a0.a0[75] = 76;
  a0.a0[76] = 77;
  a0.a0[77] = 78;
  a0.a0[78] = 79;
  a0.a0[79] = 80;
  a0.a0[80] = 81;
  a0.a0[81] = 82;
  a0.a0[82] = 83;
  a0.a0[83] = 84;
  a0.a0[84] = 85;
  a0.a0[85] = 86;
  a0.a0[86] = 87;
  a0.a0[87] = 88;
  a0.a0[88] = 89;
  a0.a0[89] = 90;
  a0.a0[90] = 91;
  a0.a0[91] = 92;
  a0.a0[92] = 93;
  a0.a0[93] = 94;
  a0.a0[94] = 95;
  a0.a0[95] = 96;
  a0.a0[96] = 97;
  a0.a0[97] = 98;
  a0.a0[98] = 99;
  a0.a0[99] = 100;

  std::cout
      << "Calling TestPassStructInlineArray100Bytes(" << "((["
      << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
      << ", " << static_cast<int>(a0.a0[2]) << ", "
      << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
      << ", " << static_cast<int>(a0.a0[5]) << ", "
      << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
      << ", " << static_cast<int>(a0.a0[8]) << ", "
      << static_cast<int>(a0.a0[9]) << ", " << static_cast<int>(a0.a0[10])
      << ", " << static_cast<int>(a0.a0[11]) << ", "
      << static_cast<int>(a0.a0[12]) << ", " << static_cast<int>(a0.a0[13])
      << ", " << static_cast<int>(a0.a0[14]) << ", "
      << static_cast<int>(a0.a0[15]) << ", " << static_cast<int>(a0.a0[16])
      << ", " << static_cast<int>(a0.a0[17]) << ", "
      << static_cast<int>(a0.a0[18]) << ", " << static_cast<int>(a0.a0[19])
      << ", " << static_cast<int>(a0.a0[20]) << ", "
      << static_cast<int>(a0.a0[21]) << ", " << static_cast<int>(a0.a0[22])
      << ", " << static_cast<int>(a0.a0[23]) << ", "
      << static_cast<int>(a0.a0[24]) << ", " << static_cast<int>(a0.a0[25])
      << ", " << static_cast<int>(a0.a0[26]) << ", "
      << static_cast<int>(a0.a0[27]) << ", " << static_cast<int>(a0.a0[28])
      << ", " << static_cast<int>(a0.a0[29]) << ", "
      << static_cast<int>(a0.a0[30]) << ", " << static_cast<int>(a0.a0[31])
      << ", " << static_cast<int>(a0.a0[32]) << ", "
      << static_cast<int>(a0.a0[33]) << ", " << static_cast<int>(a0.a0[34])
      << ", " << static_cast<int>(a0.a0[35]) << ", "
      << static_cast<int>(a0.a0[36]) << ", " << static_cast<int>(a0.a0[37])
      << ", " << static_cast<int>(a0.a0[38]) << ", "
      << static_cast<int>(a0.a0[39]) << ", " << static_cast<int>(a0.a0[40])
      << ", " << static_cast<int>(a0.a0[41]) << ", "
      << static_cast<int>(a0.a0[42]) << ", " << static_cast<int>(a0.a0[43])
      << ", " << static_cast<int>(a0.a0[44]) << ", "
      << static_cast<int>(a0.a0[45]) << ", " << static_cast<int>(a0.a0[46])
      << ", " << static_cast<int>(a0.a0[47]) << ", "
      << static_cast<int>(a0.a0[48]) << ", " << static_cast<int>(a0.a0[49])
      << ", " << static_cast<int>(a0.a0[50]) << ", "
      << static_cast<int>(a0.a0[51]) << ", " << static_cast<int>(a0.a0[52])
      << ", " << static_cast<int>(a0.a0[53]) << ", "
      << static_cast<int>(a0.a0[54]) << ", " << static_cast<int>(a0.a0[55])
      << ", " << static_cast<int>(a0.a0[56]) << ", "
      << static_cast<int>(a0.a0[57]) << ", " << static_cast<int>(a0.a0[58])
      << ", " << static_cast<int>(a0.a0[59]) << ", "
      << static_cast<int>(a0.a0[60]) << ", " << static_cast<int>(a0.a0[61])
      << ", " << static_cast<int>(a0.a0[62]) << ", "
      << static_cast<int>(a0.a0[63]) << ", " << static_cast<int>(a0.a0[64])
      << ", " << static_cast<int>(a0.a0[65]) << ", "
      << static_cast<int>(a0.a0[66]) << ", " << static_cast<int>(a0.a0[67])
      << ", " << static_cast<int>(a0.a0[68]) << ", "
      << static_cast<int>(a0.a0[69]) << ", " << static_cast<int>(a0.a0[70])
      << ", " << static_cast<int>(a0.a0[71]) << ", "
      << static_cast<int>(a0.a0[72]) << ", " << static_cast<int>(a0.a0[73])
      << ", " << static_cast<int>(a0.a0[74]) << ", "
      << static_cast<int>(a0.a0[75]) << ", " << static_cast<int>(a0.a0[76])
      << ", " << static_cast<int>(a0.a0[77]) << ", "
      << static_cast<int>(a0.a0[78]) << ", " << static_cast<int>(a0.a0[79])
      << ", " << static_cast<int>(a0.a0[80]) << ", "
      << static_cast<int>(a0.a0[81]) << ", " << static_cast<int>(a0.a0[82])
      << ", " << static_cast<int>(a0.a0[83]) << ", "
      << static_cast<int>(a0.a0[84]) << ", " << static_cast<int>(a0.a0[85])
      << ", " << static_cast<int>(a0.a0[86]) << ", "
      << static_cast<int>(a0.a0[87]) << ", " << static_cast<int>(a0.a0[88])
      << ", " << static_cast<int>(a0.a0[89]) << ", "
      << static_cast<int>(a0.a0[90]) << ", " << static_cast<int>(a0.a0[91])
      << ", " << static_cast<int>(a0.a0[92]) << ", "
      << static_cast<int>(a0.a0[93]) << ", " << static_cast<int>(a0.a0[94])
      << ", " << static_cast<int>(a0.a0[95]) << ", "
      << static_cast<int>(a0.a0[96]) << ", " << static_cast<int>(a0.a0[97])
      << ", " << static_cast<int>(a0.a0[98]) << ", "
      << static_cast<int>(a0.a0[99]) << "]))" << ")\n";

  int32_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(5050, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0[0] = 42;

  result = f(a0);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0[0] = 84;

  result = f(a0);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStructStruct16BytesHomogeneousFloat2x5(
    // NOLINTNEXTLINE(whitespace/parens)
    float (*f)(StructStruct16BytesHomogeneousFloat2 a0,
               StructStruct16BytesHomogeneousFloat2 a1,
               StructStruct16BytesHomogeneousFloat2 a2,
               StructStruct16BytesHomogeneousFloat2 a3,
               StructStruct16BytesHomogeneousFloat2 a4)) {
  StructStruct16BytesHomogeneousFloat2 a0 = {};
  StructStruct16BytesHomogeneousFloat2 a1 = {};
  StructStruct16BytesHomogeneousFloat2 a2 = {};
  StructStruct16BytesHomogeneousFloat2 a3 = {};
  StructStruct16BytesHomogeneousFloat2 a4 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;
  a1.a0.a0 = -5.0;
  a1.a1[0].a0 = 6.0;
  a1.a1[1].a0 = -7.0;
  a1.a2 = 8.0;
  a2.a0.a0 = -9.0;
  a2.a1[0].a0 = 10.0;
  a2.a1[1].a0 = -11.0;
  a2.a2 = 12.0;
  a3.a0.a0 = -13.0;
  a3.a1[0].a0 = 14.0;
  a3.a1[1].a0 = -15.0;
  a3.a2 = 16.0;
  a4.a0.a0 = -17.0;
  a4.a1[0].a0 = 18.0;
  a4.a1[1].a0 = -19.0;
  a4.a2 = 20.0;

  std::cout << "Calling TestPassStructStruct16BytesHomogeneousFloat2x5("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "), ((" << a1.a0.a0 << "), [("
            << a1.a1[0].a0 << "), (" << a1.a1[1].a0 << ")], " << a1.a2
            << "), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0 << "), ("
            << a2.a1[1].a0 << ")], " << a2.a2 << "), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << "), (" << a3.a1[1].a0 << ")], " << a3.a2
            << "), ((" << a4.a0.a0 << "), [(" << a4.a1[0].a0 << "), ("
            << a4.a1[1].a0 << ")], " << a4.a2 << "))" << ")\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.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.a0 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStructStruct32BytesHomogeneousDouble2x5(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(StructStruct32BytesHomogeneousDouble2 a0,
                StructStruct32BytesHomogeneousDouble2 a1,
                StructStruct32BytesHomogeneousDouble2 a2,
                StructStruct32BytesHomogeneousDouble2 a3,
                StructStruct32BytesHomogeneousDouble2 a4)) {
  StructStruct32BytesHomogeneousDouble2 a0 = {};
  StructStruct32BytesHomogeneousDouble2 a1 = {};
  StructStruct32BytesHomogeneousDouble2 a2 = {};
  StructStruct32BytesHomogeneousDouble2 a3 = {};
  StructStruct32BytesHomogeneousDouble2 a4 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;
  a1.a0.a0 = -5.0;
  a1.a1[0].a0 = 6.0;
  a1.a1[1].a0 = -7.0;
  a1.a2 = 8.0;
  a2.a0.a0 = -9.0;
  a2.a1[0].a0 = 10.0;
  a2.a1[1].a0 = -11.0;
  a2.a2 = 12.0;
  a3.a0.a0 = -13.0;
  a3.a1[0].a0 = 14.0;
  a3.a1[1].a0 = -15.0;
  a3.a2 = 16.0;
  a4.a0.a0 = -17.0;
  a4.a1[0].a0 = 18.0;
  a4.a1[1].a0 = -19.0;
  a4.a2 = 20.0;

  std::cout << "Calling TestPassStructStruct32BytesHomogeneousDouble2x5("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "), ((" << a1.a0.a0 << "), [("
            << a1.a1[0].a0 << "), (" << a1.a1[1].a0 << ")], " << a1.a2
            << "), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0 << "), ("
            << a2.a1[1].a0 << ")], " << a2.a2 << "), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << "), (" << a3.a1[1].a0 << ")], " << a3.a2
            << "), ((" << a4.a0.a0 << "), [(" << a4.a1[0].a0 << "), ("
            << a4.a1[1].a0 << ")], " << a4.a2 << "))" << ")\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.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.a0 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions 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 TestPassStructStruct16BytesMixed3x10(
    // NOLINTNEXTLINE(whitespace/parens)
    float (*f)(StructStruct16BytesMixed3 a0,
               StructStruct16BytesMixed3 a1,
               StructStruct16BytesMixed3 a2,
               StructStruct16BytesMixed3 a3,
               StructStruct16BytesMixed3 a4,
               StructStruct16BytesMixed3 a5,
               StructStruct16BytesMixed3 a6,
               StructStruct16BytesMixed3 a7,
               StructStruct16BytesMixed3 a8,
               StructStruct16BytesMixed3 a9)) {
  StructStruct16BytesMixed3 a0 = {};
  StructStruct16BytesMixed3 a1 = {};
  StructStruct16BytesMixed3 a2 = {};
  StructStruct16BytesMixed3 a3 = {};
  StructStruct16BytesMixed3 a4 = {};
  StructStruct16BytesMixed3 a5 = {};
  StructStruct16BytesMixed3 a6 = {};
  StructStruct16BytesMixed3 a7 = {};
  StructStruct16BytesMixed3 a8 = {};
  StructStruct16BytesMixed3 a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[0].a1 = -3;
  a0.a1[0].a2 = 4;
  a0.a2[0] = -5;
  a0.a2[1] = 6;
  a1.a0.a0 = -7.0;
  a1.a1[0].a0 = 8.0;
  a1.a1[0].a1 = -9;
  a1.a1[0].a2 = 10;
  a1.a2[0] = -11;
  a1.a2[1] = 12;
  a2.a0.a0 = -13.0;
  a2.a1[0].a0 = 14.0;
  a2.a1[0].a1 = -15;
  a2.a1[0].a2 = 16;
  a2.a2[0] = -17;
  a2.a2[1] = 18;
  a3.a0.a0 = -19.0;
  a3.a1[0].a0 = 20.0;
  a3.a1[0].a1 = -21;
  a3.a1[0].a2 = 22;
  a3.a2[0] = -23;
  a3.a2[1] = 24;
  a4.a0.a0 = -25.0;
  a4.a1[0].a0 = 26.0;
  a4.a1[0].a1 = -27;
  a4.a1[0].a2 = 28;
  a4.a2[0] = -29;
  a4.a2[1] = 30;
  a5.a0.a0 = -31.0;
  a5.a1[0].a0 = 32.0;
  a5.a1[0].a1 = -33;
  a5.a1[0].a2 = 34;
  a5.a2[0] = -35;
  a5.a2[1] = 36;
  a6.a0.a0 = -37.0;
  a6.a1[0].a0 = 38.0;
  a6.a1[0].a1 = -39;
  a6.a1[0].a2 = 40;
  a6.a2[0] = -41;
  a6.a2[1] = 42;
  a7.a0.a0 = -43.0;
  a7.a1[0].a0 = 44.0;
  a7.a1[0].a1 = -45;
  a7.a1[0].a2 = 46;
  a7.a2[0] = -47;
  a7.a2[1] = 48;
  a8.a0.a0 = -49.0;
  a8.a1[0].a0 = 50.0;
  a8.a1[0].a1 = -51;
  a8.a1[0].a2 = 52;
  a8.a2[0] = -53;
  a8.a2[1] = 54;
  a9.a0.a0 = -55.0;
  a9.a1[0].a0 = 56.0;
  a9.a1[0].a1 = -57;
  a9.a1[0].a2 = 58;
  a9.a2[0] = -59;
  a9.a2[1] = 60;

  std::cout << "Calling TestPassStructStruct16BytesMixed3x10(" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << ", " << a0.a1[0].a1 << ", "
            << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", " << a0.a2[1]
            << "]), ((" << a1.a0.a0 << "), [(" << a1.a1[0].a0 << ", "
            << a1.a1[0].a1 << ", " << a1.a1[0].a2 << ")], [" << a1.a2[0] << ", "
            << a1.a2[1] << "]), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0
            << ", " << a2.a1[0].a1 << ", " << a2.a1[0].a2 << ")], [" << a2.a2[0]
            << ", " << a2.a2[1] << "]), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << ", " << a3.a1[0].a1 << ", " << a3.a1[0].a2
            << ")], [" << a3.a2[0] << ", " << a3.a2[1] << "]), ((" << a4.a0.a0
            << "), [(" << a4.a1[0].a0 << ", " << a4.a1[0].a1 << ", "
            << a4.a1[0].a2 << ")], [" << a4.a2[0] << ", " << a4.a2[1]
            << "]), ((" << a5.a0.a0 << "), [(" << a5.a1[0].a0 << ", "
            << a5.a1[0].a1 << ", " << a5.a1[0].a2 << ")], [" << a5.a2[0] << ", "
            << a5.a2[1] << "]), ((" << a6.a0.a0 << "), [(" << a6.a1[0].a0
            << ", " << a6.a1[0].a1 << ", " << a6.a1[0].a2 << ")], [" << a6.a2[0]
            << ", " << a6.a2[1] << "]), ((" << a7.a0.a0 << "), [("
            << a7.a1[0].a0 << ", " << a7.a1[0].a1 << ", " << a7.a1[0].a2
            << ")], [" << a7.a2[0] << ", " << a7.a2[1] << "]), ((" << a8.a0.a0
            << "), [(" << a8.a1[0].a0 << ", " << a8.a1[0].a1 << ", "
            << a8.a1[0].a2 << ")], [" << a8.a2[0] << ", " << a8.a2[1]
            << "]), ((" << a9.a0.a0 << "), [(" << a9.a1[0].a0 << ", "
            << a9.a1[0].a1 << ", " << a9.a1[0].a2 << ")], [" << a9.a2[0] << ", "
            << a9.a2[1] << "]))" << ")\n";

  float result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(30.0, result);

  // Pass argument that will make the Dart callback throw.
  a0.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.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 and unions by value.
// Test multi dimensional inline array struct as argument.
DART_EXPORT intptr_t TestPassUint8Struct32BytesInlineArrayMultiDimensionalI(
    // NOLINTNEXTLINE(whitespace/parens)
    uint32_t (*f)(uint8_t a0,
                  Struct32BytesInlineArrayMultiDimensionalInt a1,
                  uint8_t a2,
                  Struct8BytesInlineArrayMultiDimensionalInt a3,
                  uint8_t a4,
                  Struct8BytesInlineArrayMultiDimensionalInt a5,
                  uint8_t a6)) {
  uint8_t a0;
  Struct32BytesInlineArrayMultiDimensionalInt a1 = {};
  uint8_t a2;
  Struct8BytesInlineArrayMultiDimensionalInt a3 = {};
  uint8_t a4;
  Struct8BytesInlineArrayMultiDimensionalInt a5 = {};
  uint8_t a6;

  a0 = 1;
  a1.a0[0][0][0][0][0] = 2;
  a1.a0[0][0][0][0][1] = 3;
  a1.a0[0][0][0][1][0] = 4;
  a1.a0[0][0][0][1][1] = 5;
  a1.a0[0][0][1][0][0] = 6;
  a1.a0[0][0][1][0][1] = 7;
  a1.a0[0][0][1][1][0] = 8;
  a1.a0[0][0][1][1][1] = 9;
  a1.a0[0][1][0][0][0] = 10;
  a1.a0[0][1][0][0][1] = 11;
  a1.a0[0][1][0][1][0] = 12;
  a1.a0[0][1][0][1][1] = 13;
  a1.a0[0][1][1][0][0] = 14;
  a1.a0[0][1][1][0][1] = 15;
  a1.a0[0][1][1][1][0] = 16;
  a1.a0[0][1][1][1][1] = 17;
  a1.a0[1][0][0][0][0] = 18;
  a1.a0[1][0][0][0][1] = 19;
  a1.a0[1][0][0][1][0] = 20;
  a1.a0[1][0][0][1][1] = 21;
  a1.a0[1][0][1][0][0] = 22;
  a1.a0[1][0][1][0][1] = 23;
  a1.a0[1][0][1][1][0] = 24;
  a1.a0[1][0][1][1][1] = 25;
  a1.a0[1][1][0][0][0] = 26;
  a1.a0[1][1][0][0][1] = 27;
  a1.a0[1][1][0][1][0] = 28;
  a1.a0[1][1][0][1][1] = 29;
  a1.a0[1][1][1][0][0] = 30;
  a1.a0[1][1][1][0][1] = 31;
  a1.a0[1][1][1][1][0] = 32;
  a1.a0[1][1][1][1][1] = 33;
  a2 = 34;
  a3.a0[0][0][0] = 35;
  a3.a0[0][0][1] = 36;
  a3.a0[0][1][0] = 37;
  a3.a0[0][1][1] = 38;
  a3.a0[1][0][0] = 39;
  a3.a0[1][0][1] = 40;
  a3.a0[1][1][0] = 41;
  a3.a0[1][1][1] = 42;
  a4 = 43;
  a5.a0[0][0][0] = 44;
  a5.a0[0][0][1] = 45;
  a5.a0[0][1][0] = 46;
  a5.a0[0][1][1] = 47;
  a5.a0[1][0][0] = 48;
  a5.a0[1][0][1] = 49;
  a5.a0[1][1][0] = 50;
  a5.a0[1][1][1] = 51;
  a6 = 52;

  std::cout << "Calling TestPassUint8Struct32BytesInlineArrayMultiDimensionalI("
            << "(" << static_cast<int>(a0) << ", ([[[[["
            << static_cast<int>(a1.a0[0][0][0][0][0]) << ", "
            << static_cast<int>(a1.a0[0][0][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][0][0][1][0]) << ", "
            << static_cast<int>(a1.a0[0][0][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[0][0][1][0][0]) << ", "
            << static_cast<int>(a1.a0[0][0][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][0][1][1][0]) << ", "
            << static_cast<int>(a1.a0[0][0][1][1][1]) << "]]], [[["
            << static_cast<int>(a1.a0[0][1][0][0][0]) << ", "
            << static_cast<int>(a1.a0[0][1][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][1][0][1][0]) << ", "
            << static_cast<int>(a1.a0[0][1][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[0][1][1][0][0]) << ", "
            << static_cast<int>(a1.a0[0][1][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[0][1][1][1][0]) << ", "
            << static_cast<int>(a1.a0[0][1][1][1][1]) << "]]]], [[[["
            << static_cast<int>(a1.a0[1][0][0][0][0]) << ", "
            << static_cast<int>(a1.a0[1][0][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][0][0][1][0]) << ", "
            << static_cast<int>(a1.a0[1][0][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[1][0][1][0][0]) << ", "
            << static_cast<int>(a1.a0[1][0][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][0][1][1][0]) << ", "
            << static_cast<int>(a1.a0[1][0][1][1][1]) << "]]], [[["
            << static_cast<int>(a1.a0[1][1][0][0][0]) << ", "
            << static_cast<int>(a1.a0[1][1][0][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][1][0][1][0]) << ", "
            << static_cast<int>(a1.a0[1][1][0][1][1]) << "]], [["
            << static_cast<int>(a1.a0[1][1][1][0][0]) << ", "
            << static_cast<int>(a1.a0[1][1][1][0][1]) << "], ["
            << static_cast<int>(a1.a0[1][1][1][1][0]) << ", "
            << static_cast<int>(a1.a0[1][1][1][1][1]) << "]]]]]), "
            << static_cast<int>(a2) << ", ([[["
            << static_cast<int>(a3.a0[0][0][0]) << ", "
            << static_cast<int>(a3.a0[0][0][1]) << "], ["
            << static_cast<int>(a3.a0[0][1][0]) << ", "
            << static_cast<int>(a3.a0[0][1][1]) << "]], [["
            << static_cast<int>(a3.a0[1][0][0]) << ", "
            << static_cast<int>(a3.a0[1][0][1]) << "], ["
            << static_cast<int>(a3.a0[1][1][0]) << ", "
            << static_cast<int>(a3.a0[1][1][1]) << "]]]), "
            << static_cast<int>(a4) << ", ([[["
            << static_cast<int>(a5.a0[0][0][0]) << ", "
            << static_cast<int>(a5.a0[0][0][1]) << "], ["
            << static_cast<int>(a5.a0[0][1][0]) << ", "
            << static_cast<int>(a5.a0[0][1][1]) << "]], [["
            << static_cast<int>(a5.a0[1][0][0]) << ", "
            << static_cast<int>(a5.a0[1][0][1]) << "], ["
            << static_cast<int>(a5.a0[1][1][0]) << ", "
            << static_cast<int>(a5.a0[1][1][1]) << "]]]), "
            << static_cast<int>(a6) << ")" << ")\n";

  uint32_t result = f(a0, a1, a2, a3, a4, a5, a6);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(1378, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4, a5, a6);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Test struct in multi dimensional inline array.
DART_EXPORT intptr_t TestPassUint8Struct4BytesInlineArrayMultiDimensionalIn(
    // NOLINTNEXTLINE(whitespace/parens)
    uint32_t (*f)(uint8_t a0,
                  Struct4BytesInlineArrayMultiDimensionalInt a1,
                  uint8_t a2)) {
  uint8_t a0;
  Struct4BytesInlineArrayMultiDimensionalInt a1 = {};
  uint8_t a2;

  a0 = 1;
  a1.a0[0][0].a0 = 2;
  a1.a0[0][1].a0 = -3;
  a1.a0[1][0].a0 = 4;
  a1.a0[1][1].a0 = -5;
  a2 = 6;

  std::cout << "Calling TestPassUint8Struct4BytesInlineArrayMultiDimensionalIn("
            << "(" << static_cast<int>(a0) << ", ([[("
            << static_cast<int>(a1.a0[0][0].a0) << "), ("
            << static_cast<int>(a1.a0[0][1].a0) << ")], [("
            << static_cast<int>(a1.a0[1][0].a0) << "), ("
            << static_cast<int>(a1.a0[1][1].a0) << ")]]), "
            << static_cast<int>(a2) << ")" << ")\n";

  uint32_t result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(5, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT intptr_t TestPassStruct3BytesPackedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct3BytesPackedInt a0,
                 Struct3BytesPackedInt a1,
                 Struct3BytesPackedInt a2,
                 Struct3BytesPackedInt a3,
                 Struct3BytesPackedInt a4,
                 Struct3BytesPackedInt a5,
                 Struct3BytesPackedInt a6,
                 Struct3BytesPackedInt a7,
                 Struct3BytesPackedInt a8,
                 Struct3BytesPackedInt a9)) {
  Struct3BytesPackedInt a0 = {};
  Struct3BytesPackedInt a1 = {};
  Struct3BytesPackedInt a2 = {};
  Struct3BytesPackedInt a3 = {};
  Struct3BytesPackedInt a4 = {};
  Struct3BytesPackedInt a5 = {};
  Struct3BytesPackedInt a6 = {};
  Struct3BytesPackedInt a7 = {};
  Struct3BytesPackedInt a8 = {};
  Struct3BytesPackedInt 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 TestPassStruct3BytesPackedIntx10(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(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 and unions by value.
// Struct with mis-aligned member.
DART_EXPORT intptr_t TestPassStruct8BytesPackedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct8BytesPackedInt a0,
                 Struct8BytesPackedInt a1,
                 Struct8BytesPackedInt a2,
                 Struct8BytesPackedInt a3,
                 Struct8BytesPackedInt a4,
                 Struct8BytesPackedInt a5,
                 Struct8BytesPackedInt a6,
                 Struct8BytesPackedInt a7,
                 Struct8BytesPackedInt a8,
                 Struct8BytesPackedInt a9)) {
  Struct8BytesPackedInt a0 = {};
  Struct8BytesPackedInt a1 = {};
  Struct8BytesPackedInt a2 = {};
  Struct8BytesPackedInt a3 = {};
  Struct8BytesPackedInt a4 = {};
  Struct8BytesPackedInt a5 = {};
  Struct8BytesPackedInt a6 = {};
  Struct8BytesPackedInt a7 = {};
  Struct8BytesPackedInt a8 = {};
  Struct8BytesPackedInt 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 TestPassStruct8BytesPackedIntx10(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
            << ", " << static_cast<int>(a0.a4) << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << ", "
            << static_cast<int>(a1.a2) << ", " << static_cast<int>(a1.a3)
            << ", " << static_cast<int>(a1.a4) << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << ", "
            << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
            << ", " << static_cast<int>(a2.a4) << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << ", "
            << static_cast<int>(a3.a2) << ", " << static_cast<int>(a3.a3)
            << ", " << static_cast<int>(a3.a4) << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << ", "
            << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
            << ", " << static_cast<int>(a4.a4) << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << ", "
            << static_cast<int>(a5.a2) << ", " << static_cast<int>(a5.a3)
            << ", " << static_cast<int>(a5.a4) << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << ", "
            << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
            << ", " << static_cast<int>(a6.a4) << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << ", "
            << static_cast<int>(a7.a2) << ", " << static_cast<int>(a7.a3)
            << ", " << static_cast<int>(a7.a4) << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << ", "
            << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
            << ", " << static_cast<int>(a8.a4) << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << ", "
            << static_cast<int>(a9.a2) << ", " << static_cast<int>(a9.a3)
            << ", " << static_cast<int>(a9.a4) << "))" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(1275, 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 and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT intptr_t TestPassStruct9BytesPackedMixedx10DoubleInt32x2(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Struct9BytesPackedMixed a0,
                Struct9BytesPackedMixed a1,
                Struct9BytesPackedMixed a2,
                Struct9BytesPackedMixed a3,
                Struct9BytesPackedMixed a4,
                Struct9BytesPackedMixed a5,
                Struct9BytesPackedMixed a6,
                Struct9BytesPackedMixed a7,
                Struct9BytesPackedMixed a8,
                Struct9BytesPackedMixed a9,
                double a10,
                int32_t a11,
                int32_t a12)) {
  Struct9BytesPackedMixed a0 = {};
  Struct9BytesPackedMixed a1 = {};
  Struct9BytesPackedMixed a2 = {};
  Struct9BytesPackedMixed a3 = {};
  Struct9BytesPackedMixed a4 = {};
  Struct9BytesPackedMixed a5 = {};
  Struct9BytesPackedMixed a6 = {};
  Struct9BytesPackedMixed a7 = {};
  Struct9BytesPackedMixed a8 = {};
  Struct9BytesPackedMixed a9 = {};
  double a10;
  int32_t a11;
  int32_t a12;

  a0.a0 = 1;
  a0.a1 = 2.0;
  a1.a0 = 3;
  a1.a1 = 4.0;
  a2.a0 = 5;
  a2.a1 = 6.0;
  a3.a0 = 7;
  a3.a1 = 8.0;
  a4.a0 = 9;
  a4.a1 = 10.0;
  a5.a0 = 11;
  a5.a1 = 12.0;
  a6.a0 = 13;
  a6.a1 = 14.0;
  a7.a0 = 15;
  a7.a1 = 16.0;
  a8.a0 = 17;
  a8.a1 = 18.0;
  a9.a0 = 19;
  a9.a1 = 20.0;
  a10 = -21.0;
  a11 = 22;
  a12 = -23;

  std::cout << "Calling TestPassStruct9BytesPackedMixedx10DoubleInt32x2("
            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << "), " << a10 << ", "
            << a11 << ", " << a12 << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(188.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, a10, a11, a12);

  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, a10, a11, a12);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// This packed struct happens to have only aligned members.
DART_EXPORT intptr_t TestPassStruct5BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Struct5BytesPackedMixed a0)) {
  Struct5BytesPackedMixed a0 = {};

  a0.a0 = -1.0;
  a0.a1 = 2;

  std::cout << "Calling TestPassStruct5BytesPackedMixed(" << "((" << a0.a0
            << ", " << static_cast<int>(a0.a1) << "))" << ")\n";

  double result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(1.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 and unions by value.
// Check alignment of packed struct in non-packed struct.
DART_EXPORT intptr_t TestPassStructNestedAlignmentStruct5BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(StructNestedAlignmentStruct5BytesPackedMixed a0)) {
  StructNestedAlignmentStruct5BytesPackedMixed a0 = {};

  a0.a0 = 1;
  a0.a1.a0 = 2.0;
  a0.a1.a1 = 3;

  std::cout << "Calling TestPassStructNestedAlignmentStruct5BytesPackedMixed("
            << "((" << static_cast<int>(a0.a0) << ", (" << a0.a1.a0 << ", "
            << static_cast<int>(a0.a1.a1) << ")))" << ")\n";

  double result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(6.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 and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT intptr_t TestPassStruct6BytesInlineArrayInt(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Struct6BytesInlineArrayInt a0)) {
  Struct6BytesInlineArrayInt a0 = {};

  a0.a0[0].a0 = -1;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3;
  a0.a0[1].a1 = 4;

  std::cout << "Calling TestPassStruct6BytesInlineArrayInt(" << "(([("
            << static_cast<int>(a0.a0[0].a0) << ", " << a0.a0[0].a1 << "), ("
            << static_cast<int>(a0.a0[1].a0) << ", " << a0.a0[1].a1 << ")]))"
            << ")\n";

  double result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(2.0, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0[0].a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0[0].a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT intptr_t TestPassStruct15BytesInlineArrayMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Struct15BytesInlineArrayMixed a0)) {
  Struct15BytesInlineArrayMixed a0 = {};

  a0.a0[0].a0 = -1.0;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3.0;
  a0.a0[1].a1 = 4;
  a0.a0[2].a0 = -5.0;
  a0.a0[2].a1 = 6;

  std::cout << "Calling TestPassStruct15BytesInlineArrayMixed(" << "(([("
            << a0.a0[0].a0 << ", " << static_cast<int>(a0.a0[0].a1) << "), ("
            << a0.a0[1].a0 << ", " << static_cast<int>(a0.a0[1].a1) << "), ("
            << a0.a0[2].a0 << ", " << static_cast<int>(a0.a0[2].a1) << ")]))"
            << ")\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[0].a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0[0].a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Check placement of mixed integer/float union.
DART_EXPORT intptr_t TestPassUnion4BytesMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Union4BytesMixed a0,
                Union4BytesMixed a1,
                Union4BytesMixed a2,
                Union4BytesMixed a3,
                Union4BytesMixed a4,
                Union4BytesMixed a5,
                Union4BytesMixed a6,
                Union4BytesMixed a7,
                Union4BytesMixed a8,
                Union4BytesMixed a9)) {
  Union4BytesMixed a0 = {};
  Union4BytesMixed a1 = {};
  Union4BytesMixed a2 = {};
  Union4BytesMixed a3 = {};
  Union4BytesMixed a4 = {};
  Union4BytesMixed a5 = {};
  Union4BytesMixed a6 = {};
  Union4BytesMixed a7 = {};
  Union4BytesMixed a8 = {};
  Union4BytesMixed 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 TestPassUnion4BytesMixedx10(" << "((" << a0.a0 << "), ("
            << a1.a0 << "), (" << a2.a0 << "), (" << a3.a0 << "), (" << a4.a0
            << "), (" << a5.a0 << "), (" << a6.a0 << "), (" << a7.a0 << "), ("
            << a8.a0 << "), (" << a9.a0 << "))" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(55.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 and unions by value.
// Check placement of mixed floats union.
DART_EXPORT intptr_t TestPassUnion8BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Union8BytesNestedFloat a0,
                Union8BytesNestedFloat a1,
                Union8BytesNestedFloat a2,
                Union8BytesNestedFloat a3,
                Union8BytesNestedFloat a4,
                Union8BytesNestedFloat a5,
                Union8BytesNestedFloat a6,
                Union8BytesNestedFloat a7,
                Union8BytesNestedFloat a8,
                Union8BytesNestedFloat a9)) {
  Union8BytesNestedFloat a0 = {};
  Union8BytesNestedFloat a1 = {};
  Union8BytesNestedFloat a2 = {};
  Union8BytesNestedFloat a3 = {};
  Union8BytesNestedFloat a4 = {};
  Union8BytesNestedFloat a5 = {};
  Union8BytesNestedFloat a6 = {};
  Union8BytesNestedFloat a7 = {};
  Union8BytesNestedFloat a8 = {};
  Union8BytesNestedFloat a9 = {};

  a0.a0 = -1.0;
  a1.a0 = 2.0;
  a2.a0 = -3.0;
  a3.a0 = 4.0;
  a4.a0 = -5.0;
  a5.a0 = 6.0;
  a6.a0 = -7.0;
  a7.a0 = 8.0;
  a8.a0 = -9.0;
  a9.a0 = 10.0;

  std::cout << "Calling TestPassUnion8BytesNestedFloatx10(" << "((" << a0.a0
            << "), (" << a1.a0 << "), (" << a2.a0 << "), (" << a3.a0 << "), ("
            << a4.a0 << "), (" << a5.a0 << "), (" << a6.a0 << "), (" << a7.a0
            << "), (" << a8.a0 << "), (" << a9.a0 << "))" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  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, 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 and unions by value.
// Mixed-size union argument.
DART_EXPORT intptr_t TestPassUnion9BytesNestedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Union9BytesNestedInt a0,
                Union9BytesNestedInt a1,
                Union9BytesNestedInt a2,
                Union9BytesNestedInt a3,
                Union9BytesNestedInt a4,
                Union9BytesNestedInt a5,
                Union9BytesNestedInt a6,
                Union9BytesNestedInt a7,
                Union9BytesNestedInt a8,
                Union9BytesNestedInt a9)) {
  Union9BytesNestedInt a0 = {};
  Union9BytesNestedInt a1 = {};
  Union9BytesNestedInt a2 = {};
  Union9BytesNestedInt a3 = {};
  Union9BytesNestedInt a4 = {};
  Union9BytesNestedInt a5 = {};
  Union9BytesNestedInt a6 = {};
  Union9BytesNestedInt a7 = {};
  Union9BytesNestedInt a8 = {};
  Union9BytesNestedInt a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a1.a0.a0 = 4;
  a1.a0.a1 = -5;
  a1.a0.a2 = 6;
  a2.a0.a0 = -7;
  a2.a0.a1 = 8;
  a2.a0.a2 = -9;
  a3.a0.a0 = 10;
  a3.a0.a1 = -11;
  a3.a0.a2 = 12;
  a4.a0.a0 = -13;
  a4.a0.a1 = 14;
  a4.a0.a2 = -15;
  a5.a0.a0 = 16;
  a5.a0.a1 = -17;
  a5.a0.a2 = 18;
  a6.a0.a0 = -19;
  a6.a0.a1 = 20;
  a6.a0.a2 = -21;
  a7.a0.a0 = 22;
  a7.a0.a1 = -23;
  a7.a0.a2 = 24;
  a8.a0.a0 = -25;
  a8.a0.a1 = 26;
  a8.a0.a2 = -27;
  a9.a0.a0 = 28;
  a9.a0.a1 = -29;
  a9.a0.a2 = 30;

  std::cout << "Calling TestPassUnion9BytesNestedIntx10(" << "(((" << a0.a0.a0
            << ", " << a0.a0.a1 << ", " << a0.a0.a2 << ")), ((" << a1.a0.a0
            << ", " << a1.a0.a1 << ", " << a1.a0.a2 << ")), ((" << a2.a0.a0
            << ", " << a2.a0.a1 << ", " << a2.a0.a2 << ")), ((" << a3.a0.a0
            << ", " << a3.a0.a1 << ", " << a3.a0.a2 << ")), ((" << a4.a0.a0
            << ", " << a4.a0.a1 << ", " << a4.a0.a2 << ")), ((" << a5.a0.a0
            << ", " << a5.a0.a1 << ", " << a5.a0.a2 << ")), ((" << a6.a0.a0
            << ", " << a6.a0.a1 << ", " << a6.a0.a2 << ")), ((" << a7.a0.a0
            << ", " << a7.a0.a1 << ", " << a7.a0.a2 << ")), ((" << a8.a0.a0
            << ", " << a8.a0.a1 << ", " << a8.a0.a2 << ")), ((" << a9.a0.a0
            << ", " << a9.a0.a1 << ", " << a9.a0.a2 << ")))" << ")\n";

  double 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.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.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 and unions by value.
// Union with homogenous floats.
DART_EXPORT intptr_t TestPassUnion16BytesNestedInlineArrayFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Union16BytesNestedInlineArrayFloat a0,
                Union16BytesNestedInlineArrayFloat a1,
                Union16BytesNestedInlineArrayFloat a2,
                Union16BytesNestedInlineArrayFloat a3,
                Union16BytesNestedInlineArrayFloat a4,
                Union16BytesNestedInlineArrayFloat a5,
                Union16BytesNestedInlineArrayFloat a6,
                Union16BytesNestedInlineArrayFloat a7,
                Union16BytesNestedInlineArrayFloat a8,
                Union16BytesNestedInlineArrayFloat a9)) {
  Union16BytesNestedInlineArrayFloat a0 = {};
  Union16BytesNestedInlineArrayFloat a1 = {};
  Union16BytesNestedInlineArrayFloat a2 = {};
  Union16BytesNestedInlineArrayFloat a3 = {};
  Union16BytesNestedInlineArrayFloat a4 = {};
  Union16BytesNestedInlineArrayFloat a5 = {};
  Union16BytesNestedInlineArrayFloat a6 = {};
  Union16BytesNestedInlineArrayFloat a7 = {};
  Union16BytesNestedInlineArrayFloat a8 = {};
  Union16BytesNestedInlineArrayFloat a9 = {};

  a0.a0[0] = -1.0;
  a0.a0[1] = 2.0;
  a0.a0[2] = -3.0;
  a0.a0[3] = 4.0;
  a1.a0[0] = -5.0;
  a1.a0[1] = 6.0;
  a1.a0[2] = -7.0;
  a1.a0[3] = 8.0;
  a2.a0[0] = -9.0;
  a2.a0[1] = 10.0;
  a2.a0[2] = -11.0;
  a2.a0[3] = 12.0;
  a3.a0[0] = -13.0;
  a3.a0[1] = 14.0;
  a3.a0[2] = -15.0;
  a3.a0[3] = 16.0;
  a4.a0[0] = -17.0;
  a4.a0[1] = 18.0;
  a4.a0[2] = -19.0;
  a4.a0[3] = 20.0;
  a5.a0[0] = -21.0;
  a5.a0[1] = 22.0;
  a5.a0[2] = -23.0;
  a5.a0[3] = 24.0;
  a6.a0[0] = -25.0;
  a6.a0[1] = 26.0;
  a6.a0[2] = -27.0;
  a6.a0[3] = 28.0;
  a7.a0[0] = -29.0;
  a7.a0[1] = 30.0;
  a7.a0[2] = -31.0;
  a7.a0[3] = 32.0;
  a8.a0[0] = -33.0;
  a8.a0[1] = 34.0;
  a8.a0[2] = -35.0;
  a8.a0[3] = 36.0;
  a9.a0[0] = -37.0;
  a9.a0[1] = 38.0;
  a9.a0[2] = -39.0;
  a9.a0[3] = 40.0;

  std::cout << "Calling TestPassUnion16BytesNestedInlineArrayFloatx10(" << "((["
            << a0.a0[0] << ", " << a0.a0[1] << ", " << a0.a0[2] << ", "
            << a0.a0[3] << "]), ([" << a1.a0[0] << ", " << a1.a0[1] << ", "
            << a1.a0[2] << ", " << a1.a0[3] << "]), ([" << a2.a0[0] << ", "
            << a2.a0[1] << ", " << a2.a0[2] << ", " << a2.a0[3] << "]), (["
            << a3.a0[0] << ", " << a3.a0[1] << ", " << a3.a0[2] << ", "
            << a3.a0[3] << "]), ([" << a4.a0[0] << ", " << a4.a0[1] << ", "
            << a4.a0[2] << ", " << a4.a0[3] << "]), ([" << a5.a0[0] << ", "
            << a5.a0[1] << ", " << a5.a0[2] << ", " << a5.a0[3] << "]), (["
            << a6.a0[0] << ", " << a6.a0[1] << ", " << a6.a0[2] << ", "
            << a6.a0[3] << "]), ([" << a7.a0[0] << ", " << a7.a0[1] << ", "
            << a7.a0[2] << ", " << a7.a0[3] << "]), ([" << a8.a0[0] << ", "
            << a8.a0[1] << ", " << a8.a0[2] << ", " << a8.a0[3] << "]), (["
            << a9.a0[0] << ", " << a9.a0[1] << ", " << a9.a0[2] << ", "
            << a9.a0[3] << "]))" << ")\n";

  double 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[0] = 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[0] = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Union with homogenous floats.
DART_EXPORT intptr_t TestPassUnion16BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(Union16BytesNestedFloat a0,
                Union16BytesNestedFloat a1,
                Union16BytesNestedFloat a2,
                Union16BytesNestedFloat a3,
                Union16BytesNestedFloat a4,
                Union16BytesNestedFloat a5,
                Union16BytesNestedFloat a6,
                Union16BytesNestedFloat a7,
                Union16BytesNestedFloat a8,
                Union16BytesNestedFloat a9)) {
  Union16BytesNestedFloat a0 = {};
  Union16BytesNestedFloat a1 = {};
  Union16BytesNestedFloat a2 = {};
  Union16BytesNestedFloat a3 = {};
  Union16BytesNestedFloat a4 = {};
  Union16BytesNestedFloat a5 = {};
  Union16BytesNestedFloat a6 = {};
  Union16BytesNestedFloat a7 = {};
  Union16BytesNestedFloat a8 = {};
  Union16BytesNestedFloat a9 = {};

  a0.a0.a0 = -1.0;
  a0.a0.a1 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a0.a1 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a0.a1 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a0.a1 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a0.a1 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a0.a1 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a0.a1 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a0.a1 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a0.a1 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a0.a1 = 20.0;

  std::cout << "Calling TestPassUnion16BytesNestedFloatx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << ")), ((" << a1.a0.a0 << ", "
            << a1.a0.a1 << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << ")), ((" << a4.a0.a0 << ", "
            << a4.a0.a1 << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << ")), ((" << a7.a0.a0 << ", "
            << a7.a0.a1 << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.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.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.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 and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT intptr_t TestPassUint8Boolx9Struct10BytesHomogeneousBoolBool(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(uint8_t a0,
                 bool a1,
                 bool a2,
                 bool a3,
                 bool a4,
                 bool a5,
                 bool a6,
                 bool a7,
                 bool a8,
                 bool a9,
                 Struct10BytesHomogeneousBool a10,
                 bool a11)) {
  uint8_t a0;
  bool a1;
  bool a2;
  bool a3;
  bool a4;
  bool a5;
  bool a6;
  bool a7;
  bool a8;
  bool a9;
  Struct10BytesHomogeneousBool a10 = {};
  bool a11;

  a0 = 1;
  a1 = false;
  a2 = true;
  a3 = false;
  a4 = true;
  a5 = false;
  a6 = true;
  a7 = false;
  a8 = true;
  a9 = false;
  a10.a0 = true;
  a10.a1 = false;
  a10.a2 = true;
  a10.a3 = false;
  a10.a4 = true;
  a10.a5 = false;
  a10.a6 = true;
  a10.a7 = false;
  a10.a8 = true;
  a10.a9 = false;
  a11 = true;

  std::cout << "Calling TestPassUint8Boolx9Struct10BytesHomogeneousBoolBool("
            << "(" << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", "
            << a3 << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7
            << ", " << a8 << ", " << a9 << ", (" << a10.a0 << ", " << a10.a1
            << ", " << a10.a2 << ", " << a10.a3 << ", " << a10.a4 << ", "
            << a10.a5 << ", " << a10.a6 << ", " << a10.a7 << ", " << a10.a8
            << ", " << a10.a9 << "), " << a11 << ")" << ")\n";

  int32_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(11, 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, a11);

  CHECK_EQ(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, a11);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT intptr_t TestPassUint8Boolx9Struct10BytesInlineArrayBoolBool(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(uint8_t a0,
                 bool a1,
                 bool a2,
                 bool a3,
                 bool a4,
                 bool a5,
                 bool a6,
                 bool a7,
                 bool a8,
                 bool a9,
                 Struct10BytesInlineArrayBool a10,
                 bool a11)) {
  uint8_t a0;
  bool a1;
  bool a2;
  bool a3;
  bool a4;
  bool a5;
  bool a6;
  bool a7;
  bool a8;
  bool a9;
  Struct10BytesInlineArrayBool a10 = {};
  bool a11;

  a0 = 1;
  a1 = false;
  a2 = true;
  a3 = false;
  a4 = true;
  a5 = false;
  a6 = true;
  a7 = false;
  a8 = true;
  a9 = false;
  a10.a0[0] = true;
  a10.a0[1] = false;
  a10.a0[2] = true;
  a10.a0[3] = false;
  a10.a0[4] = true;
  a10.a0[5] = false;
  a10.a0[6] = true;
  a10.a0[7] = false;
  a10.a0[8] = true;
  a10.a0[9] = false;
  a11 = true;

  std::cout << "Calling TestPassUint8Boolx9Struct10BytesInlineArrayBoolBool("
            << "(" << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", "
            << a3 << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7
            << ", " << a8 << ", " << a9 << ", ([" << a10.a0[0] << ", "
            << a10.a0[1] << ", " << a10.a0[2] << ", " << a10.a0[3] << ", "
            << a10.a0[4] << ", " << a10.a0[5] << ", " << a10.a0[6] << ", "
            << a10.a0[7] << ", " << a10.a0[8] << ", " << a10.a0[9] << "]), "
            << a11 << ")" << ")\n";

  int32_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(11, 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, a11);

  CHECK_EQ(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, a11);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Returning a bool.
DART_EXPORT intptr_t TestPassUint8Struct1ByteBool(
    // NOLINTNEXTLINE(whitespace/parens)
    bool (*f)(uint8_t a0, Struct1ByteBool a1)) {
  uint8_t a0;
  Struct1ByteBool a1 = {};

  a0 = 1;
  a1.a0 = false;

  std::cout << "Calling TestPassUint8Struct1ByteBool(" << "("
            << static_cast<int>(a0) << ", (" << a1.a0 << "))" << ")\n";

  bool result = f(a0, a1);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(1, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Returning a wchar.
DART_EXPORT intptr_t TestPassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
    // NOLINTNEXTLINE(whitespace/parens)
    wchar_t (*f)(wchar_t a0,
                 StructInlineArrayInt a1,
                 uintptr_t a2,
                 uintptr_t a3,
                 /* NOLINT(runtime/int) */ long a4,
                 /* NOLINT(runtime/int) */ unsigned long a5)) {
  wchar_t a0;
  StructInlineArrayInt a1 = {};
  uintptr_t a2;
  uintptr_t a3;
  /* NOLINT(runtime/int) */ long a4;
  /* NOLINT(runtime/int) */ unsigned long a5;

  a0 = 1;
  a1.a0[0] = 2;
  a1.a0[1] = 3;
  a1.a0[2] = 4;
  a1.a0[3] = 5;
  a1.a0[4] = 6;
  a1.a0[5] = 7;
  a1.a0[6] = 8;
  a1.a0[7] = 9;
  a1.a0[8] = 10;
  a1.a0[9] = 11;
  a2 = 12;
  a3 = 13;
  a4 = 14;
  a5 = 15;

  std::cout << "Calling TestPassWCharStructInlineArrayIntUintPtrx2LongUnsigned("
            << "(" << static_cast<int>(a0) << ", (["
            << static_cast<int>(a1.a0[0]) << ", " << static_cast<int>(a1.a0[1])
            << ", " << static_cast<int>(a1.a0[2]) << ", "
            << static_cast<int>(a1.a0[3]) << ", " << static_cast<int>(a1.a0[4])
            << ", " << static_cast<int>(a1.a0[5]) << ", "
            << static_cast<int>(a1.a0[6]) << ", " << static_cast<int>(a1.a0[7])
            << ", " << static_cast<int>(a1.a0[8]) << ", "
            << static_cast<int>(a1.a0[9]) << "]), " << a2 << ", " << a3 << ", "
            << a4 << ", " << a5 << ")" << ")\n";

  wchar_t result = f(a0, a1, a2, a3, a4, a5);

  std::cout << "result = " << static_cast<int>(result) << "\n";

  CHECK_EQ(120, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4, a5);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Struct stradles last argument register
DART_EXPORT intptr_t TestPassInt64x7Struct12BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0,
                 int64_t a1,
                 int64_t a2,
                 int64_t a3,
                 int64_t a4,
                 int64_t a5,
                 int64_t a6,
                 Struct12BytesHomogeneousInt32 a7)) {
  int64_t a0;
  int64_t a1;
  int64_t a2;
  int64_t a3;
  int64_t a4;
  int64_t a5;
  int64_t a6;
  Struct12BytesHomogeneousInt32 a7 = {};

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;
  a5 = 6;
  a6 = -7;
  a7.a0 = 8;
  a7.a1 = -9;
  a7.a2 = 10;

  std::cout << "Calling TestPassInt64x7Struct12BytesHomogeneousInt32(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
            << ", " << a7.a2 << "))" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(5, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Passing a pointer to a struct
DART_EXPORT intptr_t TestPassPointerStruct12BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(Struct12BytesHomogeneousInt32* a0)) {
  Struct12BytesHomogeneousInt32* a0 =
      static_cast<Struct12BytesHomogeneousInt32*>(
          calloc(1, sizeof(Struct12BytesHomogeneousInt32)));

  a0->a0 = -1;
  a0->a1 = 2;
  a0->a2 = -3;

  std::cout << "Calling TestPassPointerStruct12BytesHomogeneousInt32(" << "(("
            << a0->a0 << ", " << a0->a1 << ", " << 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);

  free(a0);

  return 0;
}

// Used for testing structs and unions by value.
// Variable length array
DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariable(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructInlineArrayVariable* a0)) {
  StructInlineArrayVariable* a0 = static_cast<StructInlineArrayVariable*>(
      calloc(1, sizeof(StructInlineArrayVariable) + 10 * sizeof(uint8_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestPassPointerStructInlineArrayVariable(" << "(("
            << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))" << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(66, 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);

  free(a0);

  return 0;
}

// Used for testing structs and unions by value.
// Variable length array with variable length element having more alignment than
// the rest of the struct.
DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariableAlign(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructInlineArrayVariableAlign* a0)) {
  StructInlineArrayVariableAlign* a0 =
      static_cast<StructInlineArrayVariableAlign*>(calloc(
          1, sizeof(StructInlineArrayVariableAlign) + 10 * sizeof(uint32_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestPassPointerStructInlineArrayVariableAlign(" << "(("
            << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
            << a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
            << a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
            << a0->a1[7] << ", " << a0->a1[8] << ", " << a0->a1[9] << "]))"
            << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(66, 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);

  free(a0);

  return 0;
}

// Used for testing structs and unions by value.
// Variable length array with variable dimension of 1.
DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariable2(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(StructInlineArrayVariable2* a0)) {
  StructInlineArrayVariable2* a0 = static_cast<StructInlineArrayVariable2*>(
      calloc(1, sizeof(StructInlineArrayVariable2) + 10 * sizeof(uint8_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestPassPointerStructInlineArrayVariable2("
            << "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))"
            << ")\n";

  int64_t result = f(a0);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(66, 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);

  free(a0);

  return 0;
}

// Used for testing structs and unions 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 and unions by value.
// Smaller than word size return value on all architectures.
DART_EXPORT intptr_t TestReturnStruct3BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct3BytesHomogeneousUint8 (*f)(uint8_t a0, uint8_t a1, uint8_t a2)) {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;

  a0 = 1;
  a1 = 2;
  a2 = 3;

  std::cout << "Calling TestReturnStruct3BytesHomogeneousUint8(" << "("
            << static_cast<int>(a0) << ", " << static_cast<int>(a1) << ", "
            << static_cast<int>(a2) << ")" << ")\n";

  Struct3BytesHomogeneousUint8 result = f(a0, a1, a2);

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << static_cast<int>(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 and unions by value.
// Smaller than word size return value on all architectures.
// With alignment rules taken into account size is 4 bytes.
DART_EXPORT intptr_t TestReturnStruct3BytesInt2ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct3BytesInt2ByteAligned (*f)(int16_t a0, int8_t a1)) {
  int16_t a0;
  int8_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestReturnStruct3BytesInt2ByteAligned(" << "(" << a0
            << ", " << static_cast<int>(a1) << ")" << ")\n";

  Struct3BytesInt2ByteAligned 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 and unions 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 and unions by value.
// Non-wordsize return value.
DART_EXPORT intptr_t TestReturnStruct7BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct7BytesHomogeneousUint8 (*f)(uint8_t a0,
                                      uint8_t a1,
                                      uint8_t a2,
                                      uint8_t a3,
                                      uint8_t a4,
                                      uint8_t a5,
                                      uint8_t a6)) {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;
  uint8_t a5;
  uint8_t a6;

  a0 = 1;
  a1 = 2;
  a2 = 3;
  a3 = 4;
  a4 = 5;
  a5 = 6;
  a6 = 7;

  std::cout << "Calling TestReturnStruct7BytesHomogeneousUint8(" << "("
            << 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) << ")" << ")\n";

  Struct7BytesHomogeneousUint8 result = f(a0, a1, a2, a3, a4, a5, a6);

  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) << ")" << "\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);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4, a5, a6);

  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);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6);

  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);

  return 0;
}

// Used for testing structs and unions by value.
// Non-wordsize return value.
// With alignment rules taken into account size is 8 bytes.
DART_EXPORT intptr_t TestReturnStruct7BytesInt4ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct7BytesInt4ByteAligned (*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 TestReturnStruct7BytesInt4ByteAligned(" << "(" << a0
            << ", " << a1 << ", " << static_cast<int>(a2) << ")" << ")\n";

  Struct7BytesInt4ByteAligned 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 and unions 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 and unions 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 and unions 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 and unions 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 TestReturnStruct9BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct9BytesHomogeneousUint8 (*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 TestReturnStruct9BytesHomogeneousUint8(" << "("
            << 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";

  Struct9BytesHomogeneousUint8 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 and unions by value.
// Return value in two integer registers on x64.
// With alignment rules taken into account size is 12 or 16 bytes.
DART_EXPORT intptr_t TestReturnStruct9BytesInt4Or8ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct9BytesInt4Or8ByteAligned (*f)(int64_t a0, int8_t a1)) {
  int64_t a0;
  int8_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestReturnStruct9BytesInt4Or8ByteAligned(" << "(" << a0
            << ", " << static_cast<int>(a1) << ")" << ")\n";

  Struct9BytesInt4Or8ByteAligned 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Return 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT intptr_t TestReturnStruct3BytesPackedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct3BytesPackedInt (*f)(int8_t a0, int16_t a1)) {
  int8_t a0;
  int16_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestReturnStruct3BytesPackedInt(" << "("
            << static_cast<int>(a0) << ", " << a1 << ")" << ")\n";

  Struct3BytesPackedInt result = f(a0, a1);

  std::cout << "result = " << "(" << static_cast<int>(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 and unions by value.
// Struct with mis-aligned member.
DART_EXPORT intptr_t TestReturnStruct8BytesPackedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesPackedInt (
        *f)(uint8_t a0, uint32_t a1, uint8_t a2, uint8_t a3, uint8_t a4)) {
  uint8_t a0;
  uint32_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;

  a0 = 1;
  a1 = 2;
  a2 = 3;
  a3 = 4;
  a4 = 5;

  std::cout << "Calling TestReturnStruct8BytesPackedInt(" << "("
            << static_cast<int>(a0) << ", " << a1 << ", "
            << static_cast<int>(a2) << ", " << static_cast<int>(a3) << ", "
            << static_cast<int>(a4) << ")" << ")\n";

  Struct8BytesPackedInt result = f(a0, a1, a2, a3, a4);

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << result.a1 << ", " << static_cast<int>(result.a2) << ", "
            << static_cast<int>(result.a3) << ", "
            << static_cast<int>(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 and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT intptr_t TestReturnStruct9BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct9BytesPackedMixed (*f)(uint8_t a0, double a1)) {
  uint8_t a0;
  double a1;

  a0 = 1;
  a1 = 2.0;

  std::cout << "Calling TestReturnStruct9BytesPackedMixed(" << "("
            << static_cast<int>(a0) << ", " << a1 << ")" << ")\n";

  Struct9BytesPackedMixed result = f(a0, a1);

  std::cout << "result = " << "(" << static_cast<int>(result.a0) << ", "
            << result.a1 << ")" << "\n";

  CHECK_EQ(a0, result.a0);
  CHECK_APPROX(a1, result.a1);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(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_EQ(0, result.a0);
  CHECK_APPROX(0.0, result.a1);

  return 0;
}

// Used for testing structs and unions by value.
// Returning a mixed integer/float union.
DART_EXPORT intptr_t TestReturnUnion4BytesMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    Union4BytesMixed (*f)(uint32_t a0)) {
  uint32_t a0;

  a0 = 1;

  std::cout << "Calling TestReturnUnion4BytesMixed(" << "(" << a0 << ")"
            << ")\n";

  Union4BytesMixed result = f(a0);

  std::cout << "result = " << "(" << 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 and unions by value.
// Returning a floating point only union.
DART_EXPORT intptr_t TestReturnUnion8BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    Union8BytesNestedFloat (*f)(double a0)) {
  double a0;

  a0 = -1.0;

  std::cout << "Calling TestReturnUnion8BytesNestedFloat(" << "(" << a0 << ")"
            << ")\n";

  Union8BytesNestedFloat result = f(a0);

  std::cout << "result = " << "(" << result.a0 << ")" << "\n";

  CHECK_APPROX(a0, result.a0);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0);

  return 0;
}

// Used for testing structs and unions by value.
// Returning a mixed-size union.
DART_EXPORT intptr_t TestReturnUnion9BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Union9BytesNestedInt (*f)(Struct8BytesInt a0)) {
  Struct8BytesInt a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;

  std::cout << "Calling TestReturnUnion9BytesNestedInt(" << "((" << a0.a0
            << ", " << a0.a1 << ", " << a0.a2 << "))" << ")\n";

  Union9BytesNestedInt result = f(a0);

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << ", " << result.a0.a2 << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_EQ(a0.a2, result.a0.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);

  return 0;
}

// Used for testing structs and unions by value.
// Returning union with homogenous floats.
DART_EXPORT intptr_t TestReturnUnion16BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    Union16BytesNestedFloat (*f)(Struct8BytesHomogeneousFloat a0)) {
  Struct8BytesHomogeneousFloat a0 = {};

  a0.a0 = -1.0;
  a0.a1 = 2.0;

  std::cout << "Calling TestReturnUnion16BytesNestedFloat(" << "((" << a0.a0
            << ", " << a0.a1 << "))" << ")\n";

  Union16BytesNestedFloat result = f(a0);

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "))" << "\n";

  CHECK_APPROX(a0.a0, result.a0.a0);
  CHECK_APPROX(a0.a1, result.a0.a1);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a0.a1);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a0.a1);

  return 0;
}

// Used for testing structs and unions 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 and unions 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 and unions 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 and unions 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 and unions 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 and unions by value.
// Test returning struct with inline array.
DART_EXPORT intptr_t TestReturnStructArgumentStruct8BytesInlineArrayInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesInlineArrayInt (*f)(Struct8BytesInlineArrayInt a0)) {
  Struct8BytesInlineArrayInt a0 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;

  std::cout << "Calling TestReturnStructArgumentStruct8BytesInlineArrayInt("
            << "(([" << static_cast<int>(a0.a0[0]) << ", "
            << static_cast<int>(a0.a0[1]) << ", " << static_cast<int>(a0.a0[2])
            << ", " << static_cast<int>(a0.a0[3]) << ", "
            << static_cast<int>(a0.a0[4]) << ", " << static_cast<int>(a0.a0[5])
            << ", " << static_cast<int>(a0.a0[6]) << ", "
            << static_cast<int>(a0.a0[7]) << "]))" << ")\n";

  Struct8BytesInlineArrayInt result = f(a0);

  std::cout << "result = " << "([" << static_cast<int>(result.a0[0]) << ", "
            << static_cast<int>(result.a0[1]) << ", "
            << static_cast<int>(result.a0[2]) << ", "
            << static_cast<int>(result.a0[3]) << ", "
            << static_cast<int>(result.a0[4]) << ", "
            << static_cast<int>(result.a0[5]) << ", "
            << static_cast<int>(result.a0[6]) << ", "
            << static_cast<int>(result.a0[7]) << "])" << "\n";

  for (intptr_t i = 0; i < 8; i++) {
    CHECK_EQ(a0.a0[i], result.a0[i]);
  }

  // Pass argument that will make the Dart callback throw.
  a0.a0[0] = 42;

  result = f(a0);

  for (intptr_t i = 0; i < 8; i++) {
    CHECK_EQ(0, result.a0[i]);
  }

  // Pass argument that will make the Dart callback return null.
  a0.a0[0] = 84;

  result = f(a0);

  for (intptr_t i = 0; i < 8; i++) {
    CHECK_EQ(0, result.a0[i]);
  }

  return 0;
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct16BytesHomogeneous(
    // NOLINTNEXTLINE(whitespace/parens)
    StructStruct16BytesHomogeneousFloat2 (*f)(
        StructStruct16BytesHomogeneousFloat2 a0)) {
  StructStruct16BytesHomogeneousFloat2 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;

  std::cout << "Calling TestReturnStructArgumentStructStruct16BytesHomogeneous("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "))" << ")\n";

  StructStruct16BytesHomogeneousFloat2 result = f(a0);

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << "), (" << result.a1[1].a0 << ")], " << result.a2 << ")" << "\n";

  CHECK_APPROX(a0.a0.a0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(a0.a1[i].a0, result.a1[i].a0);
  }
  CHECK_APPROX(a0.a2, result.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
  }
  CHECK_APPROX(0.0, result.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
  }
  CHECK_APPROX(0.0, result.a2);

  return 0;
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct32BytesHomogeneous(
    // NOLINTNEXTLINE(whitespace/parens)
    StructStruct32BytesHomogeneousDouble2 (*f)(
        StructStruct32BytesHomogeneousDouble2 a0)) {
  StructStruct32BytesHomogeneousDouble2 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;

  std::cout << "Calling TestReturnStructArgumentStructStruct32BytesHomogeneous("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "))" << ")\n";

  StructStruct32BytesHomogeneousDouble2 result = f(a0);

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << "), (" << result.a1[1].a0 << ")], " << result.a2 << ")" << "\n";

  CHECK_APPROX(a0.a0.a0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(a0.a1[i].a0, result.a1[i].a0);
  }
  CHECK_APPROX(a0.a2, result.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
  }
  CHECK_APPROX(0.0, result.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
  }
  CHECK_APPROX(0.0, result.a2);

  return 0;
}

// Used for testing structs and unions by value.
// On x64 Linux, return value is split over FP and int registers.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct16BytesMixed3(
    // NOLINTNEXTLINE(whitespace/parens)
    StructStruct16BytesMixed3 (*f)(StructStruct16BytesMixed3 a0)) {
  StructStruct16BytesMixed3 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[0].a1 = -3;
  a0.a1[0].a2 = 4;
  a0.a2[0] = -5;
  a0.a2[1] = 6;

  std::cout << "Calling TestReturnStructArgumentStructStruct16BytesMixed3("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << ", "
            << a0.a1[0].a1 << ", " << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", "
            << a0.a2[1] << "]))" << ")\n";

  StructStruct16BytesMixed3 result = f(a0);

  std::cout << "result = " << "((" << result.a0.a0 << "), [(" << result.a1[0].a0
            << ", " << result.a1[0].a1 << ", " << result.a1[0].a2 << ")], ["
            << result.a2[0] << ", " << result.a2[1] << "])" << "\n";

  CHECK_APPROX(a0.a0.a0, result.a0.a0);
  for (intptr_t i = 0; i < 1; i++) {
    CHECK_APPROX(a0.a1[i].a0, result.a1[i].a0);
    CHECK_EQ(a0.a1[i].a1, result.a1[i].a1);
    CHECK_EQ(a0.a1[i].a2, result.a1[i].a2);
  }
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_EQ(a0.a2[i], result.a2[i]);
  }

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 1; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
    CHECK_EQ(0, result.a1[i].a1);
    CHECK_EQ(0, result.a1[i].a2);
  }
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_EQ(0, result.a2[i]);
  }

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0);

  CHECK_APPROX(0.0, result.a0.a0);
  for (intptr_t i = 0; i < 1; i++) {
    CHECK_APPROX(0.0, result.a1[i].a0);
    CHECK_EQ(0, result.a1[i].a1);
    CHECK_EQ(0, result.a1[i].a2);
  }
  for (intptr_t i = 0; i < 2; i++) {
    CHECK_EQ(0, result.a2[i]);
  }

  return 0;
}

// Used for testing structs and unions 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 and unions 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 and unions 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;
}

// Used for testing structs and unions by value.
// Simple nested struct.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesNestedInt (*f)(Struct4BytesHomogeneousInt16 a0,
                               Struct4BytesHomogeneousInt16 a1)) {
  Struct4BytesHomogeneousInt16 a0 = {};
  Struct4BytesHomogeneousInt16 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a1.a0 = -3;
  a1.a1 = 4;

  std::cout << "Calling TestReturnStruct8BytesNestedInt(" << "((" << a0.a0
            << ", " << a0.a1 << "), (" << a1.a0 << ", " << a1.a1 << "))"
            << ")\n";

  Struct8BytesNestedInt result = f(a0, a1);

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "), (" << result.a1.a0 << ", " << result.a1.a1 << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_EQ(a1.a0, result.a1.a0);
  CHECK_EQ(a1.a1, result.a1.a1);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);

  return 0;
}

// Used for testing structs and unions by value.
// Simple nested struct with floats.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesNestedFloat (*f)(Struct4BytesFloat a0, Struct4BytesFloat a1)) {
  Struct4BytesFloat a0 = {};
  Struct4BytesFloat a1 = {};

  a0.a0 = -1.0;
  a1.a0 = 2.0;

  std::cout << "Calling TestReturnStruct8BytesNestedFloat(" << "((" << a0.a0
            << "), (" << a1.a0 << "))" << ")\n";

  Struct8BytesNestedFloat result = f(a0, a1);

  std::cout << "result = " << "((" << result.a0.a0 << "), (" << result.a1.a0
            << "))" << "\n";

  CHECK_APPROX(a0.a0, result.a0.a0);
  CHECK_APPROX(a1.a0, result.a1.a0);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0);

  return 0;
}

// Used for testing structs and unions by value.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedFloat2(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesNestedFloat2 (*f)(Struct4BytesFloat a0, float a1)) {
  Struct4BytesFloat a0 = {};
  float a1;

  a0.a0 = -1.0;
  a1 = 2.0;

  std::cout << "Calling TestReturnStruct8BytesNestedFloat2(" << "((" << a0.a0
            << "), " << a1 << ")" << ")\n";

  Struct8BytesNestedFloat2 result = f(a0, a1);

  std::cout << "result = " << "((" << result.a0.a0 << "), " << result.a1 << ")"
            << "\n";

  CHECK_APPROX(a0.a0, result.a0.a0);
  CHECK_APPROX(a1, result.a1);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a1);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result.a0.a0);
  CHECK_APPROX(0.0, result.a1);

  return 0;
}

// Used for testing structs and unions by value.
// Simple nested struct with mixed members.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct8BytesNestedMixed (*f)(Struct4BytesHomogeneousInt16 a0,
                                 Struct4BytesFloat a1)) {
  Struct4BytesHomogeneousInt16 a0 = {};
  Struct4BytesFloat a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a1.a0 = -3.0;

  std::cout << "Calling TestReturnStruct8BytesNestedMixed(" << "((" << a0.a0
            << ", " << a0.a1 << "), (" << a1.a0 << "))" << ")\n";

  Struct8BytesNestedMixed result = f(a0, a1);

  std::cout << "result = " << "((" << result.a0.a0 << ", " << result.a0.a1
            << "), (" << result.a1.a0 << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_APPROX(a1.a0, result.a1.a0);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_APPROX(0.0, result.a1.a0);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_APPROX(0.0, result.a1.a0);

  return 0;
}

// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestReturnStruct16BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct16BytesNestedInt (*f)(Struct8BytesNestedInt a0,
                                Struct8BytesNestedInt a1)) {
  Struct8BytesNestedInt a0 = {};
  Struct8BytesNestedInt a1 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3;
  a0.a1.a1 = 4;
  a1.a0.a0 = -5;
  a1.a0.a1 = 6;
  a1.a1.a0 = -7;
  a1.a1.a1 = 8;

  std::cout << "Calling TestReturnStruct16BytesNestedInt(" << "(((" << a0.a0.a0
            << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ", " << a0.a1.a1
            << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0
            << ", " << a1.a1.a1 << ")))" << ")\n";

  Struct16BytesNestedInt result = f(a0, a1);

  std::cout << "result = " << "(((" << result.a0.a0.a0 << ", "
            << result.a0.a0.a1 << "), (" << result.a0.a1.a0 << ", "
            << result.a0.a1.a1 << ")), ((" << result.a1.a0.a0 << ", "
            << result.a1.a0.a1 << "), (" << result.a1.a1.a0 << ", "
            << result.a1.a1.a1 << ")))" << "\n";

  CHECK_EQ(a0.a0.a0, result.a0.a0.a0);
  CHECK_EQ(a0.a0.a1, result.a0.a0.a1);
  CHECK_EQ(a0.a1.a0, result.a0.a1.a0);
  CHECK_EQ(a0.a1.a1, result.a0.a1.a1);
  CHECK_EQ(a1.a0.a0, result.a1.a0.a0);
  CHECK_EQ(a1.a0.a1, result.a1.a0.a1);
  CHECK_EQ(a1.a1.a0, result.a1.a1.a0);
  CHECK_EQ(a1.a1.a1, result.a1.a1.a1);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0.a0);
  CHECK_EQ(0, result.a0.a0.a1);
  CHECK_EQ(0, result.a0.a1.a0);
  CHECK_EQ(0, result.a0.a1.a1);
  CHECK_EQ(0, result.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1);
  CHECK_EQ(0, result.a1.a1.a0);
  CHECK_EQ(0, result.a1.a1.a1);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0.a0);
  CHECK_EQ(0, result.a0.a0.a1);
  CHECK_EQ(0, result.a0.a1.a0);
  CHECK_EQ(0, result.a0.a1.a1);
  CHECK_EQ(0, result.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1);
  CHECK_EQ(0, result.a1.a1.a0);
  CHECK_EQ(0, result.a1.a1.a1);

  return 0;
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestReturnStruct32BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    Struct32BytesNestedInt (*f)(Struct16BytesNestedInt a0,
                                Struct16BytesNestedInt a1)) {
  Struct16BytesNestedInt a0 = {};
  Struct16BytesNestedInt a1 = {};

  a0.a0.a0.a0 = -1;
  a0.a0.a0.a1 = 2;
  a0.a0.a1.a0 = -3;
  a0.a0.a1.a1 = 4;
  a0.a1.a0.a0 = -5;
  a0.a1.a0.a1 = 6;
  a0.a1.a1.a0 = -7;
  a0.a1.a1.a1 = 8;
  a1.a0.a0.a0 = -9;
  a1.a0.a0.a1 = 10;
  a1.a0.a1.a0 = -11;
  a1.a0.a1.a1 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15;
  a1.a1.a1.a1 = 16;

  std::cout << "Calling TestReturnStruct32BytesNestedInt(" << "(((("
            << a0.a0.a0.a0 << ", " << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0
            << ", " << a0.a0.a1.a1 << ")), ((" << a0.a1.a0.a0 << ", "
            << a0.a1.a0.a1 << "), (" << a0.a1.a1.a0 << ", " << a0.a1.a1.a1
            << "))), (((" << a1.a0.a0.a0 << ", " << a1.a0.a0.a1 << "), ("
            << a1.a0.a1.a0 << ", " << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0
            << ", " << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ", "
            << a1.a1.a1.a1 << "))))" << ")\n";

  Struct32BytesNestedInt result = f(a0, a1);

  std::cout << "result = " << "((((" << result.a0.a0.a0.a0 << ", "
            << result.a0.a0.a0.a1 << "), (" << result.a0.a0.a1.a0 << ", "
            << result.a0.a0.a1.a1 << ")), ((" << result.a0.a1.a0.a0 << ", "
            << result.a0.a1.a0.a1 << "), (" << result.a0.a1.a1.a0 << ", "
            << result.a0.a1.a1.a1 << "))), (((" << result.a1.a0.a0.a0 << ", "
            << result.a1.a0.a0.a1 << "), (" << result.a1.a0.a1.a0 << ", "
            << result.a1.a0.a1.a1 << ")), ((" << result.a1.a1.a0.a0 << ", "
            << result.a1.a1.a0.a1 << "), (" << result.a1.a1.a1.a0 << ", "
            << result.a1.a1.a1.a1 << "))))" << "\n";

  CHECK_EQ(a0.a0.a0.a0, result.a0.a0.a0.a0);
  CHECK_EQ(a0.a0.a0.a1, result.a0.a0.a0.a1);
  CHECK_EQ(a0.a0.a1.a0, result.a0.a0.a1.a0);
  CHECK_EQ(a0.a0.a1.a1, result.a0.a0.a1.a1);
  CHECK_EQ(a0.a1.a0.a0, result.a0.a1.a0.a0);
  CHECK_EQ(a0.a1.a0.a1, result.a0.a1.a0.a1);
  CHECK_EQ(a0.a1.a1.a0, result.a0.a1.a1.a0);
  CHECK_EQ(a0.a1.a1.a1, result.a0.a1.a1.a1);
  CHECK_EQ(a1.a0.a0.a0, result.a1.a0.a0.a0);
  CHECK_EQ(a1.a0.a0.a1, result.a1.a0.a0.a1);
  CHECK_EQ(a1.a0.a1.a0, result.a1.a0.a1.a0);
  CHECK_EQ(a1.a0.a1.a1, result.a1.a0.a1.a1);
  CHECK_EQ(a1.a1.a0.a0, result.a1.a1.a0.a0);
  CHECK_EQ(a1.a1.a0.a1, result.a1.a1.a0.a1);
  CHECK_EQ(a1.a1.a1.a0, result.a1.a1.a1.a0);
  CHECK_EQ(a1.a1.a1.a1, result.a1.a1.a1.a1);

  // Pass argument that will make the Dart callback throw.
  a0.a0.a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0.a0.a0);
  CHECK_EQ(0, result.a0.a0.a0.a1);
  CHECK_EQ(0, result.a0.a0.a1.a0);
  CHECK_EQ(0, result.a0.a0.a1.a1);
  CHECK_EQ(0, result.a0.a1.a0.a0);
  CHECK_EQ(0, result.a0.a1.a0.a1);
  CHECK_EQ(0, result.a0.a1.a1.a0);
  CHECK_EQ(0, result.a0.a1.a1.a1);
  CHECK_EQ(0, result.a1.a0.a0.a0);
  CHECK_EQ(0, result.a1.a0.a0.a1);
  CHECK_EQ(0, result.a1.a0.a1.a0);
  CHECK_EQ(0, result.a1.a0.a1.a1);
  CHECK_EQ(0, result.a1.a1.a0.a0);
  CHECK_EQ(0, result.a1.a1.a0.a1);
  CHECK_EQ(0, result.a1.a1.a1.a0);
  CHECK_EQ(0, result.a1.a1.a1.a1);

  // Pass argument that will make the Dart callback return null.
  a0.a0.a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0.a0.a0);
  CHECK_EQ(0, result.a0.a0.a0.a1);
  CHECK_EQ(0, result.a0.a0.a1.a0);
  CHECK_EQ(0, result.a0.a0.a1.a1);
  CHECK_EQ(0, result.a0.a1.a0.a0);
  CHECK_EQ(0, result.a0.a1.a0.a1);
  CHECK_EQ(0, result.a0.a1.a1.a0);
  CHECK_EQ(0, result.a0.a1.a1.a1);
  CHECK_EQ(0, result.a1.a0.a0.a0);
  CHECK_EQ(0, result.a1.a0.a0.a1);
  CHECK_EQ(0, result.a1.a0.a1.a0);
  CHECK_EQ(0, result.a1.a0.a1.a1);
  CHECK_EQ(0, result.a1.a1.a0.a0);
  CHECK_EQ(0, result.a1.a1.a0.a1);
  CHECK_EQ(0, result.a1.a1.a1.a0);
  CHECK_EQ(0, result.a1.a1.a1.a1);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    StructNestedIntStructAlignmentInt16 (*f)(StructAlignmentInt16 a0,
                                             StructAlignmentInt16 a1)) {
  StructAlignmentInt16 a0 = {};
  StructAlignmentInt16 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestReturnStructNestedIntStructAlignmentInt16(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  StructNestedIntStructAlignmentInt16 result = f(a0, a1);

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_EQ(a0.a2, result.a0.a2);
  CHECK_EQ(a1.a0, result.a1.a0);
  CHECK_EQ(a1.a1, result.a1.a1);
  CHECK_EQ(a1.a2, result.a1.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    StructNestedIntStructAlignmentInt32 (*f)(StructAlignmentInt32 a0,
                                             StructAlignmentInt32 a1)) {
  StructAlignmentInt32 a0 = {};
  StructAlignmentInt32 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestReturnStructNestedIntStructAlignmentInt32(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  StructNestedIntStructAlignmentInt32 result = f(a0, a1);

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_EQ(a0.a2, result.a0.a2);
  CHECK_EQ(a1.a0, result.a1.a0);
  CHECK_EQ(a1.a1, result.a1.a1);
  CHECK_EQ(a1.a2, result.a1.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  return 0;
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    StructNestedIntStructAlignmentInt64 (*f)(StructAlignmentInt64 a0,
                                             StructAlignmentInt64 a1)) {
  StructAlignmentInt64 a0 = {};
  StructAlignmentInt64 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestReturnStructNestedIntStructAlignmentInt64(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  StructNestedIntStructAlignmentInt64 result = f(a0, a1);

  std::cout << "result = " << "((" << static_cast<int>(result.a0.a0) << ", "
            << result.a0.a1 << ", " << static_cast<int>(result.a0.a2) << "), ("
            << static_cast<int>(result.a1.a0) << ", " << result.a1.a1 << ", "
            << static_cast<int>(result.a1.a2) << "))" << "\n";

  CHECK_EQ(a0.a0, result.a0.a0);
  CHECK_EQ(a0.a1, result.a0.a1);
  CHECK_EQ(a0.a2, result.a0.a2);
  CHECK_EQ(a1.a0, result.a1.a0);
  CHECK_EQ(a1.a1, result.a1.a1);
  CHECK_EQ(a1.a2, result.a1.a2);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result.a0.a0);
  CHECK_EQ(0, result.a0.a1);
  CHECK_EQ(0, result.a0.a2);
  CHECK_EQ(0, result.a1.a0);
  CHECK_EQ(0, result.a1.a1);
  CHECK_EQ(0, result.a1.a2);

  return 0;
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT intptr_t TestReturnStructNestedIrregularEvenBigger(
    // NOLINTNEXTLINE(whitespace/parens)
    StructNestedIrregularEvenBigger (*f)(uint64_t a0,
                                         StructNestedIrregularBigger a1,
                                         StructNestedIrregularBigger a2,
                                         double a3)) {
  uint64_t a0;
  StructNestedIrregularBigger a1 = {};
  StructNestedIrregularBigger a2 = {};
  double a3;

  a0 = 1;
  a1.a0.a0 = 2;
  a1.a0.a1.a0.a0 = -3;
  a1.a0.a1.a0.a1 = 4;
  a1.a0.a1.a1.a0 = -5.0;
  a1.a0.a2 = 6;
  a1.a0.a3.a0.a0 = -7.0;
  a1.a0.a3.a1 = 8.0;
  a1.a0.a4 = 9;
  a1.a0.a5.a0.a0 = 10.0;
  a1.a0.a5.a1.a0 = -11.0;
  a1.a0.a6 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15.0;
  a1.a2 = 16.0;
  a1.a3 = -17.0;
  a2.a0.a0 = 18;
  a2.a0.a1.a0.a0 = -19;
  a2.a0.a1.a0.a1 = 20;
  a2.a0.a1.a1.a0 = -21.0;
  a2.a0.a2 = 22;
  a2.a0.a3.a0.a0 = -23.0;
  a2.a0.a3.a1 = 24.0;
  a2.a0.a4 = 25;
  a2.a0.a5.a0.a0 = 26.0;
  a2.a0.a5.a1.a0 = -27.0;
  a2.a0.a6 = 28;
  a2.a1.a0.a0 = -29;
  a2.a1.a0.a1 = 30;
  a2.a1.a1.a0 = -31.0;
  a2.a2 = 32.0;
  a2.a3 = -33.0;
  a3 = 34.0;

  std::cout << "Calling TestReturnStructNestedIrregularEvenBigger(" << "(" << a0
            << ", ((" << a1.a0.a0 << ", ((" << a1.a0.a1.a0.a0 << ", "
            << a1.a0.a1.a0.a1 << "), (" << a1.a0.a1.a1.a0 << ")), " << a1.a0.a2
            << ", ((" << a1.a0.a3.a0.a0 << "), " << a1.a0.a3.a1 << "), "
            << a1.a0.a4 << ", ((" << a1.a0.a5.a0.a0 << "), (" << a1.a0.a5.a1.a0
            << ")), " << a1.a0.a6 << "), ((" << a1.a1.a0.a0 << ", "
            << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ")), " << a1.a2 << ", "
            << a1.a3 << "), ((" << a2.a0.a0 << ", ((" << a2.a0.a1.a0.a0 << ", "
            << a2.a0.a1.a0.a1 << "), (" << a2.a0.a1.a1.a0 << ")), " << a2.a0.a2
            << ", ((" << a2.a0.a3.a0.a0 << "), " << a2.a0.a3.a1 << "), "
            << a2.a0.a4 << ", ((" << a2.a0.a5.a0.a0 << "), (" << a2.a0.a5.a1.a0
            << ")), " << a2.a0.a6 << "), ((" << a2.a1.a0.a0 << ", "
            << a2.a1.a0.a1 << "), (" << a2.a1.a1.a0 << ")), " << a2.a2 << ", "
            << a2.a3 << "), " << a3 << ")" << ")\n";

  StructNestedIrregularEvenBigger result = f(a0, a1, a2, a3);

  std::cout << "result = " << "(" << result.a0 << ", ((" << result.a1.a0.a0
            << ", ((" << result.a1.a0.a1.a0.a0 << ", " << result.a1.a0.a1.a0.a1
            << "), (" << result.a1.a0.a1.a1.a0 << ")), " << result.a1.a0.a2
            << ", ((" << result.a1.a0.a3.a0.a0 << "), " << result.a1.a0.a3.a1
            << "), " << result.a1.a0.a4 << ", ((" << result.a1.a0.a5.a0.a0
            << "), (" << result.a1.a0.a5.a1.a0 << ")), " << result.a1.a0.a6
            << "), ((" << result.a1.a1.a0.a0 << ", " << result.a1.a1.a0.a1
            << "), (" << result.a1.a1.a1.a0 << ")), " << result.a1.a2 << ", "
            << result.a1.a3 << "), ((" << result.a2.a0.a0 << ", (("
            << result.a2.a0.a1.a0.a0 << ", " << result.a2.a0.a1.a0.a1 << "), ("
            << result.a2.a0.a1.a1.a0 << ")), " << result.a2.a0.a2 << ", (("
            << result.a2.a0.a3.a0.a0 << "), " << result.a2.a0.a3.a1 << "), "
            << result.a2.a0.a4 << ", ((" << result.a2.a0.a5.a0.a0 << "), ("
            << result.a2.a0.a5.a1.a0 << ")), " << result.a2.a0.a6 << "), (("
            << result.a2.a1.a0.a0 << ", " << result.a2.a1.a0.a1 << "), ("
            << result.a2.a1.a1.a0 << ")), " << result.a2.a2 << ", "
            << result.a2.a3 << "), " << result.a3 << ")" << "\n";

  CHECK_EQ(a0, result.a0);
  CHECK_EQ(a1.a0.a0, result.a1.a0.a0);
  CHECK_EQ(a1.a0.a1.a0.a0, result.a1.a0.a1.a0.a0);
  CHECK_EQ(a1.a0.a1.a0.a1, result.a1.a0.a1.a0.a1);
  CHECK_APPROX(a1.a0.a1.a1.a0, result.a1.a0.a1.a1.a0);
  CHECK_EQ(a1.a0.a2, result.a1.a0.a2);
  CHECK_APPROX(a1.a0.a3.a0.a0, result.a1.a0.a3.a0.a0);
  CHECK_APPROX(a1.a0.a3.a1, result.a1.a0.a3.a1);
  CHECK_EQ(a1.a0.a4, result.a1.a0.a4);
  CHECK_APPROX(a1.a0.a5.a0.a0, result.a1.a0.a5.a0.a0);
  CHECK_APPROX(a1.a0.a5.a1.a0, result.a1.a0.a5.a1.a0);
  CHECK_EQ(a1.a0.a6, result.a1.a0.a6);
  CHECK_EQ(a1.a1.a0.a0, result.a1.a1.a0.a0);
  CHECK_EQ(a1.a1.a0.a1, result.a1.a1.a0.a1);
  CHECK_APPROX(a1.a1.a1.a0, result.a1.a1.a1.a0);
  CHECK_APPROX(a1.a2, result.a1.a2);
  CHECK_APPROX(a1.a3, result.a1.a3);
  CHECK_EQ(a2.a0.a0, result.a2.a0.a0);
  CHECK_EQ(a2.a0.a1.a0.a0, result.a2.a0.a1.a0.a0);
  CHECK_EQ(a2.a0.a1.a0.a1, result.a2.a0.a1.a0.a1);
  CHECK_APPROX(a2.a0.a1.a1.a0, result.a2.a0.a1.a1.a0);
  CHECK_EQ(a2.a0.a2, result.a2.a0.a2);
  CHECK_APPROX(a2.a0.a3.a0.a0, result.a2.a0.a3.a0.a0);
  CHECK_APPROX(a2.a0.a3.a1, result.a2.a0.a3.a1);
  CHECK_EQ(a2.a0.a4, result.a2.a0.a4);
  CHECK_APPROX(a2.a0.a5.a0.a0, result.a2.a0.a5.a0.a0);
  CHECK_APPROX(a2.a0.a5.a1.a0, result.a2.a0.a5.a1.a0);
  CHECK_EQ(a2.a0.a6, result.a2.a0.a6);
  CHECK_EQ(a2.a1.a0.a0, result.a2.a1.a0.a0);
  CHECK_EQ(a2.a1.a0.a1, result.a2.a1.a0.a1);
  CHECK_APPROX(a2.a1.a1.a0, result.a2.a1.a1.a0);
  CHECK_APPROX(a2.a2, result.a2.a2);
  CHECK_APPROX(a2.a3, result.a2.a3);
  CHECK_APPROX(a3, result.a3);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result.a0);
  CHECK_EQ(0, result.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1.a0.a1);
  CHECK_APPROX(0.0, result.a1.a0.a1.a1.a0);
  CHECK_EQ(0, result.a1.a0.a2);
  CHECK_APPROX(0.0, result.a1.a0.a3.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0.a3.a1);
  CHECK_EQ(0, result.a1.a0.a4);
  CHECK_APPROX(0.0, result.a1.a0.a5.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0.a5.a1.a0);
  CHECK_EQ(0, result.a1.a0.a6);
  CHECK_EQ(0, result.a1.a1.a0.a0);
  CHECK_EQ(0, result.a1.a1.a0.a1);
  CHECK_APPROX(0.0, result.a1.a1.a1.a0);
  CHECK_APPROX(0.0, result.a1.a2);
  CHECK_APPROX(0.0, result.a1.a3);
  CHECK_EQ(0, result.a2.a0.a0);
  CHECK_EQ(0, result.a2.a0.a1.a0.a0);
  CHECK_EQ(0, result.a2.a0.a1.a0.a1);
  CHECK_APPROX(0.0, result.a2.a0.a1.a1.a0);
  CHECK_EQ(0, result.a2.a0.a2);
  CHECK_APPROX(0.0, result.a2.a0.a3.a0.a0);
  CHECK_APPROX(0.0, result.a2.a0.a3.a1);
  CHECK_EQ(0, result.a2.a0.a4);
  CHECK_APPROX(0.0, result.a2.a0.a5.a0.a0);
  CHECK_APPROX(0.0, result.a2.a0.a5.a1.a0);
  CHECK_EQ(0, result.a2.a0.a6);
  CHECK_EQ(0, result.a2.a1.a0.a0);
  CHECK_EQ(0, result.a2.a1.a0.a1);
  CHECK_APPROX(0.0, result.a2.a1.a1.a0);
  CHECK_APPROX(0.0, result.a2.a2);
  CHECK_APPROX(0.0, result.a2.a3);
  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_EQ(0, result.a0);
  CHECK_EQ(0, result.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1.a0.a0);
  CHECK_EQ(0, result.a1.a0.a1.a0.a1);
  CHECK_APPROX(0.0, result.a1.a0.a1.a1.a0);
  CHECK_EQ(0, result.a1.a0.a2);
  CHECK_APPROX(0.0, result.a1.a0.a3.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0.a3.a1);
  CHECK_EQ(0, result.a1.a0.a4);
  CHECK_APPROX(0.0, result.a1.a0.a5.a0.a0);
  CHECK_APPROX(0.0, result.a1.a0.a5.a1.a0);
  CHECK_EQ(0, result.a1.a0.a6);
  CHECK_EQ(0, result.a1.a1.a0.a0);
  CHECK_EQ(0, result.a1.a1.a0.a1);
  CHECK_APPROX(0.0, result.a1.a1.a1.a0);
  CHECK_APPROX(0.0, result.a1.a2);
  CHECK_APPROX(0.0, result.a1.a3);
  CHECK_EQ(0, result.a2.a0.a0);
  CHECK_EQ(0, result.a2.a0.a1.a0.a0);
  CHECK_EQ(0, result.a2.a0.a1.a0.a1);
  CHECK_APPROX(0.0, result.a2.a0.a1.a1.a0);
  CHECK_EQ(0, result.a2.a0.a2);
  CHECK_APPROX(0.0, result.a2.a0.a3.a0.a0);
  CHECK_APPROX(0.0, result.a2.a0.a3.a1);
  CHECK_EQ(0, result.a2.a0.a4);
  CHECK_APPROX(0.0, result.a2.a0.a5.a0.a0);
  CHECK_APPROX(0.0, result.a2.a0.a5.a1.a0);
  CHECK_EQ(0, result.a2.a0.a6);
  CHECK_EQ(0, result.a2.a1.a0.a0);
  CHECK_EQ(0, result.a2.a1.a0.a1);
  CHECK_APPROX(0.0, result.a2.a1.a1.a0);
  CHECK_APPROX(0.0, result.a2.a2);
  CHECK_APPROX(0.0, result.a2.a3);
  CHECK_APPROX(0.0, result.a3);

  return 0;
}

// Used for testing structs and unions by value.
// Smallest struct with data.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct1ByteIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct1ByteIntx10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct3BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct3BytesHomogeneousUint8 a0,
              Struct3BytesHomogeneousUint8 a1,
              Struct3BytesHomogeneousUint8 a2,
              Struct3BytesHomogeneousUint8 a3,
              Struct3BytesHomogeneousUint8 a4,
              Struct3BytesHomogeneousUint8 a5,
              Struct3BytesHomogeneousUint8 a6,
              Struct3BytesHomogeneousUint8 a7,
              Struct3BytesHomogeneousUint8 a8,
              Struct3BytesHomogeneousUint8 a9)) {
  Struct3BytesHomogeneousUint8 a0 = {};
  Struct3BytesHomogeneousUint8 a1 = {};
  Struct3BytesHomogeneousUint8 a2 = {};
  Struct3BytesHomogeneousUint8 a3 = {};
  Struct3BytesHomogeneousUint8 a4 = {};
  Struct3BytesHomogeneousUint8 a5 = {};
  Struct3BytesHomogeneousUint8 a6 = {};
  Struct3BytesHomogeneousUint8 a7 = {};
  Struct3BytesHomogeneousUint8 a8 = {};
  Struct3BytesHomogeneousUint8 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 TestAsyncPassStruct3BytesHomogeneousUint8x10(" << "(("
            << static_cast<int>(a0.a0) << ", " << static_cast<int>(a0.a1)
            << ", " << static_cast<int>(a0.a2) << "), ("
            << static_cast<int>(a1.a0) << ", " << static_cast<int>(a1.a1)
            << ", " << static_cast<int>(a1.a2) << "), ("
            << static_cast<int>(a2.a0) << ", " << static_cast<int>(a2.a1)
            << ", " << static_cast<int>(a2.a2) << "), ("
            << static_cast<int>(a3.a0) << ", " << static_cast<int>(a3.a1)
            << ", " << static_cast<int>(a3.a2) << "), ("
            << static_cast<int>(a4.a0) << ", " << static_cast<int>(a4.a1)
            << ", " << static_cast<int>(a4.a2) << "), ("
            << static_cast<int>(a5.a0) << ", " << static_cast<int>(a5.a1)
            << ", " << static_cast<int>(a5.a2) << "), ("
            << static_cast<int>(a6.a0) << ", " << static_cast<int>(a6.a1)
            << ", " << static_cast<int>(a6.a2) << "), ("
            << static_cast<int>(a7.a0) << ", " << static_cast<int>(a7.a1)
            << ", " << static_cast<int>(a7.a2) << "), ("
            << static_cast<int>(a8.a0) << ", " << static_cast<int>(a8.a1)
            << ", " << static_cast<int>(a8.a2) << "), ("
            << static_cast<int>(a9.a0) << ", " << static_cast<int>(a9.a1)
            << ", " << static_cast<int>(a9.a2) << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// With alignment rules taken into account size is 4 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct3BytesInt2ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct3BytesInt2ByteAligned a0,
              Struct3BytesInt2ByteAligned a1,
              Struct3BytesInt2ByteAligned a2,
              Struct3BytesInt2ByteAligned a3,
              Struct3BytesInt2ByteAligned a4,
              Struct3BytesInt2ByteAligned a5,
              Struct3BytesInt2ByteAligned a6,
              Struct3BytesInt2ByteAligned a7,
              Struct3BytesInt2ByteAligned a8,
              Struct3BytesInt2ByteAligned a9)) {
  Struct3BytesInt2ByteAligned a0 = {};
  Struct3BytesInt2ByteAligned a1 = {};
  Struct3BytesInt2ByteAligned a2 = {};
  Struct3BytesInt2ByteAligned a3 = {};
  Struct3BytesInt2ByteAligned a4 = {};
  Struct3BytesInt2ByteAligned a5 = {};
  Struct3BytesInt2ByteAligned a6 = {};
  Struct3BytesInt2ByteAligned a7 = {};
  Struct3BytesInt2ByteAligned a8 = {};
  Struct3BytesInt2ByteAligned 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 TestAsyncPassStruct3BytesInt2ByteAlignedx10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Exactly word size on 32-bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct4BytesHomogeneousInt16x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct4BytesHomogeneousInt16x10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct7BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct7BytesHomogeneousUint8 a0,
              Struct7BytesHomogeneousUint8 a1,
              Struct7BytesHomogeneousUint8 a2,
              Struct7BytesHomogeneousUint8 a3,
              Struct7BytesHomogeneousUint8 a4,
              Struct7BytesHomogeneousUint8 a5,
              Struct7BytesHomogeneousUint8 a6,
              Struct7BytesHomogeneousUint8 a7,
              Struct7BytesHomogeneousUint8 a8,
              Struct7BytesHomogeneousUint8 a9)) {
  Struct7BytesHomogeneousUint8 a0 = {};
  Struct7BytesHomogeneousUint8 a1 = {};
  Struct7BytesHomogeneousUint8 a2 = {};
  Struct7BytesHomogeneousUint8 a3 = {};
  Struct7BytesHomogeneousUint8 a4 = {};
  Struct7BytesHomogeneousUint8 a5 = {};
  Struct7BytesHomogeneousUint8 a6 = {};
  Struct7BytesHomogeneousUint8 a7 = {};
  Struct7BytesHomogeneousUint8 a8 = {};
  Struct7BytesHomogeneousUint8 a9 = {};

  a0.a0 = 1;
  a0.a1 = 2;
  a0.a2 = 3;
  a0.a3 = 4;
  a0.a4 = 5;
  a0.a5 = 6;
  a0.a6 = 7;
  a1.a0 = 8;
  a1.a1 = 9;
  a1.a2 = 10;
  a1.a3 = 11;
  a1.a4 = 12;
  a1.a5 = 13;
  a1.a6 = 14;
  a2.a0 = 15;
  a2.a1 = 16;
  a2.a2 = 17;
  a2.a3 = 18;
  a2.a4 = 19;
  a2.a5 = 20;
  a2.a6 = 21;
  a3.a0 = 22;
  a3.a1 = 23;
  a3.a2 = 24;
  a3.a3 = 25;
  a3.a4 = 26;
  a3.a5 = 27;
  a3.a6 = 28;
  a4.a0 = 29;
  a4.a1 = 30;
  a4.a2 = 31;
  a4.a3 = 32;
  a4.a4 = 33;
  a4.a5 = 34;
  a4.a6 = 35;
  a5.a0 = 36;
  a5.a1 = 37;
  a5.a2 = 38;
  a5.a3 = 39;
  a5.a4 = 40;
  a5.a5 = 41;
  a5.a6 = 42;
  a6.a0 = 43;
  a6.a1 = 44;
  a6.a2 = 45;
  a6.a3 = 46;
  a6.a4 = 47;
  a6.a5 = 48;
  a6.a6 = 49;
  a7.a0 = 50;
  a7.a1 = 51;
  a7.a2 = 52;
  a7.a3 = 53;
  a7.a4 = 54;
  a7.a5 = 55;
  a7.a6 = 56;
  a8.a0 = 57;
  a8.a1 = 58;
  a8.a2 = 59;
  a8.a3 = 60;
  a8.a4 = 61;
  a8.a5 = 62;
  a8.a6 = 63;
  a9.a0 = 64;
  a9.a1 = 65;
  a9.a2 = 66;
  a9.a3 = 67;
  a9.a4 = 68;
  a9.a5 = 69;
  a9.a6 = 70;

  std::cout
      << "Calling TestAsyncPassStruct7BytesHomogeneousUint8x10(" << "(("
      << 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>(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>(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>(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>(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>(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>(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>(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>(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>(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) << "))"
      << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// With alignment rules taken into account size is 8 bytes.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct7BytesInt4ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct7BytesInt4ByteAligned a0,
              Struct7BytesInt4ByteAligned a1,
              Struct7BytesInt4ByteAligned a2,
              Struct7BytesInt4ByteAligned a3,
              Struct7BytesInt4ByteAligned a4,
              Struct7BytesInt4ByteAligned a5,
              Struct7BytesInt4ByteAligned a6,
              Struct7BytesInt4ByteAligned a7,
              Struct7BytesInt4ByteAligned a8,
              Struct7BytesInt4ByteAligned a9)) {
  Struct7BytesInt4ByteAligned a0 = {};
  Struct7BytesInt4ByteAligned a1 = {};
  Struct7BytesInt4ByteAligned a2 = {};
  Struct7BytesInt4ByteAligned a3 = {};
  Struct7BytesInt4ByteAligned a4 = {};
  Struct7BytesInt4ByteAligned a5 = {};
  Struct7BytesInt4ByteAligned a6 = {};
  Struct7BytesInt4ByteAligned a7 = {};
  Struct7BytesInt4ByteAligned a8 = {};
  Struct7BytesInt4ByteAligned 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 TestAsyncPassStruct7BytesInt4ByteAlignedx10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Exactly word size struct on 64bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct8BytesIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct8BytesIntx10(" << "((" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Arguments passed in FP registers as long as they fit.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct8BytesHomogeneousFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct8BytesHomogeneousFloatx10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// On x64, arguments go in int registers because it is not only float.
// 10 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct8BytesMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct8BytesMixedx10(" << "((" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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.
// Tests upper bytes in the integer registers that are partly filled.
// Tests stack alignment of non word size stack arguments.
DART_EXPORT void TestAsyncPassStruct9BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct9BytesHomogeneousUint8 a0,
              Struct9BytesHomogeneousUint8 a1,
              Struct9BytesHomogeneousUint8 a2,
              Struct9BytesHomogeneousUint8 a3,
              Struct9BytesHomogeneousUint8 a4,
              Struct9BytesHomogeneousUint8 a5,
              Struct9BytesHomogeneousUint8 a6,
              Struct9BytesHomogeneousUint8 a7,
              Struct9BytesHomogeneousUint8 a8,
              Struct9BytesHomogeneousUint8 a9)) {
  Struct9BytesHomogeneousUint8 a0 = {};
  Struct9BytesHomogeneousUint8 a1 = {};
  Struct9BytesHomogeneousUint8 a2 = {};
  Struct9BytesHomogeneousUint8 a3 = {};
  Struct9BytesHomogeneousUint8 a4 = {};
  Struct9BytesHomogeneousUint8 a5 = {};
  Struct9BytesHomogeneousUint8 a6 = {};
  Struct9BytesHomogeneousUint8 a7 = {};
  Struct9BytesHomogeneousUint8 a8 = {};
  Struct9BytesHomogeneousUint8 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 TestAsyncPassStruct9BytesHomogeneousUint8x10(" << "(("
      << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Argument is a single byte over a multiple of word size.
// With alignment rules taken into account size is 12 or 16 bytes.
// 10 struct arguments will exhaust available registers.
//
DART_EXPORT void TestAsyncPassStruct9BytesInt4Or8ByteAlignedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct9BytesInt4Or8ByteAligned a0,
              Struct9BytesInt4Or8ByteAligned a1,
              Struct9BytesInt4Or8ByteAligned a2,
              Struct9BytesInt4Or8ByteAligned a3,
              Struct9BytesInt4Or8ByteAligned a4,
              Struct9BytesInt4Or8ByteAligned a5,
              Struct9BytesInt4Or8ByteAligned a6,
              Struct9BytesInt4Or8ByteAligned a7,
              Struct9BytesInt4Or8ByteAligned a8,
              Struct9BytesInt4Or8ByteAligned a9)) {
  Struct9BytesInt4Or8ByteAligned a0 = {};
  Struct9BytesInt4Or8ByteAligned a1 = {};
  Struct9BytesInt4Or8ByteAligned a2 = {};
  Struct9BytesInt4Or8ByteAligned a3 = {};
  Struct9BytesInt4Or8ByteAligned a4 = {};
  Struct9BytesInt4Or8ByteAligned a5 = {};
  Struct9BytesInt4Or8ByteAligned a6 = {};
  Struct9BytesInt4Or8ByteAligned a7 = {};
  Struct9BytesInt4Or8ByteAligned a8 = {};
  Struct9BytesInt4Or8ByteAligned 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 TestAsyncPassStruct9BytesInt4Or8ByteAlignedx10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct12BytesHomogeneousFloatx6(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct12BytesHomogeneousFloatx6(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct16BytesHomogeneousFloatx5(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct16BytesHomogeneousFloatx5(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct16BytesMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct16BytesMixedx10(" << "((" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct16BytesMixed2x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct16BytesMixed2x10(" << "((" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct17BytesIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct17BytesIntx10(" << "((" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct19BytesHomogeneousUint8x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct19BytesHomogeneousUint8x10(" << "(("
      << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions 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 void TestAsyncPassStruct20BytesHomogeneousInt32x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct20BytesHomogeneousInt32x10(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in hardfp and arm64.
DART_EXPORT void TestAsyncPassStruct20BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct20BytesHomogeneousFloat(" << "(("
            << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3 << ", "
            << a0.a4 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStruct32BytesHomogeneousDoublex5(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct32BytesHomogeneousDoublex5(" << "(("
            << 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";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in arm64.
DART_EXPORT void TestAsyncPassStruct40BytesHomogeneousDouble(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct40BytesHomogeneousDouble(" << "(("
            << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3 << ", "
            << a0.a4 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT void TestAsyncPassStruct1024BytesHomogeneousUint64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct1024BytesHomogeneousUint64(" << "(("
            << 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";

  f(a0);
}

// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT void TestAsyncPassFloatStruct16BytesHomogeneousFloatFloatStruct1(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassFloatStruct16BytesHomogeneousFloatFloatStruct1("
      << "(" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT void TestAsyncPassFloatStruct32BytesHomogeneousDoubleFloatStruct(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassFloatStruct32BytesHomogeneousDoubleFloatStruct("
      << "(" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions 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 void TestAsyncPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn("
      << "(" << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions 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 void TestAsyncPassDoublex6Struct16BytesMixedx4Int32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassDoublex6Struct16BytesMixedx4Int32(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", (" << a6.a0 << ", " << a6.a1 << "), (" << a7.a0
            << ", " << a7.a1 << "), (" << a8.a0 << ", " << a8.a1 << "), ("
            << a9.a0 << ", " << a9.a1 << "), " << a10 << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}

// Used for testing structs and unions 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 void TestAsyncPassInt32x4Struct16BytesMixedx4Double(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassInt32x4Struct16BytesMixedx4Double(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", (" << a4.a0
            << ", " << a4.a1 << "), (" << a5.a0 << ", " << a5.a1 << "), ("
            << a6.a0 << ", " << a6.a1 << "), (" << a7.a0 << ", " << a7.a1
            << "), " << a8 << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions by value.
// On various architectures, first struct is allocated on stack.
// Check that the other two arguments are allocated on registers.
DART_EXPORT void TestAsyncPassStruct40BytesHomogeneousDoubleStruct4BytesHomo(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncPassStruct40BytesHomogeneousDoubleStruct4BytesHomo("
      << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
      << ", " << a0.a4 << "), (" << a1.a0 << ", " << a1.a1 << "), (" << a2.a0
      << ", " << a2.a1 << "))" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT void TestAsyncPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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,
              double a8,
              double a9,
              double a10,
              double a11,
              double a12,
              double a13,
              double a14,
              double a15,
              int64_t a16,
              int8_t a17,
              Struct1ByteInt a18,
              int64_t a19,
              int8_t a20,
              Struct4BytesHomogeneousInt16 a21,
              int64_t a22,
              int8_t a23,
              Struct8BytesInt a24,
              int64_t a25,
              int8_t a26,
              Struct8BytesHomogeneousFloat a27,
              int64_t a28,
              int8_t a29,
              Struct8BytesMixed a30,
              int64_t a31,
              int8_t a32,
              StructAlignmentInt16 a33,
              int64_t a34,
              int8_t a35,
              StructAlignmentInt32 a36,
              int64_t a37,
              int8_t a38,
              StructAlignmentInt64 a39)) {
  int32_t a0;
  int32_t a1;
  int32_t a2;
  int32_t a3;
  int32_t a4;
  int32_t a5;
  int32_t a6;
  int32_t a7;
  double a8;
  double a9;
  double a10;
  double a11;
  double a12;
  double a13;
  double a14;
  double a15;
  int64_t a16;
  int8_t a17;
  Struct1ByteInt a18 = {};
  int64_t a19;
  int8_t a20;
  Struct4BytesHomogeneousInt16 a21 = {};
  int64_t a22;
  int8_t a23;
  Struct8BytesInt a24 = {};
  int64_t a25;
  int8_t a26;
  Struct8BytesHomogeneousFloat a27 = {};
  int64_t a28;
  int8_t a29;
  Struct8BytesMixed a30 = {};
  int64_t a31;
  int8_t a32;
  StructAlignmentInt16 a33 = {};
  int64_t a34;
  int8_t a35;
  StructAlignmentInt32 a36 = {};
  int64_t a37;
  int8_t a38;
  StructAlignmentInt64 a39 = {};

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;
  a5 = 6;
  a6 = -7;
  a7 = 8;
  a8 = -9.0;
  a9 = 10.0;
  a10 = -11.0;
  a11 = 12.0;
  a12 = -13.0;
  a13 = 14.0;
  a14 = -15.0;
  a15 = 16.0;
  a16 = -17;
  a17 = 18;
  a18.a0 = -19;
  a19 = 20;
  a20 = -21;
  a21.a0 = 22;
  a21.a1 = -23;
  a22 = 24;
  a23 = -25;
  a24.a0 = 26;
  a24.a1 = -27;
  a24.a2 = 28;
  a25 = -29;
  a26 = 30;
  a27.a0 = -31.0;
  a27.a1 = 32.0;
  a28 = -33;
  a29 = 34;
  a30.a0 = -35.0;
  a30.a1 = 36;
  a30.a2 = -37;
  a31 = 38;
  a32 = -39;
  a33.a0 = 40;
  a33.a1 = -41;
  a33.a2 = 42;
  a34 = -43;
  a35 = 44;
  a36.a0 = -45;
  a36.a1 = 46;
  a36.a2 = -47;
  a37 = 48;
  a38 = -49;
  a39.a0 = 50;
  a39.a1 = -51;
  a39.a2 = 52;

  std::cout
      << "Calling TestAsyncPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int("
      << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
      << ", " << a5 << ", " << a6 << ", " << a7 << ", " << a8 << ", " << a9
      << ", " << a10 << ", " << a11 << ", " << a12 << ", " << a13 << ", " << a14
      << ", " << a15 << ", " << a16 << ", " << static_cast<int>(a17) << ", ("
      << static_cast<int>(a18.a0) << "), " << a19 << ", "
      << static_cast<int>(a20) << ", (" << a21.a0 << ", " << a21.a1 << "), "
      << a22 << ", " << static_cast<int>(a23) << ", (" << a24.a0 << ", "
      << a24.a1 << ", " << a24.a2 << "), " << a25 << ", "
      << static_cast<int>(a26) << ", (" << a27.a0 << ", " << a27.a1 << "), "
      << a28 << ", " << static_cast<int>(a29) << ", (" << a30.a0 << ", "
      << a30.a1 << ", " << a30.a2 << "), " << a31 << ", "
      << static_cast<int>(a32) << ", (" << static_cast<int>(a33.a0) << ", "
      << a33.a1 << ", " << static_cast<int>(a33.a2) << "), " << a34 << ", "
      << static_cast<int>(a35) << ", (" << static_cast<int>(a36.a0) << ", "
      << a36.a1 << ", " << static_cast<int>(a36.a2) << "), " << a37 << ", "
      << static_cast<int>(a38) << ", (" << static_cast<int>(a39.a0) << ", "
      << a39.a1 << ", " << static_cast<int>(a39.a2) << "))" << ")\n";

  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);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT void TestAsyncPassStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt16 a0)) {
  StructAlignmentInt16 a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;

  std::cout << "Calling TestAsyncPassStructAlignmentInt16(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT void TestAsyncPassStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt32 a0)) {
  StructAlignmentInt32 a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;

  std::cout << "Calling TestAsyncPassStructAlignmentInt32(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT void TestAsyncPassStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt64 a0)) {
  StructAlignmentInt64 a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;

  std::cout << "Calling TestAsyncPassStructAlignmentInt64(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust registers on all platforms.
DART_EXPORT void TestAsyncPassStruct8BytesNestedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesNestedInt a0,
              Struct8BytesNestedInt a1,
              Struct8BytesNestedInt a2,
              Struct8BytesNestedInt a3,
              Struct8BytesNestedInt a4,
              Struct8BytesNestedInt a5,
              Struct8BytesNestedInt a6,
              Struct8BytesNestedInt a7,
              Struct8BytesNestedInt a8,
              Struct8BytesNestedInt a9)) {
  Struct8BytesNestedInt a0 = {};
  Struct8BytesNestedInt a1 = {};
  Struct8BytesNestedInt a2 = {};
  Struct8BytesNestedInt a3 = {};
  Struct8BytesNestedInt a4 = {};
  Struct8BytesNestedInt a5 = {};
  Struct8BytesNestedInt a6 = {};
  Struct8BytesNestedInt a7 = {};
  Struct8BytesNestedInt a8 = {};
  Struct8BytesNestedInt a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3;
  a0.a1.a1 = 4;
  a1.a0.a0 = -5;
  a1.a0.a1 = 6;
  a1.a1.a0 = -7;
  a1.a1.a1 = 8;
  a2.a0.a0 = -9;
  a2.a0.a1 = 10;
  a2.a1.a0 = -11;
  a2.a1.a1 = 12;
  a3.a0.a0 = -13;
  a3.a0.a1 = 14;
  a3.a1.a0 = -15;
  a3.a1.a1 = 16;
  a4.a0.a0 = -17;
  a4.a0.a1 = 18;
  a4.a1.a0 = -19;
  a4.a1.a1 = 20;
  a5.a0.a0 = -21;
  a5.a0.a1 = 22;
  a5.a1.a0 = -23;
  a5.a1.a1 = 24;
  a6.a0.a0 = -25;
  a6.a0.a1 = 26;
  a6.a1.a0 = -27;
  a6.a1.a1 = 28;
  a7.a0.a0 = -29;
  a7.a0.a1 = 30;
  a7.a1.a0 = -31;
  a7.a1.a1 = 32;
  a8.a0.a0 = -33;
  a8.a0.a1 = 34;
  a8.a1.a0 = -35;
  a8.a1.a1 = 36;
  a9.a0.a0 = -37;
  a9.a0.a1 = 38;
  a9.a1.a0 = -39;
  a9.a1.a1 = 40;

  std::cout << "Calling TestAsyncPassStruct8BytesNestedIntx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ", "
            << a0.a1.a1 << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), ("
            << a1.a1.a0 << ", " << a1.a1.a1 << ")), ((" << a2.a0.a0 << ", "
            << a2.a0.a1 << "), (" << a2.a1.a0 << ", " << a2.a1.a1 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << "), (" << a3.a1.a0 << ", "
            << a3.a1.a1 << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << "), ("
            << a4.a1.a0 << ", " << a4.a1.a1 << ")), ((" << a5.a0.a0 << ", "
            << a5.a0.a1 << "), (" << a5.a1.a0 << ", " << a5.a1.a1 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << "), (" << a6.a1.a0 << ", "
            << a6.a1.a1 << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << "), ("
            << a7.a1.a0 << ", " << a7.a1.a1 << ")), ((" << a8.a0.a0 << ", "
            << a8.a0.a1 << "), (" << a8.a1.a0 << ", " << a8.a1.a1 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.a1 << "), (" << a9.a1.a0 << ", "
            << a9.a1.a1 << ")))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
DART_EXPORT void TestAsyncPassStruct8BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesNestedFloat a0,
              Struct8BytesNestedFloat a1,
              Struct8BytesNestedFloat a2,
              Struct8BytesNestedFloat a3,
              Struct8BytesNestedFloat a4,
              Struct8BytesNestedFloat a5,
              Struct8BytesNestedFloat a6,
              Struct8BytesNestedFloat a7,
              Struct8BytesNestedFloat a8,
              Struct8BytesNestedFloat a9)) {
  Struct8BytesNestedFloat a0 = {};
  Struct8BytesNestedFloat a1 = {};
  Struct8BytesNestedFloat a2 = {};
  Struct8BytesNestedFloat a3 = {};
  Struct8BytesNestedFloat a4 = {};
  Struct8BytesNestedFloat a5 = {};
  Struct8BytesNestedFloat a6 = {};
  Struct8BytesNestedFloat a7 = {};
  Struct8BytesNestedFloat a8 = {};
  Struct8BytesNestedFloat a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1.a0 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a1.a0 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a1.a0 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a1.a0 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a1.a0 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a1.a0 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a1.a0 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a1.a0 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a1.a0 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a1.a0 = 20.0;

  std::cout << "Calling TestAsyncPassStruct8BytesNestedFloatx10(" << "((("
            << a0.a0.a0 << "), (" << a0.a1.a0 << ")), ((" << a1.a0.a0 << "), ("
            << a1.a1.a0 << ")), ((" << a2.a0.a0 << "), (" << a2.a1.a0
            << ")), ((" << a3.a0.a0 << "), (" << a3.a1.a0 << ")), (("
            << a4.a0.a0 << "), (" << a4.a1.a0 << ")), ((" << a5.a0.a0 << "), ("
            << a5.a1.a0 << ")), ((" << a6.a0.a0 << "), (" << a6.a1.a0
            << ")), ((" << a7.a0.a0 << "), (" << a7.a1.a0 << ")), (("
            << a8.a0.a0 << "), (" << a8.a1.a0 << ")), ((" << a9.a0.a0 << "), ("
            << a9.a1.a0 << ")))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT void TestAsyncPassStruct8BytesNestedFloat2x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesNestedFloat2 a0,
              Struct8BytesNestedFloat2 a1,
              Struct8BytesNestedFloat2 a2,
              Struct8BytesNestedFloat2 a3,
              Struct8BytesNestedFloat2 a4,
              Struct8BytesNestedFloat2 a5,
              Struct8BytesNestedFloat2 a6,
              Struct8BytesNestedFloat2 a7,
              Struct8BytesNestedFloat2 a8,
              Struct8BytesNestedFloat2 a9)) {
  Struct8BytesNestedFloat2 a0 = {};
  Struct8BytesNestedFloat2 a1 = {};
  Struct8BytesNestedFloat2 a2 = {};
  Struct8BytesNestedFloat2 a3 = {};
  Struct8BytesNestedFloat2 a4 = {};
  Struct8BytesNestedFloat2 a5 = {};
  Struct8BytesNestedFloat2 a6 = {};
  Struct8BytesNestedFloat2 a7 = {};
  Struct8BytesNestedFloat2 a8 = {};
  Struct8BytesNestedFloat2 a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a1 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a1 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a1 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a1 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a1 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a1 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a1 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a1 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a1 = 20.0;

  std::cout << "Calling TestAsyncPassStruct8BytesNestedFloat2x10(" << "((("
            << a0.a0.a0 << "), " << a0.a1 << "), ((" << a1.a0.a0 << "), "
            << a1.a1 << "), ((" << a2.a0.a0 << "), " << a2.a1 << "), (("
            << a3.a0.a0 << "), " << a3.a1 << "), ((" << a4.a0.a0 << "), "
            << a4.a1 << "), ((" << a5.a0.a0 << "), " << a5.a1 << "), (("
            << a6.a0.a0 << "), " << a6.a1 << "), ((" << a7.a0.a0 << "), "
            << a7.a1 << "), ((" << a8.a0.a0 << "), " << a8.a1 << "), (("
            << a9.a0.a0 << "), " << a9.a1 << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust all registers on all platforms.
DART_EXPORT void TestAsyncPassStruct8BytesNestedMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesNestedMixed a0,
              Struct8BytesNestedMixed a1,
              Struct8BytesNestedMixed a2,
              Struct8BytesNestedMixed a3,
              Struct8BytesNestedMixed a4,
              Struct8BytesNestedMixed a5,
              Struct8BytesNestedMixed a6,
              Struct8BytesNestedMixed a7,
              Struct8BytesNestedMixed a8,
              Struct8BytesNestedMixed a9)) {
  Struct8BytesNestedMixed a0 = {};
  Struct8BytesNestedMixed a1 = {};
  Struct8BytesNestedMixed a2 = {};
  Struct8BytesNestedMixed a3 = {};
  Struct8BytesNestedMixed a4 = {};
  Struct8BytesNestedMixed a5 = {};
  Struct8BytesNestedMixed a6 = {};
  Struct8BytesNestedMixed a7 = {};
  Struct8BytesNestedMixed a8 = {};
  Struct8BytesNestedMixed a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3.0;
  a1.a0.a0 = 4;
  a1.a0.a1 = -5;
  a1.a1.a0 = 6.0;
  a2.a0.a0 = -7;
  a2.a0.a1 = 8;
  a2.a1.a0 = -9.0;
  a3.a0.a0 = 10;
  a3.a0.a1 = -11;
  a3.a1.a0 = 12.0;
  a4.a0.a0 = -13;
  a4.a0.a1 = 14;
  a4.a1.a0 = -15.0;
  a5.a0.a0 = 16;
  a5.a0.a1 = -17;
  a5.a1.a0 = 18.0;
  a6.a0.a0 = -19;
  a6.a0.a1 = 20;
  a6.a1.a0 = -21.0;
  a7.a0.a0 = 22;
  a7.a0.a1 = -23;
  a7.a1.a0 = 24.0;
  a8.a0.a0 = -25;
  a8.a0.a1 = 26;
  a8.a1.a0 = -27.0;
  a9.a0.a0 = 28;
  a9.a0.a1 = -29;
  a9.a1.a0 = 30.0;

  std::cout << "Calling TestAsyncPassStruct8BytesNestedMixedx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ")), (("
            << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0 << ")), (("
            << a2.a0.a0 << ", " << a2.a0.a1 << "), (" << a2.a1.a0 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << "), (" << a3.a1.a0 << ")), (("
            << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0 << ")), (("
            << a5.a0.a0 << ", " << a5.a0.a1 << "), (" << a5.a1.a0 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << "), (" << a6.a1.a0 << ")), (("
            << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0 << ")), (("
            << a8.a0.a0 << ", " << a8.a0.a1 << "), (" << a8.a1.a0 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.a1 << "), (" << a9.a1.a0 << ")))"
            << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT void TestAsyncPassStruct16BytesNestedIntx2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct16BytesNestedInt a0, Struct16BytesNestedInt a1)) {
  Struct16BytesNestedInt a0 = {};
  Struct16BytesNestedInt a1 = {};

  a0.a0.a0.a0 = -1;
  a0.a0.a0.a1 = 2;
  a0.a0.a1.a0 = -3;
  a0.a0.a1.a1 = 4;
  a0.a1.a0.a0 = -5;
  a0.a1.a0.a1 = 6;
  a0.a1.a1.a0 = -7;
  a0.a1.a1.a1 = 8;
  a1.a0.a0.a0 = -9;
  a1.a0.a0.a1 = 10;
  a1.a0.a1.a0 = -11;
  a1.a0.a1.a1 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15;
  a1.a1.a1.a1 = 16;

  std::cout << "Calling TestAsyncPassStruct16BytesNestedIntx2(" << "(((("
            << a0.a0.a0.a0 << ", " << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0
            << ", " << a0.a0.a1.a1 << ")), ((" << a0.a1.a0.a0 << ", "
            << a0.a1.a0.a1 << "), (" << a0.a1.a1.a0 << ", " << a0.a1.a1.a1
            << "))), (((" << a1.a0.a0.a0 << ", " << a1.a0.a0.a1 << "), ("
            << a1.a0.a1.a0 << ", " << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0
            << ", " << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ", "
            << a1.a1.a1.a1 << "))))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT void TestAsyncPassStruct32BytesNestedIntx2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct32BytesNestedInt a0, Struct32BytesNestedInt a1)) {
  Struct32BytesNestedInt a0 = {};
  Struct32BytesNestedInt a1 = {};

  a0.a0.a0.a0.a0 = -1;
  a0.a0.a0.a0.a1 = 2;
  a0.a0.a0.a1.a0 = -3;
  a0.a0.a0.a1.a1 = 4;
  a0.a0.a1.a0.a0 = -5;
  a0.a0.a1.a0.a1 = 6;
  a0.a0.a1.a1.a0 = -7;
  a0.a0.a1.a1.a1 = 8;
  a0.a1.a0.a0.a0 = -9;
  a0.a1.a0.a0.a1 = 10;
  a0.a1.a0.a1.a0 = -11;
  a0.a1.a0.a1.a1 = 12;
  a0.a1.a1.a0.a0 = -13;
  a0.a1.a1.a0.a1 = 14;
  a0.a1.a1.a1.a0 = -15;
  a0.a1.a1.a1.a1 = 16;
  a1.a0.a0.a0.a0 = -17;
  a1.a0.a0.a0.a1 = 18;
  a1.a0.a0.a1.a0 = -19;
  a1.a0.a0.a1.a1 = 20;
  a1.a0.a1.a0.a0 = -21;
  a1.a0.a1.a0.a1 = 22;
  a1.a0.a1.a1.a0 = -23;
  a1.a0.a1.a1.a1 = 24;
  a1.a1.a0.a0.a0 = -25;
  a1.a1.a0.a0.a1 = 26;
  a1.a1.a0.a1.a0 = -27;
  a1.a1.a0.a1.a1 = 28;
  a1.a1.a1.a0.a0 = -29;
  a1.a1.a1.a0.a1 = 30;
  a1.a1.a1.a1.a0 = -31;
  a1.a1.a1.a1.a1 = 32;

  std::cout << "Calling TestAsyncPassStruct32BytesNestedIntx2(" << "((((("
            << a0.a0.a0.a0.a0 << ", " << a0.a0.a0.a0.a1 << "), ("
            << a0.a0.a0.a1.a0 << ", " << a0.a0.a0.a1.a1 << ")), (("
            << a0.a0.a1.a0.a0 << ", " << a0.a0.a1.a0.a1 << "), ("
            << a0.a0.a1.a1.a0 << ", " << a0.a0.a1.a1.a1 << "))), ((("
            << a0.a1.a0.a0.a0 << ", " << a0.a1.a0.a0.a1 << "), ("
            << a0.a1.a0.a1.a0 << ", " << a0.a1.a0.a1.a1 << ")), (("
            << a0.a1.a1.a0.a0 << ", " << a0.a1.a1.a0.a1 << "), ("
            << a0.a1.a1.a1.a0 << ", " << a0.a1.a1.a1.a1 << ")))), (((("
            << a1.a0.a0.a0.a0 << ", " << a1.a0.a0.a0.a1 << "), ("
            << a1.a0.a0.a1.a0 << ", " << a1.a0.a0.a1.a1 << ")), (("
            << a1.a0.a1.a0.a0 << ", " << a1.a0.a1.a0.a1 << "), ("
            << a1.a0.a1.a1.a0 << ", " << a1.a0.a1.a1.a1 << "))), ((("
            << a1.a1.a0.a0.a0 << ", " << a1.a1.a0.a0.a1 << "), ("
            << a1.a1.a0.a1.a0 << ", " << a1.a1.a0.a1.a1 << ")), (("
            << a1.a1.a1.a0.a0 << ", " << a1.a1.a1.a0.a1 << "), ("
            << a1.a1.a1.a1.a0 << ", " << a1.a1.a1.a1.a1 << ")))))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT void TestAsyncPassStructNestedIntStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructNestedIntStructAlignmentInt16 a0)) {
  StructNestedIntStructAlignmentInt16 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestAsyncPassStructNestedIntStructAlignmentInt16("
            << "(((" << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT void TestAsyncPassStructNestedIntStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructNestedIntStructAlignmentInt32 a0)) {
  StructNestedIntStructAlignmentInt32 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestAsyncPassStructNestedIntStructAlignmentInt32("
            << "(((" << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT void TestAsyncPassStructNestedIntStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructNestedIntStructAlignmentInt64 a0)) {
  StructNestedIntStructAlignmentInt64 a0 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a0.a1.a0 = 4;
  a0.a1.a1 = -5;
  a0.a1.a2 = 6;

  std::cout << "Calling TestAsyncPassStructNestedIntStructAlignmentInt64("
            << "(((" << static_cast<int>(a0.a0.a0) << ", " << a0.a0.a1 << ", "
            << static_cast<int>(a0.a0.a2) << "), ("
            << static_cast<int>(a0.a1.a0) << ", " << a0.a1.a1 << ", "
            << static_cast<int>(a0.a1.a2) << ")))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT void TestAsyncPassStructNestedIrregularEvenBiggerx4(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructNestedIrregularEvenBigger a0,
              StructNestedIrregularEvenBigger a1,
              StructNestedIrregularEvenBigger a2,
              StructNestedIrregularEvenBigger a3)) {
  StructNestedIrregularEvenBigger a0 = {};
  StructNestedIrregularEvenBigger a1 = {};
  StructNestedIrregularEvenBigger a2 = {};
  StructNestedIrregularEvenBigger a3 = {};

  a0.a0 = 1;
  a0.a1.a0.a0 = 2;
  a0.a1.a0.a1.a0.a0 = -3;
  a0.a1.a0.a1.a0.a1 = 4;
  a0.a1.a0.a1.a1.a0 = -5.0;
  a0.a1.a0.a2 = 6;
  a0.a1.a0.a3.a0.a0 = -7.0;
  a0.a1.a0.a3.a1 = 8.0;
  a0.a1.a0.a4 = 9;
  a0.a1.a0.a5.a0.a0 = 10.0;
  a0.a1.a0.a5.a1.a0 = -11.0;
  a0.a1.a0.a6 = 12;
  a0.a1.a1.a0.a0 = -13;
  a0.a1.a1.a0.a1 = 14;
  a0.a1.a1.a1.a0 = -15.0;
  a0.a1.a2 = 16.0;
  a0.a1.a3 = -17.0;
  a0.a2.a0.a0 = 18;
  a0.a2.a0.a1.a0.a0 = -19;
  a0.a2.a0.a1.a0.a1 = 20;
  a0.a2.a0.a1.a1.a0 = -21.0;
  a0.a2.a0.a2 = 22;
  a0.a2.a0.a3.a0.a0 = -23.0;
  a0.a2.a0.a3.a1 = 24.0;
  a0.a2.a0.a4 = 25;
  a0.a2.a0.a5.a0.a0 = 26.0;
  a0.a2.a0.a5.a1.a0 = -27.0;
  a0.a2.a0.a6 = 28;
  a0.a2.a1.a0.a0 = -29;
  a0.a2.a1.a0.a1 = 30;
  a0.a2.a1.a1.a0 = -31.0;
  a0.a2.a2 = 32.0;
  a0.a2.a3 = -33.0;
  a0.a3 = 34.0;
  a1.a0 = 35;
  a1.a1.a0.a0 = 36;
  a1.a1.a0.a1.a0.a0 = -37;
  a1.a1.a0.a1.a0.a1 = 38;
  a1.a1.a0.a1.a1.a0 = -39.0;
  a1.a1.a0.a2 = 40;
  a1.a1.a0.a3.a0.a0 = -41.0;
  a1.a1.a0.a3.a1 = 42.0;
  a1.a1.a0.a4 = 43;
  a1.a1.a0.a5.a0.a0 = 44.0;
  a1.a1.a0.a5.a1.a0 = -45.0;
  a1.a1.a0.a6 = 46;
  a1.a1.a1.a0.a0 = -47;
  a1.a1.a1.a0.a1 = 48;
  a1.a1.a1.a1.a0 = -49.0;
  a1.a1.a2 = 50.0;
  a1.a1.a3 = -51.0;
  a1.a2.a0.a0 = 52;
  a1.a2.a0.a1.a0.a0 = -53;
  a1.a2.a0.a1.a0.a1 = 54;
  a1.a2.a0.a1.a1.a0 = -55.0;
  a1.a2.a0.a2 = 56;
  a1.a2.a0.a3.a0.a0 = -57.0;
  a1.a2.a0.a3.a1 = 58.0;
  a1.a2.a0.a4 = 59;
  a1.a2.a0.a5.a0.a0 = 60.0;
  a1.a2.a0.a5.a1.a0 = -61.0;
  a1.a2.a0.a6 = 62;
  a1.a2.a1.a0.a0 = -63;
  a1.a2.a1.a0.a1 = 64;
  a1.a2.a1.a1.a0 = -65.0;
  a1.a2.a2 = 66.0;
  a1.a2.a3 = -67.0;
  a1.a3 = 68.0;
  a2.a0 = 69;
  a2.a1.a0.a0 = 70;
  a2.a1.a0.a1.a0.a0 = -71;
  a2.a1.a0.a1.a0.a1 = 72;
  a2.a1.a0.a1.a1.a0 = -73.0;
  a2.a1.a0.a2 = 74;
  a2.a1.a0.a3.a0.a0 = -75.0;
  a2.a1.a0.a3.a1 = 76.0;
  a2.a1.a0.a4 = 77;
  a2.a1.a0.a5.a0.a0 = 78.0;
  a2.a1.a0.a5.a1.a0 = -79.0;
  a2.a1.a0.a6 = 80;
  a2.a1.a1.a0.a0 = -81;
  a2.a1.a1.a0.a1 = 82;
  a2.a1.a1.a1.a0 = -83.0;
  a2.a1.a2 = 84.0;
  a2.a1.a3 = -85.0;
  a2.a2.a0.a0 = 86;
  a2.a2.a0.a1.a0.a0 = -87;
  a2.a2.a0.a1.a0.a1 = 88;
  a2.a2.a0.a1.a1.a0 = -89.0;
  a2.a2.a0.a2 = 90;
  a2.a2.a0.a3.a0.a0 = -91.0;
  a2.a2.a0.a3.a1 = 92.0;
  a2.a2.a0.a4 = 93;
  a2.a2.a0.a5.a0.a0 = 94.0;
  a2.a2.a0.a5.a1.a0 = -95.0;
  a2.a2.a0.a6 = 96;
  a2.a2.a1.a0.a0 = -97;
  a2.a2.a1.a0.a1 = 98;
  a2.a2.a1.a1.a0 = -99.0;
  a2.a2.a2 = 100.0;
  a2.a2.a3 = -101.0;
  a2.a3 = 102.0;
  a3.a0 = 103;
  a3.a1.a0.a0 = 104;
  a3.a1.a0.a1.a0.a0 = -105;
  a3.a1.a0.a1.a0.a1 = 106;
  a3.a1.a0.a1.a1.a0 = -107.0;
  a3.a1.a0.a2 = 108;
  a3.a1.a0.a3.a0.a0 = -109.0;
  a3.a1.a0.a3.a1 = 110.0;
  a3.a1.a0.a4 = 111;
  a3.a1.a0.a5.a0.a0 = 112.0;
  a3.a1.a0.a5.a1.a0 = -113.0;
  a3.a1.a0.a6 = 114;
  a3.a1.a1.a0.a0 = -115;
  a3.a1.a1.a0.a1 = 116;
  a3.a1.a1.a1.a0 = -117.0;
  a3.a1.a2 = 118.0;
  a3.a1.a3 = -119.0;
  a3.a2.a0.a0 = 120;
  a3.a2.a0.a1.a0.a0 = -121;
  a3.a2.a0.a1.a0.a1 = 122;
  a3.a2.a0.a1.a1.a0 = -123.0;
  a3.a2.a0.a2 = 124;
  a3.a2.a0.a3.a0.a0 = -125.0;
  a3.a2.a0.a3.a1 = 126.0;
  a3.a2.a0.a4 = 127;
  a3.a2.a0.a5.a0.a0 = 128.0;
  a3.a2.a0.a5.a1.a0 = -129.0;
  a3.a2.a0.a6 = 130;
  a3.a2.a1.a0.a0 = -131;
  a3.a2.a1.a0.a1 = 132;
  a3.a2.a1.a1.a0 = -133.0;
  a3.a2.a2 = 134.0;
  a3.a2.a3 = -135.0;
  a3.a3 = 136.0;

  std::cout
      << "Calling TestAsyncPassStructNestedIrregularEvenBiggerx4(" << "(("
      << a0.a0 << ", ((" << a0.a1.a0.a0 << ", ((" << a0.a1.a0.a1.a0.a0 << ", "
      << a0.a1.a0.a1.a0.a1 << "), (" << a0.a1.a0.a1.a1.a0 << ")), "
      << a0.a1.a0.a2 << ", ((" << a0.a1.a0.a3.a0.a0 << "), " << a0.a1.a0.a3.a1
      << "), " << a0.a1.a0.a4 << ", ((" << a0.a1.a0.a5.a0.a0 << "), ("
      << a0.a1.a0.a5.a1.a0 << ")), " << a0.a1.a0.a6 << "), ((" << a0.a1.a1.a0.a0
      << ", " << a0.a1.a1.a0.a1 << "), (" << a0.a1.a1.a1.a0 << ")), "
      << a0.a1.a2 << ", " << a0.a1.a3 << "), ((" << a0.a2.a0.a0 << ", (("
      << a0.a2.a0.a1.a0.a0 << ", " << a0.a2.a0.a1.a0.a1 << "), ("
      << a0.a2.a0.a1.a1.a0 << ")), " << a0.a2.a0.a2 << ", (("
      << a0.a2.a0.a3.a0.a0 << "), " << a0.a2.a0.a3.a1 << "), " << a0.a2.a0.a4
      << ", ((" << a0.a2.a0.a5.a0.a0 << "), (" << a0.a2.a0.a5.a1.a0 << ")), "
      << a0.a2.a0.a6 << "), ((" << a0.a2.a1.a0.a0 << ", " << a0.a2.a1.a0.a1
      << "), (" << a0.a2.a1.a1.a0 << ")), " << a0.a2.a2 << ", " << a0.a2.a3
      << "), " << a0.a3 << "), (" << a1.a0 << ", ((" << a1.a1.a0.a0 << ", (("
      << a1.a1.a0.a1.a0.a0 << ", " << a1.a1.a0.a1.a0.a1 << "), ("
      << a1.a1.a0.a1.a1.a0 << ")), " << a1.a1.a0.a2 << ", (("
      << a1.a1.a0.a3.a0.a0 << "), " << a1.a1.a0.a3.a1 << "), " << a1.a1.a0.a4
      << ", ((" << a1.a1.a0.a5.a0.a0 << "), (" << a1.a1.a0.a5.a1.a0 << ")), "
      << a1.a1.a0.a6 << "), ((" << a1.a1.a1.a0.a0 << ", " << a1.a1.a1.a0.a1
      << "), (" << a1.a1.a1.a1.a0 << ")), " << a1.a1.a2 << ", " << a1.a1.a3
      << "), ((" << a1.a2.a0.a0 << ", ((" << a1.a2.a0.a1.a0.a0 << ", "
      << a1.a2.a0.a1.a0.a1 << "), (" << a1.a2.a0.a1.a1.a0 << ")), "
      << a1.a2.a0.a2 << ", ((" << a1.a2.a0.a3.a0.a0 << "), " << a1.a2.a0.a3.a1
      << "), " << a1.a2.a0.a4 << ", ((" << a1.a2.a0.a5.a0.a0 << "), ("
      << a1.a2.a0.a5.a1.a0 << ")), " << a1.a2.a0.a6 << "), ((" << a1.a2.a1.a0.a0
      << ", " << a1.a2.a1.a0.a1 << "), (" << a1.a2.a1.a1.a0 << ")), "
      << a1.a2.a2 << ", " << a1.a2.a3 << "), " << a1.a3 << "), (" << a2.a0
      << ", ((" << a2.a1.a0.a0 << ", ((" << a2.a1.a0.a1.a0.a0 << ", "
      << a2.a1.a0.a1.a0.a1 << "), (" << a2.a1.a0.a1.a1.a0 << ")), "
      << a2.a1.a0.a2 << ", ((" << a2.a1.a0.a3.a0.a0 << "), " << a2.a1.a0.a3.a1
      << "), " << a2.a1.a0.a4 << ", ((" << a2.a1.a0.a5.a0.a0 << "), ("
      << a2.a1.a0.a5.a1.a0 << ")), " << a2.a1.a0.a6 << "), ((" << a2.a1.a1.a0.a0
      << ", " << a2.a1.a1.a0.a1 << "), (" << a2.a1.a1.a1.a0 << ")), "
      << a2.a1.a2 << ", " << a2.a1.a3 << "), ((" << a2.a2.a0.a0 << ", (("
      << a2.a2.a0.a1.a0.a0 << ", " << a2.a2.a0.a1.a0.a1 << "), ("
      << a2.a2.a0.a1.a1.a0 << ")), " << a2.a2.a0.a2 << ", (("
      << a2.a2.a0.a3.a0.a0 << "), " << a2.a2.a0.a3.a1 << "), " << a2.a2.a0.a4
      << ", ((" << a2.a2.a0.a5.a0.a0 << "), (" << a2.a2.a0.a5.a1.a0 << ")), "
      << a2.a2.a0.a6 << "), ((" << a2.a2.a1.a0.a0 << ", " << a2.a2.a1.a0.a1
      << "), (" << a2.a2.a1.a1.a0 << ")), " << a2.a2.a2 << ", " << a2.a2.a3
      << "), " << a2.a3 << "), (" << a3.a0 << ", ((" << a3.a1.a0.a0 << ", (("
      << a3.a1.a0.a1.a0.a0 << ", " << a3.a1.a0.a1.a0.a1 << "), ("
      << a3.a1.a0.a1.a1.a0 << ")), " << a3.a1.a0.a2 << ", (("
      << a3.a1.a0.a3.a0.a0 << "), " << a3.a1.a0.a3.a1 << "), " << a3.a1.a0.a4
      << ", ((" << a3.a1.a0.a5.a0.a0 << "), (" << a3.a1.a0.a5.a1.a0 << ")), "
      << a3.a1.a0.a6 << "), ((" << a3.a1.a1.a0.a0 << ", " << a3.a1.a1.a0.a1
      << "), (" << a3.a1.a1.a1.a0 << ")), " << a3.a1.a2 << ", " << a3.a1.a3
      << "), ((" << a3.a2.a0.a0 << ", ((" << a3.a2.a0.a1.a0.a0 << ", "
      << a3.a2.a0.a1.a0.a1 << "), (" << a3.a2.a0.a1.a1.a0 << ")), "
      << a3.a2.a0.a2 << ", ((" << a3.a2.a0.a3.a0.a0 << "), " << a3.a2.a0.a3.a1
      << "), " << a3.a2.a0.a4 << ", ((" << a3.a2.a0.a5.a0.a0 << "), ("
      << a3.a2.a0.a5.a1.a0 << ")), " << a3.a2.a0.a6 << "), ((" << a3.a2.a1.a0.a0
      << ", " << a3.a2.a1.a0.a1 << "), (" << a3.a2.a1.a1.a0 << ")), "
      << a3.a2.a2 << ", " << a3.a2.a3 << "), " << a3.a3 << "))" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Simple struct with inline array.
DART_EXPORT void TestAsyncPassStruct8BytesInlineArrayIntx4(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesInlineArrayInt a0,
              Struct8BytesInlineArrayInt a1,
              Struct8BytesInlineArrayInt a2,
              Struct8BytesInlineArrayInt a3)) {
  Struct8BytesInlineArrayInt a0 = {};
  Struct8BytesInlineArrayInt a1 = {};
  Struct8BytesInlineArrayInt a2 = {};
  Struct8BytesInlineArrayInt a3 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;
  a1.a0[0] = 9;
  a1.a0[1] = 10;
  a1.a0[2] = 11;
  a1.a0[3] = 12;
  a1.a0[4] = 13;
  a1.a0[5] = 14;
  a1.a0[6] = 15;
  a1.a0[7] = 16;
  a2.a0[0] = 17;
  a2.a0[1] = 18;
  a2.a0[2] = 19;
  a2.a0[3] = 20;
  a2.a0[4] = 21;
  a2.a0[5] = 22;
  a2.a0[6] = 23;
  a2.a0[7] = 24;
  a3.a0[0] = 25;
  a3.a0[1] = 26;
  a3.a0[2] = 27;
  a3.a0[3] = 28;
  a3.a0[4] = 29;
  a3.a0[5] = 30;
  a3.a0[6] = 31;
  a3.a0[7] = 32;

  std::cout << "Calling TestAsyncPassStruct8BytesInlineArrayIntx4(" << "((["
            << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
            << ", " << static_cast<int>(a0.a0[2]) << ", "
            << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
            << ", " << static_cast<int>(a0.a0[5]) << ", "
            << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
            << "]), ([" << static_cast<int>(a1.a0[0]) << ", "
            << static_cast<int>(a1.a0[1]) << ", " << static_cast<int>(a1.a0[2])
            << ", " << static_cast<int>(a1.a0[3]) << ", "
            << static_cast<int>(a1.a0[4]) << ", " << static_cast<int>(a1.a0[5])
            << ", " << static_cast<int>(a1.a0[6]) << ", "
            << static_cast<int>(a1.a0[7]) << "]), (["
            << static_cast<int>(a2.a0[0]) << ", " << static_cast<int>(a2.a0[1])
            << ", " << static_cast<int>(a2.a0[2]) << ", "
            << static_cast<int>(a2.a0[3]) << ", " << static_cast<int>(a2.a0[4])
            << ", " << static_cast<int>(a2.a0[5]) << ", "
            << static_cast<int>(a2.a0[6]) << ", " << static_cast<int>(a2.a0[7])
            << "]), ([" << static_cast<int>(a3.a0[0]) << ", "
            << static_cast<int>(a3.a0[1]) << ", " << static_cast<int>(a3.a0[2])
            << ", " << static_cast<int>(a3.a0[3]) << ", "
            << static_cast<int>(a3.a0[4]) << ", " << static_cast<int>(a3.a0[5])
            << ", " << static_cast<int>(a3.a0[6]) << ", "
            << static_cast<int>(a3.a0[7]) << "]))" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Irregular struct with inline array.
DART_EXPORT void TestAsyncPassStructInlineArrayIrregularx4(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructInlineArrayIrregular a0,
              StructInlineArrayIrregular a1,
              StructInlineArrayIrregular a2,
              StructInlineArrayIrregular a3)) {
  StructInlineArrayIrregular a0 = {};
  StructInlineArrayIrregular a1 = {};
  StructInlineArrayIrregular a2 = {};
  StructInlineArrayIrregular a3 = {};

  a0.a0[0].a0 = -1;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3;
  a0.a0[1].a1 = 4;
  a0.a1 = 5;
  a1.a0[0].a0 = 6;
  a1.a0[0].a1 = -7;
  a1.a0[1].a0 = 8;
  a1.a0[1].a1 = -9;
  a1.a1 = 10;
  a2.a0[0].a0 = -11;
  a2.a0[0].a1 = 12;
  a2.a0[1].a0 = -13;
  a2.a0[1].a1 = 14;
  a2.a1 = 15;
  a3.a0[0].a0 = 16;
  a3.a0[0].a1 = -17;
  a3.a0[1].a0 = 18;
  a3.a0[1].a1 = -19;
  a3.a1 = 20;

  std::cout << "Calling TestAsyncPassStructInlineArrayIrregularx4(" << "(([("
            << a0.a0[0].a0 << ", " << static_cast<int>(a0.a0[0].a1) << "), ("
            << a0.a0[1].a0 << ", " << static_cast<int>(a0.a0[1].a1) << ")], "
            << static_cast<int>(a0.a1) << "), ([(" << a1.a0[0].a0 << ", "
            << static_cast<int>(a1.a0[0].a1) << "), (" << a1.a0[1].a0 << ", "
            << static_cast<int>(a1.a0[1].a1) << ")], "
            << static_cast<int>(a1.a1) << "), ([(" << a2.a0[0].a0 << ", "
            << static_cast<int>(a2.a0[0].a1) << "), (" << a2.a0[1].a0 << ", "
            << static_cast<int>(a2.a0[1].a1) << ")], "
            << static_cast<int>(a2.a1) << "), ([(" << a3.a0[0].a0 << ", "
            << static_cast<int>(a3.a0[0].a1) << "), (" << a3.a0[1].a0 << ", "
            << static_cast<int>(a3.a0[1].a1) << ")], "
            << static_cast<int>(a3.a1) << "))" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Regular larger struct with inline array.
DART_EXPORT void TestAsyncPassStructInlineArray100Bytes(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructInlineArray100Bytes a0)) {
  StructInlineArray100Bytes a0 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;
  a0.a0[8] = 9;
  a0.a0[9] = 10;
  a0.a0[10] = 11;
  a0.a0[11] = 12;
  a0.a0[12] = 13;
  a0.a0[13] = 14;
  a0.a0[14] = 15;
  a0.a0[15] = 16;
  a0.a0[16] = 17;
  a0.a0[17] = 18;
  a0.a0[18] = 19;
  a0.a0[19] = 20;
  a0.a0[20] = 21;
  a0.a0[21] = 22;
  a0.a0[22] = 23;
  a0.a0[23] = 24;
  a0.a0[24] = 25;
  a0.a0[25] = 26;
  a0.a0[26] = 27;
  a0.a0[27] = 28;
  a0.a0[28] = 29;
  a0.a0[29] = 30;
  a0.a0[30] = 31;
  a0.a0[31] = 32;
  a0.a0[32] = 33;
  a0.a0[33] = 34;
  a0.a0[34] = 35;
  a0.a0[35] = 36;
  a0.a0[36] = 37;
  a0.a0[37] = 38;
  a0.a0[38] = 39;
  a0.a0[39] = 40;
  a0.a0[40] = 41;
  a0.a0[41] = 42;
  a0.a0[42] = 43;
  a0.a0[43] = 44;
  a0.a0[44] = 45;
  a0.a0[45] = 46;
  a0.a0[46] = 47;
  a0.a0[47] = 48;
  a0.a0[48] = 49;
  a0.a0[49] = 50;
  a0.a0[50] = 51;
  a0.a0[51] = 52;
  a0.a0[52] = 53;
  a0.a0[53] = 54;
  a0.a0[54] = 55;
  a0.a0[55] = 56;
  a0.a0[56] = 57;
  a0.a0[57] = 58;
  a0.a0[58] = 59;
  a0.a0[59] = 60;
  a0.a0[60] = 61;
  a0.a0[61] = 62;
  a0.a0[62] = 63;
  a0.a0[63] = 64;
  a0.a0[64] = 65;
  a0.a0[65] = 66;
  a0.a0[66] = 67;
  a0.a0[67] = 68;
  a0.a0[68] = 69;
  a0.a0[69] = 70;
  a0.a0[70] = 71;
  a0.a0[71] = 72;
  a0.a0[72] = 73;
  a0.a0[73] = 74;
  a0.a0[74] = 75;
  a0.a0[75] = 76;
  a0.a0[76] = 77;
  a0.a0[77] = 78;
  a0.a0[78] = 79;
  a0.a0[79] = 80;
  a0.a0[80] = 81;
  a0.a0[81] = 82;
  a0.a0[82] = 83;
  a0.a0[83] = 84;
  a0.a0[84] = 85;
  a0.a0[85] = 86;
  a0.a0[86] = 87;
  a0.a0[87] = 88;
  a0.a0[88] = 89;
  a0.a0[89] = 90;
  a0.a0[90] = 91;
  a0.a0[91] = 92;
  a0.a0[92] = 93;
  a0.a0[93] = 94;
  a0.a0[94] = 95;
  a0.a0[95] = 96;
  a0.a0[96] = 97;
  a0.a0[97] = 98;
  a0.a0[98] = 99;
  a0.a0[99] = 100;

  std::cout
      << "Calling TestAsyncPassStructInlineArray100Bytes(" << "((["
      << static_cast<int>(a0.a0[0]) << ", " << static_cast<int>(a0.a0[1])
      << ", " << static_cast<int>(a0.a0[2]) << ", "
      << static_cast<int>(a0.a0[3]) << ", " << static_cast<int>(a0.a0[4])
      << ", " << static_cast<int>(a0.a0[5]) << ", "
      << static_cast<int>(a0.a0[6]) << ", " << static_cast<int>(a0.a0[7])
      << ", " << static_cast<int>(a0.a0[8]) << ", "
      << static_cast<int>(a0.a0[9]) << ", " << static_cast<int>(a0.a0[10])
      << ", " << static_cast<int>(a0.a0[11]) << ", "
      << static_cast<int>(a0.a0[12]) << ", " << static_cast<int>(a0.a0[13])
      << ", " << static_cast<int>(a0.a0[14]) << ", "
      << static_cast<int>(a0.a0[15]) << ", " << static_cast<int>(a0.a0[16])
      << ", " << static_cast<int>(a0.a0[17]) << ", "
      << static_cast<int>(a0.a0[18]) << ", " << static_cast<int>(a0.a0[19])
      << ", " << static_cast<int>(a0.a0[20]) << ", "
      << static_cast<int>(a0.a0[21]) << ", " << static_cast<int>(a0.a0[22])
      << ", " << static_cast<int>(a0.a0[23]) << ", "
      << static_cast<int>(a0.a0[24]) << ", " << static_cast<int>(a0.a0[25])
      << ", " << static_cast<int>(a0.a0[26]) << ", "
      << static_cast<int>(a0.a0[27]) << ", " << static_cast<int>(a0.a0[28])
      << ", " << static_cast<int>(a0.a0[29]) << ", "
      << static_cast<int>(a0.a0[30]) << ", " << static_cast<int>(a0.a0[31])
      << ", " << static_cast<int>(a0.a0[32]) << ", "
      << static_cast<int>(a0.a0[33]) << ", " << static_cast<int>(a0.a0[34])
      << ", " << static_cast<int>(a0.a0[35]) << ", "
      << static_cast<int>(a0.a0[36]) << ", " << static_cast<int>(a0.a0[37])
      << ", " << static_cast<int>(a0.a0[38]) << ", "
      << static_cast<int>(a0.a0[39]) << ", " << static_cast<int>(a0.a0[40])
      << ", " << static_cast<int>(a0.a0[41]) << ", "
      << static_cast<int>(a0.a0[42]) << ", " << static_cast<int>(a0.a0[43])
      << ", " << static_cast<int>(a0.a0[44]) << ", "
      << static_cast<int>(a0.a0[45]) << ", " << static_cast<int>(a0.a0[46])
      << ", " << static_cast<int>(a0.a0[47]) << ", "
      << static_cast<int>(a0.a0[48]) << ", " << static_cast<int>(a0.a0[49])
      << ", " << static_cast<int>(a0.a0[50]) << ", "
      << static_cast<int>(a0.a0[51]) << ", " << static_cast<int>(a0.a0[52])
      << ", " << static_cast<int>(a0.a0[53]) << ", "
      << static_cast<int>(a0.a0[54]) << ", " << static_cast<int>(a0.a0[55])
      << ", " << static_cast<int>(a0.a0[56]) << ", "
      << static_cast<int>(a0.a0[57]) << ", " << static_cast<int>(a0.a0[58])
      << ", " << static_cast<int>(a0.a0[59]) << ", "
      << static_cast<int>(a0.a0[60]) << ", " << static_cast<int>(a0.a0[61])
      << ", " << static_cast<int>(a0.a0[62]) << ", "
      << static_cast<int>(a0.a0[63]) << ", " << static_cast<int>(a0.a0[64])
      << ", " << static_cast<int>(a0.a0[65]) << ", "
      << static_cast<int>(a0.a0[66]) << ", " << static_cast<int>(a0.a0[67])
      << ", " << static_cast<int>(a0.a0[68]) << ", "
      << static_cast<int>(a0.a0[69]) << ", " << static_cast<int>(a0.a0[70])
      << ", " << static_cast<int>(a0.a0[71]) << ", "
      << static_cast<int>(a0.a0[72]) << ", " << static_cast<int>(a0.a0[73])
      << ", " << static_cast<int>(a0.a0[74]) << ", "
      << static_cast<int>(a0.a0[75]) << ", " << static_cast<int>(a0.a0[76])
      << ", " << static_cast<int>(a0.a0[77]) << ", "
      << static_cast<int>(a0.a0[78]) << ", " << static_cast<int>(a0.a0[79])
      << ", " << static_cast<int>(a0.a0[80]) << ", "
      << static_cast<int>(a0.a0[81]) << ", " << static_cast<int>(a0.a0[82])
      << ", " << static_cast<int>(a0.a0[83]) << ", "
      << static_cast<int>(a0.a0[84]) << ", " << static_cast<int>(a0.a0[85])
      << ", " << static_cast<int>(a0.a0[86]) << ", "
      << static_cast<int>(a0.a0[87]) << ", " << static_cast<int>(a0.a0[88])
      << ", " << static_cast<int>(a0.a0[89]) << ", "
      << static_cast<int>(a0.a0[90]) << ", " << static_cast<int>(a0.a0[91])
      << ", " << static_cast<int>(a0.a0[92]) << ", "
      << static_cast<int>(a0.a0[93]) << ", " << static_cast<int>(a0.a0[94])
      << ", " << static_cast<int>(a0.a0[95]) << ", "
      << static_cast<int>(a0.a0[96]) << ", " << static_cast<int>(a0.a0[97])
      << ", " << static_cast<int>(a0.a0[98]) << ", "
      << static_cast<int>(a0.a0[99]) << "]))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStructStruct16BytesHomogeneousFloat2x5(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct16BytesHomogeneousFloat2 a0,
              StructStruct16BytesHomogeneousFloat2 a1,
              StructStruct16BytesHomogeneousFloat2 a2,
              StructStruct16BytesHomogeneousFloat2 a3,
              StructStruct16BytesHomogeneousFloat2 a4)) {
  StructStruct16BytesHomogeneousFloat2 a0 = {};
  StructStruct16BytesHomogeneousFloat2 a1 = {};
  StructStruct16BytesHomogeneousFloat2 a2 = {};
  StructStruct16BytesHomogeneousFloat2 a3 = {};
  StructStruct16BytesHomogeneousFloat2 a4 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;
  a1.a0.a0 = -5.0;
  a1.a1[0].a0 = 6.0;
  a1.a1[1].a0 = -7.0;
  a1.a2 = 8.0;
  a2.a0.a0 = -9.0;
  a2.a1[0].a0 = 10.0;
  a2.a1[1].a0 = -11.0;
  a2.a2 = 12.0;
  a3.a0.a0 = -13.0;
  a3.a1[0].a0 = 14.0;
  a3.a1[1].a0 = -15.0;
  a3.a2 = 16.0;
  a4.a0.a0 = -17.0;
  a4.a1[0].a0 = 18.0;
  a4.a1[1].a0 = -19.0;
  a4.a2 = 20.0;

  std::cout << "Calling TestAsyncPassStructStruct16BytesHomogeneousFloat2x5("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "), ((" << a1.a0.a0 << "), [("
            << a1.a1[0].a0 << "), (" << a1.a1[1].a0 << ")], " << a1.a2
            << "), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0 << "), ("
            << a2.a1[1].a0 << ")], " << a2.a2 << "), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << "), (" << a3.a1[1].a0 << ")], " << a3.a2
            << "), ((" << a4.a0.a0 << "), [(" << a4.a1[0].a0 << "), ("
            << a4.a1[1].a0 << ")], " << a4.a2 << "))" << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT void TestAsyncPassStructStruct32BytesHomogeneousDouble2x5(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct32BytesHomogeneousDouble2 a0,
              StructStruct32BytesHomogeneousDouble2 a1,
              StructStruct32BytesHomogeneousDouble2 a2,
              StructStruct32BytesHomogeneousDouble2 a3,
              StructStruct32BytesHomogeneousDouble2 a4)) {
  StructStruct32BytesHomogeneousDouble2 a0 = {};
  StructStruct32BytesHomogeneousDouble2 a1 = {};
  StructStruct32BytesHomogeneousDouble2 a2 = {};
  StructStruct32BytesHomogeneousDouble2 a3 = {};
  StructStruct32BytesHomogeneousDouble2 a4 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;
  a1.a0.a0 = -5.0;
  a1.a1[0].a0 = 6.0;
  a1.a1[1].a0 = -7.0;
  a1.a2 = 8.0;
  a2.a0.a0 = -9.0;
  a2.a1[0].a0 = 10.0;
  a2.a1[1].a0 = -11.0;
  a2.a2 = 12.0;
  a3.a0.a0 = -13.0;
  a3.a1[0].a0 = 14.0;
  a3.a1[1].a0 = -15.0;
  a3.a2 = 16.0;
  a4.a0.a0 = -17.0;
  a4.a1[0].a0 = 18.0;
  a4.a1[1].a0 = -19.0;
  a4.a2 = 20.0;

  std::cout << "Calling TestAsyncPassStructStruct32BytesHomogeneousDouble2x5("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), ("
            << a0.a1[1].a0 << ")], " << a0.a2 << "), ((" << a1.a0.a0 << "), [("
            << a1.a1[0].a0 << "), (" << a1.a1[1].a0 << ")], " << a1.a2
            << "), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0 << "), ("
            << a2.a1[1].a0 << ")], " << a2.a2 << "), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << "), (" << a3.a1[1].a0 << ")], " << a3.a2
            << "), ((" << a4.a0.a0 << "), [(" << a4.a1[0].a0 << "), ("
            << a4.a1[1].a0 << ")], " << a4.a2 << "))" << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions 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 void TestAsyncPassStructStruct16BytesMixed3x10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct16BytesMixed3 a0,
              StructStruct16BytesMixed3 a1,
              StructStruct16BytesMixed3 a2,
              StructStruct16BytesMixed3 a3,
              StructStruct16BytesMixed3 a4,
              StructStruct16BytesMixed3 a5,
              StructStruct16BytesMixed3 a6,
              StructStruct16BytesMixed3 a7,
              StructStruct16BytesMixed3 a8,
              StructStruct16BytesMixed3 a9)) {
  StructStruct16BytesMixed3 a0 = {};
  StructStruct16BytesMixed3 a1 = {};
  StructStruct16BytesMixed3 a2 = {};
  StructStruct16BytesMixed3 a3 = {};
  StructStruct16BytesMixed3 a4 = {};
  StructStruct16BytesMixed3 a5 = {};
  StructStruct16BytesMixed3 a6 = {};
  StructStruct16BytesMixed3 a7 = {};
  StructStruct16BytesMixed3 a8 = {};
  StructStruct16BytesMixed3 a9 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[0].a1 = -3;
  a0.a1[0].a2 = 4;
  a0.a2[0] = -5;
  a0.a2[1] = 6;
  a1.a0.a0 = -7.0;
  a1.a1[0].a0 = 8.0;
  a1.a1[0].a1 = -9;
  a1.a1[0].a2 = 10;
  a1.a2[0] = -11;
  a1.a2[1] = 12;
  a2.a0.a0 = -13.0;
  a2.a1[0].a0 = 14.0;
  a2.a1[0].a1 = -15;
  a2.a1[0].a2 = 16;
  a2.a2[0] = -17;
  a2.a2[1] = 18;
  a3.a0.a0 = -19.0;
  a3.a1[0].a0 = 20.0;
  a3.a1[0].a1 = -21;
  a3.a1[0].a2 = 22;
  a3.a2[0] = -23;
  a3.a2[1] = 24;
  a4.a0.a0 = -25.0;
  a4.a1[0].a0 = 26.0;
  a4.a1[0].a1 = -27;
  a4.a1[0].a2 = 28;
  a4.a2[0] = -29;
  a4.a2[1] = 30;
  a5.a0.a0 = -31.0;
  a5.a1[0].a0 = 32.0;
  a5.a1[0].a1 = -33;
  a5.a1[0].a2 = 34;
  a5.a2[0] = -35;
  a5.a2[1] = 36;
  a6.a0.a0 = -37.0;
  a6.a1[0].a0 = 38.0;
  a6.a1[0].a1 = -39;
  a6.a1[0].a2 = 40;
  a6.a2[0] = -41;
  a6.a2[1] = 42;
  a7.a0.a0 = -43.0;
  a7.a1[0].a0 = 44.0;
  a7.a1[0].a1 = -45;
  a7.a1[0].a2 = 46;
  a7.a2[0] = -47;
  a7.a2[1] = 48;
  a8.a0.a0 = -49.0;
  a8.a1[0].a0 = 50.0;
  a8.a1[0].a1 = -51;
  a8.a1[0].a2 = 52;
  a8.a2[0] = -53;
  a8.a2[1] = 54;
  a9.a0.a0 = -55.0;
  a9.a1[0].a0 = 56.0;
  a9.a1[0].a1 = -57;
  a9.a1[0].a2 = 58;
  a9.a2[0] = -59;
  a9.a2[1] = 60;

  std::cout << "Calling TestAsyncPassStructStruct16BytesMixed3x10(" << "((("
            << a0.a0.a0 << "), [(" << a0.a1[0].a0 << ", " << a0.a1[0].a1 << ", "
            << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", " << a0.a2[1]
            << "]), ((" << a1.a0.a0 << "), [(" << a1.a1[0].a0 << ", "
            << a1.a1[0].a1 << ", " << a1.a1[0].a2 << ")], [" << a1.a2[0] << ", "
            << a1.a2[1] << "]), ((" << a2.a0.a0 << "), [(" << a2.a1[0].a0
            << ", " << a2.a1[0].a1 << ", " << a2.a1[0].a2 << ")], [" << a2.a2[0]
            << ", " << a2.a2[1] << "]), ((" << a3.a0.a0 << "), [("
            << a3.a1[0].a0 << ", " << a3.a1[0].a1 << ", " << a3.a1[0].a2
            << ")], [" << a3.a2[0] << ", " << a3.a2[1] << "]), ((" << a4.a0.a0
            << "), [(" << a4.a1[0].a0 << ", " << a4.a1[0].a1 << ", "
            << a4.a1[0].a2 << ")], [" << a4.a2[0] << ", " << a4.a2[1]
            << "]), ((" << a5.a0.a0 << "), [(" << a5.a1[0].a0 << ", "
            << a5.a1[0].a1 << ", " << a5.a1[0].a2 << ")], [" << a5.a2[0] << ", "
            << a5.a2[1] << "]), ((" << a6.a0.a0 << "), [(" << a6.a1[0].a0
            << ", " << a6.a1[0].a1 << ", " << a6.a1[0].a2 << ")], [" << a6.a2[0]
            << ", " << a6.a2[1] << "]), ((" << a7.a0.a0 << "), [("
            << a7.a1[0].a0 << ", " << a7.a1[0].a1 << ", " << a7.a1[0].a2
            << ")], [" << a7.a2[0] << ", " << a7.a2[1] << "]), ((" << a8.a0.a0
            << "), [(" << a8.a1[0].a0 << ", " << a8.a1[0].a1 << ", "
            << a8.a1[0].a2 << ")], [" << a8.a2[0] << ", " << a8.a2[1]
            << "]), ((" << a9.a0.a0 << "), [(" << a9.a1[0].a0 << ", "
            << a9.a1[0].a1 << ", " << a9.a1[0].a2 << ")], [" << a9.a2[0] << ", "
            << a9.a2[1] << "]))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Test multi dimensional inline array struct as argument.
DART_EXPORT void TestAsyncPassUint8Struct32BytesInlineArrayMultiDimensionalI(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0,
              Struct32BytesInlineArrayMultiDimensionalInt a1,
              uint8_t a2,
              Struct8BytesInlineArrayMultiDimensionalInt a3,
              uint8_t a4,
              Struct8BytesInlineArrayMultiDimensionalInt a5,
              uint8_t a6)) {
  uint8_t a0;
  Struct32BytesInlineArrayMultiDimensionalInt a1 = {};
  uint8_t a2;
  Struct8BytesInlineArrayMultiDimensionalInt a3 = {};
  uint8_t a4;
  Struct8BytesInlineArrayMultiDimensionalInt a5 = {};
  uint8_t a6;

  a0 = 1;
  a1.a0[0][0][0][0][0] = 2;
  a1.a0[0][0][0][0][1] = 3;
  a1.a0[0][0][0][1][0] = 4;
  a1.a0[0][0][0][1][1] = 5;
  a1.a0[0][0][1][0][0] = 6;
  a1.a0[0][0][1][0][1] = 7;
  a1.a0[0][0][1][1][0] = 8;
  a1.a0[0][0][1][1][1] = 9;
  a1.a0[0][1][0][0][0] = 10;
  a1.a0[0][1][0][0][1] = 11;
  a1.a0[0][1][0][1][0] = 12;
  a1.a0[0][1][0][1][1] = 13;
  a1.a0[0][1][1][0][0] = 14;
  a1.a0[0][1][1][0][1] = 15;
  a1.a0[0][1][1][1][0] = 16;
  a1.a0[0][1][1][1][1] = 17;
  a1.a0[1][0][0][0][0] = 18;
  a1.a0[1][0][0][0][1] = 19;
  a1.a0[1][0][0][1][0] = 20;
  a1.a0[1][0][0][1][1] = 21;
  a1.a0[1][0][1][0][0] = 22;
  a1.a0[1][0][1][0][1] = 23;
  a1.a0[1][0][1][1][0] = 24;
  a1.a0[1][0][1][1][1] = 25;
  a1.a0[1][1][0][0][0] = 26;
  a1.a0[1][1][0][0][1] = 27;
  a1.a0[1][1][0][1][0] = 28;
  a1.a0[1][1][0][1][1] = 29;
  a1.a0[1][1][1][0][0] = 30;
  a1.a0[1][1][1][0][1] = 31;
  a1.a0[1][1][1][1][0] = 32;
  a1.a0[1][1][1][1][1] = 33;
  a2 = 34;
  a3.a0[0][0][0] = 35;
  a3.a0[0][0][1] = 36;
  a3.a0[0][1][0] = 37;
  a3.a0[0][1][1] = 38;
  a3.a0[1][0][0] = 39;
  a3.a0[1][0][1] = 40;
  a3.a0[1][1][0] = 41;
  a3.a0[1][1][1] = 42;
  a4 = 43;
  a5.a0[0][0][0] = 44;
  a5.a0[0][0][1] = 45;
  a5.a0[0][1][0] = 46;
  a5.a0[0][1][1] = 47;
  a5.a0[1][0][0] = 48;
  a5.a0[1][0][1] = 49;
  a5.a0[1][1][0] = 50;
  a5.a0[1][1][1] = 51;
  a6 = 52;

  std::cout
      << "Calling TestAsyncPassUint8Struct32BytesInlineArrayMultiDimensionalI("
      << "(" << static_cast<int>(a0) << ", ([[[[["
      << static_cast<int>(a1.a0[0][0][0][0][0]) << ", "
      << static_cast<int>(a1.a0[0][0][0][0][1]) << "], ["
      << static_cast<int>(a1.a0[0][0][0][1][0]) << ", "
      << static_cast<int>(a1.a0[0][0][0][1][1]) << "]], [["
      << static_cast<int>(a1.a0[0][0][1][0][0]) << ", "
      << static_cast<int>(a1.a0[0][0][1][0][1]) << "], ["
      << static_cast<int>(a1.a0[0][0][1][1][0]) << ", "
      << static_cast<int>(a1.a0[0][0][1][1][1]) << "]]], [[["
      << static_cast<int>(a1.a0[0][1][0][0][0]) << ", "
      << static_cast<int>(a1.a0[0][1][0][0][1]) << "], ["
      << static_cast<int>(a1.a0[0][1][0][1][0]) << ", "
      << static_cast<int>(a1.a0[0][1][0][1][1]) << "]], [["
      << static_cast<int>(a1.a0[0][1][1][0][0]) << ", "
      << static_cast<int>(a1.a0[0][1][1][0][1]) << "], ["
      << static_cast<int>(a1.a0[0][1][1][1][0]) << ", "
      << static_cast<int>(a1.a0[0][1][1][1][1]) << "]]]], [[[["
      << static_cast<int>(a1.a0[1][0][0][0][0]) << ", "
      << static_cast<int>(a1.a0[1][0][0][0][1]) << "], ["
      << static_cast<int>(a1.a0[1][0][0][1][0]) << ", "
      << static_cast<int>(a1.a0[1][0][0][1][1]) << "]], [["
      << static_cast<int>(a1.a0[1][0][1][0][0]) << ", "
      << static_cast<int>(a1.a0[1][0][1][0][1]) << "], ["
      << static_cast<int>(a1.a0[1][0][1][1][0]) << ", "
      << static_cast<int>(a1.a0[1][0][1][1][1]) << "]]], [[["
      << static_cast<int>(a1.a0[1][1][0][0][0]) << ", "
      << static_cast<int>(a1.a0[1][1][0][0][1]) << "], ["
      << static_cast<int>(a1.a0[1][1][0][1][0]) << ", "
      << static_cast<int>(a1.a0[1][1][0][1][1]) << "]], [["
      << static_cast<int>(a1.a0[1][1][1][0][0]) << ", "
      << static_cast<int>(a1.a0[1][1][1][0][1]) << "], ["
      << static_cast<int>(a1.a0[1][1][1][1][0]) << ", "
      << static_cast<int>(a1.a0[1][1][1][1][1]) << "]]]]]), "
      << static_cast<int>(a2) << ", ([[[" << static_cast<int>(a3.a0[0][0][0])
      << ", " << static_cast<int>(a3.a0[0][0][1]) << "], ["
      << static_cast<int>(a3.a0[0][1][0]) << ", "
      << static_cast<int>(a3.a0[0][1][1]) << "]], [["
      << static_cast<int>(a3.a0[1][0][0]) << ", "
      << static_cast<int>(a3.a0[1][0][1]) << "], ["
      << static_cast<int>(a3.a0[1][1][0]) << ", "
      << static_cast<int>(a3.a0[1][1][1]) << "]]]), " << static_cast<int>(a4)
      << ", ([[[" << static_cast<int>(a5.a0[0][0][0]) << ", "
      << static_cast<int>(a5.a0[0][0][1]) << "], ["
      << static_cast<int>(a5.a0[0][1][0]) << ", "
      << static_cast<int>(a5.a0[0][1][1]) << "]], [["
      << static_cast<int>(a5.a0[1][0][0]) << ", "
      << static_cast<int>(a5.a0[1][0][1]) << "], ["
      << static_cast<int>(a5.a0[1][1][0]) << ", "
      << static_cast<int>(a5.a0[1][1][1]) << "]]]), " << static_cast<int>(a6)
      << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6);
}

// Used for testing structs and unions by value.
// Test struct in multi dimensional inline array.
DART_EXPORT void TestAsyncPassUint8Struct4BytesInlineArrayMultiDimensionalIn(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0,
              Struct4BytesInlineArrayMultiDimensionalInt a1,
              uint8_t a2)) {
  uint8_t a0;
  Struct4BytesInlineArrayMultiDimensionalInt a1 = {};
  uint8_t a2;

  a0 = 1;
  a1.a0[0][0].a0 = 2;
  a1.a0[0][1].a0 = -3;
  a1.a0[1][0].a0 = 4;
  a1.a0[1][1].a0 = -5;
  a2 = 6;

  std::cout
      << "Calling TestAsyncPassUint8Struct4BytesInlineArrayMultiDimensionalIn("
      << "(" << static_cast<int>(a0) << ", ([[("
      << static_cast<int>(a1.a0[0][0].a0) << "), ("
      << static_cast<int>(a1.a0[0][1].a0) << ")], [("
      << static_cast<int>(a1.a0[1][0].a0) << "), ("
      << static_cast<int>(a1.a0[1][1].a0) << ")]]), " << static_cast<int>(a2)
      << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT void TestAsyncPassStruct3BytesPackedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct3BytesPackedInt a0,
              Struct3BytesPackedInt a1,
              Struct3BytesPackedInt a2,
              Struct3BytesPackedInt a3,
              Struct3BytesPackedInt a4,
              Struct3BytesPackedInt a5,
              Struct3BytesPackedInt a6,
              Struct3BytesPackedInt a7,
              Struct3BytesPackedInt a8,
              Struct3BytesPackedInt a9)) {
  Struct3BytesPackedInt a0 = {};
  Struct3BytesPackedInt a1 = {};
  Struct3BytesPackedInt a2 = {};
  Struct3BytesPackedInt a3 = {};
  Struct3BytesPackedInt a4 = {};
  Struct3BytesPackedInt a5 = {};
  Struct3BytesPackedInt a6 = {};
  Struct3BytesPackedInt a7 = {};
  Struct3BytesPackedInt a8 = {};
  Struct3BytesPackedInt 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 TestAsyncPassStruct3BytesPackedIntx10(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT void TestAsyncPassStruct8BytesPackedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesPackedInt a0,
              Struct8BytesPackedInt a1,
              Struct8BytesPackedInt a2,
              Struct8BytesPackedInt a3,
              Struct8BytesPackedInt a4,
              Struct8BytesPackedInt a5,
              Struct8BytesPackedInt a6,
              Struct8BytesPackedInt a7,
              Struct8BytesPackedInt a8,
              Struct8BytesPackedInt a9)) {
  Struct8BytesPackedInt a0 = {};
  Struct8BytesPackedInt a1 = {};
  Struct8BytesPackedInt a2 = {};
  Struct8BytesPackedInt a3 = {};
  Struct8BytesPackedInt a4 = {};
  Struct8BytesPackedInt a5 = {};
  Struct8BytesPackedInt a6 = {};
  Struct8BytesPackedInt a7 = {};
  Struct8BytesPackedInt a8 = {};
  Struct8BytesPackedInt 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 TestAsyncPassStruct8BytesPackedIntx10(" << "(("
            << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << ", " << static_cast<int>(a0.a3)
            << ", " << static_cast<int>(a0.a4) << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << ", "
            << static_cast<int>(a1.a2) << ", " << static_cast<int>(a1.a3)
            << ", " << static_cast<int>(a1.a4) << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << ", "
            << static_cast<int>(a2.a2) << ", " << static_cast<int>(a2.a3)
            << ", " << static_cast<int>(a2.a4) << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << ", "
            << static_cast<int>(a3.a2) << ", " << static_cast<int>(a3.a3)
            << ", " << static_cast<int>(a3.a4) << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << ", "
            << static_cast<int>(a4.a2) << ", " << static_cast<int>(a4.a3)
            << ", " << static_cast<int>(a4.a4) << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << ", "
            << static_cast<int>(a5.a2) << ", " << static_cast<int>(a5.a3)
            << ", " << static_cast<int>(a5.a4) << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << ", "
            << static_cast<int>(a6.a2) << ", " << static_cast<int>(a6.a3)
            << ", " << static_cast<int>(a6.a4) << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << ", "
            << static_cast<int>(a7.a2) << ", " << static_cast<int>(a7.a3)
            << ", " << static_cast<int>(a7.a4) << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << ", "
            << static_cast<int>(a8.a2) << ", " << static_cast<int>(a8.a3)
            << ", " << static_cast<int>(a8.a4) << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << ", "
            << static_cast<int>(a9.a2) << ", " << static_cast<int>(a9.a3)
            << ", " << static_cast<int>(a9.a4) << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT void TestAsyncPassStruct9BytesPackedMixedx10DoubleInt32x2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct9BytesPackedMixed a0,
              Struct9BytesPackedMixed a1,
              Struct9BytesPackedMixed a2,
              Struct9BytesPackedMixed a3,
              Struct9BytesPackedMixed a4,
              Struct9BytesPackedMixed a5,
              Struct9BytesPackedMixed a6,
              Struct9BytesPackedMixed a7,
              Struct9BytesPackedMixed a8,
              Struct9BytesPackedMixed a9,
              double a10,
              int32_t a11,
              int32_t a12)) {
  Struct9BytesPackedMixed a0 = {};
  Struct9BytesPackedMixed a1 = {};
  Struct9BytesPackedMixed a2 = {};
  Struct9BytesPackedMixed a3 = {};
  Struct9BytesPackedMixed a4 = {};
  Struct9BytesPackedMixed a5 = {};
  Struct9BytesPackedMixed a6 = {};
  Struct9BytesPackedMixed a7 = {};
  Struct9BytesPackedMixed a8 = {};
  Struct9BytesPackedMixed a9 = {};
  double a10;
  int32_t a11;
  int32_t a12;

  a0.a0 = 1;
  a0.a1 = 2.0;
  a1.a0 = 3;
  a1.a1 = 4.0;
  a2.a0 = 5;
  a2.a1 = 6.0;
  a3.a0 = 7;
  a3.a1 = 8.0;
  a4.a0 = 9;
  a4.a1 = 10.0;
  a5.a0 = 11;
  a5.a1 = 12.0;
  a6.a0 = 13;
  a6.a1 = 14.0;
  a7.a0 = 15;
  a7.a1 = 16.0;
  a8.a0 = 17;
  a8.a1 = 18.0;
  a9.a0 = 19;
  a9.a1 = 20.0;
  a10 = -21.0;
  a11 = 22;
  a12 = -23;

  std::cout << "Calling TestAsyncPassStruct9BytesPackedMixedx10DoubleInt32x2("
            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << "), ("
            << static_cast<int>(a1.a0) << ", " << a1.a1 << "), ("
            << static_cast<int>(a2.a0) << ", " << a2.a1 << "), ("
            << static_cast<int>(a3.a0) << ", " << a3.a1 << "), ("
            << static_cast<int>(a4.a0) << ", " << a4.a1 << "), ("
            << static_cast<int>(a5.a0) << ", " << a5.a1 << "), ("
            << static_cast<int>(a6.a0) << ", " << a6.a1 << "), ("
            << static_cast<int>(a7.a0) << ", " << a7.a1 << "), ("
            << static_cast<int>(a8.a0) << ", " << a8.a1 << "), ("
            << static_cast<int>(a9.a0) << ", " << a9.a1 << "), " << a10 << ", "
            << a11 << ", " << a12 << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
}

// Used for testing structs and unions by value.
// This packed struct happens to have only aligned members.
DART_EXPORT void TestAsyncPassStruct5BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct5BytesPackedMixed a0)) {
  Struct5BytesPackedMixed a0 = {};

  a0.a0 = -1.0;
  a0.a1 = 2;

  std::cout << "Calling TestAsyncPassStruct5BytesPackedMixed(" << "((" << a0.a0
            << ", " << static_cast<int>(a0.a1) << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Check alignment of packed struct in non-packed struct.
DART_EXPORT void TestAsyncPassStructNestedAlignmentStruct5BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructNestedAlignmentStruct5BytesPackedMixed a0)) {
  StructNestedAlignmentStruct5BytesPackedMixed a0 = {};

  a0.a0 = 1;
  a0.a1.a0 = 2.0;
  a0.a1.a1 = 3;

  std::cout
      << "Calling TestAsyncPassStructNestedAlignmentStruct5BytesPackedMixed("
      << "((" << static_cast<int>(a0.a0) << ", (" << a0.a1.a0 << ", "
      << static_cast<int>(a0.a1.a1) << ")))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT void TestAsyncPassStruct6BytesInlineArrayInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct6BytesInlineArrayInt a0)) {
  Struct6BytesInlineArrayInt a0 = {};

  a0.a0[0].a0 = -1;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3;
  a0.a0[1].a1 = 4;

  std::cout << "Calling TestAsyncPassStruct6BytesInlineArrayInt(" << "(([("
            << static_cast<int>(a0.a0[0].a0) << ", " << a0.a0[0].a1 << "), ("
            << static_cast<int>(a0.a0[1].a0) << ", " << a0.a0[1].a1 << ")]))"
            << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT void TestAsyncPassStruct15BytesInlineArrayMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct15BytesInlineArrayMixed a0)) {
  Struct15BytesInlineArrayMixed a0 = {};

  a0.a0[0].a0 = -1.0;
  a0.a0[0].a1 = 2;
  a0.a0[1].a0 = -3.0;
  a0.a0[1].a1 = 4;
  a0.a0[2].a0 = -5.0;
  a0.a0[2].a1 = 6;

  std::cout << "Calling TestAsyncPassStruct15BytesInlineArrayMixed(" << "(([("
            << a0.a0[0].a0 << ", " << static_cast<int>(a0.a0[0].a1) << "), ("
            << a0.a0[1].a0 << ", " << static_cast<int>(a0.a0[1].a1) << "), ("
            << a0.a0[2].a0 << ", " << static_cast<int>(a0.a0[2].a1) << ")]))"
            << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Check placement of mixed integer/float union.
DART_EXPORT void TestAsyncPassUnion4BytesMixedx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Union4BytesMixed a0,
              Union4BytesMixed a1,
              Union4BytesMixed a2,
              Union4BytesMixed a3,
              Union4BytesMixed a4,
              Union4BytesMixed a5,
              Union4BytesMixed a6,
              Union4BytesMixed a7,
              Union4BytesMixed a8,
              Union4BytesMixed a9)) {
  Union4BytesMixed a0 = {};
  Union4BytesMixed a1 = {};
  Union4BytesMixed a2 = {};
  Union4BytesMixed a3 = {};
  Union4BytesMixed a4 = {};
  Union4BytesMixed a5 = {};
  Union4BytesMixed a6 = {};
  Union4BytesMixed a7 = {};
  Union4BytesMixed a8 = {};
  Union4BytesMixed 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 TestAsyncPassUnion4BytesMixedx10(" << "((" << a0.a0
            << "), (" << a1.a0 << "), (" << a2.a0 << "), (" << a3.a0 << "), ("
            << a4.a0 << "), (" << a5.a0 << "), (" << a6.a0 << "), (" << a7.a0
            << "), (" << a8.a0 << "), (" << a9.a0 << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Check placement of mixed floats union.
DART_EXPORT void TestAsyncPassUnion8BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Union8BytesNestedFloat a0,
              Union8BytesNestedFloat a1,
              Union8BytesNestedFloat a2,
              Union8BytesNestedFloat a3,
              Union8BytesNestedFloat a4,
              Union8BytesNestedFloat a5,
              Union8BytesNestedFloat a6,
              Union8BytesNestedFloat a7,
              Union8BytesNestedFloat a8,
              Union8BytesNestedFloat a9)) {
  Union8BytesNestedFloat a0 = {};
  Union8BytesNestedFloat a1 = {};
  Union8BytesNestedFloat a2 = {};
  Union8BytesNestedFloat a3 = {};
  Union8BytesNestedFloat a4 = {};
  Union8BytesNestedFloat a5 = {};
  Union8BytesNestedFloat a6 = {};
  Union8BytesNestedFloat a7 = {};
  Union8BytesNestedFloat a8 = {};
  Union8BytesNestedFloat a9 = {};

  a0.a0 = -1.0;
  a1.a0 = 2.0;
  a2.a0 = -3.0;
  a3.a0 = 4.0;
  a4.a0 = -5.0;
  a5.a0 = 6.0;
  a6.a0 = -7.0;
  a7.a0 = 8.0;
  a8.a0 = -9.0;
  a9.a0 = 10.0;

  std::cout << "Calling TestAsyncPassUnion8BytesNestedFloatx10(" << "(("
            << a0.a0 << "), (" << a1.a0 << "), (" << a2.a0 << "), (" << a3.a0
            << "), (" << a4.a0 << "), (" << a5.a0 << "), (" << a6.a0 << "), ("
            << a7.a0 << "), (" << a8.a0 << "), (" << a9.a0 << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Mixed-size union argument.
DART_EXPORT void TestAsyncPassUnion9BytesNestedIntx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Union9BytesNestedInt a0,
              Union9BytesNestedInt a1,
              Union9BytesNestedInt a2,
              Union9BytesNestedInt a3,
              Union9BytesNestedInt a4,
              Union9BytesNestedInt a5,
              Union9BytesNestedInt a6,
              Union9BytesNestedInt a7,
              Union9BytesNestedInt a8,
              Union9BytesNestedInt a9)) {
  Union9BytesNestedInt a0 = {};
  Union9BytesNestedInt a1 = {};
  Union9BytesNestedInt a2 = {};
  Union9BytesNestedInt a3 = {};
  Union9BytesNestedInt a4 = {};
  Union9BytesNestedInt a5 = {};
  Union9BytesNestedInt a6 = {};
  Union9BytesNestedInt a7 = {};
  Union9BytesNestedInt a8 = {};
  Union9BytesNestedInt a9 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a0.a2 = -3;
  a1.a0.a0 = 4;
  a1.a0.a1 = -5;
  a1.a0.a2 = 6;
  a2.a0.a0 = -7;
  a2.a0.a1 = 8;
  a2.a0.a2 = -9;
  a3.a0.a0 = 10;
  a3.a0.a1 = -11;
  a3.a0.a2 = 12;
  a4.a0.a0 = -13;
  a4.a0.a1 = 14;
  a4.a0.a2 = -15;
  a5.a0.a0 = 16;
  a5.a0.a1 = -17;
  a5.a0.a2 = 18;
  a6.a0.a0 = -19;
  a6.a0.a1 = 20;
  a6.a0.a2 = -21;
  a7.a0.a0 = 22;
  a7.a0.a1 = -23;
  a7.a0.a2 = 24;
  a8.a0.a0 = -25;
  a8.a0.a1 = 26;
  a8.a0.a2 = -27;
  a9.a0.a0 = 28;
  a9.a0.a1 = -29;
  a9.a0.a2 = 30;

  std::cout << "Calling TestAsyncPassUnion9BytesNestedIntx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << ", " << a0.a0.a2 << ")), (("
            << a1.a0.a0 << ", " << a1.a0.a1 << ", " << a1.a0.a2 << ")), (("
            << a2.a0.a0 << ", " << a2.a0.a1 << ", " << a2.a0.a2 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << ", " << a3.a0.a2 << ")), (("
            << a4.a0.a0 << ", " << a4.a0.a1 << ", " << a4.a0.a2 << ")), (("
            << a5.a0.a0 << ", " << a5.a0.a1 << ", " << a5.a0.a2 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << ", " << a6.a0.a2 << ")), (("
            << a7.a0.a0 << ", " << a7.a0.a1 << ", " << a7.a0.a2 << ")), (("
            << a8.a0.a0 << ", " << a8.a0.a1 << ", " << a8.a0.a2 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.a1 << ", " << a9.a0.a2 << ")))"
            << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Union with homogenous floats.
DART_EXPORT void TestAsyncPassUnion16BytesNestedInlineArrayFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Union16BytesNestedInlineArrayFloat a0,
              Union16BytesNestedInlineArrayFloat a1,
              Union16BytesNestedInlineArrayFloat a2,
              Union16BytesNestedInlineArrayFloat a3,
              Union16BytesNestedInlineArrayFloat a4,
              Union16BytesNestedInlineArrayFloat a5,
              Union16BytesNestedInlineArrayFloat a6,
              Union16BytesNestedInlineArrayFloat a7,
              Union16BytesNestedInlineArrayFloat a8,
              Union16BytesNestedInlineArrayFloat a9)) {
  Union16BytesNestedInlineArrayFloat a0 = {};
  Union16BytesNestedInlineArrayFloat a1 = {};
  Union16BytesNestedInlineArrayFloat a2 = {};
  Union16BytesNestedInlineArrayFloat a3 = {};
  Union16BytesNestedInlineArrayFloat a4 = {};
  Union16BytesNestedInlineArrayFloat a5 = {};
  Union16BytesNestedInlineArrayFloat a6 = {};
  Union16BytesNestedInlineArrayFloat a7 = {};
  Union16BytesNestedInlineArrayFloat a8 = {};
  Union16BytesNestedInlineArrayFloat a9 = {};

  a0.a0[0] = -1.0;
  a0.a0[1] = 2.0;
  a0.a0[2] = -3.0;
  a0.a0[3] = 4.0;
  a1.a0[0] = -5.0;
  a1.a0[1] = 6.0;
  a1.a0[2] = -7.0;
  a1.a0[3] = 8.0;
  a2.a0[0] = -9.0;
  a2.a0[1] = 10.0;
  a2.a0[2] = -11.0;
  a2.a0[3] = 12.0;
  a3.a0[0] = -13.0;
  a3.a0[1] = 14.0;
  a3.a0[2] = -15.0;
  a3.a0[3] = 16.0;
  a4.a0[0] = -17.0;
  a4.a0[1] = 18.0;
  a4.a0[2] = -19.0;
  a4.a0[3] = 20.0;
  a5.a0[0] = -21.0;
  a5.a0[1] = 22.0;
  a5.a0[2] = -23.0;
  a5.a0[3] = 24.0;
  a6.a0[0] = -25.0;
  a6.a0[1] = 26.0;
  a6.a0[2] = -27.0;
  a6.a0[3] = 28.0;
  a7.a0[0] = -29.0;
  a7.a0[1] = 30.0;
  a7.a0[2] = -31.0;
  a7.a0[3] = 32.0;
  a8.a0[0] = -33.0;
  a8.a0[1] = 34.0;
  a8.a0[2] = -35.0;
  a8.a0[3] = 36.0;
  a9.a0[0] = -37.0;
  a9.a0[1] = 38.0;
  a9.a0[2] = -39.0;
  a9.a0[3] = 40.0;

  std::cout << "Calling TestAsyncPassUnion16BytesNestedInlineArrayFloatx10("
            << "(([" << a0.a0[0] << ", " << a0.a0[1] << ", " << a0.a0[2] << ", "
            << a0.a0[3] << "]), ([" << a1.a0[0] << ", " << a1.a0[1] << ", "
            << a1.a0[2] << ", " << a1.a0[3] << "]), ([" << a2.a0[0] << ", "
            << a2.a0[1] << ", " << a2.a0[2] << ", " << a2.a0[3] << "]), (["
            << a3.a0[0] << ", " << a3.a0[1] << ", " << a3.a0[2] << ", "
            << a3.a0[3] << "]), ([" << a4.a0[0] << ", " << a4.a0[1] << ", "
            << a4.a0[2] << ", " << a4.a0[3] << "]), ([" << a5.a0[0] << ", "
            << a5.a0[1] << ", " << a5.a0[2] << ", " << a5.a0[3] << "]), (["
            << a6.a0[0] << ", " << a6.a0[1] << ", " << a6.a0[2] << ", "
            << a6.a0[3] << "]), ([" << a7.a0[0] << ", " << a7.a0[1] << ", "
            << a7.a0[2] << ", " << a7.a0[3] << "]), ([" << a8.a0[0] << ", "
            << a8.a0[1] << ", " << a8.a0[2] << ", " << a8.a0[3] << "]), (["
            << a9.a0[0] << ", " << a9.a0[1] << ", " << a9.a0[2] << ", "
            << a9.a0[3] << "]))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Union with homogenous floats.
DART_EXPORT void TestAsyncPassUnion16BytesNestedFloatx10(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Union16BytesNestedFloat a0,
              Union16BytesNestedFloat a1,
              Union16BytesNestedFloat a2,
              Union16BytesNestedFloat a3,
              Union16BytesNestedFloat a4,
              Union16BytesNestedFloat a5,
              Union16BytesNestedFloat a6,
              Union16BytesNestedFloat a7,
              Union16BytesNestedFloat a8,
              Union16BytesNestedFloat a9)) {
  Union16BytesNestedFloat a0 = {};
  Union16BytesNestedFloat a1 = {};
  Union16BytesNestedFloat a2 = {};
  Union16BytesNestedFloat a3 = {};
  Union16BytesNestedFloat a4 = {};
  Union16BytesNestedFloat a5 = {};
  Union16BytesNestedFloat a6 = {};
  Union16BytesNestedFloat a7 = {};
  Union16BytesNestedFloat a8 = {};
  Union16BytesNestedFloat a9 = {};

  a0.a0.a0 = -1.0;
  a0.a0.a1 = 2.0;
  a1.a0.a0 = -3.0;
  a1.a0.a1 = 4.0;
  a2.a0.a0 = -5.0;
  a2.a0.a1 = 6.0;
  a3.a0.a0 = -7.0;
  a3.a0.a1 = 8.0;
  a4.a0.a0 = -9.0;
  a4.a0.a1 = 10.0;
  a5.a0.a0 = -11.0;
  a5.a0.a1 = 12.0;
  a6.a0.a0 = -13.0;
  a6.a0.a1 = 14.0;
  a7.a0.a0 = -15.0;
  a7.a0.a1 = 16.0;
  a8.a0.a0 = -17.0;
  a8.a0.a1 = 18.0;
  a9.a0.a0 = -19.0;
  a9.a0.a1 = 20.0;

  std::cout << "Calling TestAsyncPassUnion16BytesNestedFloatx10(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << ")), ((" << a1.a0.a0 << ", "
            << a1.a0.a1 << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << ")), (("
            << a3.a0.a0 << ", " << a3.a0.a1 << ")), ((" << a4.a0.a0 << ", "
            << a4.a0.a1 << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << ")), (("
            << a6.a0.a0 << ", " << a6.a0.a1 << ")), ((" << a7.a0.a0 << ", "
            << a7.a0.a1 << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << ")), (("
            << a9.a0.a0 << ", " << a9.a0.a1 << ")))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}

// Used for testing structs and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT void TestAsyncPassUint8Boolx9Struct10BytesHomogeneousBoolBool(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0,
              bool a1,
              bool a2,
              bool a3,
              bool a4,
              bool a5,
              bool a6,
              bool a7,
              bool a8,
              bool a9,
              Struct10BytesHomogeneousBool a10,
              bool a11)) {
  uint8_t a0;
  bool a1;
  bool a2;
  bool a3;
  bool a4;
  bool a5;
  bool a6;
  bool a7;
  bool a8;
  bool a9;
  Struct10BytesHomogeneousBool a10 = {};
  bool a11;

  a0 = 1;
  a1 = false;
  a2 = true;
  a3 = false;
  a4 = true;
  a5 = false;
  a6 = true;
  a7 = false;
  a8 = true;
  a9 = false;
  a10.a0 = true;
  a10.a1 = false;
  a10.a2 = true;
  a10.a3 = false;
  a10.a4 = true;
  a10.a5 = false;
  a10.a6 = true;
  a10.a7 = false;
  a10.a8 = true;
  a10.a9 = false;
  a11 = true;

  std::cout
      << "Calling TestAsyncPassUint8Boolx9Struct10BytesHomogeneousBoolBool("
      << "(" << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", " << a3
      << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7 << ", " << a8
      << ", " << a9 << ", (" << a10.a0 << ", " << a10.a1 << ", " << a10.a2
      << ", " << a10.a3 << ", " << a10.a4 << ", " << a10.a5 << ", " << a10.a6
      << ", " << a10.a7 << ", " << a10.a8 << ", " << a10.a9 << "), " << a11
      << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
}

// Used for testing structs and unions by value.
// Passing bools and a struct with bools.
// Exhausts the registers to test bools and the bool struct alignment on the
// stack.
DART_EXPORT void TestAsyncPassUint8Boolx9Struct10BytesInlineArrayBoolBool(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0,
              bool a1,
              bool a2,
              bool a3,
              bool a4,
              bool a5,
              bool a6,
              bool a7,
              bool a8,
              bool a9,
              Struct10BytesInlineArrayBool a10,
              bool a11)) {
  uint8_t a0;
  bool a1;
  bool a2;
  bool a3;
  bool a4;
  bool a5;
  bool a6;
  bool a7;
  bool a8;
  bool a9;
  Struct10BytesInlineArrayBool a10 = {};
  bool a11;

  a0 = 1;
  a1 = false;
  a2 = true;
  a3 = false;
  a4 = true;
  a5 = false;
  a6 = true;
  a7 = false;
  a8 = true;
  a9 = false;
  a10.a0[0] = true;
  a10.a0[1] = false;
  a10.a0[2] = true;
  a10.a0[3] = false;
  a10.a0[4] = true;
  a10.a0[5] = false;
  a10.a0[6] = true;
  a10.a0[7] = false;
  a10.a0[8] = true;
  a10.a0[9] = false;
  a11 = true;

  std::cout
      << "Calling TestAsyncPassUint8Boolx9Struct10BytesInlineArrayBoolBool("
      << "(" << static_cast<int>(a0) << ", " << a1 << ", " << a2 << ", " << a3
      << ", " << a4 << ", " << a5 << ", " << a6 << ", " << a7 << ", " << a8
      << ", " << a9 << ", ([" << a10.a0[0] << ", " << a10.a0[1] << ", "
      << a10.a0[2] << ", " << a10.a0[3] << ", " << a10.a0[4] << ", "
      << a10.a0[5] << ", " << a10.a0[6] << ", " << a10.a0[7] << ", "
      << a10.a0[8] << ", " << a10.a0[9] << "]), " << a11 << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
}

// Used for testing structs and unions by value.
// Returning a bool.
DART_EXPORT void TestAsyncPassUint8Struct1ByteBool(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0, Struct1ByteBool a1)) {
  uint8_t a0;
  Struct1ByteBool a1 = {};

  a0 = 1;
  a1.a0 = false;

  std::cout << "Calling TestAsyncPassUint8Struct1ByteBool(" << "("
            << static_cast<int>(a0) << ", (" << a1.a0 << "))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Returning a wchar.
DART_EXPORT void TestAsyncPassWCharStructInlineArrayIntUintPtrx2LongUnsigned(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(wchar_t a0,
              StructInlineArrayInt a1,
              uintptr_t a2,
              uintptr_t a3,
              /* NOLINT(runtime/int) */ long a4,
              /* NOLINT(runtime/int) */ unsigned long a5)) {
  wchar_t a0;
  StructInlineArrayInt a1 = {};
  uintptr_t a2;
  uintptr_t a3;
  /* NOLINT(runtime/int) */ long a4;
  /* NOLINT(runtime/int) */ unsigned long a5;

  a0 = 1;
  a1.a0[0] = 2;
  a1.a0[1] = 3;
  a1.a0[2] = 4;
  a1.a0[3] = 5;
  a1.a0[4] = 6;
  a1.a0[5] = 7;
  a1.a0[6] = 8;
  a1.a0[7] = 9;
  a1.a0[8] = 10;
  a1.a0[9] = 11;
  a2 = 12;
  a3 = 13;
  a4 = 14;
  a5 = 15;

  std::cout
      << "Calling TestAsyncPassWCharStructInlineArrayIntUintPtrx2LongUnsigned("
      << "(" << static_cast<int>(a0) << ", ([" << static_cast<int>(a1.a0[0])
      << ", " << static_cast<int>(a1.a0[1]) << ", "
      << static_cast<int>(a1.a0[2]) << ", " << static_cast<int>(a1.a0[3])
      << ", " << static_cast<int>(a1.a0[4]) << ", "
      << static_cast<int>(a1.a0[5]) << ", " << static_cast<int>(a1.a0[6])
      << ", " << static_cast<int>(a1.a0[7]) << ", "
      << static_cast<int>(a1.a0[8]) << ", " << static_cast<int>(a1.a0[9])
      << "]), " << a2 << ", " << a3 << ", " << a4 << ", " << a5 << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5);
}

// Used for testing structs and unions by value.
// Struct stradles last argument register
DART_EXPORT void TestAsyncPassInt64x7Struct12BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int64_t a0,
              int64_t a1,
              int64_t a2,
              int64_t a3,
              int64_t a4,
              int64_t a5,
              int64_t a6,
              Struct12BytesHomogeneousInt32 a7)) {
  int64_t a0;
  int64_t a1;
  int64_t a2;
  int64_t a3;
  int64_t a4;
  int64_t a5;
  int64_t a6;
  Struct12BytesHomogeneousInt32 a7 = {};

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;
  a5 = 6;
  a6 = -7;
  a7.a0 = 8;
  a7.a1 = -9;
  a7.a2 = 10;

  std::cout << "Calling TestAsyncPassInt64x7Struct12BytesHomogeneousInt32("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
            << ", " << a7.a2 << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7);
}

// Used for testing structs and unions by value.
// Passing a pointer to a struct
DART_EXPORT void TestAsyncPassPointerStruct12BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct12BytesHomogeneousInt32* a0)) {
  Struct12BytesHomogeneousInt32* a0 =
      static_cast<Struct12BytesHomogeneousInt32*>(
          calloc(1, sizeof(Struct12BytesHomogeneousInt32)));

  a0->a0 = -1;
  a0->a1 = 2;
  a0->a2 = -3;

  std::cout << "Calling TestAsyncPassPointerStruct12BytesHomogeneousInt32("
            << "((" << a0->a0 << ", " << a0->a1 << ", " << a0->a2 << "))"
            << ")\n";

  f(a0);

  free(a0);
}

// Used for testing structs and unions by value.
// Variable length array
DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariable(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructInlineArrayVariable* a0)) {
  StructInlineArrayVariable* a0 = static_cast<StructInlineArrayVariable*>(
      calloc(1, sizeof(StructInlineArrayVariable) + 10 * sizeof(uint8_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestAsyncPassPointerStructInlineArrayVariable(" << "(("
            << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))" << ")\n";

  f(a0);

  free(a0);
}

// Used for testing structs and unions by value.
// Variable length array with variable length element having more alignment than
// the rest of the struct.
DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariableAlign(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructInlineArrayVariableAlign* a0)) {
  StructInlineArrayVariableAlign* a0 =
      static_cast<StructInlineArrayVariableAlign*>(calloc(
          1, sizeof(StructInlineArrayVariableAlign) + 10 * sizeof(uint32_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestAsyncPassPointerStructInlineArrayVariableAlign("
            << "((" << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
            << a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
            << a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
            << a0->a1[7] << ", " << a0->a1[8] << ", " << a0->a1[9] << "]))"
            << ")\n";

  f(a0);

  free(a0);
}

// Used for testing structs and unions by value.
// Variable length array with variable dimension of 1.
DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariable2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructInlineArrayVariable2* a0)) {
  StructInlineArrayVariable2* a0 = static_cast<StructInlineArrayVariable2*>(
      calloc(1, sizeof(StructInlineArrayVariable2) + 10 * sizeof(uint8_t)));

  a0->a0 = 1;
  a0->a1[0] = 2;
  a0->a1[1] = 3;
  a0->a1[2] = 4;
  a0->a1[3] = 5;
  a0->a1[4] = 6;
  a0->a1[5] = 7;
  a0->a1[6] = 8;
  a0->a1[7] = 9;
  a0->a1[8] = 10;
  a0->a1[9] = 11;

  std::cout << "Calling TestAsyncPassPointerStructInlineArrayVariable2("
            << "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
            << static_cast<int>(a0->a1[1]) << ", "
            << static_cast<int>(a0->a1[2]) << ", "
            << static_cast<int>(a0->a1[3]) << ", "
            << static_cast<int>(a0->a1[4]) << ", "
            << static_cast<int>(a0->a1[5]) << ", "
            << static_cast<int>(a0->a1[6]) << ", "
            << static_cast<int>(a0->a1[7]) << ", "
            << static_cast<int>(a0->a1[8]) << ", "
            << static_cast<int>(a0->a1[9]) << "]))"
            << ")\n";

  f(a0);

  free(a0);
}

// Used for testing structs and unions by value.
// Smallest struct with data.
DART_EXPORT void TestAsyncReturnStruct1ByteInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int8_t a0)) {
  int8_t a0;

  a0 = -1;

  std::cout << "Calling TestAsyncReturnStruct1ByteInt(" << "("
            << static_cast<int>(a0) << ")" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
DART_EXPORT void TestAsyncReturnStruct3BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0, uint8_t a1, uint8_t a2)) {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;

  a0 = 1;
  a1 = 2;
  a2 = 3;

  std::cout << "Calling TestAsyncReturnStruct3BytesHomogeneousUint8(" << "("
            << static_cast<int>(a0) << ", " << static_cast<int>(a1) << ", "
            << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
// With alignment rules taken into account size is 4 bytes.
DART_EXPORT void TestAsyncReturnStruct3BytesInt2ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int16_t a0, int8_t a1)) {
  int16_t a0;
  int8_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestAsyncReturnStruct3BytesInt2ByteAligned(" << "("
            << a0 << ", " << static_cast<int>(a1) << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Word size return value on 32 bit architectures..
DART_EXPORT void TestAsyncReturnStruct4BytesHomogeneousInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int16_t a0, int16_t a1)) {
  int16_t a0;
  int16_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestAsyncReturnStruct4BytesHomogeneousInt16(" << "("
            << a0 << ", " << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Non-wordsize return value.
DART_EXPORT void TestAsyncReturnStruct7BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0,
              uint8_t a1,
              uint8_t a2,
              uint8_t a3,
              uint8_t a4,
              uint8_t a5,
              uint8_t a6)) {
  uint8_t a0;
  uint8_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;
  uint8_t a5;
  uint8_t a6;

  a0 = 1;
  a1 = 2;
  a2 = 3;
  a3 = 4;
  a4 = 5;
  a5 = 6;
  a6 = 7;

  std::cout << "Calling TestAsyncReturnStruct7BytesHomogeneousUint8(" << "("
            << 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) << ")" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6);
}

// Used for testing structs and unions by value.
// Non-wordsize return value.
// With alignment rules taken into account size is 8 bytes.
DART_EXPORT void TestAsyncReturnStruct7BytesInt4ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct7BytesInt4ByteAligned(" << "("
            << a0 << ", " << a1 << ", " << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Return value in integer registers on many architectures.
DART_EXPORT void TestAsyncReturnStruct8BytesInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct8BytesInt(" << "(" << a0 << ", "
            << a1 << ", " << a2 << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Return value in FP registers on many architectures.
DART_EXPORT void TestAsyncReturnStruct8BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(float a0, float a1)) {
  float a0;
  float a1;

  a0 = -1.0;
  a1 = 2.0;

  std::cout << "Calling TestAsyncReturnStruct8BytesHomogeneousFloat(" << "("
            << a0 << ", " << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT void TestAsyncReturnStruct8BytesMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct8BytesMixed(" << "(" << a0 << ", "
            << a1 << ", " << a2 << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions 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 void TestAsyncReturnStruct9BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct9BytesHomogeneousUint8(" << "("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions by value.
// Return value in two integer registers on x64.
// With alignment rules taken into account size is 12 or 16 bytes.
DART_EXPORT void TestAsyncReturnStruct9BytesInt4Or8ByteAligned(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int64_t a0, int8_t a1)) {
  int64_t a0;
  int8_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestAsyncReturnStruct9BytesInt4Or8ByteAligned(" << "("
            << a0 << ", " << static_cast<int>(a1) << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Return value in FPU registers, but does not use all registers on arm hardfp
// and arm64.
DART_EXPORT void TestAsyncReturnStruct12BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct12BytesHomogeneousFloat(" << "("
            << a0 << ", " << a1 << ", " << a2 << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT void TestAsyncReturnStruct16BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct16BytesHomogeneousFloat(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT void TestAsyncReturnStruct16BytesMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(double a0, int64_t a1)) {
  double a0;
  int64_t a1;

  a0 = -1.0;
  a1 = 2;

  std::cout << "Calling TestAsyncReturnStruct16BytesMixed(" << "(" << a0 << ", "
            << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
// The integer register contains half float half int.
DART_EXPORT void TestAsyncReturnStruct16BytesMixed2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct16BytesMixed2(" << "(" << a0
            << ", " << a1 << ", " << a2 << ", " << a3 << ")" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Return 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 void TestAsyncReturnStruct17BytesInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct17BytesInt(" << "(" << a0 << ", "
            << a1 << ", " << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions 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 void TestAsyncReturnStruct19BytesHomogeneousUint8(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct19BytesHomogeneousUint8(" << "("
            << 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";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16,
    a17, a18);
}

// Used for testing structs and unions by value.
// Return value too big to go in cpu registers on arm64.
DART_EXPORT void TestAsyncReturnStruct20BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct20BytesHomogeneousInt32(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ")"
            << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
DART_EXPORT void TestAsyncReturnStruct20BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct20BytesHomogeneousFloat(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ")"
            << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT void TestAsyncReturnStruct32BytesHomogeneousDouble(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct32BytesHomogeneousDouble(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ")" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on arm64.
DART_EXPORT void TestAsyncReturnStruct40BytesHomogeneousDouble(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct40BytesHomogeneousDouble(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ")"
            << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT void TestAsyncReturnStruct1024BytesHomogeneousUint64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStruct1024BytesHomogeneousUint64(" << "("
            << 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";

  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);
}

// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT void TestAsyncReturnStruct3BytesPackedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(int8_t a0, int16_t a1)) {
  int8_t a0;
  int16_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestAsyncReturnStruct3BytesPackedInt(" << "("
            << static_cast<int>(a0) << ", " << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT void TestAsyncReturnStruct8BytesPackedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0, uint32_t a1, uint8_t a2, uint8_t a3, uint8_t a4)) {
  uint8_t a0;
  uint32_t a1;
  uint8_t a2;
  uint8_t a3;
  uint8_t a4;

  a0 = 1;
  a1 = 2;
  a2 = 3;
  a3 = 4;
  a4 = 5;

  std::cout << "Calling TestAsyncReturnStruct8BytesPackedInt(" << "("
            << static_cast<int>(a0) << ", " << a1 << ", "
            << static_cast<int>(a2) << ", " << static_cast<int>(a3) << ", "
            << static_cast<int>(a4) << ")" << ")\n";

  f(a0, a1, a2, a3, a4);
}

// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT void TestAsyncReturnStruct9BytesPackedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint8_t a0, double a1)) {
  uint8_t a0;
  double a1;

  a0 = 1;
  a1 = 2.0;

  std::cout << "Calling TestAsyncReturnStruct9BytesPackedMixed(" << "("
            << static_cast<int>(a0) << ", " << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Returning a mixed integer/float union.
DART_EXPORT void TestAsyncReturnUnion4BytesMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint32_t a0)) {
  uint32_t a0;

  a0 = 1;

  std::cout << "Calling TestAsyncReturnUnion4BytesMixed(" << "(" << a0 << ")"
            << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Returning a floating point only union.
DART_EXPORT void TestAsyncReturnUnion8BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(double a0)) {
  double a0;

  a0 = -1.0;

  std::cout << "Calling TestAsyncReturnUnion8BytesNestedFloat(" << "(" << a0
            << ")" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Returning a mixed-size union.
DART_EXPORT void TestAsyncReturnUnion9BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesInt a0)) {
  Struct8BytesInt a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;

  std::cout << "Calling TestAsyncReturnUnion9BytesNestedInt(" << "((" << a0.a0
            << ", " << a0.a1 << ", " << a0.a2 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Returning union with homogenous floats.
DART_EXPORT void TestAsyncReturnUnion16BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesHomogeneousFloat a0)) {
  Struct8BytesHomogeneousFloat a0 = {};

  a0.a0 = -1.0;
  a0.a1 = 2.0;

  std::cout << "Calling TestAsyncReturnUnion16BytesNestedFloat(" << "(("
            << a0.a0 << ", " << a0.a1 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions 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 void TestAsyncReturnStructArgumentStruct1ByteInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct1ByteInt a0)) {
  Struct1ByteInt a0 = {};

  a0.a0 = -1;

  std::cout << "Calling TestAsyncReturnStructArgumentStruct1ByteInt(" << "(("
            << static_cast<int>(a0.a0) << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions 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 void TestAsyncReturnStructArgumentInt32x8Struct1ByteInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStructArgumentInt32x8Struct1ByteInt("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", " << a7 << ", ("
            << static_cast<int>(a8.a0) << "))" << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions 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 void TestAsyncReturnStructArgumentStruct8BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesHomogeneousFloat a0)) {
  Struct8BytesHomogeneousFloat a0 = {};

  a0.a0 = -1.0;
  a0.a1 = 2.0;

  std::cout
      << "Calling TestAsyncReturnStructArgumentStruct8BytesHomogeneousFloat("
      << "((" << a0.a0 << ", " << a0.a1 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// On arm64, both argument and return value are passed in by pointer.
DART_EXPORT void TestAsyncReturnStructArgumentStruct20BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct20BytesHomogeneousInt32 a0)) {
  Struct20BytesHomogeneousInt32 a0 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a0.a3 = 4;
  a0.a4 = -5;

  std::cout
      << "Calling TestAsyncReturnStructArgumentStruct20BytesHomogeneousInt32("
      << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << ", " << a0.a3
      << ", " << a0.a4 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions 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 void TestAsyncReturnStructArgumentInt32x8Struct20BytesHomogeneou(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStructArgumentInt32x8Struct20BytesHomogeneou("
      << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
      << ", " << a5 << ", " << a6 << ", " << a7 << ", (" << a8.a0 << ", "
      << a8.a1 << ", " << a8.a2 << ", " << a8.a3 << ", " << a8.a4 << "))"
      << ")\n";

  f(a0, a1, a2, a3, a4, a5, a6, a7, a8);
}

// Used for testing structs and unions by value.
// Test returning struct with inline array.
DART_EXPORT void TestAsyncReturnStructArgumentStruct8BytesInlineArrayInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesInlineArrayInt a0)) {
  Struct8BytesInlineArrayInt a0 = {};

  a0.a0[0] = 1;
  a0.a0[1] = 2;
  a0.a0[2] = 3;
  a0.a0[3] = 4;
  a0.a0[4] = 5;
  a0.a0[5] = 6;
  a0.a0[6] = 7;
  a0.a0[7] = 8;

  std::cout
      << "Calling TestAsyncReturnStructArgumentStruct8BytesInlineArrayInt("
      << "(([" << static_cast<int>(a0.a0[0]) << ", "
      << static_cast<int>(a0.a0[1]) << ", " << static_cast<int>(a0.a0[2])
      << ", " << static_cast<int>(a0.a0[3]) << ", "
      << static_cast<int>(a0.a0[4]) << ", " << static_cast<int>(a0.a0[5])
      << ", " << static_cast<int>(a0.a0[6]) << ", "
      << static_cast<int>(a0.a0[7]) << "]))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT void TestAsyncReturnStructArgumentStructStruct16BytesHomogeneous(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct16BytesHomogeneousFloat2 a0)) {
  StructStruct16BytesHomogeneousFloat2 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;

  std::cout
      << "Calling TestAsyncReturnStructArgumentStructStruct16BytesHomogeneous("
      << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0
      << ")], " << a0.a2 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT void TestAsyncReturnStructArgumentStructStruct32BytesHomogeneous(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct32BytesHomogeneousDouble2 a0)) {
  StructStruct32BytesHomogeneousDouble2 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[1].a0 = -3.0;
  a0.a2 = 4.0;

  std::cout
      << "Calling TestAsyncReturnStructArgumentStructStruct32BytesHomogeneous("
      << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << "), (" << a0.a1[1].a0
      << ")], " << a0.a2 << "))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// On x64 Linux, return value is split over FP and int registers.
DART_EXPORT void TestAsyncReturnStructArgumentStructStruct16BytesMixed3(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructStruct16BytesMixed3 a0)) {
  StructStruct16BytesMixed3 a0 = {};

  a0.a0.a0 = -1.0;
  a0.a1[0].a0 = 2.0;
  a0.a1[0].a1 = -3;
  a0.a1[0].a2 = 4;
  a0.a2[0] = -5;
  a0.a2[1] = 6;

  std::cout << "Calling TestAsyncReturnStructArgumentStructStruct16BytesMixed3("
            << "(((" << a0.a0.a0 << "), [(" << a0.a1[0].a0 << ", "
            << a0.a1[0].a1 << ", " << a0.a1[0].a2 << ")], [" << a0.a2[0] << ", "
            << a0.a2[1] << "]))" << ")\n";

  f(a0);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT void TestAsyncReturnStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStructAlignmentInt16(" << "("
            << static_cast<int>(a0) << ", " << a1 << ", "
            << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT void TestAsyncReturnStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStructAlignmentInt32(" << "("
            << static_cast<int>(a0) << ", " << a1 << ", "
            << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT void TestAsyncReturnStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*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 TestAsyncReturnStructAlignmentInt64(" << "("
            << static_cast<int>(a0) << ", " << a1 << ", "
            << static_cast<int>(a2) << ")" << ")\n";

  f(a0, a1, a2);
}

// Used for testing structs and unions by value.
// Simple nested struct.
DART_EXPORT void TestAsyncReturnStruct8BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct4BytesHomogeneousInt16 a0,
              Struct4BytesHomogeneousInt16 a1)) {
  Struct4BytesHomogeneousInt16 a0 = {};
  Struct4BytesHomogeneousInt16 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a1.a0 = -3;
  a1.a1 = 4;

  std::cout << "Calling TestAsyncReturnStruct8BytesNestedInt(" << "((" << a0.a0
            << ", " << a0.a1 << "), (" << a1.a0 << ", " << a1.a1 << "))"
            << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Simple nested struct with floats.
DART_EXPORT void TestAsyncReturnStruct8BytesNestedFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct4BytesFloat a0, Struct4BytesFloat a1)) {
  Struct4BytesFloat a0 = {};
  Struct4BytesFloat a1 = {};

  a0.a0 = -1.0;
  a1.a0 = 2.0;

  std::cout << "Calling TestAsyncReturnStruct8BytesNestedFloat(" << "(("
            << a0.a0 << "), (" << a1.a0 << "))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT void TestAsyncReturnStruct8BytesNestedFloat2(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct4BytesFloat a0, float a1)) {
  Struct4BytesFloat a0 = {};
  float a1;

  a0.a0 = -1.0;
  a1 = 2.0;

  std::cout << "Calling TestAsyncReturnStruct8BytesNestedFloat2(" << "(("
            << a0.a0 << "), " << a1 << ")" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Simple nested struct with mixed members.
DART_EXPORT void TestAsyncReturnStruct8BytesNestedMixed(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct4BytesHomogeneousInt16 a0, Struct4BytesFloat a1)) {
  Struct4BytesHomogeneousInt16 a0 = {};
  Struct4BytesFloat a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a1.a0 = -3.0;

  std::cout << "Calling TestAsyncReturnStruct8BytesNestedMixed(" << "(("
            << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << "))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT void TestAsyncReturnStruct16BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct8BytesNestedInt a0, Struct8BytesNestedInt a1)) {
  Struct8BytesNestedInt a0 = {};
  Struct8BytesNestedInt a1 = {};

  a0.a0.a0 = -1;
  a0.a0.a1 = 2;
  a0.a1.a0 = -3;
  a0.a1.a1 = 4;
  a1.a0.a0 = -5;
  a1.a0.a1 = 6;
  a1.a1.a0 = -7;
  a1.a1.a1 = 8;

  std::cout << "Calling TestAsyncReturnStruct16BytesNestedInt(" << "((("
            << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0 << ", "
            << a0.a1.a1 << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), ("
            << a1.a1.a0 << ", " << a1.a1.a1 << ")))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT void TestAsyncReturnStruct32BytesNestedInt(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(Struct16BytesNestedInt a0, Struct16BytesNestedInt a1)) {
  Struct16BytesNestedInt a0 = {};
  Struct16BytesNestedInt a1 = {};

  a0.a0.a0.a0 = -1;
  a0.a0.a0.a1 = 2;
  a0.a0.a1.a0 = -3;
  a0.a0.a1.a1 = 4;
  a0.a1.a0.a0 = -5;
  a0.a1.a0.a1 = 6;
  a0.a1.a1.a0 = -7;
  a0.a1.a1.a1 = 8;
  a1.a0.a0.a0 = -9;
  a1.a0.a0.a1 = 10;
  a1.a0.a1.a0 = -11;
  a1.a0.a1.a1 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15;
  a1.a1.a1.a1 = 16;

  std::cout << "Calling TestAsyncReturnStruct32BytesNestedInt(" << "(((("
            << a0.a0.a0.a0 << ", " << a0.a0.a0.a1 << "), (" << a0.a0.a1.a0
            << ", " << a0.a0.a1.a1 << ")), ((" << a0.a1.a0.a0 << ", "
            << a0.a1.a0.a1 << "), (" << a0.a1.a1.a0 << ", " << a0.a1.a1.a1
            << "))), (((" << a1.a0.a0.a0 << ", " << a1.a0.a0.a1 << "), ("
            << a1.a0.a1.a0 << ", " << a1.a0.a1.a1 << ")), ((" << a1.a1.a0.a0
            << ", " << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ", "
            << a1.a1.a1.a1 << "))))" << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT void TestAsyncReturnStructNestedIntStructAlignmentInt16(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt16 a0, StructAlignmentInt16 a1)) {
  StructAlignmentInt16 a0 = {};
  StructAlignmentInt16 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestAsyncReturnStructNestedIntStructAlignmentInt16("
            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT void TestAsyncReturnStructNestedIntStructAlignmentInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt32 a0, StructAlignmentInt32 a1)) {
  StructAlignmentInt32 a0 = {};
  StructAlignmentInt32 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestAsyncReturnStructNestedIntStructAlignmentInt32("
            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT void TestAsyncReturnStructNestedIntStructAlignmentInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(StructAlignmentInt64 a0, StructAlignmentInt64 a1)) {
  StructAlignmentInt64 a0 = {};
  StructAlignmentInt64 a1 = {};

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1.a0 = 4;
  a1.a1 = -5;
  a1.a2 = 6;

  std::cout << "Calling TestAsyncReturnStructNestedIntStructAlignmentInt64("
            << "((" << static_cast<int>(a0.a0) << ", " << a0.a1 << ", "
            << static_cast<int>(a0.a2) << "), (" << static_cast<int>(a1.a0)
            << ", " << a1.a1 << ", " << static_cast<int>(a1.a2) << "))"
            << ")\n";

  f(a0, a1);
}

// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT void TestAsyncReturnStructNestedIrregularEvenBigger(
    // NOLINTNEXTLINE(whitespace/parens)
    void (*f)(uint64_t a0,
              StructNestedIrregularBigger a1,
              StructNestedIrregularBigger a2,
              double a3)) {
  uint64_t a0;
  StructNestedIrregularBigger a1 = {};
  StructNestedIrregularBigger a2 = {};
  double a3;

  a0 = 1;
  a1.a0.a0 = 2;
  a1.a0.a1.a0.a0 = -3;
  a1.a0.a1.a0.a1 = 4;
  a1.a0.a1.a1.a0 = -5.0;
  a1.a0.a2 = 6;
  a1.a0.a3.a0.a0 = -7.0;
  a1.a0.a3.a1 = 8.0;
  a1.a0.a4 = 9;
  a1.a0.a5.a0.a0 = 10.0;
  a1.a0.a5.a1.a0 = -11.0;
  a1.a0.a6 = 12;
  a1.a1.a0.a0 = -13;
  a1.a1.a0.a1 = 14;
  a1.a1.a1.a0 = -15.0;
  a1.a2 = 16.0;
  a1.a3 = -17.0;
  a2.a0.a0 = 18;
  a2.a0.a1.a0.a0 = -19;
  a2.a0.a1.a0.a1 = 20;
  a2.a0.a1.a1.a0 = -21.0;
  a2.a0.a2 = 22;
  a2.a0.a3.a0.a0 = -23.0;
  a2.a0.a3.a1 = 24.0;
  a2.a0.a4 = 25;
  a2.a0.a5.a0.a0 = 26.0;
  a2.a0.a5.a1.a0 = -27.0;
  a2.a0.a6 = 28;
  a2.a1.a0.a0 = -29;
  a2.a1.a0.a1 = 30;
  a2.a1.a1.a0 = -31.0;
  a2.a2 = 32.0;
  a2.a3 = -33.0;
  a3 = 34.0;

  std::cout << "Calling TestAsyncReturnStructNestedIrregularEvenBigger(" << "("
            << a0 << ", ((" << a1.a0.a0 << ", ((" << a1.a0.a1.a0.a0 << ", "
            << a1.a0.a1.a0.a1 << "), (" << a1.a0.a1.a1.a0 << ")), " << a1.a0.a2
            << ", ((" << a1.a0.a3.a0.a0 << "), " << a1.a0.a3.a1 << "), "
            << a1.a0.a4 << ", ((" << a1.a0.a5.a0.a0 << "), (" << a1.a0.a5.a1.a0
            << ")), " << a1.a0.a6 << "), ((" << a1.a1.a0.a0 << ", "
            << a1.a1.a0.a1 << "), (" << a1.a1.a1.a0 << ")), " << a1.a2 << ", "
            << a1.a3 << "), ((" << a2.a0.a0 << ", ((" << a2.a0.a1.a0.a0 << ", "
            << a2.a0.a1.a0.a1 << "), (" << a2.a0.a1.a1.a0 << ")), " << a2.a0.a2
            << ", ((" << a2.a0.a3.a0.a0 << "), " << a2.a0.a3.a1 << "), "
            << a2.a0.a4 << ", ((" << a2.a0.a5.a0.a0 << "), (" << a2.a0.a5.a1.a0
            << ")), " << a2.a0.a6 << "), ((" << a2.a1.a0.a0 << ", "
            << a2.a1.a0.a1 << "), (" << a2.a1.a1.a0 << ")), " << a2.a2 << ", "
            << a2.a3 << "), " << a3 << ")" << ")\n";

  f(a0, a1, a2, a3);
}

// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT int64_t VariadicAt1Int64x2(int64_t a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  va_end(var_args);

  std::cout << "VariadicAt1Int64x2" << "(" << a0 << ", " << a1 << ")" << "\n";

  int64_t result = 0;

  result += a0;
  result += a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT double VariadicAt1Doublex2(double a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  double a1 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1Doublex2" << "(" << a0 << ", " << a1 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments.
DART_EXPORT int64_t VariadicAt1Int64x5(int64_t a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  int64_t a2 = va_arg(var_args, int64_t);
  int64_t a3 = va_arg(var_args, int64_t);
  int64_t a4 = va_arg(var_args, int64_t);
  va_end(var_args);

  std::cout << "VariadicAt1Int64x5" << "(" << a0 << ", " << a1 << ", " << a2
            << ", " << a3 << ", " << a4 << ")" << "\n";

  int64_t result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments.
DART_EXPORT double VariadicAt1Doublex5(double a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  double a1 = va_arg(var_args, double);
  double a2 = va_arg(var_args, double);
  double a3 = va_arg(var_args, double);
  double a4 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1Doublex5" << "(" << a0 << ", " << a1 << ", " << a2
            << ", " << a3 << ", " << a4 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments exhaust registers.
DART_EXPORT int64_t VariadicAt1Int64x20(int64_t a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  int64_t a2 = va_arg(var_args, int64_t);
  int64_t a3 = va_arg(var_args, int64_t);
  int64_t a4 = va_arg(var_args, int64_t);
  int64_t a5 = va_arg(var_args, int64_t);
  int64_t a6 = va_arg(var_args, int64_t);
  int64_t a7 = va_arg(var_args, int64_t);
  int64_t a8 = va_arg(var_args, int64_t);
  int64_t a9 = va_arg(var_args, int64_t);
  int64_t a10 = va_arg(var_args, int64_t);
  int64_t a11 = va_arg(var_args, int64_t);
  int64_t a12 = va_arg(var_args, int64_t);
  int64_t a13 = va_arg(var_args, int64_t);
  int64_t a14 = va_arg(var_args, int64_t);
  int64_t a15 = va_arg(var_args, int64_t);
  int64_t a16 = va_arg(var_args, int64_t);
  int64_t a17 = va_arg(var_args, int64_t);
  int64_t a18 = va_arg(var_args, int64_t);
  int64_t a19 = va_arg(var_args, int64_t);
  va_end(var_args);

  std::cout << "VariadicAt1Int64x20" << "(" << a0 << ", " << a1 << ", " << a2
            << ", " << a3 << ", " << a4 << ", " << a5 << ", " << a6 << ", "
            << a7 << ", " << a8 << ", " << a9 << ", " << a10 << ", " << a11
            << ", " << a12 << ", " << a13 << ", " << a14 << ", " << a15 << ", "
            << a16 << ", " << a17 << ", " << a18 << ", " << a19 << ")" << "\n";

  int64_t result = 0;

  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;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments exhaust registers.
DART_EXPORT double VariadicAt1Doublex20(double a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  double a1 = va_arg(var_args, double);
  double a2 = va_arg(var_args, double);
  double a3 = va_arg(var_args, double);
  double a4 = va_arg(var_args, double);
  double a5 = va_arg(var_args, double);
  double a6 = va_arg(var_args, double);
  double a7 = va_arg(var_args, double);
  double a8 = va_arg(var_args, double);
  double a9 = va_arg(var_args, double);
  double a10 = va_arg(var_args, double);
  double a11 = va_arg(var_args, double);
  double a12 = va_arg(var_args, double);
  double a13 = va_arg(var_args, double);
  double a14 = va_arg(var_args, double);
  double a15 = va_arg(var_args, double);
  double a16 = va_arg(var_args, double);
  double a17 = va_arg(var_args, double);
  double a18 = va_arg(var_args, double);
  double a19 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1Doublex20" << "(" << a0 << ", " << a1 << ", " << a2
            << ", " << a3 << ", " << a4 << ", " << a5 << ", " << a6 << ", "
            << a7 << ", " << a8 << ", " << a9 << ", " << a10 << ", " << a11
            << ", " << a12 << ", " << a13 << ", " << a14 << ", " << a15 << ", "
            << a16 << ", " << a17 << ", " << a18 << ", " << a19 << ")" << "\n";

  double result = 0;

  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;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT int64_t VariadicAt1Int64x2Struct8BytesIntInt64(int64_t a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  Struct8BytesInt a2 = va_arg(var_args, Struct8BytesInt);
  int64_t a3 = va_arg(var_args, int64_t);
  va_end(var_args);

  std::cout << "VariadicAt1Int64x2Struct8BytesIntInt64" << "(" << a0 << ", "
            << a1 << ", (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2 << "), "
            << a3 << ")" << "\n";

  int64_t result = 0;

  result += a0;
  result += a1;
  result += a2.a0;
  result += a2.a1;
  result += a2.a2;
  result += a3;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT double VariadicAt1Doublex2Struct32BytesHomogeneousDoubleD(double a0,
                                                                      ...) {
  va_list var_args;
  va_start(var_args, a0);
  double a1 = va_arg(var_args, double);
  Struct32BytesHomogeneousDouble a2 =
      va_arg(var_args, Struct32BytesHomogeneousDouble);
  double a3 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1Doublex2Struct32BytesHomogeneousDoubleD" << "(" << a0
            << ", " << a1 << ", (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
            << ", " << a2.a3 << "), " << a3 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2.a0;
  result += a2.a1;
  result += a2.a2;
  result += a2.a3;
  result += a3;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT double VariadicAt1DoubleStruct12BytesHomogeneousFloatDoub(double a0,
                                                                      ...) {
  va_list var_args;
  va_start(var_args, a0);
  Struct12BytesHomogeneousFloat a1 =
      va_arg(var_args, Struct12BytesHomogeneousFloat);
  double a2 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1DoubleStruct12BytesHomogeneousFloatDoub" << "(" << a0
            << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << "), " << a2
            << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1.a0;
  result += a1.a1;
  result += a1.a2;
  result += a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT int32_t
VariadicAt1Int32Struct20BytesHomogeneousInt32Int32(int32_t a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  Struct20BytesHomogeneousInt32 a1 =
      va_arg(var_args, Struct20BytesHomogeneousInt32);
  int32_t a2 = va_arg(var_args, int32_t);
  va_end(var_args);

  std::cout << "VariadicAt1Int32Struct20BytesHomogeneousInt32Int32" << "(" << a0
            << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", " << a1.a3
            << ", " << a1.a4 << "), " << a2 << ")" << "\n";

  int32_t result = 0;

  result += a0;
  result += a1.a0;
  result += a1.a1;
  result += a1.a2;
  result += a1.a3;
  result += a1.a4;
  result += a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT double VariadicAt1DoubleStruct20BytesHomogeneousFloatDoub(double a0,
                                                                      ...) {
  va_list var_args;
  va_start(var_args, a0);
  Struct20BytesHomogeneousFloat a1 =
      va_arg(var_args, Struct20BytesHomogeneousFloat);
  double a2 = va_arg(var_args, double);
  va_end(var_args);

  std::cout << "VariadicAt1DoubleStruct20BytesHomogeneousFloatDoub" << "(" << a0
            << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2 << ", " << a1.a3
            << ", " << a1.a4 << "), " << a2 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1.a0;
  result += a1.a1;
  result += a1.a2;
  result += a1.a3;
  result += a1.a4;
  result += a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Regression test for variadic arguments.
// https://github.com/dart-lang/sdk/issues/49460
DART_EXPORT int32_t VariadicAt2Int32Int64IntPtr(int32_t a0, int64_t a1, ...) {
  va_list var_args;
  va_start(var_args, a1);
  intptr_t a2 = va_arg(var_args, intptr_t);
  va_end(var_args);

  std::cout << "VariadicAt2Int32Int64IntPtr" << "(" << a0 << ", " << a1 << ", "
            << a2 << ")" << "\n";

  int32_t result = 0;

  result += a0;
  result += a1;
  result += a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments mixed.
DART_EXPORT double VariadicAt1DoubleInt64Int32DoubleInt64Int32(double a0, ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  int32_t a2 = va_arg(var_args, int32_t);
  double a3 = va_arg(var_args, double);
  int64_t a4 = va_arg(var_args, int64_t);
  int32_t a5 = va_arg(var_args, int32_t);
  va_end(var_args);

  std::cout << "VariadicAt1DoubleInt64Int32DoubleInt64Int32" << "(" << a0
            << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ", "
            << a5 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;
  result += a5;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments homogenous struct stack alignment on macos_arm64.
DART_EXPORT double VariadicAt1Int64Int32Struct12BytesHomogeneousFloat(
    int64_t a0,
    ...) {
  va_list var_args;
  va_start(var_args, a0);
  int32_t a1 = va_arg(var_args, int32_t);
  Struct12BytesHomogeneousFloat a2 =
      va_arg(var_args, Struct12BytesHomogeneousFloat);
  va_end(var_args);

  std::cout << "VariadicAt1Int64Int32Struct12BytesHomogeneousFloat" << "(" << a0
            << ", " << a1 << ", (" << a2.a0 << ", " << a2.a1 << ", " << a2.a2
            << "))" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2.a0;
  result += a2.a1;
  result += a2.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments homogenous struct stack alignment on macos_arm64.
DART_EXPORT double VariadicAt11Doublex8FloatStruct12BytesHomogeneousF(
    double a0,
    double a1,
    double a2,
    double a3,
    double a4,
    double a5,
    double a6,
    double a7,
    float a8,
    Struct12BytesHomogeneousFloat a9,
    int64_t a10,
    ...) {
  va_list var_args;
  va_start(var_args, a10);
  int32_t a11 = va_arg(var_args, int32_t);
  Struct12BytesHomogeneousFloat a12 =
      va_arg(var_args, Struct12BytesHomogeneousFloat);
  va_end(var_args);

  std::cout << "VariadicAt11Doublex8FloatStruct12BytesHomogeneousF" << "(" << a0
            << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ", "
            << a5 << ", " << a6 << ", " << a7 << ", " << a8 << ", (" << a9.a0
            << ", " << a9.a1 << ", " << a9.a2 << "), " << a10 << ", " << a11
            << ", (" << a12.a0 << ", " << a12.a1 << ", " << a12.a2 << "))"
            << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;
  result += a5;
  result += a6;
  result += a7;
  result += a8;
  result += a9.a0;
  result += a9.a1;
  result += a9.a2;
  result += a10;
  result += a11;
  result += a12.a0;
  result += a12.a1;
  result += a12.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments mixed.
DART_EXPORT double VariadicAt1DoubleInt64Int32Struct20BytesHomogeneou(double a0,
                                                                      ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  int32_t a2 = va_arg(var_args, int32_t);
  Struct20BytesHomogeneousInt32 a3 =
      va_arg(var_args, Struct20BytesHomogeneousInt32);
  double a4 = va_arg(var_args, double);
  int64_t a5 = va_arg(var_args, int64_t);
  int32_t a6 = va_arg(var_args, int32_t);
  Struct12BytesHomogeneousFloat a7 =
      va_arg(var_args, Struct12BytesHomogeneousFloat);
  int64_t a8 = va_arg(var_args, int64_t);
  va_end(var_args);

  std::cout << "VariadicAt1DoubleInt64Int32Struct20BytesHomogeneou" << "(" << a0
            << ", " << a1 << ", " << a2 << ", (" << a3.a0 << ", " << a3.a1
            << ", " << a3.a2 << ", " << a3.a3 << ", " << a3.a4 << "), " << a4
            << ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
            << ", " << a7.a2 << "), " << a8 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3.a0;
  result += a3.a1;
  result += a3.a2;
  result += a3.a3;
  result += a3.a4;
  result += a4;
  result += a5;
  result += a6;
  result += a7.a0;
  result += a7.a1;
  result += a7.a2;
  result += a8;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments function definition, but not passing any.
DART_EXPORT double VariadicAt5Doublex5(double a0,
                                       double a1,
                                       double a2,
                                       double a3,
                                       double a4,
                                       ...) {
  va_list var_args;
  va_start(var_args, a4);

  va_end(var_args);

  std::cout << "VariadicAt5Doublex5" << "(" << a0 << ", " << a1 << ", " << a2
            << ", " << a3 << ", " << a4 << ")" << "\n";

  double result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Struct stradles last argument register, variadic
DART_EXPORT int64_t VariadicAt1Int64x7Struct12BytesHomogeneousInt32(int64_t a0,
                                                                    ...) {
  va_list var_args;
  va_start(var_args, a0);
  int64_t a1 = va_arg(var_args, int64_t);
  int64_t a2 = va_arg(var_args, int64_t);
  int64_t a3 = va_arg(var_args, int64_t);
  int64_t a4 = va_arg(var_args, int64_t);
  int64_t a5 = va_arg(var_args, int64_t);
  int64_t a6 = va_arg(var_args, int64_t);
  Struct12BytesHomogeneousInt32 a7 =
      va_arg(var_args, Struct12BytesHomogeneousInt32);
  va_end(var_args);

  std::cout << "VariadicAt1Int64x7Struct12BytesHomogeneousInt32" << "(" << a0
            << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4 << ", "
            << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1 << ", "
            << a7.a2 << "))" << "\n";

  int64_t result = 0;

  result += a0;
  result += a1;
  result += a2;
  result += a3;
  result += a4;
  result += a5;
  result += a6;
  result += a7.a0;
  result += a7.a1;
  result += a7.a2;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Variadic arguments test on macos_arm64.
DART_EXPORT int32_t VariadicAt1Struct12BytesHomogeneousInt32Int32x4(
    Struct12BytesHomogeneousInt32 a0,
    ...) {
  va_list var_args;
  va_start(var_args, a0);
  int32_t a1 = va_arg(var_args, int32_t);
  int32_t a2 = va_arg(var_args, int32_t);
  int32_t a3 = va_arg(var_args, int32_t);
  int32_t a4 = va_arg(var_args, int32_t);
  va_end(var_args);

  std::cout << "VariadicAt1Struct12BytesHomogeneousInt32Int32x4" << "(("
            << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1 << ", "
            << a2 << ", " << a3 << ", " << a4 << ")" << "\n";

  int32_t result = 0;

  result += a0.a0;
  result += a0.a1;
  result += a0.a2;
  result += a1;
  result += a2;
  result += a3;
  result += a4;

  std::cout << "result = " << result << "\n";

  return result;
}

// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT intptr_t TestVariadicAt1Int64x2(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0, ...)) {
  int64_t a0;
  int64_t a1;

  a0 = -1;
  a1 = 2;

  std::cout << "Calling TestVariadicAt1Int64x2(" << "(" << a0 << ", " << a1
            << ")" << ")\n";

  int64_t result = f(a0, a1);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(1, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT intptr_t TestVariadicAt1Doublex2(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  double a1;

  a0 = -1.0;
  a1 = 2.0;

  std::cout << "Calling TestVariadicAt1Doublex2(" << "(" << a0 << ", " << a1
            << ")" << ")\n";

  double result = f(a0, a1);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(1.0, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments.
DART_EXPORT intptr_t TestVariadicAt1Int64x5(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0, ...)) {
  int64_t a0;
  int64_t a1;
  int64_t a2;
  int64_t a3;
  int64_t a4;

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;

  std::cout << "Calling TestVariadicAt1Int64x5(" << "(" << a0 << ", " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(-3, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments.
DART_EXPORT intptr_t TestVariadicAt1Doublex5(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  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 TestVariadicAt1Doublex5(" << "(" << a0 << ", " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-3.0, result);

  // Pass argument that will make the Dart callback throw.
  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 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments exhaust registers.
DART_EXPORT intptr_t TestVariadicAt1Int64x20(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0, ...)) {
  int64_t a0;
  int64_t a1;
  int64_t a2;
  int64_t a3;
  int64_t a4;
  int64_t a5;
  int64_t a6;
  int64_t a7;
  int64_t a8;
  int64_t a9;
  int64_t a10;
  int64_t a11;
  int64_t a12;
  int64_t a13;
  int64_t a14;
  int64_t a15;
  int64_t a16;
  int64_t a17;
  int64_t a18;
  int64_t a19;

  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;

  std::cout << "Calling TestVariadicAt1Int64x20(" << "(" << a0 << ", " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ", " << a5 << ", "
            << a6 << ", " << a7 << ", " << a8 << ", " << a9 << ", " << a10
            << ", " << a11 << ", " << a12 << ", " << a13 << ", " << a14 << ", "
            << a15 << ", " << a16 << ", " << a17 << ", " << a18 << ", " << a19
            << ")" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13,
                     a14, a15, a16, a17, a18, a19);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(10, 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, a11, a12, a13, a14,
             a15, a16, a17, a18, a19);

  CHECK_EQ(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, a11, a12, a13, a14,
             a15, a16, a17, a18, a19);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments exhaust registers.
DART_EXPORT intptr_t TestVariadicAt1Doublex20(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  double a1;
  double a2;
  double a3;
  double a4;
  double a5;
  double a6;
  double a7;
  double a8;
  double a9;
  double a10;
  double a11;
  double a12;
  double a13;
  double a14;
  double a15;
  double a16;
  double a17;
  double a18;
  double a19;

  a0 = -1.0;
  a1 = 2.0;
  a2 = -3.0;
  a3 = 4.0;
  a4 = -5.0;
  a5 = 6.0;
  a6 = -7.0;
  a7 = 8.0;
  a8 = -9.0;
  a9 = 10.0;
  a10 = -11.0;
  a11 = 12.0;
  a12 = -13.0;
  a13 = 14.0;
  a14 = -15.0;
  a15 = 16.0;
  a16 = -17.0;
  a17 = 18.0;
  a18 = -19.0;
  a19 = 20.0;

  std::cout << "Calling TestVariadicAt1Doublex20(" << "(" << a0 << ", " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ", " << a5 << ", "
            << a6 << ", " << a7 << ", " << a8 << ", " << a9 << ", " << a10
            << ", " << a11 << ", " << a12 << ", " << a13 << ", " << a14 << ", "
            << a15 << ", " << a16 << ", " << a17 << ", " << a18 << ", " << a19
            << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13,
                    a14, a15, a16, a17, a18, a19);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(10.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, a11, a12, a13, a14,
             a15, a16, a17, a18, a19);

  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, a11, a12, a13, a14,
             a15, a16, a17, a18, a19);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT intptr_t TestVariadicAt1Int64x2Struct8BytesIntInt64(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0, ...)) {
  int64_t a0;
  int64_t a1;
  Struct8BytesInt a2 = {};
  int64_t a3;

  a0 = -1;
  a1 = 2;
  a2.a0 = -3;
  a2.a1 = 4;
  a2.a2 = -5;
  a3 = 6;

  std::cout << "Calling TestVariadicAt1Int64x2Struct8BytesIntInt64(" << "("
            << a0 << ", " << a1 << ", (" << a2.a0 << ", " << a2.a1 << ", "
            << a2.a2 << "), " << a3 << ")" << ")\n";

  int64_t result = f(a0, a1, a2, a3);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(3, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT intptr_t TestVariadicAt1Doublex2Struct32BytesHomogeneousDoubleD(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  double a1;
  Struct32BytesHomogeneousDouble a2 = {};
  double a3;

  a0 = -1.0;
  a1 = 2.0;
  a2.a0 = -3.0;
  a2.a1 = 4.0;
  a2.a2 = -5.0;
  a2.a3 = 6.0;
  a3 = -7.0;

  std::cout << "Calling TestVariadicAt1Doublex2Struct32BytesHomogeneousDoubleD("
            << "(" << a0 << ", " << a1 << ", (" << a2.a0 << ", " << a2.a1
            << ", " << a2.a2 << ", " << a2.a3 << "), " << a3 << ")" << ")\n";

  double result = f(a0, a1, a2, a3);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-4.0, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT intptr_t TestVariadicAt1DoubleStruct12BytesHomogeneousFloatDoub(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  Struct12BytesHomogeneousFloat a1 = {};
  double a2;

  a0 = -1.0;
  a1.a0 = 2.0;
  a1.a1 = -3.0;
  a1.a2 = 4.0;
  a2 = -5.0;

  std::cout << "Calling TestVariadicAt1DoubleStruct12BytesHomogeneousFloatDoub("
            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
            << "), " << a2 << ")" << ")\n";

  double result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-3.0, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT intptr_t TestVariadicAt1Int32Struct20BytesHomogeneousInt32Int32(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(int32_t a0, ...)) {
  int32_t a0;
  Struct20BytesHomogeneousInt32 a1 = {};
  int32_t a2;

  a0 = -1;
  a1.a0 = 2;
  a1.a1 = -3;
  a1.a2 = 4;
  a1.a3 = -5;
  a1.a4 = 6;
  a2 = -7;

  std::cout << "Calling TestVariadicAt1Int32Struct20BytesHomogeneousInt32Int32("
            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
            << ", " << a1.a3 << ", " << a1.a4 << "), " << a2 << ")" << ")\n";

  int32_t result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(-4, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments including struct.
DART_EXPORT intptr_t TestVariadicAt1DoubleStruct20BytesHomogeneousFloatDoub(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  Struct20BytesHomogeneousFloat a1 = {};
  double a2;

  a0 = -1.0;
  a1.a0 = 2.0;
  a1.a1 = -3.0;
  a1.a2 = 4.0;
  a1.a3 = -5.0;
  a1.a4 = 6.0;
  a2 = -7.0;

  std::cout << "Calling TestVariadicAt1DoubleStruct20BytesHomogeneousFloatDoub("
            << "(" << a0 << ", (" << a1.a0 << ", " << a1.a1 << ", " << a1.a2
            << ", " << a1.a3 << ", " << a1.a4 << "), " << a2 << ")" << ")\n";

  double result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-4.0, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Regression test for variadic arguments.
// https://github.com/dart-lang/sdk/issues/49460
DART_EXPORT intptr_t TestVariadicAt2Int32Int64IntPtr(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(int32_t a0, int64_t a1, ...)) {
  int32_t a0;
  int64_t a1;
  intptr_t a2;

  a0 = -1;
  a1 = 2;
  a2 = -3;

  std::cout << "Calling TestVariadicAt2Int32Int64IntPtr(" << "(" << a0 << ", "
            << a1 << ", " << a2 << ")" << ")\n";

  int32_t result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(-2, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments mixed.
DART_EXPORT intptr_t TestVariadicAt1DoubleInt64Int32DoubleInt64Int32(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  int64_t a1;
  int32_t a2;
  double a3;
  int64_t a4;
  int32_t a5;

  a0 = -1.0;
  a1 = 2;
  a2 = -3;
  a3 = 4.0;
  a4 = -5;
  a5 = 6;

  std::cout << "Calling TestVariadicAt1DoubleInt64Int32DoubleInt64Int32(" << "("
            << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(3.0, result);

  // Pass argument that will make the Dart callback throw.
  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 = 84;

  result = f(a0, a1, a2, a3, a4, a5);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments homogenous struct stack alignment on macos_arm64.
DART_EXPORT intptr_t TestVariadicAt1Int64Int32Struct12BytesHomogeneousFloat(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(int64_t a0, ...)) {
  int64_t a0;
  int32_t a1;
  Struct12BytesHomogeneousFloat a2 = {};

  a0 = -1;
  a1 = 2;
  a2.a0 = -3.0;
  a2.a1 = 4.0;
  a2.a2 = -5.0;

  std::cout << "Calling TestVariadicAt1Int64Int32Struct12BytesHomogeneousFloat("
            << "(" << a0 << ", " << a1 << ", (" << a2.a0 << ", " << a2.a1
            << ", " << a2.a2 << "))" << ")\n";

  double result = f(a0, a1, a2);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-3.0, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments homogenous struct stack alignment on macos_arm64.
DART_EXPORT intptr_t TestVariadicAt11Doublex8FloatStruct12BytesHomogeneousF(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0,
                double a1,
                double a2,
                double a3,
                double a4,
                double a5,
                double a6,
                double a7,
                float a8,
                Struct12BytesHomogeneousFloat a9,
                int64_t a10,
                ...)) {
  double a0;
  double a1;
  double a2;
  double a3;
  double a4;
  double a5;
  double a6;
  double a7;
  float a8;
  Struct12BytesHomogeneousFloat a9 = {};
  int64_t a10;
  int32_t a11;
  Struct12BytesHomogeneousFloat a12 = {};

  a0 = -1.0;
  a1 = 2.0;
  a2 = -3.0;
  a3 = 4.0;
  a4 = -5.0;
  a5 = 6.0;
  a6 = -7.0;
  a7 = 8.0;
  a8 = -9.0;
  a9.a0 = 10.0;
  a9.a1 = -11.0;
  a9.a2 = 12.0;
  a10 = -13;
  a11 = 14;
  a12.a0 = -15.0;
  a12.a1 = 16.0;
  a12.a2 = -17.0;

  std::cout << "Calling TestVariadicAt11Doublex8FloatStruct12BytesHomogeneousF("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", " << a7 << ", " << a8 << ", ("
            << a9.a0 << ", " << a9.a1 << ", " << a9.a2 << "), " << a10 << ", "
            << a11 << ", (" << a12.a0 << ", " << a12.a1 << ", " << a12.a2
            << "))" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-9.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, a11, a12);

  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, a11, a12);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments mixed.
DART_EXPORT intptr_t TestVariadicAt1DoubleInt64Int32Struct20BytesHomogeneou(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*f)(double a0, ...)) {
  double a0;
  int64_t a1;
  int32_t a2;
  Struct20BytesHomogeneousInt32 a3 = {};
  double a4;
  int64_t a5;
  int32_t a6;
  Struct12BytesHomogeneousFloat a7 = {};
  int64_t a8;

  a0 = -1.0;
  a1 = 2;
  a2 = -3;
  a3.a0 = 4;
  a3.a1 = -5;
  a3.a2 = 6;
  a3.a3 = -7;
  a3.a4 = 8;
  a4 = -9.0;
  a5 = 10;
  a6 = -11;
  a7.a0 = 12.0;
  a7.a1 = -13.0;
  a7.a2 = 14.0;
  a8 = -15;

  std::cout << "Calling TestVariadicAt1DoubleInt64Int32Struct20BytesHomogeneou("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", (" << a3.a0 << ", "
            << a3.a1 << ", " << a3.a2 << ", " << a3.a3 << ", " << a3.a4 << "), "
            << a4 << ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
            << ", " << a7.a2 << "), " << a8 << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8);

  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);

  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 and unions by value.
// Variadic arguments function definition, but not passing any.
DART_EXPORT intptr_t TestVariadicAt5Doublex5(
    // NOLINTNEXTLINE(whitespace/parens)
    double (*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 TestVariadicAt5Doublex5(" << "(" << a0 << ", " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";

  double result = f(a0, a1, a2, a3, a4);

  std::cout << "result = " << result << "\n";

  CHECK_APPROX(-3.0, result);

  // Pass argument that will make the Dart callback throw.
  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 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_APPROX(0.0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Struct stradles last argument register, variadic
DART_EXPORT intptr_t TestVariadicAt1Int64x7Struct12BytesHomogeneousInt32(
    // NOLINTNEXTLINE(whitespace/parens)
    int64_t (*f)(int64_t a0, ...)) {
  int64_t a0;
  int64_t a1;
  int64_t a2;
  int64_t a3;
  int64_t a4;
  int64_t a5;
  int64_t a6;
  Struct12BytesHomogeneousInt32 a7 = {};

  a0 = -1;
  a1 = 2;
  a2 = -3;
  a3 = 4;
  a4 = -5;
  a5 = 6;
  a6 = -7;
  a7.a0 = 8;
  a7.a1 = -9;
  a7.a2 = 10;

  std::cout << "Calling TestVariadicAt1Int64x7Struct12BytesHomogeneousInt32("
            << "(" << a0 << ", " << a1 << ", " << a2 << ", " << a3 << ", " << a4
            << ", " << a5 << ", " << a6 << ", (" << a7.a0 << ", " << a7.a1
            << ", " << a7.a2 << "))" << ")\n";

  int64_t result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(5, result);

  // Pass argument that will make the Dart callback throw.
  a0 = 42;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0 = 84;

  result = f(a0, a1, a2, a3, a4, a5, a6, a7);

  CHECK_EQ(0, result);

  return 0;
}

// Used for testing structs and unions by value.
// Variadic arguments test on macos_arm64.
DART_EXPORT intptr_t TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4(
    // NOLINTNEXTLINE(whitespace/parens)
    int32_t (*f)(Struct12BytesHomogeneousInt32 a0, ...)) {
  Struct12BytesHomogeneousInt32 a0 = {};
  int32_t a1;
  int32_t a2;
  int32_t a3;
  int32_t a4;

  a0.a0 = -1;
  a0.a1 = 2;
  a0.a2 = -3;
  a1 = 4;
  a2 = -5;
  a3 = 6;
  a4 = -7;

  std::cout << "Calling TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4("
            << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1
            << ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";

  int32_t result = f(a0, a1, a2, a3, a4);

  std::cout << "result = " << result << "\n";

  CHECK_EQ(-4, result);

  // Pass argument that will make the Dart callback throw.
  a0.a0 = 42;

  result = f(a0, a1, a2, a3, a4);

  CHECK_EQ(0, result);

  // Pass argument that will make the Dart callback return null.
  a0.a0 = 84;

  result = f(a0, a1, a2, a3, a4);

  CHECK_EQ(0, result);

  return 0;
}

}  // namespace dart
