Version 2.12.0-28.0.dev

Merge commit '9d132ebba9f1e0434fdd13491c4e03f80127a5f3' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7db0cc..e478d0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -85,15 +85,31 @@
 
 #### Pub
 
+* **Breaking**: The Dart SDK constraint is now **required** in `pubspec.yaml`.
+
+  You now have to include a section like:
+
+  ```yaml
+  environment:
+    sdk: '>=2.10.0 <3.0.0'
+  ```
+
+  See [#44072][].
 * The top level `pub` executable has been deprecated. Use `dart pub` instead.
-* New commands `dart pub add` and `dart pub remove` that adds and removes new
-  dependencies to your `pubspec.yaml`.
-* New option `dart pub outdated mode=null-safety` that will analyze your
+  See [dart tool][].
+* New command `dart pub add` that adds  new dependencies to your `pubspec.yaml`.
+  
+  And a corresponding `dart pub remove` that removes dependencies.
+* New option `dart pub outdated --mode=null-safety` that will analyze your
   dependencies for null-safety.
 * `dart pub publish` will now check your pubspec keys for likely typos.
-* `dart pub get` will print a warning if the resolution is in mixed-mode requiring
-  the code to run with `dart --no-sound-null-safety`.
 * New command `dart pub login` that logs in to pub.dev.
+* The `--server` option to `dart pub publish` and `dart pub uploader` have been
+  deprecated. Use `publish_to` in your `pubspec.yaml` or set the 
+  `$PUB_HOSTED_URL` environment variable.
+
+[#44072]: https://github.com/dart-lang/sdk/issues/44072
+[dart tool]: https://dart.dev/tools/dart-tool
 
 ## 2.10.3 - 2020-10-29
 
diff --git a/DEPS b/DEPS
index 57a2c16..1e6598a 100644
--- a/DEPS
+++ b/DEPS
@@ -132,7 +132,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "eedbd5fde84f9a1a8da643b475305a81841da599",
   "protobuf_rev": "3746c8fd3f2b0147623a8e3db89c3ff4330de760",
-  "pub_rev": "900e796a37fd9f68de9dd183cf4798fe5f055eaa",
+  "pub_rev": "4ca4767a6c00b2dadecdaee9a4866dae40ef25f2",
   "pub_semver_tag": "v1.4.4",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 3dbf51c..0706fb6 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -392,7 +392,7 @@
 }
 
 class _SimpleDartSdkTest with ResourceProviderMixin {
-  DartSdk sdk;
+  /*late*/ DartSdk sdk;
 
   void setUp() {
     newFile('/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart',
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 75588bf..53e2e9a 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -58,10 +58,10 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
       expect(name1.staticElement, isClassElement);
       expect(name1.staticElement.displayName, 'A');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isConstructorElement);
       expect(name2.staticElement.displayName, 'named');
       expect(name3, isNull);
@@ -87,13 +87,13 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
+      assert(name3 != null);
       expect(name1.staticElement, isPrefixElement);
       expect(name1.staticElement.displayName, 'p');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
       expect(name2.staticElement.displayName, 'A');
-      expect(name3, isNotNull);
       expect(name3.staticElement, isConstructorElement);
       expect(name3.staticElement.displayName, 'named');
       if (annotationElement is ConstructorElement) {
@@ -118,13 +118,13 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
+      assert(name3 != null);
       expect(name1.staticElement, isPrefixElement);
       expect(name1.staticElement.displayName, 'p');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
       expect(name2.staticElement.displayName, 'A');
-      expect(name3, isNotNull);
       expect(name3.staticElement, isPropertyAccessorElement);
       expect(name3.staticElement.displayName, 'V');
       if (annotationElement is PropertyAccessorElement) {
@@ -148,10 +148,10 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
       expect(name1.staticElement, isPrefixElement);
       expect(name1.staticElement.displayName, 'p');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
       expect(name2.staticElement.displayName, 'A');
       expect(name3, isNull);
@@ -176,10 +176,10 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
       expect(name1.staticElement, isClassElement);
       expect(name1.staticElement.displayName, 'A');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isPropertyAccessorElement);
       expect(name2.staticElement.displayName, 'V');
       expect(name3, isNull);
@@ -204,7 +204,7 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
       expect(name1.staticElement, isClassElement);
       expect(name1.staticElement.displayName, 'A');
       expect(name2, isNull);
@@ -228,7 +228,7 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
       expect(name1.staticElement, isPropertyAccessorElement);
       expect(name1.staticElement.displayName, 'V');
       expect(name2, isNull);
@@ -252,10 +252,10 @@
         SimpleIdentifier name2,
         SimpleIdentifier name3,
         Element annotationElement) {
-      expect(name1, isNotNull);
+      assert(name1 != null);
+      assert(name2 != null);
       expect(name1.staticElement, isPrefixElement);
       expect(name1.staticElement.displayName, 'p');
-      expect(name2, isNotNull);
       expect(name2.staticElement, isPropertyAccessorElement);
       expect(name2.staticElement.displayName, 'V');
       expect(name3, isNull);
@@ -299,19 +299,19 @@
 @reflectiveTest
 class ElementResolverTest with ResourceProviderMixin, ElementsTypesMixin {
   /// The error listener to which errors will be reported.
-  GatheringErrorListener _listener;
+  /*late*/ GatheringErrorListener _listener;
 
   /// The type provider used to access the types.
-  TypeProvider _typeProvider;
+  /*late*/ TypeProvider _typeProvider;
 
   /// The library containing the code being resolved.
-  LibraryElementImpl _definingLibrary;
+  /*late*/ LibraryElementImpl _definingLibrary;
 
   /// The resolver visitor that maintains the state for the resolver.
-  ResolverVisitor _visitor;
+  /*late*/ ResolverVisitor _visitor;
 
   /// The resolver being used to resolve the test cases.
-  ElementResolver _resolver;
+  /*late*/ ElementResolver _resolver;
 
   @override
   TypeProvider get typeProvider => _typeProvider;
diff --git a/pkg/analyzer/test/generated/elements_types_mixin.dart b/pkg/analyzer/test/generated/elements_types_mixin.dart
index 60c16a5..3f8afd5 100644
--- a/pkg/analyzer/test/generated/elements_types_mixin.dart
+++ b/pkg/analyzer/test/generated/elements_types_mixin.dart
@@ -151,7 +151,7 @@
 
   LibraryElementImpl get testLibrary => null;
 
-  TypeProvider get typeProvider;
+  TypeProvider /*!*/ get typeProvider;
 
   VoidTypeImpl get voidNone => VoidTypeImpl.instance;
 
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index d2cfceb..5a6b51f 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -120,17 +120,17 @@
     CompilationUnitImpl unit = parseCompilationUnit(
         'class C { foo(int value) { x >>>= value; } }',
         featureSet: tripleShift);
-    ClassDeclaration declaration = unit.declarations[0];
-    MethodDeclaration method = declaration.members[0];
-    BlockFunctionBody blockFunctionBody = method.body;
+    var declaration = unit.declarations[0] as ClassDeclaration;
+    var method = declaration.members[0] as MethodDeclaration;
+    var blockFunctionBody = method.body as BlockFunctionBody;
     NodeList<Statement> statements = blockFunctionBody.block.statements;
     expect(statements, hasLength(1));
-    ExpressionStatement statement = statements[0];
-    AssignmentExpression assignment = statement.expression;
-    SimpleIdentifier leftHandSide = assignment.leftHandSide;
+    var statement = statements[0] as ExpressionStatement;
+    var assignment = statement.expression as AssignmentExpression;
+    var leftHandSide = assignment.leftHandSide as SimpleIdentifier;
     expect(leftHandSide.name, 'x');
     expect(assignment.operator.lexeme, '>>>=');
-    SimpleIdentifier rightHandSide = assignment.rightHandSide;
+    var rightHandSide = assignment.rightHandSide as SimpleIdentifier;
     expect(rightHandSide.name, 'value');
   }
 
@@ -178,7 +178,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
   }
 
@@ -190,7 +190,7 @@
       expectedError(ParserErrorCode.ABSTRACT_EXTERNAL_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
     expect(field.externalKeyword, isNotNull);
   }
@@ -203,7 +203,7 @@
       expectedError(ParserErrorCode.ABSTRACT_LATE_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
   }
 
@@ -215,7 +215,7 @@
       expectedError(ParserErrorCode.ABSTRACT_LATE_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
   }
 
@@ -227,7 +227,7 @@
       expectedError(ParserErrorCode.ABSTRACT_STATIC_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
   }
 
@@ -239,7 +239,7 @@
       expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 6, 4),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -263,7 +263,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.externalKeyword, isNotNull);
   }
 
@@ -275,7 +275,7 @@
       expectedError(ParserErrorCode.ABSTRACT_EXTERNAL_FIELD, 9, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNotNull);
     expect(field.externalKeyword, isNotNull);
   }
@@ -288,7 +288,7 @@
       expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.externalKeyword, isNotNull);
   }
 
@@ -300,7 +300,7 @@
       expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.externalKeyword, isNotNull);
   }
 
@@ -310,7 +310,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.externalKeyword, isNotNull);
   }
 
@@ -322,7 +322,7 @@
     ]);
     expect(member, isNotNull);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -346,7 +346,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -372,7 +372,7 @@
       expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 5, 5),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -396,7 +396,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -419,7 +419,7 @@
     ClassMember member = parser.parseClassMember('C');
     expect(member, isNotNull);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
@@ -443,7 +443,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.abstractKeyword, isNull);
   }
 
@@ -453,7 +453,7 @@
     expect(member, isNotNull);
     assertNoErrors();
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.externalKeyword, isNull);
   }
 
@@ -465,7 +465,7 @@
       expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 4, 4),
     ]);
     expect(member, isFieldDeclaration);
-    FieldDeclaration field = member;
+    var field = member as FieldDeclaration;
     expect(field.covariantKeyword, isNull);
     expect(field.documentationComment, isNull);
     expect(field.metadata, hasLength(0));
diff --git a/pkg/dartdev/lib/src/commands/pub.dart b/pkg/dartdev/lib/src/commands/pub.dart
new file mode 100644
index 0000000..d77dce6
--- /dev/null
+++ b/pkg/dartdev/lib/src/commands/pub.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:args/args.dart';
+
+import '../core.dart';
+import '../experiments.dart';
+import '../sdk.dart';
+import '../vm_interop_handler.dart';
+
+class PubCommand extends DartdevCommand {
+  static const String cmdName = 'pub';
+
+  PubCommand() : super(cmdName, 'Work with packages.');
+
+  // TODO(jwren) as soon as pub commands are are implemented directly in
+  //  dartdev, remove this static list.
+  /// A list of all subcommands, used only for the implementation of
+  /// [usagePath], see below.
+  static List<String> pubSubcommands = [
+    'cache',
+    'deps',
+    'downgrade',
+    'get',
+    'global',
+    'logout',
+    'outdated',
+    'publish',
+    'run',
+    'upgrade',
+    'uploader',
+    'version',
+  ];
+
+  @override
+  ArgParser createArgParser() => ArgParser.allowAnything();
+
+  @override
+  void printUsage() {
+    // Override [printUsage] for invocations of 'dart help pub' which won't
+    // execute [run] below.  Without this, the 'dart help pub' reports the
+    // command pub with no commands or flags.
+    if (!Sdk.checkArtifactExists(sdk.pubSnapshot)) {
+      return;
+    }
+    final command = sdk.pubSnapshot;
+    final args = ['help'];
+
+    log.trace('$command ${args.first}');
+
+    // Call 'pub help'
+    VmInteropHandler.run(command, args);
+  }
+
+  @override
+  FutureOr<int> run() async {
+    if (!Sdk.checkArtifactExists(sdk.pubSnapshot)) {
+      return 255;
+    }
+    final command = sdk.pubSnapshot;
+    var args = argResults.arguments;
+
+    // Pass any --enable-experiment options along.
+    if (args.isNotEmpty && wereExperimentsSpecified) {
+      List<String> experimentIds = specifiedExperiments;
+
+      if (args.first == 'run') {
+        args = [
+          ...args.sublist(0, 1),
+          '--$experimentFlagName=${experimentIds.join(',')}',
+          ...args.sublist(1),
+        ];
+      } else if (args.length > 1 && args[0] == 'global' && args[0] == 'run') {
+        args = [
+          ...args.sublist(0, 2),
+          '--$experimentFlagName=${experimentIds.join(',')}',
+          ...args.sublist(2),
+        ];
+      }
+    }
+
+    log.trace('$command ${args.join(' ')}');
+    VmInteropHandler.run(command, args);
+    return 0;
+  }
+}
diff --git a/pkg/dartdev/test/commands/pub_test.dart b/pkg/dartdev/test/commands/pub_test.dart
index d8a4a04..82f00d0 100644
--- a/pkg/dartdev/test/commands/pub_test.dart
+++ b/pkg/dartdev/test/commands/pub_test.dart
@@ -86,8 +86,9 @@
     expect(result.stdout, isEmpty);
     expect(
         result.stderr,
-        contains('bin/main.dart:1:18: Error: This requires the \'non-nullable\''
-            ' language feature to be enabled.\n'));
+        contains('bin/main.dart:1:18: Error: This requires the null safety '
+            'language feature, which requires language version of 2.12 or '
+            'higher.\n'));
   });
 
   test('failure', () {
diff --git a/pkg/dartdev/test/commands/test_test.dart b/pkg/dartdev/test/commands/test_test.dart
index 93aa6b1..cf7aea9 100644
--- a/pkg/dartdev/test/commands/test_test.dart
+++ b/pkg/dartdev/test/commands/test_test.dart
@@ -69,7 +69,11 @@
 
   test('no package:test dependency', () {
     p = project(mainSrc: 'int get foo => 1;\n');
-    p.file('pubspec.yaml', 'name: ${p.name}\n');
+    p.file('pubspec.yaml', '''
+name: ${p.name}
+environment:
+  sdk: '>=2.10.0 <3.0.0'
+''');
 
     var result = p.runSync('pub', ['get']);
     expect(result.exitCode, 0);
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index 4d67099..bbc46df 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -42,7 +42,14 @@
     this.logAnalytics = false,
   }) {
     dir = Directory.systemTemp.createTempSync('dartdev');
-    file('pubspec.yaml', 'name: $name\ndev_dependencies:\n  test: any\n');
+    file('pubspec.yaml', '''
+name: $name
+environment:
+  sdk: '>=2.10.0 <3.0.0'
+
+dev_dependencies:
+  test: any
+''');
     if (analysisOptions != null) {
       file('analysis_options.yaml', analysisOptions);
     }
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 595dc6b..6ea866c 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -1085,8 +1085,7 @@
 }
 
 abstract class VMKernelCompilerMixin {
-  static final noCausalAsyncStacksRegExp =
-      RegExp('--no[_-]causal[_-]async[_-]stacks');
+  static final causalAsyncStacksRegExp = RegExp('--causal[_-]async[_-]stacks');
 
   TestConfiguration get _configuration;
 
@@ -1117,7 +1116,7 @@
 
     var isProductMode = _configuration.configuration.mode == Mode.product;
 
-    var causalAsyncStacks = !arguments.any(noCausalAsyncStacksRegExp.hasMatch);
+    var causalAsyncStacks = arguments.any(causalAsyncStacksRegExp.hasMatch);
 
     var args = [
       _isAot ? '--aot' : '--no-aot',
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
index cbb631f..74f27e4 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -2388,6 +2388,131 @@
 
 // Used for testing structs 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 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 << ", "
@@ -6359,6 +6484,196 @@
 
 // Used for testing structs 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 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)) {
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index def74e4..714de1b 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -180,7 +180,7 @@
       "$root_out_dir/vm_outline" + output_postfix + ".dill",
     ]
     args = [ "dart:core" ]
-    allow_causal_async_stacks = !is_product_flag
+    allow_causal_async_stacks = false
     args += [
       "-Ddart.vm.product=$is_product_flag",
       "-Ddart.developer.causal_async_stacks=$allow_causal_async_stacks",
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 51e4a3f..5e02239 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -55,8 +55,8 @@
 #define VM_GLOBAL_FLAG_LIST(P, R, C, D)                                        \
   P(dwarf_stack_traces_mode, bool, false,                                      \
     "Use --[no-]dwarf-stack-traces instead.")                                  \
-  P(causal_async_stacks, bool, !USING_PRODUCT, "Improved async stacks")        \
-  P(lazy_async_stacks, bool, false, "Reconstruct async stacks from listeners") \
+  P(causal_async_stacks, bool, false, "Improved async stacks")                 \
+  P(lazy_async_stacks, bool, true, "Reconstruct async stacks from listeners")  \
   P(lazy_dispatchers, bool, true, "Generate dispatchers lazily")               \
   P(use_bare_instructions, bool, true, "Enable bare instructions mode.")       \
   R(dedup_instructions, true, bool, false,                                     \
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index 5d40791..94a8070 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -322,11 +322,11 @@
 
 #if defined(DEBUG)
   bool IsCurrentThreadReader() {
-    SafepointMonitorLocker ml(&monitor_);
     ThreadId id = OSThread::GetCurrentThreadId();
     if (IsCurrentThreadWriter()) {
       return true;
     }
+    MutexLocker ml(&reader_ids_mutex_);
     for (intptr_t i = readers_ids_.length() - 1; i >= 0; i--) {
       if (readers_ids_.At(i) == id) {
         return true;
@@ -356,7 +356,10 @@
       ml.Wait();
     }
 #if defined(DEBUG)
-    readers_ids_.Add(OSThread::GetCurrentThreadId());
+    {
+      MutexLocker ml(&reader_ids_mutex_);
+      readers_ids_.Add(OSThread::GetCurrentThreadId());
+    }
 #endif
     ++state_;
     return true;
@@ -365,16 +368,19 @@
     SafepointMonitorLocker ml(&monitor_);
     ASSERT(state_ > 0);
 #if defined(DEBUG)
-    intptr_t i = readers_ids_.length() - 1;
-    ThreadId id = OSThread::GetCurrentThreadId();
-    while (i >= 0) {
-      if (readers_ids_.At(i) == id) {
-        readers_ids_.RemoveAt(i);
-        break;
+    {
+      MutexLocker ml(&reader_ids_mutex_);
+      intptr_t i = readers_ids_.length() - 1;
+      ThreadId id = OSThread::GetCurrentThreadId();
+      while (i >= 0) {
+        if (readers_ids_.At(i) == id) {
+          readers_ids_.RemoveAt(i);
+          break;
+        }
+        i--;
       }
-      i--;
+      ASSERT(i >= 0);
     }
-    ASSERT(i >= 0);
 #endif
     if (--state_ == 0) {
       ml.NotifyAll();
@@ -411,6 +417,7 @@
   intptr_t state_ = 0;
 
 #if defined(DEBUG)
+  Mutex reader_ids_mutex_;
   MallocGrowableArray<ThreadId> readers_ids_;
 #endif
   ThreadId writer_id_ = OSThread::kInvalidThreadId;
diff --git a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
index 7985c51..845ebb9 100644
--- a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
@@ -172,6 +172,12 @@
           passStruct40BytesHomogeneousDoubleStruct4BytesHomo, 0.0),
       passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback),
   CallbackTest.withCheck(
+      "PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int",
+      Pointer.fromFunction<
+              PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntType>(
+          passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int, 0.0),
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntAfterCallback),
+  CallbackTest.withCheck(
       "PassStructAlignmentInt16",
       Pointer.fromFunction<PassStructAlignmentInt16Type>(
           passStructAlignmentInt16, 0),
@@ -3704,6 +3710,277 @@
   Expect.approxEquals(-5.0, result);
 }
 
+typedef PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntType
+    = Double Function(
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Int64,
+        Int8,
+        Struct1ByteInt,
+        Int64,
+        Int8,
+        Struct4BytesHomogeneousInt16,
+        Int64,
+        Int8,
+        Struct8BytesInt,
+        Int64,
+        Int8,
+        Struct8BytesHomogeneousFloat,
+        Int64,
+        Int8,
+        Struct8BytesMixed,
+        Int64,
+        Int8,
+        StructAlignmentInt16,
+        Int64,
+        Int8,
+        StructAlignmentInt32,
+        Int64,
+        Int8,
+        StructAlignmentInt64);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7 = 0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15 = 0.0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17 = 0;
+Struct1ByteInt passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18 =
+    Struct1ByteInt();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20 = 0;
+Struct4BytesHomogeneousInt16
+    passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21 =
+    Struct4BytesHomogeneousInt16();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23 = 0;
+Struct8BytesInt passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24 =
+    Struct8BytesInt();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26 = 0;
+Struct8BytesHomogeneousFloat
+    passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27 =
+    Struct8BytesHomogeneousFloat();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29 = 0;
+Struct8BytesMixed passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30 =
+    Struct8BytesMixed();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32 = 0;
+StructAlignmentInt16 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33 =
+    StructAlignmentInt16();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35 = 0;
+StructAlignmentInt32 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36 =
+    StructAlignmentInt32();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38 = 0;
+StructAlignmentInt64 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39 =
+    StructAlignmentInt64();
+
+// Result variable also global, so we can delete it after the callback.
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntResult = 0.0;
+
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult() {
+  double result = 0;
+
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a2;
+
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntResult = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
+    int a0,
+    int a1,
+    int a2,
+    int a3,
+    int a4,
+    int a5,
+    int a6,
+    int a7,
+    double a8,
+    double a9,
+    double a10,
+    double a11,
+    double a12,
+    double a13,
+    double a14,
+    double a15,
+    int a16,
+    int a17,
+    Struct1ByteInt a18,
+    int a19,
+    int a20,
+    Struct4BytesHomogeneousInt16 a21,
+    int a22,
+    int a23,
+    Struct8BytesInt a24,
+    int a25,
+    int a26,
+    Struct8BytesHomogeneousFloat a27,
+    int a28,
+    int a29,
+    Struct8BytesMixed a30,
+    int a31,
+    int a32,
+    StructAlignmentInt16 a33,
+    int a34,
+    int a35,
+    StructAlignmentInt32 a36,
+    int a37,
+    int a38,
+    StructAlignmentInt64 a39) {
+  print(
+      "passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(${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})");
+
+  // In legacy mode, possibly return null.
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int throwing on purpuse!");
+  }
+
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0 = a0;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1 = a1;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2 = a2;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3 = a3;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4 = a4;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5 = a5;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6 = a6;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7 = a7;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8 = a8;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9 = a9;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10 = a10;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11 = a11;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12 = a12;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13 = a13;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14 = a14;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15 = a15;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16 = a16;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17 = a17;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18 = a18;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19 = a19;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20 = a20;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21 = a21;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22 = a22;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23 = a23;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24 = a24;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25 = a25;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26 = a26;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27 = a27;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28 = a28;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29 = a29;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30 = a30;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31 = a31;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32 = a32;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33 = a33;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34 = a34;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35 = a35;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36 = a36;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37 = a37;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38 = a38;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39 = a39;
+
+  final result =
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntAfterCallback() {
+  final result =
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(26.0, result);
+}
+
 typedef PassStructAlignmentInt16Type = Int64 Function(StructAlignmentInt16);
 
 // Global variables to be able to test inputs after callback returned.
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index 26f48ea..35936e9 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -48,6 +48,7 @@
     testPassDoublex6Struct16BytesMixedx4Int32();
     testPassInt32x4Struct16BytesMixedx4Double();
     testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo();
+    testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int();
     testPassStructAlignmentInt16();
     testPassStructAlignmentInt32();
     testPassStructAlignmentInt64();
@@ -3357,6 +3358,245 @@
   free(a2.addressOf);
 }
 
+final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int =
+    ffiTestFunctions.lookupFunction<
+        Double Function(
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Int64,
+            Int8,
+            Struct1ByteInt,
+            Int64,
+            Int8,
+            Struct4BytesHomogeneousInt16,
+            Int64,
+            Int8,
+            Struct8BytesInt,
+            Int64,
+            Int8,
+            Struct8BytesHomogeneousFloat,
+            Int64,
+            Int8,
+            Struct8BytesMixed,
+            Int64,
+            Int8,
+            StructAlignmentInt16,
+            Int64,
+            Int8,
+            StructAlignmentInt32,
+            Int64,
+            Int8,
+            StructAlignmentInt64),
+        double Function(
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            int,
+            int,
+            Struct1ByteInt,
+            int,
+            int,
+            Struct4BytesHomogeneousInt16,
+            int,
+            int,
+            Struct8BytesInt,
+            int,
+            int,
+            Struct8BytesHomogeneousFloat,
+            int,
+            int,
+            Struct8BytesMixed,
+            int,
+            int,
+            StructAlignmentInt16,
+            int,
+            int,
+            StructAlignmentInt32,
+            int,
+            int,
+            StructAlignmentInt64)>("PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  double a8;
+  double a9;
+  double a10;
+  double a11;
+  double a12;
+  double a13;
+  double a14;
+  double a15;
+  int a16;
+  int a17;
+  Struct1ByteInt a18 = allocate<Struct1ByteInt>().ref;
+  int a19;
+  int a20;
+  Struct4BytesHomogeneousInt16 a21 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  int a22;
+  int a23;
+  Struct8BytesInt a24 = allocate<Struct8BytesInt>().ref;
+  int a25;
+  int a26;
+  Struct8BytesHomogeneousFloat a27 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  int a28;
+  int a29;
+  Struct8BytesMixed a30 = allocate<Struct8BytesMixed>().ref;
+  int a31;
+  int a32;
+  StructAlignmentInt16 a33 = allocate<StructAlignmentInt16>().ref;
+  int a34;
+  int a35;
+  StructAlignmentInt32 a36 = allocate<StructAlignmentInt32>().ref;
+  int a37;
+  int a38;
+  StructAlignmentInt64 a39 = allocate<StructAlignmentInt64>().ref;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+  a5 = 6;
+  a6 = -7;
+  a7 = 8;
+  a8 = -9.0;
+  a9 = 10.0;
+  a10 = -11.0;
+  a11 = 12.0;
+  a12 = -13.0;
+  a13 = 14.0;
+  a14 = -15.0;
+  a15 = 16.0;
+  a16 = -17;
+  a17 = 18;
+  a18.a0 = -19;
+  a19 = 20;
+  a20 = -21;
+  a21.a0 = 22;
+  a21.a1 = -23;
+  a22 = 24;
+  a23 = -25;
+  a24.a0 = 26;
+  a24.a1 = -27;
+  a24.a2 = 28;
+  a25 = -29;
+  a26 = 30;
+  a27.a0 = -31.0;
+  a27.a1 = 32.0;
+  a28 = -33;
+  a29 = 34;
+  a30.a0 = -35.0;
+  a30.a1 = 36;
+  a30.a2 = -37;
+  a31 = 38;
+  a32 = -39;
+  a33.a0 = 40;
+  a33.a1 = -41;
+  a33.a2 = 42;
+  a34 = -43;
+  a35 = 44;
+  a36.a0 = -45;
+  a36.a1 = 46;
+  a36.a2 = -47;
+  a37 = 48;
+  a38 = -49;
+  a39.a0 = 50;
+  a39.a1 = -51;
+  a39.a2 = 52;
+
+  final result = passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
+      a0,
+      a1,
+      a2,
+      a3,
+      a4,
+      a5,
+      a6,
+      a7,
+      a8,
+      a9,
+      a10,
+      a11,
+      a12,
+      a13,
+      a14,
+      a15,
+      a16,
+      a17,
+      a18,
+      a19,
+      a20,
+      a21,
+      a22,
+      a23,
+      a24,
+      a25,
+      a26,
+      a27,
+      a28,
+      a29,
+      a30,
+      a31,
+      a32,
+      a33,
+      a34,
+      a35,
+      a36,
+      a37,
+      a38,
+      a39);
+
+  print("result = $result");
+
+  Expect.approxEquals(26.0, result);
+
+  free(a18.addressOf);
+  free(a21.addressOf);
+  free(a24.addressOf);
+  free(a27.addressOf);
+  free(a30.addressOf);
+  free(a33.addressOf);
+  free(a36.addressOf);
+  free(a39.addressOf);
+}
+
 final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
     Int64 Function(StructAlignmentInt16),
     int Function(StructAlignmentInt16)>("PassStructAlignmentInt16");
diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart
index 5ea4cff..46f5108 100644
--- a/tests/ffi/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart
@@ -189,6 +189,58 @@
 On various architectures, first struct is allocated on stack.
 Check that the other two arguments are allocated on registers."""),
   FunctionType(
+      [
+        // Exhaust integer registers on all architectures
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        // Exhaust floating point registers on all architectures.
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        // Pass all kinds of structs to exercise stack placement behavior.
+        //
+        // For all structs, align stack with int64, then align to 1-byte with
+        // int8, then pass struct.
+        int64,
+        int8,
+        struct1byteInt,
+        int64,
+        int8,
+        struct4bytesInt,
+        int64,
+        int8,
+        struct8bytesInt,
+        int64,
+        int8,
+        struct8bytesFloat,
+        int64,
+        int8,
+        struct8BytesMixed,
+        int64,
+        int8,
+        structAlignmentInt16,
+        int64,
+        int8,
+        structAlignmentInt32,
+        int64,
+        int8,
+        structAlignmentInt64,
+      ],
+      double_,
+      """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(
       [structAlignmentInt16],
       int64,
       """
diff --git a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
index 76620d7..38714fd 100644
--- a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
@@ -172,6 +172,12 @@
           passStruct40BytesHomogeneousDoubleStruct4BytesHomo, 0.0),
       passStruct40BytesHomogeneousDoubleStruct4BytesHomoAfterCallback),
   CallbackTest.withCheck(
+      "PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int",
+      Pointer.fromFunction<
+              PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntType>(
+          passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int, 0.0),
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntAfterCallback),
+  CallbackTest.withCheck(
       "PassStructAlignmentInt16",
       Pointer.fromFunction<PassStructAlignmentInt16Type>(
           passStructAlignmentInt16, 0),
@@ -3816,6 +3822,281 @@
   Expect.approxEquals(-5.0, result);
 }
 
+typedef PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntType
+    = Double Function(
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Int32,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Double,
+        Int64,
+        Int8,
+        Struct1ByteInt,
+        Int64,
+        Int8,
+        Struct4BytesHomogeneousInt16,
+        Int64,
+        Int8,
+        Struct8BytesInt,
+        Int64,
+        Int8,
+        Struct8BytesHomogeneousFloat,
+        Int64,
+        Int8,
+        Struct8BytesMixed,
+        Int64,
+        Int8,
+        StructAlignmentInt16,
+        Int64,
+        Int8,
+        StructAlignmentInt32,
+        Int64,
+        Int8,
+        StructAlignmentInt64);
+
+// Global variables to be able to test inputs after callback returned.
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7 = 0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14 = 0.0;
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15 = 0.0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17 = 0;
+Struct1ByteInt passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18 =
+    Struct1ByteInt();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20 = 0;
+Struct4BytesHomogeneousInt16
+    passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21 =
+    Struct4BytesHomogeneousInt16();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23 = 0;
+Struct8BytesInt passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24 =
+    Struct8BytesInt();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26 = 0;
+Struct8BytesHomogeneousFloat
+    passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27 =
+    Struct8BytesHomogeneousFloat();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29 = 0;
+Struct8BytesMixed passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30 =
+    Struct8BytesMixed();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32 = 0;
+StructAlignmentInt16 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33 =
+    StructAlignmentInt16();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35 = 0;
+StructAlignmentInt32 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36 =
+    StructAlignmentInt32();
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37 = 0;
+int passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38 = 0;
+StructAlignmentInt64 passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39 =
+    StructAlignmentInt64();
+
+// Result variable also global, so we can delete it after the callback.
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntResult = 0.0;
+
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult() {
+  double result = 0;
+
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36.a2;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a0;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a1;
+  result += passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39.a2;
+
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntResult = result;
+
+  return result;
+}
+
+/// Test alignment and padding of 16 byte int within struct.
+double passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
+    int a0,
+    int a1,
+    int a2,
+    int a3,
+    int a4,
+    int a5,
+    int a6,
+    int a7,
+    double a8,
+    double a9,
+    double a10,
+    double a11,
+    double a12,
+    double a13,
+    double a14,
+    double a15,
+    int a16,
+    int a17,
+    Struct1ByteInt a18,
+    int a19,
+    int a20,
+    Struct4BytesHomogeneousInt16 a21,
+    int a22,
+    int a23,
+    Struct8BytesInt a24,
+    int a25,
+    int a26,
+    Struct8BytesHomogeneousFloat a27,
+    int a28,
+    int a29,
+    Struct8BytesMixed a30,
+    int a31,
+    int a32,
+    StructAlignmentInt16 a33,
+    int a34,
+    int a35,
+    StructAlignmentInt32 a36,
+    int a37,
+    int a38,
+    StructAlignmentInt64 a39) {
+  print(
+      "passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(${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})");
+
+  // In legacy mode, possibly return null.
+  if (a0 == 84) {
+    print("returning null!");
+    return null;
+  }
+
+  // In both nnbd and legacy mode, possibly throw.
+  if (a0 == 42 || a0 == 84) {
+    print("throwing!");
+    throw Exception(
+        "PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int throwing on purpuse!");
+  }
+
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a0 = a0;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a1 = a1;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a2 = a2;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a3 = a3;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a4 = a4;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a5 = a5;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a6 = a6;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a7 = a7;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a8 = a8;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a9 = a9;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a10 = a10;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a11 = a11;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a12 = a12;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a13 = a13;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a14 = a14;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a15 = a15;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a16 = a16;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a17 = a17;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a18 = a18;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a19 = a19;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a20 = a20;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a21 = a21;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a22 = a22;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a23 = a23;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a24 = a24;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a25 = a25;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a26 = a26;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a27 = a27;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a28 = a28;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a29 = a29;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a30 = a30;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a31 = a31;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a32 = a32;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a33 = a33;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a34 = a34;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a35 = a35;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a36 = a36;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a37 = a37;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a38 = a38;
+  passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int_a39 = a39;
+
+  final result =
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult();
+
+  print("result = $result");
+
+  return result;
+}
+
+void passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntAfterCallback() {
+  final result =
+      passInt32x8Doublex8Int64Int8Struct1ByteIntInt64IntCalculateResult();
+
+  print("after callback result = $result");
+
+  Expect.approxEquals(26.0, result);
+}
+
 typedef PassStructAlignmentInt16Type = Int64 Function(StructAlignmentInt16);
 
 // Global variables to be able to test inputs after callback returned.
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
index a548274..dfb17cd 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -48,6 +48,7 @@
     testPassDoublex6Struct16BytesMixedx4Int32();
     testPassInt32x4Struct16BytesMixedx4Double();
     testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo();
+    testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int();
     testPassStructAlignmentInt16();
     testPassStructAlignmentInt32();
     testPassStructAlignmentInt64();
@@ -3357,6 +3358,245 @@
   free(a2.addressOf);
 }
 
+final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int =
+    ffiTestFunctions.lookupFunction<
+        Double Function(
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Int32,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Double,
+            Int64,
+            Int8,
+            Struct1ByteInt,
+            Int64,
+            Int8,
+            Struct4BytesHomogeneousInt16,
+            Int64,
+            Int8,
+            Struct8BytesInt,
+            Int64,
+            Int8,
+            Struct8BytesHomogeneousFloat,
+            Int64,
+            Int8,
+            Struct8BytesMixed,
+            Int64,
+            Int8,
+            StructAlignmentInt16,
+            Int64,
+            Int8,
+            StructAlignmentInt32,
+            Int64,
+            Int8,
+            StructAlignmentInt64),
+        double Function(
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            int,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            double,
+            int,
+            int,
+            Struct1ByteInt,
+            int,
+            int,
+            Struct4BytesHomogeneousInt16,
+            int,
+            int,
+            Struct8BytesInt,
+            int,
+            int,
+            Struct8BytesHomogeneousFloat,
+            int,
+            int,
+            Struct8BytesMixed,
+            int,
+            int,
+            StructAlignmentInt16,
+            int,
+            int,
+            StructAlignmentInt32,
+            int,
+            int,
+            StructAlignmentInt64)>("PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int");
+
+/// Test alignment and padding of 16 byte int within struct.
+void testPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int() {
+  int a0;
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  double a8;
+  double a9;
+  double a10;
+  double a11;
+  double a12;
+  double a13;
+  double a14;
+  double a15;
+  int a16;
+  int a17;
+  Struct1ByteInt a18 = allocate<Struct1ByteInt>().ref;
+  int a19;
+  int a20;
+  Struct4BytesHomogeneousInt16 a21 =
+      allocate<Struct4BytesHomogeneousInt16>().ref;
+  int a22;
+  int a23;
+  Struct8BytesInt a24 = allocate<Struct8BytesInt>().ref;
+  int a25;
+  int a26;
+  Struct8BytesHomogeneousFloat a27 =
+      allocate<Struct8BytesHomogeneousFloat>().ref;
+  int a28;
+  int a29;
+  Struct8BytesMixed a30 = allocate<Struct8BytesMixed>().ref;
+  int a31;
+  int a32;
+  StructAlignmentInt16 a33 = allocate<StructAlignmentInt16>().ref;
+  int a34;
+  int a35;
+  StructAlignmentInt32 a36 = allocate<StructAlignmentInt32>().ref;
+  int a37;
+  int a38;
+  StructAlignmentInt64 a39 = allocate<StructAlignmentInt64>().ref;
+
+  a0 = -1;
+  a1 = 2;
+  a2 = -3;
+  a3 = 4;
+  a4 = -5;
+  a5 = 6;
+  a6 = -7;
+  a7 = 8;
+  a8 = -9.0;
+  a9 = 10.0;
+  a10 = -11.0;
+  a11 = 12.0;
+  a12 = -13.0;
+  a13 = 14.0;
+  a14 = -15.0;
+  a15 = 16.0;
+  a16 = -17;
+  a17 = 18;
+  a18.a0 = -19;
+  a19 = 20;
+  a20 = -21;
+  a21.a0 = 22;
+  a21.a1 = -23;
+  a22 = 24;
+  a23 = -25;
+  a24.a0 = 26;
+  a24.a1 = -27;
+  a24.a2 = 28;
+  a25 = -29;
+  a26 = 30;
+  a27.a0 = -31.0;
+  a27.a1 = 32.0;
+  a28 = -33;
+  a29 = 34;
+  a30.a0 = -35.0;
+  a30.a1 = 36;
+  a30.a2 = -37;
+  a31 = 38;
+  a32 = -39;
+  a33.a0 = 40;
+  a33.a1 = -41;
+  a33.a2 = 42;
+  a34 = -43;
+  a35 = 44;
+  a36.a0 = -45;
+  a36.a1 = 46;
+  a36.a2 = -47;
+  a37 = 48;
+  a38 = -49;
+  a39.a0 = 50;
+  a39.a1 = -51;
+  a39.a2 = 52;
+
+  final result = passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
+      a0,
+      a1,
+      a2,
+      a3,
+      a4,
+      a5,
+      a6,
+      a7,
+      a8,
+      a9,
+      a10,
+      a11,
+      a12,
+      a13,
+      a14,
+      a15,
+      a16,
+      a17,
+      a18,
+      a19,
+      a20,
+      a21,
+      a22,
+      a23,
+      a24,
+      a25,
+      a26,
+      a27,
+      a28,
+      a29,
+      a30,
+      a31,
+      a32,
+      a33,
+      a34,
+      a35,
+      a36,
+      a37,
+      a38,
+      a39);
+
+  print("result = $result");
+
+  Expect.approxEquals(26.0, result);
+
+  free(a18.addressOf);
+  free(a21.addressOf);
+  free(a24.addressOf);
+  free(a27.addressOf);
+  free(a30.addressOf);
+  free(a33.addressOf);
+  free(a36.addressOf);
+  free(a39.addressOf);
+}
+
 final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
     Int64 Function(StructAlignmentInt16),
     int Function(StructAlignmentInt16)>("PassStructAlignmentInt16");
diff --git a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
index 5ea4cff..46f5108 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
@@ -189,6 +189,58 @@
 On various architectures, first struct is allocated on stack.
 Check that the other two arguments are allocated on registers."""),
   FunctionType(
+      [
+        // Exhaust integer registers on all architectures
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        int32,
+        // Exhaust floating point registers on all architectures.
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        double_,
+        // Pass all kinds of structs to exercise stack placement behavior.
+        //
+        // For all structs, align stack with int64, then align to 1-byte with
+        // int8, then pass struct.
+        int64,
+        int8,
+        struct1byteInt,
+        int64,
+        int8,
+        struct4bytesInt,
+        int64,
+        int8,
+        struct8bytesInt,
+        int64,
+        int8,
+        struct8bytesFloat,
+        int64,
+        int8,
+        struct8BytesMixed,
+        int64,
+        int8,
+        structAlignmentInt16,
+        int64,
+        int8,
+        structAlignmentInt32,
+        int64,
+        int8,
+        structAlignmentInt64,
+      ],
+      double_,
+      """
+Test alignment and padding of 16 byte int within struct."""),
+  FunctionType(
       [structAlignmentInt16],
       int64,
       """
diff --git a/tools/VERSION b/tools/VERSION
index 453aadb2..25b9347 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 27
+PRERELEASE 28
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/pub_integration_test.py b/tools/bots/pub_integration_test.py
index 6d71e1e..6d6ef43 100755
--- a/tools/bots/pub_integration_test.py
+++ b/tools/bots/pub_integration_test.py
@@ -11,6 +11,8 @@
 import tempfile
 
 PUBSPEC = """name: pub_integration_test
+environment:
+  sdk: '>=2.10.0 <=3.0.0'
 dependencies:
   shelf:
   test: