Version 2.12.0-224.0.dev

Merge commit 'd37e833e23641ae65d1cc0aca24ef0852fc79f65' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 3e6b7cb..9257edd 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -296,7 +296,7 @@
       "name": "html",
       "rootUri": "../third_party/pkg/html",
       "packageUri": "lib/",
-      "languageVersion": "2.3"
+      "languageVersion": "2.8"
     },
     {
       "name": "http",
diff --git a/DEPS b/DEPS
index eb1da40..2c9ef02 100644
--- a/DEPS
+++ b/DEPS
@@ -73,7 +73,7 @@
   "bazel_worker_rev": "060c55a933d39798681a4f533b161b81dc48d77e",
   "benchmark_harness_rev": "ec6b646f5443faa871e126ac1ba248c94ca06257",
   "boolean_selector_rev": "665e6921ab246569420376f827bff4585dff0b14",
-  "boringssl_gen_rev": "429ccb1877f7987a6f3988228bc2440e61293499",
+  "boringssl_gen_rev": "aaac86738c4f2d1bdf00f54d197f50f247ffee04",
   "boringssl_rev" : "4dfd5af70191b068aebe567b8e29ce108cee85ce",
   "browser-compat-data_tag": "v1.0.22",
   "charcode_rev": "bcd8a12c315b7a83390e4865ad847ecd9344cba2",
@@ -98,7 +98,7 @@
   #     and land the review.
   #
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
-"dart_style_tag": "1.3.10",  # Please see the note above before updating.
+  "dart_style_tag": "1.3.11",  # Please see the note above before updating.
 
   "chromedriver_tag": "83.0.4103.39",
   "dartdoc_rev" : "a1d86f2c992f4660ddcc09b27733396e92765d2a",
@@ -106,7 +106,7 @@
   "fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
   "file_rev": "0e09370f581ab6388d46fda4cdab66638c0171a1",
   "glob_rev": "7c0ef8d4fa086f6b185c4dd724b700e7d7ad8f79",
-  "html_rev": "22f17e97fedeacaa1e945cf84d8016284eed33a6",
+  "html_rev": "137be8db5d5b7f00530fca1591292849ce6779c9",
   "http_io_rev": "2fa188caf7937e313026557713f7feffedd4978b",
   "http_multi_server_rev" : "e8c8be7f15b4fb50757ff5bf29766721fbe24fe4",
   "http_parser_rev": "5dd4d16693242049dfb43b5efa429fedbf932e98",
diff --git a/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
index 7025194..b4ba0c3 100644
--- a/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
+++ b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
@@ -11,6 +11,7 @@
 import 'package:benchmark_harness/benchmark_harness.dart';
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'digest.dart';
 import 'types.dart';
 
@@ -48,11 +49,11 @@
   EVP_DigestInit(context, hashAlgorithm);
   EVP_DigestUpdate(context, data, length);
   final int resultSize = EVP_MD_CTX_size(context);
-  final Pointer<Bytes> result = allocate<Uint8>(count: resultSize).cast();
+  final Pointer<Bytes> result = calloc<Uint8>(resultSize).cast();
   EVP_DigestFinal(context, result, nullptr);
   EVP_MD_CTX_free(context);
   final String hash = base64Encode(toUint8List(result.ref, resultSize));
-  free(result);
+  calloc.free(result);
   return hash;
 }
 
@@ -83,14 +84,14 @@
 
   @override
   void setup() {
-    data = allocate<Uint8>(count: L).cast();
+    data = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(inventData(L), data.ref);
     hash(data, L, hashAlgorithm);
   }
 
   @override
   void teardown() {
-    free(data);
+    calloc.free(data);
   }
 
   @override
@@ -113,10 +114,10 @@
   @override
   void setup() {
     data = inventData(L);
-    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(data, dataInC.ref);
     hash(dataInC, L, hashAlgorithm);
-    free(dataInC);
+    calloc.free(dataInC);
   }
 
   @override
@@ -124,10 +125,10 @@
 
   @override
   void run() {
-    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(data, dataInC.ref);
     final String result = hash(dataInC, L, hashAlgorithm);
-    free(dataInC);
+    calloc.free(dataInC);
     if (result != expectedHash) {
       throw Exception('$name: Unexpected result: $result');
     }
diff --git a/benchmarks/FfiBoringssl/dart/calloc.dart b/benchmarks/FfiBoringssl/dart/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/benchmarks/FfiBoringssl/dart/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart b/benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
index 7db1f91..6bd064a 100644
--- a/benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
+++ b/benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
@@ -13,6 +13,7 @@
 import 'package:benchmark_harness/benchmark_harness.dart';
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'digest.dart';
 import 'types.dart';
 
@@ -50,11 +51,11 @@
   EVP_DigestInit(context, hashAlgorithm);
   EVP_DigestUpdate(context, data, length);
   final int resultSize = EVP_MD_CTX_size(context);
-  final Pointer<Bytes> result = allocate<Uint8>(count: resultSize).cast();
+  final Pointer<Bytes> result = calloc<Uint8>(resultSize).cast();
   EVP_DigestFinal(context, result, nullptr);
   EVP_MD_CTX_free(context);
   final String hash = base64Encode(toUint8List(result.ref, resultSize));
-  free(result);
+  calloc.free(result);
   return hash;
 }
 
@@ -85,14 +86,14 @@
 
   @override
   void setup() {
-    data = allocate<Uint8>(count: L).cast();
+    data = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(inventData(L), data.ref);
     hash(data, L, hashAlgorithm);
   }
 
   @override
   void teardown() {
-    free(data);
+    calloc.free(data);
   }
 
   @override
@@ -115,10 +116,10 @@
   @override
   void setup() {
     data = inventData(L);
-    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(data, dataInC.ref);
     hash(dataInC, L, hashAlgorithm);
-    free(dataInC);
+    calloc.free(dataInC);
   }
 
   @override
@@ -126,10 +127,10 @@
 
   @override
   void run() {
-    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
     copyFromUint8ListToTarget(data, dataInC.ref);
     final String result = hash(dataInC, L, hashAlgorithm);
-    free(dataInC);
+    calloc.free(dataInC);
     if (result != expectedHash) {
       throw Exception('$name: Unexpected result: $result');
     }
diff --git a/benchmarks/FfiBoringssl/dart2/calloc.dart b/benchmarks/FfiBoringssl/dart2/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/benchmarks/FfiBoringssl/dart2/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiCall/dart/FfiCall.dart b/benchmarks/FfiCall/dart/FfiCall.dart
index c2392a1..d33e120 100644
--- a/benchmarks/FfiCall/dart/FfiCall.dart
+++ b/benchmarks/FfiCall/dart/FfiCall.dart
@@ -13,6 +13,7 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
 import 'dlopen_helper.dart';
 
 //
@@ -1070,9 +1071,9 @@
 
   Pointer<Uint8> pointer = nullptr;
   @override
-  void setup() => pointer = allocate(count: N + 1);
+  void setup() => pointer = calloc(N + 1);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -1091,13 +1092,13 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
   }
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1119,7 +1120,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1127,7 +1128,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1156,7 +1157,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1170,7 +1171,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1219,7 +1220,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1243,7 +1244,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
diff --git a/benchmarks/FfiCall/dart/calloc.dart b/benchmarks/FfiCall/dart/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/benchmarks/FfiCall/dart/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiCall/dart2/FfiCall.dart b/benchmarks/FfiCall/dart2/FfiCall.dart
index fa67dce..3da29b4 100644
--- a/benchmarks/FfiCall/dart2/FfiCall.dart
+++ b/benchmarks/FfiCall/dart2/FfiCall.dart
@@ -15,6 +15,7 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
 import 'dlopen_helper.dart';
 
 //
@@ -1072,9 +1073,9 @@
 
   Pointer<Uint8> pointer;
   @override
-  void setup() => pointer = allocate(count: N + 1);
+  void setup() => pointer = calloc(N + 1);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -1092,13 +1093,13 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
   }
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1117,7 +1118,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1125,7 +1126,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1154,7 +1155,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1168,7 +1169,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
@@ -1217,7 +1218,7 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N + 1);
+    pointer = calloc(N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1241,7 +1242,7 @@
 
   @override
   void teardown() {
-    free(pointer);
+    calloc.free(pointer);
   }
 
   @override
diff --git a/benchmarks/FfiCall/dart2/calloc.dart b/benchmarks/FfiCall/dart2/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/benchmarks/FfiCall/dart2/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiMemory/dart/FfiMemory.dart b/benchmarks/FfiMemory/dart/FfiMemory.dart
index d9ee487..423fa74 100644
--- a/benchmarks/FfiMemory/dart/FfiMemory.dart
+++ b/benchmarks/FfiMemory/dart/FfiMemory.dart
@@ -14,6 +14,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
+
 //
 // Pointer store.
 //
@@ -210,9 +212,9 @@
   PointerInt8() : super('FfiMemory.PointerInt8');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -229,9 +231,9 @@
   PointerUint8() : super('FfiMemory.PointerUint8');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -248,9 +250,9 @@
   PointerInt16() : super('FfiMemory.PointerInt16');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -267,9 +269,9 @@
   PointerUint16() : super('FfiMemory.PointerUint16');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -286,9 +288,9 @@
   PointerInt32() : super('FfiMemory.PointerInt32');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -305,9 +307,9 @@
   PointerUint32() : super('FfiMemory.PointerUint32');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -324,9 +326,9 @@
   PointerInt64() : super('FfiMemory.PointerInt64');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -343,9 +345,9 @@
   PointerUint64() : super('FfiMemory.PointerUint64');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -362,9 +364,9 @@
   PointerFloat() : super('FfiMemory.PointerFloat');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -381,9 +383,9 @@
   PointerDouble() : super('FfiMemory.PointerDouble');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -402,14 +404,14 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N);
-    data = allocate();
+    pointer = calloc(N);
+    data = calloc();
   }
 
   @override
   void teardown() {
-    free(pointer);
-    free(data);
+    calloc.free(pointer);
+    calloc.free(data);
   }
 
   @override
@@ -427,9 +429,9 @@
   PointerInt64Mint() : super('FfiMemory.PointerInt64Mint');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
diff --git a/benchmarks/FfiMemory/dart/calloc.dart b/benchmarks/FfiMemory/dart/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/benchmarks/FfiMemory/dart/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiMemory/dart2/FfiMemory.dart b/benchmarks/FfiMemory/dart2/FfiMemory.dart
index 11fbea2..d8d41e2 100644
--- a/benchmarks/FfiMemory/dart2/FfiMemory.dart
+++ b/benchmarks/FfiMemory/dart2/FfiMemory.dart
@@ -16,6 +16,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
+
 //
 // Pointer store.
 //
@@ -212,9 +214,9 @@
   PointerInt8() : super('FfiMemory.PointerInt8');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -231,9 +233,9 @@
   PointerUint8() : super('FfiMemory.PointerUint8');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -250,9 +252,9 @@
   PointerInt16() : super('FfiMemory.PointerInt16');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -269,9 +271,9 @@
   PointerUint16() : super('FfiMemory.PointerUint16');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -288,9 +290,9 @@
   PointerInt32() : super('FfiMemory.PointerInt32');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -307,9 +309,9 @@
   PointerUint32() : super('FfiMemory.PointerUint32');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -326,9 +328,9 @@
   PointerInt64() : super('FfiMemory.PointerInt64');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -345,9 +347,9 @@
   PointerUint64() : super('FfiMemory.PointerUint64');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -364,9 +366,9 @@
   PointerFloat() : super('FfiMemory.PointerFloat');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -383,9 +385,9 @@
   PointerDouble() : super('FfiMemory.PointerDouble');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
@@ -404,14 +406,14 @@
 
   @override
   void setup() {
-    pointer = allocate(count: N);
-    data = allocate();
+    pointer = calloc(N);
+    data = calloc();
   }
 
   @override
   void teardown() {
-    free(pointer);
-    free(data);
+    calloc.free(pointer);
+    calloc.free(data);
   }
 
   @override
@@ -429,9 +431,9 @@
   PointerInt64Mint() : super('FfiMemory.PointerInt64Mint');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
diff --git a/benchmarks/FfiMemory/dart2/calloc.dart b/benchmarks/FfiMemory/dart2/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/benchmarks/FfiMemory/dart2/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiStruct/dart/FfiStruct.dart b/benchmarks/FfiStruct/dart/FfiStruct.dart
index 26768c5..a4a8f14 100644
--- a/benchmarks/FfiStruct/dart/FfiStruct.dart
+++ b/benchmarks/FfiStruct/dart/FfiStruct.dart
@@ -12,6 +12,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
+
 //
 // Struct field store (plus Pointer elementAt and load).
 //
@@ -50,9 +52,9 @@
   FieldLoadStore() : super('FfiStruct.FieldLoadStore');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
diff --git a/benchmarks/FfiStruct/dart/calloc.dart b/benchmarks/FfiStruct/dart/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/benchmarks/FfiStruct/dart/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/benchmarks/FfiStruct/dart2/FfiStruct.dart b/benchmarks/FfiStruct/dart2/FfiStruct.dart
index a11e8ab..6f4e17c 100644
--- a/benchmarks/FfiStruct/dart2/FfiStruct.dart
+++ b/benchmarks/FfiStruct/dart2/FfiStruct.dart
@@ -14,6 +14,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
+import 'calloc.dart';
+
 //
 // Struct field store (plus Pointer elementAt and load).
 //
@@ -52,9 +54,9 @@
   FieldLoadStore() : super('FfiStruct.FieldLoadStore');
 
   @override
-  void setup() => pointer = allocate(count: N);
+  void setup() => pointer = calloc(N);
   @override
-  void teardown() => free(pointer);
+  void teardown() => calloc.free(pointer);
 
   @override
   void run() {
diff --git a/benchmarks/FfiStruct/dart2/calloc.dart b/benchmarks/FfiStruct/dart2/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/benchmarks/FfiStruct/dart2/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/docs/process/breaking-changes.md b/docs/process/breaking-changes.md
index b277e44..b7023bd 100644
--- a/docs/process/breaking-changes.md
+++ b/docs/process/breaking-changes.md
@@ -35,7 +35,8 @@
 * Must access libraries via the public API (for example, must not reach into
   the internals of a package located in the `/src/` directory).
 
-* Must not rely on an [experiment flag](flags.md).
+* Must not rely on an [experiment flag](experimental-flags.md), or depend on
+  libraries or APIs that are documented as being experimental.
 
 * Must not circumvent clear restrictions documented in the public API
   documentation (for example, must not mixin a class clearly documented as
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/this.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/this.dart
new file mode 100644
index 0000000..4ea657e
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/this.dart
@@ -0,0 +1,24 @@
+// 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 test verifies that `this` cannot be promoted, even if it appears in an
+// extension method.
+
+class C {
+  void insideClass() {
+    if (this is D) {
+      this;
+    }
+  }
+}
+
+class D extends C {}
+
+extension on C {
+  void insideExtension() {
+    if (this is D) {
+      this;
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 4599f0a..95b2236 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -757,6 +757,11 @@
   }
 
   @override
+  void afterContextRefresh() {
+    analysisServer.addContextsToDeclarationsTracker();
+  }
+
+  @override
   void afterWatchEvent(WatchEvent event) {
     analysisServer._onAnalysisSetChangedController.add(null);
   }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 6fdd12d..d552d08 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -305,6 +305,10 @@
   /// Create and return a new analysis driver rooted at the given [folder].
   AnalysisDriver addAnalysisDriver(Folder folder, ContextRoot contextRoot);
 
+  /// Called after contexts are rebuilt, such as after recovering from a watcher
+  /// failure.
+  void afterContextRefresh();
+
   /// An [event] was processed, so analysis state might be different now.
   void afterWatchEvent(WatchEvent event);
 
@@ -563,6 +567,8 @@
 
     // Rebuild contexts based on the data last sent to setRoots().
     setRoots(includedPaths, excludedPaths);
+
+    callbacks.afterContextRefresh();
   }
 
   /// Sets the [ignorePatterns] for the context having info [info].
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index 4a302a2..6ac4547 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -52,9 +52,9 @@
 
     final result = await requireResolvedUnit(path);
     return result.mapResult((result) async {
-      return _getRefactoring(
-              RefactoringKind(kind), result, offset, length, options)
-          .mapResult((refactoring) async {
+      final refactoring = await _getRefactoring(
+          RefactoringKind(kind), result, offset, length, options);
+      return refactoring.mapResult((refactoring) async {
         // If the token we were given is not cancellable, replace it with one that
         // is for the rest of this request, as a future refactor may need to cancel
         // this request.
@@ -99,24 +99,46 @@
     });
   }
 
-  ErrorOr<Refactoring> _getRefactoring(
+  Future<ErrorOr<Refactoring>> _getRefactoring(
     RefactoringKind kind,
     ResolvedUnitResult result,
     int offset,
     int length,
     Map<String, dynamic> options,
-  ) {
+  ) async {
     switch (kind) {
       case RefactoringKind.EXTRACT_METHOD:
         final refactor = ExtractMethodRefactoring(
             server.searchEngine, result, offset, length);
-        // TODO(dantup): For now we don't have a good way to prompt the user
-        // for a method name so we just use a placeholder and expect them to
-        // rename (this is what C#/Omnisharp does), but there's an open request
-        // to handle this better.
-        // https://github.com/microsoft/language-server-protocol/issues/764
-        refactor.name =
-            (options != null ? options['name'] : null) ?? 'newMethod';
+
+        var preferredName = options != null ? options['name'] : null;
+        // checkInitialConditions will populate names with suggestions.
+        if (preferredName == null) {
+          await refactor.checkInitialConditions();
+          if (refactor.names.isNotEmpty) {
+            preferredName = refactor.names.first;
+          }
+        }
+        refactor.name = preferredName ?? 'newMethod';
+
+        // Defaults to true, but may be surprising if users didn't have an option
+        // to opt in.
+        refactor.extractAll = false;
+        return success(refactor);
+
+      case RefactoringKind.EXTRACT_LOCAL_VARIABLE:
+        final refactor = ExtractLocalRefactoring(result, offset, length);
+
+        var preferredName = options != null ? options['name'] : null;
+        // checkInitialConditions will populate names with suggestions.
+        if (preferredName == null) {
+          await refactor.checkInitialConditions();
+          if (refactor.names.isNotEmpty) {
+            preferredName = refactor.names.first;
+          }
+        }
+        refactor.name = preferredName ?? 'newVariable';
+
         // Defaults to true, but may be surprising if users didn't have an option
         // to opt in.
         refactor.extractAll = false;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 355cbde..f2bec91 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -439,6 +439,12 @@
             'Extract Method', RefactoringKind.EXTRACT_METHOD));
       }
 
+      // Extract Local Variable
+      if (ExtractLocalRefactoring(unit, offset, length).isAvailable()) {
+        refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
+            'Extract Local Variable', RefactoringKind.EXTRACT_LOCAL_VARIABLE));
+      }
+
       // Extract Widget
       if (ExtractWidgetRefactoring(server.searchEngine, unit, offset, length)
           .isAvailable()) {
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 7ec69da..106cd91 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -814,6 +814,11 @@
   }
 
   @override
+  void afterContextRefresh() {
+    analysisServer.addContextsToDeclarationsTracker();
+  }
+
+  @override
   void afterWatchEvent(WatchEvent event) {
     // TODO: implement afterWatchEvent
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 01b7721..ecaa1a8 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -153,8 +153,11 @@
 
     var containingNode = request.target.containingNode;
     var entity = request.target.entity;
-    var token =
-        entity is AstNode ? entity.endToken : entity is Token ? entity : null;
+    var token = entity is AstNode
+        ? entity.endToken
+        : entity is Token
+            ? entity
+            : null;
     return (token != containingNode?.endToken) &&
         token?.next?.type == TokenType.COMMA &&
         !token.next.isSynthetic;
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 45318c1b..1bc803f 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -32,6 +32,7 @@
 import 'package:analysis_server/src/services/correction/dart/create_method.dart';
 import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
 import 'package:analysis_server/src/services/correction/dart/inline_invocation.dart';
+import 'package:analysis_server/src/services/correction/dart/inline_typedef.dart';
 import 'package:analysis_server/src/services/correction/dart/make_final.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_argument.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_await.dart';
@@ -107,6 +108,9 @@
     LintNames.avoid_init_to_null: [
       RemoveInitializer.newInstance,
     ],
+    LintNames.avoid_private_typedef_functions: [
+      InlineTypedef.newInstance,
+    ],
     LintNames.avoid_redundant_argument_values: [
       RemoveArgument.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
index b4a176f..c62d89e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
@@ -188,20 +188,19 @@
       } else if (node.parent is PropertyAccess) {
         target = (node.parent as PropertyAccess).target;
       }
-      // find getter
-      if (node.inGetterContext()) {
-        await _proposeClassOrMixinMember(builder, target, (Element element) {
-          return element is PropertyAccessorElement && element.isGetter ||
-              element is FieldElement && element.getter != null;
-        });
-      }
-      // find setter
-      if (node.inSetterContext()) {
-        await _proposeClassOrMixinMember(builder, target, (Element element) {
-          return element is PropertyAccessorElement && element.isSetter ||
-              element is FieldElement && element.setter != null;
-        });
-      }
+      // find getter or setter
+      var wantGetter = node.inGetterContext();
+      var wantSetter = node.inSetterContext();
+      await _proposeClassOrMixinMember(builder, target, (Element element) {
+        if (element is PropertyAccessorElement) {
+          return wantGetter && element.isGetter ||
+              wantSetter && element.isSetter;
+        } else if (element is FieldElement) {
+          return wantGetter && element.getter != null ||
+              wantSetter && element.setter != null;
+        }
+        return false;
+      });
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart
new file mode 100644
index 0000000..765178a
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class ConvertToNullAwareSpread extends CorrectionProducer {
+  @override
+  FixKind get fixKind => DartFixKind.CONVERT_TO_NULL_AWARE_SPREAD;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var parent = coveredNode.parent;
+    if (parent is SpreadElement && !parent.isNullAware) {
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleInsertion(parent.spreadOperator.end, '?');
+      });
+    }
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static ConvertToNullAwareSpread newInstance() => ConvertToNullAwareSpread();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 23e7182..bce5281 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -247,6 +247,8 @@
       'dart.fix.convert.toNamedArguments', 50, 'Convert to named arguments');
   static const CONVERT_TO_NULL_AWARE =
       FixKind('dart.fix.convert.toNullAware', 50, "Convert to use '?.'");
+  static const CONVERT_TO_NULL_AWARE_SPREAD = FixKind(
+      'dart.fix.convert.toNullAwareSpread', 50, "Convert to use '...?'");
   static const CONVERT_TO_ON_TYPE =
       FixKind('dart.fix.convert.toOnType', 50, "Convert to 'on {0}'");
   static const CONVERT_TO_PACKAGE_IMPORT = FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index b84c1e6..97be45b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -49,6 +49,7 @@
 import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_named_arguments.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware_spread.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_on_type.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_package_import.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_relative_import.dart';
@@ -846,6 +847,7 @@
     ],
     CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD: [
       AddNullCheck.newInstance,
+      ConvertToNullAwareSpread.newInstance,
     ],
     CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH: [
       AddNullCheck.newInstance,
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 8b50d8f..61e3ffa 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -2325,6 +2325,9 @@
   }
 
   @override
+  void afterContextRefresh() {}
+
+  @override
   void afterWatchEvent(WatchEvent event) {}
 
   @override
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index 0db9f8d..bd236eb 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -17,6 +17,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(ExtractMethodRefactorCodeActionsTest);
     defineReflectiveTests(ExtractWidgetRefactorCodeActionsTest);
+    defineReflectiveTests(ExtractVariableRefactorCodeActionsTest);
   });
 }
 
@@ -158,6 +159,38 @@
         req1, throwsA(isResponseError(ErrorCodes.ContentModified)));
   }
 
+  Future<void> test_generatesNames() async {
+    const content = '''
+Object main() {
+  return Container([[Text('Test!')]]);
+}
+
+Object Container(Object text) => null;
+Object Text(Object text) => null;
+    ''';
+    const expectedContent = '''
+Object main() {
+  return Container(text());
+}
+
+Object text() => Text('Test!');
+
+Object Container(Object text) => null;
+Object Text(Object text) => null;
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        range: rangeFromMarkers(content));
+    final codeAction =
+        findCommand(codeActions, Commands.performRefactor, extractMethodTitle);
+    expect(codeAction, isNotNull);
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+
   Future<void> test_invalidLocation() async {
     const content = '''
 import 'dart:convert';
@@ -297,6 +330,71 @@
 }
 
 @reflectiveTest
+class ExtractVariableRefactorCodeActionsTest extends AbstractCodeActionsTest {
+  final extractVariableTitle = 'Extract Local Variable';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+main() {
+  foo([[1 + 2]]);
+}
+
+void foo(int arg) {}
+    ''';
+    const expectedContent = '''
+main() {
+  var arg = 1 + 2;
+  foo(arg);
+}
+
+void foo(int arg) {}
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        range: rangeFromMarkers(content));
+    final codeAction = findCommand(
+        codeActions, Commands.performRefactor, extractVariableTitle);
+    expect(codeAction, isNotNull);
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+
+  Future<void> test_doesNotCreateNameConflicts() async {
+    const content = '''
+main() {
+  var arg = "test";
+  foo([[1 + 2]]);
+}
+
+void foo(int arg) {}
+    ''';
+    const expectedContent = '''
+main() {
+  var arg = "test";
+  var arg2 = 1 + 2;
+  foo(arg2);
+}
+
+void foo(int arg) {}
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        range: rangeFromMarkers(content));
+    final codeAction = findCommand(
+        codeActions, Commands.performRefactor, extractVariableTitle);
+    expect(codeAction, isNotNull);
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+}
+
+@reflectiveTest
 class ExtractWidgetRefactorCodeActionsTest extends AbstractCodeActionsTest {
   final extractWidgetTitle = 'Extract Widget';
 
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index 623b668..6d9e3fc 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -67,6 +67,25 @@
     expect(includedIdSet, contains(asyncSet.id));
   }
 
+  Future<void> test_dart_afterRecovery() async {
+    addTestFile('');
+    // Wait for a known set to be available.
+    await waitForSetWithUri('dart:math');
+
+    // Ensure the set is returned in the results.
+    var results = await _getSuggestions(testFile, 0);
+    expect(results.includedSuggestionSets, isNotEmpty);
+
+    // Force the server to rebuild all contexts, as happens when the file watcher
+    // fails on Windows.
+    // https://github.com/dart-lang/sdk/issues/44650
+    server.contextManager.refresh(null);
+
+    // Ensure the set is still returned after the rebuild.
+    results = await _getSuggestions(testFile, 0);
+    expect(results.includedSuggestionSets, isNotEmpty);
+  }
+
   Future<void> test_dart_instanceCreationExpression() async {
     addTestFile(r'''
 main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
index e3a1c37..676a700 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
@@ -37,6 +37,52 @@
   @override
   FixKind get kind => DartFixKind.ADD_LATE;
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/44534')
+  Future<void> test_changeInImportedLib() async {
+    addSource('/home/test/lib/a.dart', '''
+class C {
+  final String s;
+}
+''');
+    await resolveTestCode('''
+import 'a.dart';
+
+void f(C c) {
+  c.s = '';
+}
+''');
+    await assertHasFix('''
+class C {
+  late final String s;
+}
+''', target: '/home/test/lib/a.dart');
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/44534')
+  Future<void> test_changeInPart() async {
+    addSource('/home/test/lib/a.dart', '''
+part 'test.dart';
+
+class C {
+  final String s;
+}
+''');
+    await resolveTestCode('''
+part of 'a.dart';
+
+void f(C c) {
+  c.s = '';
+}
+''');
+    await assertHasFix('''
+part 'test.dart';
+
+class C {
+  late final String s;
+}
+''', target: '/home/test/lib/a.dart');
+  }
+
   Future<void> test_withFinal() async {
     await resolveTestCode('''
 class C {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/inline_typedef_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/inline_typedef_test.dart
new file mode 100644
index 0000000..c2612f9
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/inline_typedef_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InlineTypedefTest);
+  });
+}
+
+@reflectiveTest
+class InlineTypedefTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.avoid_private_typedef_functions;
+
+  Future<void> test_singleFile() async {
+    await resolveTestCode('''
+typedef _F1 = void Function(int);
+typedef _F2<T> = void Function(T);
+void g(_F2<_F1> f) {}
+''');
+    // Eventually both fixes will be applied but for now we're satisfied that
+    // the results are clean.
+    await assertHasFix('''
+typedef _F2<T> = void Function(T);
+void g(_F2<void Function(int)> f) {}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
index 4ed3e33..76e9f01 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
@@ -34,6 +34,7 @@
 import 'create_method_test.dart' as create_method;
 import 'data_driven_test.dart' as data_driven;
 import 'inline_invocation_test.dart' as inline_invocation;
+import 'inline_typedef_test.dart' as inline_typedef;
 import 'make_final_test.dart' as make_final;
 import 'remove_argument_test.dart' as remove_argument;
 import 'remove_await_test.dart' as remove_await;
@@ -97,6 +98,7 @@
     create_method.main();
     data_driven.main();
     inline_invocation.main();
+    inline_typedef.main();
     make_final.main();
     remove_argument.main();
     remove_await.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
index e3e581b..da9231f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -311,6 +312,75 @@
 ''');
   }
 
+  Future<void> test_getterSetter_qualified() async {
+    await resolveTestCode('''
+class A {
+  int get foo => 0;
+  set foo(int _) {}
+}
+
+void f(A a) {
+  a.foo2 += 2;
+}
+''');
+    await assertHasFix('''
+class A {
+  int get foo => 0;
+  set foo(int _) {}
+}
+
+void f(A a) {
+  a.foo += 2;
+}
+''', errorFilter: (e) => e.errorCode == CompileTimeErrorCode.UNDEFINED_GETTER);
+  }
+
+  Future<void> test_getterSetter_qualified_static() async {
+    await resolveTestCode('''
+class A {
+  static int get foo => 0;
+  static set foo(int _) {}
+}
+
+void f() {
+  A.foo2 += 2;
+}
+''');
+    await assertHasFix('''
+class A {
+  static int get foo => 0;
+  static set foo(int _) {}
+}
+
+void f() {
+  A.foo += 2;
+}
+''', errorFilter: (e) => e.errorCode == CompileTimeErrorCode.UNDEFINED_GETTER);
+  }
+
+  Future<void> test_getterSetter_unqualified() async {
+    await resolveTestCode('''
+class A {
+  int get foo => 0;
+  set foo(int _) {}
+
+  void f() {
+    foo2 += 2;
+  }
+}
+''');
+    await assertHasFix('''
+class A {
+  int get foo => 0;
+  set foo(int _) {}
+
+  void f() {
+    foo += 2;
+  }
+}
+''');
+  }
+
   Future<void> test_method_ignoreOperators() async {
     await resolveTestCode('''
 main(Object object) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_spread_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_spread_test.dart
new file mode 100644
index 0000000..8cdcb25
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_spread_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../abstract_context.dart';
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToNullAwareSpreadTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToNullAwareSpreadTest extends FixProcessorTest
+    with WithNullSafetyMixin {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_NULL_AWARE_SPREAD;
+
+  Future<void> test_spreadList() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  [...args];
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  [...?args];
+}
+''');
+  }
+
+  Future<void> test_spreadMap() async {
+    await resolveTestCode('''
+void f (Map<int, String>? args) {
+  print({...args});
+}
+''');
+    await assertHasFix('''
+void f (Map<int, String>? args) {
+  print({...?args});
+}
+''');
+  }
+
+  Future<void> test_spreadSet() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  print({...args});
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  print({...?args});
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index f4b05e6..62832b7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -54,6 +54,7 @@
 import 'convert_to_list_literal_test.dart' as convert_to_list_literal;
 import 'convert_to_map_literal_test.dart' as convert_to_map_literal;
 import 'convert_to_named_arguments_test.dart' as convert_to_named_arguments;
+import 'convert_to_null_aware_spread_test.dart' as convert_to_null_aware_spread;
 import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
 import 'convert_to_on_type_test.dart' as convert_to_on_type;
 import 'convert_to_package_import_test.dart' as convert_to_package_import;
@@ -219,6 +220,7 @@
     convert_to_map_literal.main();
     convert_to_named_arguments.main();
     convert_to_null_aware.main();
+    convert_to_null_aware_spread.main();
     convert_to_on_type.main();
     convert_to_package_import.main();
     convert_to_relative_import.main();
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index c2ae7ca..ee72b09 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -63,13 +63,13 @@
   }
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (value == null) {
       return UNKNOWN_VALUE;
     }
@@ -94,11 +94,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   BoolState lazyOr(InstanceState Function() rightOperandComputer) {
     if (value == true) {
       return TRUE_STATE;
@@ -415,7 +410,7 @@
       return DartObjectImpl(
         typeSystem,
         typeSystem.typeProvider.boolType,
-        _state.equalEqual(rightOperand._state),
+        _state.equalEqual(typeSystem, rightOperand._state),
       );
     }
     throw EvaluationException(
@@ -544,7 +539,7 @@
     return DartObjectImpl(
       typeSystem,
       typeSystem.typeProvider.boolType,
-      _state.isIdentical(rightOperand._state),
+      _state.isIdentical(typeSystem, rightOperand._state),
     );
   }
 
@@ -582,7 +577,7 @@
       return DartObjectImpl(
         typeSystem,
         typeSystem.typeProvider.boolType,
-        _state.lazyEqualEqual(rightOperand._state),
+        _state.lazyEqualEqual(typeSystem, rightOperand._state),
       );
     }
     throw EvaluationException(
@@ -1065,7 +1060,7 @@
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (value == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -1086,11 +1081,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   BoolState lessThan(InstanceState rightOperand) {
     assertNumOrNull(rightOperand);
     if (value == null) {
@@ -1249,12 +1239,12 @@
   }
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (_element == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -1269,11 +1259,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() => _element == null ? "-unknown-" : _element.name;
 }
 
@@ -1340,22 +1325,17 @@
   StringState convertToString() => StringState.UNKNOWN_VALUE;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     return BoolState.from(this == rightOperand);
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() {
     StringBuffer buffer = StringBuffer();
     List<String> fieldNames = _fieldMap.keys.toList();
@@ -1536,7 +1516,7 @@
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  BoolState equalEqual(InstanceState rightOperand);
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand);
 
   /// Return the result of invoking the '&gt;' operator on this object with the
   /// [rightOperand].
@@ -1573,7 +1553,7 @@
 
   /// Return the result of invoking the identical function on this object with
   /// the [rightOperand].
-  BoolState isIdentical(InstanceState rightOperand);
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand);
 
   /// Return the result of invoking the '&&' operator on this object with the
   /// [rightOperand].
@@ -1595,7 +1575,12 @@
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  BoolState lazyEqualEqual(InstanceState rightOperand);
+  BoolState lazyEqualEqual(
+    TypeSystemImpl typeSystem,
+    InstanceState rightOperand,
+  ) {
+    return isIdentical(typeSystem, rightOperand);
+  }
 
   /// Return the result of invoking the '||' operator on this object with the
   /// [rightOperand].
@@ -1988,7 +1973,7 @@
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (value == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -2009,11 +1994,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   BoolState lessThan(InstanceState rightOperand) {
     assertNumOrNull(rightOperand);
     if (value == null) {
@@ -2262,22 +2242,17 @@
   StringState convertToString() => StringState.UNKNOWN_VALUE;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     return BoolState.from(this == rightOperand);
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() {
     StringBuffer buffer = StringBuffer();
     buffer.write('[');
@@ -2342,22 +2317,17 @@
   StringState convertToString() => StringState.UNKNOWN_VALUE;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     return BoolState.from(this == rightOperand);
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() {
     StringBuffer buffer = StringBuffer();
     buffer.write('{');
@@ -2406,22 +2376,17 @@
   StringState convertToString() => StringState("null");
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     return BoolState.from(rightOperand is NullState);
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   BoolState logicalNot() {
     throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
   }
@@ -2436,9 +2401,9 @@
   bool get isBoolNumStringOrNull => true;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 }
 
@@ -2488,22 +2453,17 @@
   StringState convertToString() => StringState.UNKNOWN_VALUE;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     return BoolState.from(this == rightOperand);
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() {
     StringBuffer buffer = StringBuffer();
     buffer.write('{');
@@ -2567,13 +2527,13 @@
   StringState convertToString() => this;
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (value == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -2588,11 +2548,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   IntState stringLength() {
     if (value == null) {
       return IntState.UNKNOWN_VALUE;
@@ -2631,13 +2586,13 @@
   }
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (value == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -2652,11 +2607,6 @@
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() => value == null ? "-unknown-" : "#$value";
 }
 
@@ -2687,13 +2637,13 @@
   }
 
   @override
-  BoolState equalEqual(InstanceState rightOperand) {
+  BoolState equalEqual(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     assertBoolNumStringOrNull(rightOperand);
-    return isIdentical(rightOperand);
+    return isIdentical(typeSystem, rightOperand);
   }
 
   @override
-  BoolState isIdentical(InstanceState rightOperand) {
+  BoolState isIdentical(TypeSystemImpl typeSystem, InstanceState rightOperand) {
     if (_type == null) {
       return BoolState.UNKNOWN_VALUE;
     }
@@ -2702,17 +2652,15 @@
       if (rightType == null) {
         return BoolState.UNKNOWN_VALUE;
       }
-      return BoolState.from(_type == rightType);
+
+      return BoolState.from(
+        typeSystem.runtimeTypesEqual(_type, rightType),
+      );
     }
     return BoolState.FALSE_STATE;
   }
 
   @override
-  BoolState lazyEqualEqual(InstanceState rightOperand) {
-    return isIdentical(rightOperand);
-  }
-
-  @override
   String toString() {
     return _type?.getDisplayString(withNullability: true) ?? '-unknown-';
   }
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index d3d43e6..b46391b 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -285,7 +285,8 @@
         errorNode: node,
       );
 
-      if (superMember is MethodElement &&
+      if (!_isNonNullableByDefault &&
+          superMember is MethodElement &&
           member is MethodElement &&
           methodParameterNodes != null) {
         _checkForOptionalParametersDifferentDefaultValues(
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 160ed2f..aa2140b 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -14,6 +14,12 @@
 /// used. See 'pkg/vm/lib/transformations/ffi_checks.md' for the specification
 /// of the desired hints.
 class FfiVerifier extends RecursiveAstVisitor<void> {
+  static const _allocatorClassName = 'Allocator';
+  static const _allocateExtensionMethodName = 'call';
+  static const _allocatorExtensionName = 'AllocatorAlloc';
+  static const _dartFfiLibraryName = 'dart.ffi';
+  static const _opaqueClassName = 'Opaque';
+
   static const List<String> _primitiveIntegerNativeTypes = [
     'Int8',
     'Int16',
@@ -31,6 +37,8 @@
     'Double',
   ];
 
+  static const _structClassName = 'Struct';
+
   /// The type system used to check types.
   final TypeSystemImpl typeSystem;
 
@@ -47,14 +55,16 @@
   @override
   void visitClassDeclaration(ClassDeclaration node) {
     inStruct = false;
-    // Only the Struct class may be extended.
+    // Only the Allocator, Opaque and Struct class may be extended.
     ExtendsClause extendsClause = node.extendsClause;
     if (extendsClause != null) {
       final TypeName superclass = extendsClause.superclass;
       if (_isDartFfiClass(superclass)) {
-        if (superclass.name.staticElement.name == 'Struct') {
+        final className = superclass.name.staticElement.name;
+        if (className == _structClassName) {
           inStruct = true;
-        } else {
+        } else if (className != _allocatorClassName &&
+            className != _opaqueClassName) {
           _errorReporter.reportErrorForNode(
               FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
               superclass.name,
@@ -71,6 +81,10 @@
     // No classes from the FFI may be explicitly implemented.
     void checkSupertype(TypeName typename, FfiCode subtypeOfFfiCode,
         FfiCode subtypeOfStructCode) {
+      final superName = typename.name.staticElement?.name;
+      if (superName == _allocatorClassName) {
+        return;
+      }
       if (_isDartFfiClass(typename)) {
         _errorReporter.reportErrorForNode(
             subtypeOfFfiCode, typename, [node.name, typename.name]);
@@ -120,6 +134,21 @@
   }
 
   @override
+  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    Element element = node.staticElement;
+    if (element is MethodElement) {
+      Element enclosingElement = element.enclosingElement;
+      if (enclosingElement is ExtensionElement) {
+        if (_isAllocatorExtension(enclosingElement) &&
+            element.name == _allocateExtensionMethodName) {
+          _validateAllocate(node);
+        }
+      }
+    }
+    super.visitFunctionExpressionInvocation(node);
+  }
+
+  @override
   void visitMethodInvocation(MethodInvocation node) {
     Element element = node.methodName.staticElement;
     if (element is MethodElement) {
@@ -145,6 +174,12 @@
     super.visitMethodInvocation(node);
   }
 
+  /// Return `true` if the given [element] represents the extension
+  /// `AllocatorAlloc`.
+  bool _isAllocatorExtension(Element element) =>
+      element.name == _allocatorExtensionName &&
+      element.library.name == _dartFfiLibraryName;
+
   /// Return `true` if the [typeName] is the name of a type from `dart:ffi`.
   bool _isDartFfiClass(TypeName typeName) =>
       _isDartFfiElement(typeName.name.staticElement);
@@ -154,14 +189,15 @@
     if (element is ConstructorElement) {
       element = element.enclosingElement;
     }
-    return element is ClassElement && element.library.name == 'dart.ffi';
+    return element is ClassElement &&
+        element.library.name == _dartFfiLibraryName;
   }
 
   /// Return `true` if the given [element] represents the extension
   /// `DynamicLibraryExtension`.
   bool _isDynamicLibraryExtension(Element element) =>
       element.name == 'DynamicLibraryExtension' &&
-      element.library.name == 'dart.ffi';
+      element.library.name == _dartFfiLibraryName;
 
   bool _isEmptyStruct(ClassElement classElement) {
     final fields = classElement.fields;
@@ -182,13 +218,13 @@
   }
 
   bool _isHandle(Element element) =>
-      element.name == 'Handle' && element.library.name == 'dart.ffi';
+      element.name == 'Handle' && element.library.name == _dartFfiLibraryName;
 
   /// Returns `true` iff [nativeType] is a `ffi.NativeFunction<???>` type.
   bool _isNativeFunctionInterfaceType(DartType nativeType) {
     if (nativeType is InterfaceType) {
       final element = nativeType.element;
-      if (element.library.name == 'dart.ffi') {
+      if (element.library.name == _dartFfiLibraryName) {
         return element.name == 'NativeFunction' &&
             nativeType.typeArguments?.length == 1;
       }
@@ -198,28 +234,43 @@
 
   bool _isNativeFunctionPointerExtension(Element element) =>
       element.name == 'NativeFunctionPointer' &&
-      element.library.name == 'dart.ffi';
+      element.library.name == _dartFfiLibraryName;
 
   /// Returns `true` iff [nativeType] is a `ffi.NativeType` type.
   bool _isNativeTypeInterfaceType(DartType nativeType) {
     if (nativeType is InterfaceType) {
       final element = nativeType.element;
-      if (element.library.name == 'dart.ffi') {
+      if (element.library.name == _dartFfiLibraryName) {
         return element.name == 'NativeType';
       }
     }
     return false;
   }
 
+  /// Returns `true` iff [nativeType] is a opaque type, i.e. a subtype of `Opaque`.
+  bool _isOpaqueClass(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final superType = nativeType.element.supertype;
+      if (superType == null) {
+        return false;
+      }
+      final superClassElement = superType.element;
+      if (superClassElement.library.name == _dartFfiLibraryName) {
+        return superClassElement.name == _opaqueClassName;
+      }
+    }
+    return false;
+  }
+
   /// Return `true` if the given [element] represents the class `Pointer`.
   bool _isPointer(Element element) =>
-      element.name == 'Pointer' && element.library.name == 'dart.ffi';
+      element.name == 'Pointer' && element.library.name == _dartFfiLibraryName;
 
   /// Returns `true` iff [nativeType] is a `ffi.Pointer<???>` type.
   bool _isPointerInterfaceType(DartType nativeType) {
     if (nativeType is InterfaceType) {
       final element = nativeType.element;
-      if (element.library.name == 'dart.ffi') {
+      if (element.library.name == _dartFfiLibraryName) {
         return element.name == 'Pointer' &&
             nativeType.typeArguments?.length == 1;
       }
@@ -235,8 +286,8 @@
         return false;
       }
       final superClassElement = superType.element;
-      if (superClassElement.library.name == 'dart.ffi') {
-        return superClassElement.name == 'Struct' &&
+      if (superClassElement.library.name == _dartFfiLibraryName) {
+        return superClassElement.name == _structClassName &&
             nativeType.typeArguments?.isEmpty == true;
       }
     }
@@ -249,8 +300,8 @@
     if (superType is ClassElement) {
       bool isStruct(InterfaceType type) {
         return type != null &&
-            type.element.name == 'Struct' &&
-            type.element.library.name == 'dart.ffi';
+            type.element.name == _structClassName &&
+            type.element.library.name == _dartFfiLibraryName;
       }
 
       return isStruct(superType.supertype) ||
@@ -311,6 +362,9 @@
         }
         return true;
       }
+      if (_isOpaqueClass(nativeType)) {
+        return true;
+      }
     } else if (nativeType is FunctionType) {
       return _isValidFfiNativeFunctionType(nativeType);
     }
@@ -320,7 +374,7 @@
   _PrimitiveDartType _primitiveNativeType(DartType nativeType) {
     if (nativeType is InterfaceType) {
       final element = nativeType.element;
-      if (element.library.name == 'dart.ffi') {
+      if (element.library.name == _dartFfiLibraryName) {
         final String name = element.name;
         if (_primitiveIntegerNativeTypes.contains(name)) {
           return _PrimitiveDartType.int;
@@ -353,6 +407,17 @@
     return _PrimitiveDartType.none;
   }
 
+  void _validateAllocate(FunctionExpressionInvocation node) {
+    final DartType dartType = node.typeArgumentTypes[0];
+    if (!_isValidFfiNativeType(dartType, true, true)) {
+      final AstNode errorNode = node;
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
+          errorNode,
+          ['$_allocatorExtensionName.$_allocateExtensionMethodName']);
+    }
+  }
+
   /// Validate that the [annotations] include exactly one annotation that
   /// satisfies the [requiredTypes]. If an error is produced that cannot be
   /// associated with an annotation, associate it with the [errorNode].
diff --git a/pkg/analyzer/test/src/dart/constant/value_test.dart b/pkg/analyzer/test/src/dart/constant/value_test.dart
index f9aa5a8..0a47069 100644
--- a/pkg/analyzer/test/src/dart/constant/value_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/value_test.dart
@@ -834,6 +834,34 @@
     _assertIdentical(_boolValue(null), _stringValue(null), _stringValue("def"));
   }
 
+  void test_identical_Type_interfaceType() {
+    _assertIdentical(
+      _boolValue(true),
+      _typeValue(_typeProvider.intType),
+      _typeValue(_typeProvider.intType),
+    );
+
+    _assertIdentical(
+      _boolValue(false),
+      _typeValue(_typeProvider.intType),
+      _typeValue(_typeProvider.numType),
+    );
+
+    _assertIdentical(
+      _boolValue(true),
+      _typeValue(_typeProvider.futureOrType2(_typeProvider.objectType)),
+      _typeValue(_typeProvider.objectType),
+    );
+  }
+
+  void test_identical_Type_notType() {
+    _assertIdentical(
+      _boolValue(false),
+      _typeValue(_typeProvider.intType),
+      _intValue(0),
+    );
+  }
+
   void test_integerDivide_infinity_knownDouble() {
     _assertIntegerDivide(
       null,
@@ -2142,4 +2170,12 @@
       SymbolState(value),
     );
   }
+
+  DartObjectImpl _typeValue(DartType value) {
+    return DartObjectImpl(
+      _typeSystem,
+      _typeProvider.typeType,
+      TypeState(value),
+    );
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_named_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_named_test.dart
index 110480c..2c6d4f1 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_named_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_named_test.dart
@@ -20,7 +20,8 @@
 class InvalidOverrideDifferentDefaultValuesNamedTest
     extends PubPackageResolutionTest {
   test_abstract_different_base_value() async {
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 abstract class A {
   void foo({x = 0}) {}
 }
@@ -28,10 +29,12 @@
 abstract class B extends A {
   void foo({x = 1});
 }
-''', [
-      error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
-          86, 5),
-    ]);
+''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
+            86, 5),
+      ]),
+    );
   }
 
   test_abstract_noDefault_base_noDefault() async {
@@ -132,16 +135,19 @@
   }
 
   test_concrete_different() async {
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 class A {
   void foo({x = 0}) {}
 }
 class B extends A {
   void foo({x = 1}) {}
-}''', [
-      error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
-          67, 5),
-    ]);
+}''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
+            67, 5),
+      ]),
+    );
   }
 
   test_concrete_equal() async {
@@ -282,17 +288,20 @@
     // If the base class provided an explicit value for a default parameter,
     // then it is a static warning for the derived class to provide a different
     // value, even if implicitly.
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 class A {
   void foo({x: 1}) {}
 }
 class B extends A {
   void foo({x}) {}
 }
-''', [
-      error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
-          66, 1),
-    ]);
+''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
+            66, 1),
+      ]),
+    );
   }
 }
 
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
index 50128c9..c25b8e0 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
@@ -20,7 +20,8 @@
 class InvalidOverrideDifferentDefaultValuesPositionalTest
     extends PubPackageResolutionTest {
   test_abstract_different_base_value() async {
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 abstract class A {
   void foo([x = 0]) {}
 }
@@ -28,13 +29,15 @@
 abstract class B extends A {
   void foo([x = 1]);
 }
-''', [
-      error(
-          StaticWarningCode
-              .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
-          86,
-          5),
-    ]);
+''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(
+            StaticWarningCode
+                .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
+            86,
+            5),
+      ]),
+    );
   }
 
   test_abstract_noDefault_base_noDefault() async {
@@ -140,20 +143,23 @@
   }
 
   test_concrete_different() async {
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 class A {
   void foo([x = 0]) {}
 }
 class B extends A {
   void foo([x = 1]) {}
 }
-''', [
-      error(
-          StaticWarningCode
-              .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
-          67,
-          5),
-    ]);
+''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(
+            StaticWarningCode
+                .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
+            67,
+            5),
+      ]),
+    );
   }
 
   test_concrete_equal() async {
@@ -294,20 +300,23 @@
     // If the base class provided an explicit value for a default parameter,
     // then it is a static warning for the derived class to provide a different
     // value, even if implicitly.
-    await assertErrorsInCode(r'''
+    await assertErrorsInCode(
+      r'''
 class A {
   void foo([x = 1]) {}
 }
 class B extends A {
   void foo([x]) {}
 }
-''', [
-      error(
-          StaticWarningCode
-              .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
-          67,
-          1),
-    ]);
+''',
+      expectedErrorsByNullability(nullable: [], legacy: [
+        error(
+            StaticWarningCode
+                .INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
+            67,
+            1),
+      ]),
+    );
   }
 }
 
diff --git a/pkg/dds/test/sse_smoke_test.dart b/pkg/dds/test/sse_smoke_test.dart
index 823f816..9d4a9a6 100644
--- a/pkg/dds/test/sse_smoke_test.dart
+++ b/pkg/dds/test/sse_smoke_test.dart
@@ -106,7 +106,7 @@
 
     createTest(true);
     createTest(false);
-  });
+  }, timeout: Timeout.none);
 }
 
 FutureOr<shelf.Response> _faviconHandler(shelf.Request request) {
diff --git a/pkg/front_end/lib/src/api_prototype/lowering_predicates.dart b/pkg/front_end/lib/src/api_prototype/lowering_predicates.dart
index 28122d7..391be7e 100644
--- a/pkg/front_end/lib/src/api_prototype/lowering_predicates.dart
+++ b/pkg/front_end/lib/src/api_prototype/lowering_predicates.dart
@@ -31,6 +31,34 @@
       !node.name.text.endsWith(lateIsSetSuffix);
 }
 
+/// Returns the name of the original field for a lowered late field where
+/// [node] is the field holding the value of a lowered late field.
+///
+/// For instance
+///
+///    late int field;
+///
+/// is lowered to (simplified):
+///
+///    int? _#field = null;
+///    int get field => _#field != null ? _#field : throw 'Uninitialized';
+///    void set field(int value) {
+///      _#field = value;
+///    }
+///
+/// where '_#field' is the field holding that value and 'field' is the name of
+/// the original field.
+///
+/// This assumes that `isLateLoweredField(node)` is true.
+Name extractFieldNameFromLateLoweredField(Field node) {
+  assert(isLateLoweredField(node));
+  String prefix = lateFieldPrefix;
+  if (node.isInstanceMember) {
+    prefix = '$prefix${node.enclosingClass.name}#';
+  }
+  return new Name(node.name.text.substring(prefix.length), node.name.library);
+}
+
 /// Returns `true` if [node] is the field holding the marker for whether a
 /// lowered late field has been set or not.
 ///
@@ -58,6 +86,40 @@
       node.name.text.endsWith(lateIsSetSuffix);
 }
 
+/// Returns the name of the original field for a lowered late field where [node]
+/// is the field holding the marker for whether the lowered late field has been
+/// set or not.
+///
+/// For instance
+///
+///    late int? field;
+///
+/// is lowered to (simplified):
+///
+///    bool _#field#isSet = false;
+///    int? _#field = null;
+///    int get field => _#field#isSet ? _#field : throw 'Uninitialized';
+///    void set field(int value) {
+///      _#field = value;
+///      _#field#isSet = true;
+///    }
+///
+/// where '_#field#isSet' is the field holding the marker and 'field' is the
+/// name of the original field.
+///
+/// This assumes that `isLateLoweredIsSetField(node)` is true.
+Name extractFieldNameFromLateLoweredIsSetField(Field node) {
+  assert(isLateLoweredIsSetField(node));
+  String prefix = lateFieldPrefix;
+  if (node.isInstanceMember) {
+    prefix = '$prefix${node.enclosingClass.name}#';
+  }
+  return new Name(
+      node.name.text.substring(
+          prefix.length, node.name.text.length - lateIsSetSuffix.length),
+      node.name.library);
+}
+
 /// Returns `true` if [node] is the getter for reading the value of a lowered
 /// late field.
 ///
@@ -93,6 +155,30 @@
   return false;
 }
 
+/// Returns the name of the original field for a lowered late field where [node]
+/// is the getter for reading the value of a lowered late field.
+///
+/// For instance
+///
+///    late int field;
+///
+/// is lowered to (simplified):
+///
+///    int? _#field = null;
+///    int get field => _#field != null ? _#field : throw 'Uninitialized';
+///    void set field(int value) {
+///      _#field = value;
+///    }
+///
+/// where 'int get field' is the getter for reading the field and 'field' is the
+/// name of the original field.
+///
+/// This assumes that `isLateLoweredFieldGetter(node)` is true.
+Name extractFieldNameFromLateLoweredFieldGetter(Procedure node) {
+  assert(isLateLoweredFieldGetter(node));
+  return node.name;
+}
+
 /// Returns `true` if [node] is the setter for setting the value of a lowered
 /// late field.
 ///
@@ -128,6 +214,265 @@
   return false;
 }
 
+/// Returns the name of the original field for a lowered late field where [node]
+/// is the setter for setting the value of a lowered late field.
+///
+/// For instance
+///
+///    late int field;
+///
+/// is lowered to (simplified):
+///
+///    int? _#field = null;
+///    int get field => _#field != null ? _#field : throw 'Uninitialized';
+///    void set field(int value) {
+///      _#field = value;
+///    }
+///
+/// where 'void set field' is the setter for setting the value of the field and
+/// 'field' is the name of the original field.
+///
+/// This assumes that `isLateLoweredFieldSetter(node)` is true.
+Name extractFieldNameFromLateLoweredFieldSetter(Procedure node) {
+  assert(isLateLoweredFieldSetter(node));
+  return node.name;
+}
+
+/// Returns the original initializer of a lowered late field where [node] is
+/// either the field holding the value, the field holding the marker for whether
+/// it has been set or not, getter for reading the value, or the setter for
+/// setting the value of the field.
+///
+/// For instance
+///
+///    late int field = 42;
+///
+/// is lowered to (simplified):
+///
+///    int? _#field = null;
+///    int get field => _#field == null ? throw 'Uninitialized' : _#field = 42;
+///    void set field(int value) {
+///      _#field = value;
+///    }
+///
+/// where this original initializer is `42`, '_#field' is the field holding that
+/// value,  '_#field#isSet' is the field holding the marker, 'int get field' is
+/// the getter for reading the field, and 'void set field' is the setter for
+/// setting the value of the field.
+///
+/// If the original late field had no initializer, `null` is returned.
+///
+/// If [node] is not part of a late field lowering, `null` is returned.
+Expression getLateFieldInitializer(Member node) {
+  Procedure lateFieldGetter = _getLateFieldTarget(node);
+  if (lateFieldGetter != null) {
+    Statement body = lateFieldGetter.function.body;
+    if (body is Block &&
+        body.statements.length == 2 &&
+        body.statements.first is IfStatement) {
+      IfStatement ifStatement = body.statements.first;
+      if (ifStatement.then is Block) {
+        Block block = ifStatement.then;
+        if (block.statements.isNotEmpty &&
+            block.statements.first is ExpressionStatement) {
+          ExpressionStatement firstStatement = block.statements.first;
+          if (firstStatement.expression is PropertySet) {
+            // We have
+            //
+            //    get field {
+            //      if (!_#isSet#field) {
+            //        this._#field = <init>;
+            //        ...
+            //      }
+            //      return _#field;
+            //    }
+            //
+            // in case `<init>` is the initializer.
+            PropertySet propertySet = firstStatement.expression;
+            assert(propertySet.interfaceTarget == getLateFieldTarget(node));
+            return propertySet.value;
+          } else if (firstStatement.expression is StaticSet) {
+            // We have
+            //
+            //    get field {
+            //      if (!_#isSet#field) {
+            //        _#field = <init>;
+            //        ...
+            //      }
+            //      return _#field;
+            //    }
+            //
+            // in case `<init>` is the initializer.
+            StaticSet staticSet = firstStatement.expression;
+            assert(staticSet.target == getLateFieldTarget(node));
+            return staticSet.value;
+          }
+        } else if (block.statements.isNotEmpty &&
+            block.statements.first is VariableDeclaration) {
+          // We have
+          //
+          //    get field {
+          //      if (!_#isSet#field) {
+          //        var temp = <init>;
+          //        if (_#isSet#field) throw '...'
+          //        _#field = temp;
+          //        _#isSet#field = true
+          //      }
+          //      return _#field;
+          //    }
+          //
+          // in case `<init>` is the initializer.
+          VariableDeclaration variableDeclaration = block.statements.first;
+          return variableDeclaration.initializer;
+        }
+      }
+      return null;
+    } else if (body is ReturnStatement) {
+      Expression expression = body.expression;
+      if (expression is ConditionalExpression &&
+          expression.otherwise is Throw) {
+        // We have
+        //
+        //    get field => _#field#isSet ? #field : throw ...;
+        //
+        // in which case there is no initializer.
+        return null;
+      } else if (expression is Let) {
+        Expression letBody = expression.body;
+        if (letBody is ConditionalExpression) {
+          Expression then = letBody.then;
+          if (then is Throw) {
+            // We have
+            //
+            //    get field => let # = _#field in <is-unset> ? throw ... : #;
+            //
+            // in which case there is no initializer.
+            return null;
+          } else if (then is PropertySet) {
+            // We have
+            //
+            //    get field => let # = this._#field in <is-unset>
+            //        ? this._#field = <init> : #;
+            //
+            // in which case `<init>` is the initializer.
+            assert(then.interfaceTarget == getLateFieldTarget(node));
+            return then.value;
+          } else if (then is StaticSet) {
+            // We have
+            //
+            //    get field => let # = this._#field in <is-unset>
+            //        ? this._#field = <init> : #;
+            //
+            // in which case `<init>` is the initializer.
+            assert(then.target == getLateFieldTarget(node));
+            return then.value;
+          } else if (then is Let && then.body is ConditionalExpression) {
+            // We have
+            //
+            //    get field => let #1 = _#field in <is-unset>
+            //        ? let #2 = <init> in ...
+            //        : #1;
+            //
+            // in which case `<init>` is the initializer.
+            return then.variable.initializer;
+          }
+        }
+      }
+    }
+    throw new UnsupportedError(
+        'Unrecognized late getter encoding for $lateFieldGetter: ${body}');
+  }
+
+  return null;
+}
+
+/// Returns getter for reading the value of a lowered late field where [node] is
+/// either the field holding the value, the field holding the marker for whether
+/// it has been set or not, getter for reading the value, or the setter for
+/// setting the value of the field.
+Procedure _getLateFieldTarget(Member node) {
+  Name lateFieldName;
+  if (node is Procedure) {
+    if (isLateLoweredFieldGetter(node)) {
+      return node;
+    } else if (isLateLoweredFieldSetter(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredFieldSetter(node);
+    }
+  } else if (node is Field) {
+    if (isLateLoweredField(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredField(node);
+    } else if (isLateLoweredIsSetField(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredIsSetField(node);
+    }
+  }
+  if (lateFieldName != null) {
+    TreeNode parent = node.parent;
+    List<Procedure> procedures;
+    if (parent is Class) {
+      procedures = parent.procedures;
+    } else if (parent is Library) {
+      procedures = parent.procedures;
+    }
+    return procedures.singleWhere((Procedure procedure) =>
+        isLateLoweredFieldGetter(procedure) &&
+        extractFieldNameFromLateLoweredFieldGetter(procedure) == lateFieldName);
+  }
+  return null;
+}
+
+/// Returns the field holding the value for a lowered late field where [node] is
+/// either the field holding the value, the field holding the marker for whether
+/// it has been set or not, getter for reading the value, or the setter for
+/// setting the value of the field.
+///
+/// For instance
+///
+///    late int field = 42;
+///
+/// is lowered to (simplified):
+///
+///    int? _#field = null;
+///    int get field => _#field == null ? throw 'Uninitialized' : _#field = 42;
+///    void set field(int value) {
+///      _#field = value;
+///    }
+///
+/// where '_#field' is the field holding that value,  '_#field#isSet' is the
+/// field holding the marker, 'int get field' is the getter for reading the
+/// field, and 'void set field' is the setter for setting the value of the
+/// field.
+///
+/// If [node] is not part of a late field lowering, `null` is returned.
+Field getLateFieldTarget(Member node) {
+  Name lateFieldName;
+  if (node is Procedure) {
+    if (isLateLoweredFieldGetter(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredFieldGetter(node);
+    } else if (isLateLoweredFieldSetter(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredFieldSetter(node);
+    }
+  } else if (node is Field) {
+    if (isLateLoweredField(node)) {
+      return node;
+    } else if (isLateLoweredIsSetField(node)) {
+      lateFieldName = extractFieldNameFromLateLoweredIsSetField(node);
+    }
+  }
+  if (lateFieldName != null) {
+    TreeNode parent = node.parent;
+    List<Field> fields;
+    if (parent is Class) {
+      fields = parent.fields;
+    } else if (parent is Library) {
+      fields = parent.fields;
+    }
+    return fields.singleWhere((Field field) =>
+        isLateLoweredField(field) &&
+        extractFieldNameFromLateLoweredField(field) == lateFieldName);
+  }
+  return null;
+}
+
 /// Returns `true` if [node] is the local variable holding the value of a
 /// lowered late variable.
 ///
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index a56f41c..2d5ad31 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -902,6 +902,7 @@
     if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
       _field.initializer = new StaticInvocation(coreTypes.createSentinelMethod,
           new Arguments([], types: [_type])..fileOffset = fileOffset)
+        ..fileOffset = fileOffset
         ..parent = _field;
     } else {
       _field.initializer = new NullLiteral()
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 2173fcb..ebb0cce 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5,6 +5,7 @@
 import 'dart:core' hide MapEntry;
 
 import 'package:_fe_analyzer_shared/src/util/link.dart';
+import 'package:front_end/src/api_prototype/lowering_predicates.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/src/legacy_erasure.dart';
 import 'package:kernel/type_algebra.dart' show Substitution;
@@ -6541,6 +6542,7 @@
         node.initializer = new StaticInvocation(
             inferrer.coreTypes.createSentinelMethod,
             new Arguments([], types: [node.type])..fileOffset = fileOffset)
+          ..fileOffset = fileOffset
           ..parent = node;
       } else {
         node.initializer = null;
@@ -6567,8 +6569,12 @@
         if (nonNullableType != variable.type) {
           promotedType = nonNullableType;
         }
-      } else if (!variable.isLocalFunction) {
+      } else if (variable.isLocalFunction) {
         // Don't promote local functions.
+      } else if (isExtensionThis(variable)) {
+        // Don't promote the synthetic variable `#this` that we use to represent
+        // `this` inside extension methods.
+      } else {
         promotedType = inferrer.flowAnalysis.variableRead(node, variable);
       }
     } else {
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index 52c8586..8d98cff 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -168,8 +168,12 @@
           offset = cls.fileOffset;
         }
       } else {
-        member = lookupLibraryMember(library, id.memberName);
-        offset = member.fileOffset;
+        member = lookupLibraryMember(library, id.memberName, required: false);
+        if (member != null) {
+          offset = member.fileOffset;
+        } else {
+          offset = 0;
+        }
       }
       if (offset == -1) {
         offset = 0;
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 1b71339..74b4740 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -24,6 +24,14 @@
   return member.name.text;
 }
 
+/// Returns a canonical qualified name for [member].
+String getQualifiedMemberName(Member member) {
+  if (member.enclosingClass != null) {
+    return '${member.enclosingClass.name}.${getMemberName(member)}';
+  }
+  return getMemberName(member);
+}
+
 /// Returns the enclosing [Member] for [node].
 Member getEnclosingMember(TreeNode node) {
   while (node is! Member) {
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 7e4bc88..0dd5247 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -295,6 +295,9 @@
   String get updateExpectationsOption => '${UPDATE_EXPECTATIONS}=true';
 
   @override
+  bool get canBeFixWithUpdateExpectations => true;
+
+  @override
   final ExpectationSet expectationSet =
       new ExpectationSet.fromJsonList(jsonDecode(EXPECTATIONS));
 
@@ -1117,7 +1120,8 @@
                     description, p, userLibraries, options, sourceTarget),
                 context.expectationSet["InstrumentationMismatch"],
                 instrumentation.problemsAsString,
-                autoFixCommand: '${UPDATE_COMMENTS}=true');
+                autoFixCommand: '${UPDATE_COMMENTS}=true',
+                canBeFixWithUpdateExpectations: true);
           }
         }
       }
diff --git a/pkg/front_end/test/fasta/textual_outline_suite.dart b/pkg/front_end/test/fasta/textual_outline_suite.dart
index f0dbb30..8e38277 100644
--- a/pkg/front_end/test/fasta/textual_outline_suite.dart
+++ b/pkg/front_end/test/fasta/textual_outline_suite.dart
@@ -59,6 +59,9 @@
   @override
   String get updateExpectationsOption => '${UPDATE_EXPECTATIONS}=true';
 
+  @override
+  bool get canBeFixWithUpdateExpectations => true;
+
   Context(this.updateExpectations);
 
   final List<Step> steps = const <Step>[
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index dba9923..70a5360 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -1120,7 +1120,8 @@
           "${extra}Unexpected serialized representation. "
           "Fix or update $uri to contain the below:\n\n"
           "$actualSerialized",
-          autoFixCommand: "updateExpectations=true");
+          autoFixCommand: "updateExpectations=true",
+          canBeFixWithUpdateExpectations: true);
     }
   }
   return null;
diff --git a/pkg/front_end/test/parser_suite.dart b/pkg/front_end/test/parser_suite.dart
index 70bbcad..3bc79a2 100644
--- a/pkg/front_end/test/parser_suite.dart
+++ b/pkg/front_end/test/parser_suite.dart
@@ -101,6 +101,9 @@
   @override
   String get updateExpectationsOption => '${UPDATE_EXPECTATIONS}=true';
 
+  @override
+  bool get canBeFixWithUpdateExpectations => true;
+
   final bool addTrace;
   final bool annotateLines;
   final String suiteName;
diff --git a/pkg/front_end/test/predicates/data/late.dart b/pkg/front_end/test/predicates/data/late.dart
index 55cfbb6..ebf4162 100644
--- a/pkg/front_end/test/predicates/data/late.dart
+++ b/pkg/front_end/test/predicates/data/late.dart
@@ -2,184 +2,842 @@
 // 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.
 
-/*member: _#topLevelNonNullableWithoutInitializer:lateField*/
-/*member: topLevelNonNullableWithoutInitializer:lateFieldGetter*/
-/*member: topLevelNonNullableWithoutInitializer=:lateFieldSetter*/
-/*member: _#topLevelNonNullableWithoutInitializer#isSet:lateIsSetField*/
+/*member: _#topLevelNonNullableWithoutInitializer:
+ lateField,
+ lateFieldName=topLevelNonNullableWithoutInitializer,
+ lateFieldTarget=_#topLevelNonNullableWithoutInitializer
+*/
+/*member: topLevelNonNullableWithoutInitializer:
+ lateFieldGetter,
+ lateFieldName=topLevelNonNullableWithoutInitializer,
+ lateFieldTarget=_#topLevelNonNullableWithoutInitializer
+*/
+/*member: topLevelNonNullableWithoutInitializer=:
+ lateFieldName=topLevelNonNullableWithoutInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#topLevelNonNullableWithoutInitializer
+*/
 late int topLevelNonNullableWithoutInitializer;
-/*member: _#finalTopLevelNonNullableWithoutInitializer:lateField*/
-/*member: finalTopLevelNonNullableWithoutInitializer:lateFieldGetter*/
-/*member: finalTopLevelNonNullableWithoutInitializer=:lateFieldSetter*/
-/*member: _#finalTopLevelNonNullableWithoutInitializer#isSet:lateIsSetField*/
+/*member: _#finalTopLevelNonNullableWithoutInitializer:
+ lateField,
+ lateFieldName=finalTopLevelNonNullableWithoutInitializer,
+ lateFieldTarget=_#finalTopLevelNonNullableWithoutInitializer
+*/
+/*member: finalTopLevelNonNullableWithoutInitializer:
+ lateFieldGetter,
+ lateFieldName=finalTopLevelNonNullableWithoutInitializer,
+ lateFieldTarget=_#finalTopLevelNonNullableWithoutInitializer
+*/
+/*member: finalTopLevelNonNullableWithoutInitializer=:
+ lateFieldName=finalTopLevelNonNullableWithoutInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#finalTopLevelNonNullableWithoutInitializer
+*/
 late final int finalTopLevelNonNullableWithoutInitializer;
-/*member: _#topLevelNullableWithoutInitializer:lateField*/
-/*member: _#topLevelNullableWithoutInitializer#isSet:lateIsSetField*/
-/*member: topLevelNullableWithoutInitializer:lateFieldGetter*/
-/*member: topLevelNullableWithoutInitializer=:lateFieldSetter*/
+/*member: _#topLevelNullableWithoutInitializer:
+ lateField,
+ lateFieldName=topLevelNullableWithoutInitializer,
+ lateFieldTarget=_#topLevelNullableWithoutInitializer
+*/
+/*is-null.member: _#topLevelNullableWithoutInitializer#isSet:
+ lateFieldName=topLevelNullableWithoutInitializer,
+ lateFieldTarget=_#topLevelNullableWithoutInitializer,
+ lateIsSetField
+*/
+/*member: topLevelNullableWithoutInitializer:
+ lateFieldGetter,
+ lateFieldName=topLevelNullableWithoutInitializer,
+ lateFieldTarget=_#topLevelNullableWithoutInitializer
+*/
+/*member: topLevelNullableWithoutInitializer=:
+ lateFieldName=topLevelNullableWithoutInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#topLevelNullableWithoutInitializer
+*/
 late int? topLevelNullableWithoutInitializer;
-/*member: _#finalTopLevelNullableWithoutInitializer:lateField*/
-/*member: _#finalTopLevelNullableWithoutInitializer#isSet:lateIsSetField*/
-/*member: finalTopLevelNullableWithoutInitializer:lateFieldGetter*/
-/*member: finalTopLevelNullableWithoutInitializer=:lateFieldSetter*/
+/*member: _#finalTopLevelNullableWithoutInitializer:
+ lateField,
+ lateFieldName=finalTopLevelNullableWithoutInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithoutInitializer
+*/
+/*is-null.member: _#finalTopLevelNullableWithoutInitializer#isSet:
+ lateFieldName=finalTopLevelNullableWithoutInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithoutInitializer,
+ lateIsSetField
+*/
+/*member: finalTopLevelNullableWithoutInitializer:
+ lateFieldGetter,
+ lateFieldName=finalTopLevelNullableWithoutInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithoutInitializer
+*/
+/*member: finalTopLevelNullableWithoutInitializer=:
+ lateFieldName=finalTopLevelNullableWithoutInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#finalTopLevelNullableWithoutInitializer
+*/
 late final int? finalTopLevelNullableWithoutInitializer;
-/*member: _#topLevelNonNullableWithInitializer:lateField*/
-/*member: topLevelNonNullableWithInitializer:lateFieldGetter*/
-/*member: topLevelNonNullableWithInitializer=:lateFieldSetter*/
-/*member: _#topLevelNonNullableWithInitializer#isSet:lateIsSetField*/
-late int topLevelNonNullableWithInitializer = 0;
-/*member: _#finalTopLevelNonNullableWithInitializer:lateField*/
-/*member: finalTopLevelNonNullableWithInitializer:lateFieldGetter*/
-/*member: _#finalTopLevelNonNullableWithInitializer#isSet:lateIsSetField*/
-late final int finalTopLevelNonNullableWithInitializer = 0;
-/*member: _#topLevelNullableWithInitializer:lateField*/
-/*member: _#topLevelNullableWithInitializer#isSet:lateIsSetField*/
-/*member: topLevelNullableWithInitializer:lateFieldGetter*/
-/*member: topLevelNullableWithInitializer=:lateFieldSetter*/
-late int? topLevelNullableWithInitializer = 0;
-/*member: _#finalTopLevelNullableWithInitializer:lateField*/
-/*member: _#finalTopLevelNullableWithInitializer#isSet:lateIsSetField*/
-/*member: finalTopLevelNullableWithInitializer:lateFieldGetter*/
-late final int? finalTopLevelNullableWithInitializer = 0;
+/*member: _#topLevelNonNullableWithInitializer:
+ lateField,
+ lateFieldInitializer=1,
+ lateFieldName=topLevelNonNullableWithInitializer,
+ lateFieldTarget=_#topLevelNonNullableWithInitializer
+*/
+/*member: topLevelNonNullableWithInitializer:
+ lateFieldGetter,
+ lateFieldInitializer=1,
+ lateFieldName=topLevelNonNullableWithInitializer,
+ lateFieldTarget=_#topLevelNonNullableWithInitializer
+*/
+/*member: topLevelNonNullableWithInitializer=:
+ lateFieldInitializer=1,
+ lateFieldName=topLevelNonNullableWithInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#topLevelNonNullableWithInitializer
+*/
+late int topLevelNonNullableWithInitializer = 1;
+/*member: _#finalTopLevelNonNullableWithInitializer:
+ lateField,
+ lateFieldInitializer=2,
+ lateFieldName=finalTopLevelNonNullableWithInitializer,
+ lateFieldTarget=_#finalTopLevelNonNullableWithInitializer
+*/
+/*member: finalTopLevelNonNullableWithInitializer:
+ lateFieldGetter,
+ lateFieldInitializer=2,
+ lateFieldName=finalTopLevelNonNullableWithInitializer,
+ lateFieldTarget=_#finalTopLevelNonNullableWithInitializer
+*/
+late final int finalTopLevelNonNullableWithInitializer = 2;
+/*member: _#topLevelNullableWithInitializer:
+ lateField,
+ lateFieldInitializer=3,
+ lateFieldName=topLevelNullableWithInitializer,
+ lateFieldTarget=_#topLevelNullableWithInitializer
+*/
+/*is-null.member: _#topLevelNullableWithInitializer#isSet:
+ lateFieldInitializer=3,
+ lateFieldName=topLevelNullableWithInitializer,
+ lateFieldTarget=_#topLevelNullableWithInitializer,
+ lateIsSetField
+*/
+/*member: topLevelNullableWithInitializer:
+ lateFieldGetter,
+ lateFieldInitializer=3,
+ lateFieldName=topLevelNullableWithInitializer,
+ lateFieldTarget=_#topLevelNullableWithInitializer
+*/
+/*member: topLevelNullableWithInitializer=:
+ lateFieldInitializer=3,
+ lateFieldName=topLevelNullableWithInitializer,
+ lateFieldSetter,
+ lateFieldTarget=_#topLevelNullableWithInitializer
+*/
+late int? topLevelNullableWithInitializer = 3;
+/*member: _#finalTopLevelNullableWithInitializer:
+ lateField,
+ lateFieldInitializer=4,
+ lateFieldName=finalTopLevelNullableWithInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithInitializer
+*/
+/*is-null.member: _#finalTopLevelNullableWithInitializer#isSet:
+ lateFieldInitializer=4,
+ lateFieldName=finalTopLevelNullableWithInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithInitializer,
+ lateIsSetField
+*/
+/*member: finalTopLevelNullableWithInitializer:
+ lateFieldGetter,
+ lateFieldInitializer=4,
+ lateFieldName=finalTopLevelNullableWithInitializer,
+ lateFieldTarget=_#finalTopLevelNullableWithInitializer
+*/
+late final int? finalTopLevelNullableWithInitializer = 4;
 
 class Class {
-  /*member: Class._#Class#instanceNonNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class._#Class#instanceNonNullableWithoutInitializer:lateField*/
-  /*member: Class.instanceNonNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.instanceNonNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#Class#instanceNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=instanceNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithoutInitializer
+  */
+  /*member: Class.instanceNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=instanceNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithoutInitializer
+  */
+  /*member: Class.instanceNonNullableWithoutInitializer=:
+   lateFieldName=instanceNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithoutInitializer
+  */
   late int instanceNonNullableWithoutInitializer;
-  /*member: Class._#Class#finalInstanceNonNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class._#Class#finalInstanceNonNullableWithoutInitializer:lateField*/
-  /*member: Class.finalInstanceNonNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.finalInstanceNonNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#Class#finalInstanceNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=finalInstanceNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNonNullableWithoutInitializer
+  */
+  /*member: Class.finalInstanceNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=finalInstanceNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNonNullableWithoutInitializer
+  */
+  /*member: Class.finalInstanceNonNullableWithoutInitializer=:
+   lateFieldName=finalInstanceNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#finalInstanceNonNullableWithoutInitializer
+  */
   late final int finalInstanceNonNullableWithoutInitializer;
-  /*member: Class._#Class#instanceNullableWithoutInitializer:lateField*/
-  /*member: Class._#Class#instanceNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class.instanceNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.instanceNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#Class#instanceNullableWithoutInitializer:
+   lateField,
+   lateFieldName=instanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithoutInitializer
+  */
+  /*is-null.member: Class._#Class#instanceNullableWithoutInitializer#isSet:
+   lateFieldName=instanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Class.instanceNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=instanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithoutInitializer
+  */
+  /*member: Class.instanceNullableWithoutInitializer=:
+   lateFieldName=instanceNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#instanceNullableWithoutInitializer
+  */
   late int? instanceNullableWithoutInitializer;
-  /*member: Class._#Class#finalInstanceNullableWithoutInitializer:lateField*/
-  /*member: Class._#Class#finalInstanceNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class.finalInstanceNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.finalInstanceNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#Class#finalInstanceNullableWithoutInitializer:
+   lateField,
+   lateFieldName=finalInstanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithoutInitializer
+  */
+  /*is-null.member: Class._#Class#finalInstanceNullableWithoutInitializer#isSet:
+   lateFieldName=finalInstanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Class.finalInstanceNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=finalInstanceNullableWithoutInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithoutInitializer
+  */
+  /*member: Class.finalInstanceNullableWithoutInitializer=:
+   lateFieldName=finalInstanceNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithoutInitializer
+  */
   late final int? finalInstanceNullableWithoutInitializer;
-  /*member: Class._#Class#instanceNonNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class._#Class#instanceNonNullableWithInitializer:lateField*/
-  /*member: Class.instanceNonNullableWithInitializer:lateFieldGetter*/
-  /*member: Class.instanceNonNullableWithInitializer=:lateFieldSetter*/
-  late int instanceNonNullableWithInitializer = 0;
-  /*member: Class._#Class#finalInstanceNonNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class._#Class#finalInstanceNonNullableWithInitializer:lateField*/
-  /*member: Class.finalInstanceNonNullableWithInitializer:lateFieldGetter*/
-  late final int finalInstanceNonNullableWithInitializer = 0;
-  /*member: Class._#Class#instanceNullableWithInitializer:lateField*/
-  /*member: Class._#Class#instanceNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class.instanceNullableWithInitializer:lateFieldGetter*/
-  /*member: Class.instanceNullableWithInitializer=:lateFieldSetter*/
-  late int? instanceNullableWithInitializer = 0;
-  /*member: Class._#Class#finalInstanceNullableWithInitializer:lateField*/
-  /*member: Class._#Class#finalInstanceNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class.finalInstanceNullableWithInitializer:lateFieldGetter*/
-  late final int? finalInstanceNullableWithInitializer = 0;
+  /*member: Class._#Class#instanceNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=5,
+   lateFieldName=instanceNonNullableWithInitializer,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithInitializer
+  */
+  /*member: Class.instanceNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=5,
+   lateFieldName=instanceNonNullableWithInitializer,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithInitializer
+  */
+  /*member: Class.instanceNonNullableWithInitializer=:
+   lateFieldInitializer=5,
+   lateFieldName=instanceNonNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#instanceNonNullableWithInitializer
+  */
+  late int instanceNonNullableWithInitializer = 5;
+  /*member: Class._#Class#finalInstanceNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=6,
+   lateFieldName=finalInstanceNonNullableWithInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNonNullableWithInitializer
+  */
+  /*member: Class.finalInstanceNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=6,
+   lateFieldName=finalInstanceNonNullableWithInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNonNullableWithInitializer
+  */
+  late final int finalInstanceNonNullableWithInitializer = 6;
+  /*member: Class._#Class#instanceNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=7,
+   lateFieldName=instanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithInitializer
+  */
+  /*is-null.member: Class._#Class#instanceNullableWithInitializer#isSet:
+   lateFieldInitializer=7,
+   lateFieldName=instanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Class.instanceNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=7,
+   lateFieldName=instanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#instanceNullableWithInitializer
+  */
+  /*member: Class.instanceNullableWithInitializer=:
+   lateFieldInitializer=7,
+   lateFieldName=instanceNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#instanceNullableWithInitializer
+  */
+  late int? instanceNullableWithInitializer = 7;
+  /*member: Class._#Class#finalInstanceNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=8,
+   lateFieldName=finalInstanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithInitializer
+  */
+  /*is-null.member: Class._#Class#finalInstanceNullableWithInitializer#isSet:
+   lateFieldInitializer=8,
+   lateFieldName=finalInstanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Class.finalInstanceNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=8,
+   lateFieldName=finalInstanceNullableWithInitializer,
+   lateFieldTarget=Class._#Class#finalInstanceNullableWithInitializer
+  */
+  late final int? finalInstanceNullableWithInitializer = 8;
 
-  /*member: Class._#staticNonNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class._#staticNonNullableWithoutInitializer:lateField*/
-  /*member: Class.staticNonNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.staticNonNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#staticNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=staticNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#staticNonNullableWithoutInitializer
+  */
+  /*member: Class.staticNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=staticNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#staticNonNullableWithoutInitializer
+  */
+  /*member: Class.staticNonNullableWithoutInitializer=:
+   lateFieldName=staticNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#staticNonNullableWithoutInitializer
+  */
   static late int staticNonNullableWithoutInitializer;
-  /*member: Class._#finalStaticNonNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class._#finalStaticNonNullableWithoutInitializer:lateField*/
-  /*member: Class.finalStaticNonNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.finalStaticNonNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#finalStaticNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=finalStaticNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#finalStaticNonNullableWithoutInitializer
+  */
+  /*member: Class.finalStaticNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=finalStaticNonNullableWithoutInitializer,
+   lateFieldTarget=Class._#finalStaticNonNullableWithoutInitializer
+  */
+  /*member: Class.finalStaticNonNullableWithoutInitializer=:
+   lateFieldName=finalStaticNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#finalStaticNonNullableWithoutInitializer
+  */
   static late final int finalStaticNonNullableWithoutInitializer;
-  /*member: Class._#staticNullableWithoutInitializer:lateField*/
-  /*member: Class._#staticNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class.staticNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.staticNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#staticNullableWithoutInitializer:
+   lateField,
+   lateFieldName=staticNullableWithoutInitializer,
+   lateFieldTarget=Class._#staticNullableWithoutInitializer
+  */
+  /*is-null.member: Class._#staticNullableWithoutInitializer#isSet:
+   lateFieldName=staticNullableWithoutInitializer,
+   lateFieldTarget=Class._#staticNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Class.staticNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=staticNullableWithoutInitializer,
+   lateFieldTarget=Class._#staticNullableWithoutInitializer
+  */
+  /*member: Class.staticNullableWithoutInitializer=:
+   lateFieldName=staticNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#staticNullableWithoutInitializer
+  */
   static late int? staticNullableWithoutInitializer;
-  /*member: Class._#finalStaticNullableWithoutInitializer:lateField*/
-  /*member: Class._#finalStaticNullableWithoutInitializer#isSet:lateIsSetField*/
-  /*member: Class.finalStaticNullableWithoutInitializer:lateFieldGetter*/
-  /*member: Class.finalStaticNullableWithoutInitializer=:lateFieldSetter*/
+  /*member: Class._#finalStaticNullableWithoutInitializer:
+   lateField,
+   lateFieldName=finalStaticNullableWithoutInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithoutInitializer
+  */
+  /*is-null.member: Class._#finalStaticNullableWithoutInitializer#isSet:
+   lateFieldName=finalStaticNullableWithoutInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Class.finalStaticNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=finalStaticNullableWithoutInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithoutInitializer
+  */
+  /*member: Class.finalStaticNullableWithoutInitializer=:
+   lateFieldName=finalStaticNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#finalStaticNullableWithoutInitializer
+  */
   static late final int? finalStaticNullableWithoutInitializer;
-  /*member: Class._#staticNonNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class._#staticNonNullableWithInitializer:lateField*/
-  /*member: Class.staticNonNullableWithInitializer:lateFieldGetter*/
-  /*member: Class.staticNonNullableWithInitializer=:lateFieldSetter*/
-  static late int staticNonNullableWithInitializer = 0;
-  /*member: Class._#finalStaticNonNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class._#finalStaticNonNullableWithInitializer:lateField*/
-  /*member: Class.finalStaticNonNullableWithInitializer:lateFieldGetter*/
-  static late final int finalStaticNonNullableWithInitializer = 0;
-  /*member: Class._#staticNullableWithInitializer:lateField*/
-  /*member: Class._#staticNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class.staticNullableWithInitializer:lateFieldGetter*/
-  /*member: Class.staticNullableWithInitializer=:lateFieldSetter*/
-  static late int? staticNullableWithInitializer = 0;
-  /*member: Class._#finalStaticNullableWithInitializer:lateField*/
-  /*member: Class._#finalStaticNullableWithInitializer#isSet:lateIsSetField*/
-  /*member: Class.finalStaticNullableWithInitializer:lateFieldGetter*/
-  static late final int? finalStaticNullableWithInitializer = 0;
+  /*member: Class._#staticNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=9,
+   lateFieldName=staticNonNullableWithInitializer,
+   lateFieldTarget=Class._#staticNonNullableWithInitializer
+  */
+  /*member: Class.staticNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=9,
+   lateFieldName=staticNonNullableWithInitializer,
+   lateFieldTarget=Class._#staticNonNullableWithInitializer
+  */
+  /*member: Class.staticNonNullableWithInitializer=:
+   lateFieldInitializer=9,
+   lateFieldName=staticNonNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#staticNonNullableWithInitializer
+  */
+  static late int staticNonNullableWithInitializer = 9;
+  /*member: Class._#finalStaticNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=10,
+   lateFieldName=finalStaticNonNullableWithInitializer,
+   lateFieldTarget=Class._#finalStaticNonNullableWithInitializer
+  */
+  /*member: Class.finalStaticNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=10,
+   lateFieldName=finalStaticNonNullableWithInitializer,
+   lateFieldTarget=Class._#finalStaticNonNullableWithInitializer
+  */
+  static late final int finalStaticNonNullableWithInitializer = 10;
+  /*member: Class._#staticNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=11,
+   lateFieldName=staticNullableWithInitializer,
+   lateFieldTarget=Class._#staticNullableWithInitializer
+  */
+  /*is-null.member: Class._#staticNullableWithInitializer#isSet:
+   lateFieldInitializer=11,
+   lateFieldName=staticNullableWithInitializer,
+   lateFieldTarget=Class._#staticNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Class.staticNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=11,
+   lateFieldName=staticNullableWithInitializer,
+   lateFieldTarget=Class._#staticNullableWithInitializer
+  */
+  /*member: Class.staticNullableWithInitializer=:
+   lateFieldInitializer=11,
+   lateFieldName=staticNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=Class._#staticNullableWithInitializer
+  */
+  static late int? staticNullableWithInitializer = 11;
+  /*member: Class._#finalStaticNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=12,
+   lateFieldName=finalStaticNullableWithInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithInitializer
+  */
+  /*is-null.member: Class._#finalStaticNullableWithInitializer#isSet:
+   lateFieldInitializer=12,
+   lateFieldName=finalStaticNullableWithInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Class.finalStaticNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=12,
+   lateFieldName=finalStaticNullableWithInitializer,
+   lateFieldTarget=Class._#finalStaticNullableWithInitializer
+  */
+  static late final int? finalStaticNullableWithInitializer = 12;
+}
+
+extension on int? {
+  /*member: _#_extension#0|unnamedExtensionNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNonNullableWithoutInitializer=:
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithoutInitializer
+  */
+  static late int unnamedExtensionNonNullableWithoutInitializer;
+  /*member: _#_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: _extension#0|finalUnnamedExtensionNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: _extension#0|finalUnnamedExtensionNonNullableWithoutInitializer=:
+   lateFieldName=_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNonNullableWithoutInitializer
+  */
+  static late final int finalUnnamedExtensionNonNullableWithoutInitializer;
+  /*member: _#_extension#0|unnamedExtensionNullableWithoutInitializer:
+   lateField,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithoutInitializer
+  */
+  /*is-null.member: _#_extension#0|unnamedExtensionNullableWithoutInitializer#isSet:
+   lateFieldName=_extension#0|unnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: _extension#0|unnamedExtensionNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithoutInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNullableWithoutInitializer=:
+   lateFieldName=_extension#0|unnamedExtensionNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithoutInitializer
+  */
+  static late int? unnamedExtensionNullableWithoutInitializer;
+  /*member: _#_extension#0|finalUnnamedExtensionNullableWithoutInitializer:
+   lateField,
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithoutInitializer
+  */
+  /*is-null.member: _#_extension#0|finalUnnamedExtensionNullableWithoutInitializer#isSet:
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: _extension#0|finalUnnamedExtensionNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithoutInitializer
+  */
+  /*member: _extension#0|finalUnnamedExtensionNullableWithoutInitializer=:
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithoutInitializer
+  */
+  static late final int? finalUnnamedExtensionNullableWithoutInitializer;
+  /*member: _#_extension#0|unnamedExtensionNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=13,
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=13,
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNonNullableWithInitializer=:
+   lateFieldInitializer=13,
+   lateFieldName=_extension#0|unnamedExtensionNonNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNonNullableWithInitializer
+  */
+  static late int unnamedExtensionNonNullableWithInitializer = 13;
+  /*member: _#_extension#0|finalUnnamedExtensionNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=14,
+   lateFieldName=_extension#0|finalUnnamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNonNullableWithInitializer
+  */
+  /*member: _extension#0|finalUnnamedExtensionNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=14,
+   lateFieldName=_extension#0|finalUnnamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNonNullableWithInitializer
+  */
+  static late final int finalUnnamedExtensionNonNullableWithInitializer = 14;
+  /*member: _#_extension#0|unnamedExtensionNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=15,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithInitializer
+  */
+  /*is-null.member: _#_extension#0|unnamedExtensionNullableWithInitializer#isSet:
+   lateFieldInitializer=15,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: _extension#0|unnamedExtensionNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=15,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithInitializer
+  */
+  /*member: _extension#0|unnamedExtensionNullableWithInitializer=:
+   lateFieldInitializer=15,
+   lateFieldName=_extension#0|unnamedExtensionNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|unnamedExtensionNullableWithInitializer
+  */
+  static late int? unnamedExtensionNullableWithInitializer = 15;
+  /*member: _#_extension#0|finalUnnamedExtensionNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=16,
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithInitializer
+  */
+  /*is-null.member: _#_extension#0|finalUnnamedExtensionNullableWithInitializer#isSet:
+   lateFieldInitializer=16,
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: _extension#0|finalUnnamedExtensionNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=16,
+   lateFieldName=_extension#0|finalUnnamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#_extension#0|finalUnnamedExtensionNullableWithInitializer
+  */
+  static late final int? finalUnnamedExtensionNullableWithInitializer = 16;
+}
+
+extension Extension on int? {
+  /*member: _#Extension|namedExtensionNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=Extension|namedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithoutInitializer
+  */
+  /*member: Extension|namedExtensionNonNullableWithoutInitializer=:
+   lateFieldName=Extension|namedExtensionNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithoutInitializer
+  */
+  /*member: Extension|namedExtensionNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=Extension|namedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithoutInitializer
+  */
+  static late int namedExtensionNonNullableWithoutInitializer;
+  /*member: _#Extension|finalNamedExtensionNonNullableWithoutInitializer:
+   lateField,
+   lateFieldName=Extension|finalNamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: Extension|finalNamedExtensionNonNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=Extension|finalNamedExtensionNonNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNonNullableWithoutInitializer
+  */
+  /*member: Extension|finalNamedExtensionNonNullableWithoutInitializer=:
+   lateFieldName=Extension|finalNamedExtensionNonNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|finalNamedExtensionNonNullableWithoutInitializer
+  */
+  static late final int finalNamedExtensionNonNullableWithoutInitializer;
+  /*member: _#Extension|namedExtensionNullableWithoutInitializer:
+   lateField,
+   lateFieldName=Extension|namedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithoutInitializer
+  */
+  /*is-null.member: _#Extension|namedExtensionNullableWithoutInitializer#isSet:
+   lateFieldName=Extension|namedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Extension|namedExtensionNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=Extension|namedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithoutInitializer
+  */
+  /*member: Extension|namedExtensionNullableWithoutInitializer=:
+   lateFieldName=Extension|namedExtensionNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithoutInitializer
+  */
+  static late int? namedExtensionNullableWithoutInitializer;
+  /*member: _#Extension|finalNamedExtensionNullableWithoutInitializer:
+   lateField,
+   lateFieldName=Extension|finalNamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithoutInitializer
+  */
+  /*is-null.member: _#Extension|finalNamedExtensionNullableWithoutInitializer#isSet:
+   lateFieldName=Extension|finalNamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithoutInitializer,
+   lateIsSetField
+  */
+  /*member: Extension|finalNamedExtensionNullableWithoutInitializer:
+   lateFieldGetter,
+   lateFieldName=Extension|finalNamedExtensionNullableWithoutInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithoutInitializer
+  */
+  /*member: Extension|finalNamedExtensionNullableWithoutInitializer=:
+   lateFieldName=Extension|finalNamedExtensionNullableWithoutInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithoutInitializer
+  */
+  static late final int? finalNamedExtensionNullableWithoutInitializer;
+  /*member: _#Extension|namedExtensionNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=17,
+   lateFieldName=Extension|namedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithInitializer
+  */
+  /*member: Extension|namedExtensionNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=17,
+   lateFieldName=Extension|namedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithInitializer
+  */
+  /*member: Extension|namedExtensionNonNullableWithInitializer=:
+   lateFieldInitializer=17,
+   lateFieldName=Extension|namedExtensionNonNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|namedExtensionNonNullableWithInitializer
+  */
+  static late int namedExtensionNonNullableWithInitializer = 17;
+  /*member: _#Extension|finalNamedExtensionNonNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=18,
+   lateFieldName=Extension|finalNamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNonNullableWithInitializer
+  */
+  /*member: Extension|finalNamedExtensionNonNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=18,
+   lateFieldName=Extension|finalNamedExtensionNonNullableWithInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNonNullableWithInitializer
+  */
+  static late final int finalNamedExtensionNonNullableWithInitializer = 18;
+  /*member: _#Extension|namedExtensionNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=19,
+   lateFieldName=Extension|namedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithInitializer
+  */
+  /*is-null.member: _#Extension|namedExtensionNullableWithInitializer#isSet:
+   lateFieldInitializer=19,
+   lateFieldName=Extension|namedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Extension|namedExtensionNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=19,
+   lateFieldName=Extension|namedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithInitializer
+  */
+  /*member: Extension|namedExtensionNullableWithInitializer=:
+   lateFieldInitializer=19,
+   lateFieldName=Extension|namedExtensionNullableWithInitializer,
+   lateFieldSetter,
+   lateFieldTarget=_#Extension|namedExtensionNullableWithInitializer
+  */
+  static late int? namedExtensionNullableWithInitializer = 19;
+  /*member: _#Extension|finalNamedExtensionNullableWithInitializer:
+   lateField,
+   lateFieldInitializer=20,
+   lateFieldName=Extension|finalNamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithInitializer
+  */
+  /*is-null.member: _#Extension|finalNamedExtensionNullableWithInitializer#isSet:
+   lateFieldInitializer=20,
+   lateFieldName=Extension|finalNamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithInitializer,
+   lateIsSetField
+  */
+  /*member: Extension|finalNamedExtensionNullableWithInitializer:
+   lateFieldGetter,
+   lateFieldInitializer=20,
+   lateFieldName=Extension|finalNamedExtensionNullableWithInitializer,
+   lateFieldTarget=_#Extension|finalNamedExtensionNullableWithInitializer
+  */
+  static late final int? finalNamedExtensionNullableWithInitializer = 20;
 }
 
 method() {
   late int
       /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter,
-   lateLocalSetter
-  */
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
       localNonNullableWithoutInitializer;
   late final int
       /*
-       lateIsSetLocal,
        lateLocal,
        lateLocalGetter,
        lateLocalSetter
       */
       finalLocalNonNullableWithoutInitializer;
   late int?
-      /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter,
-   lateLocalSetter
-  */
+      /*is-null.
+       lateIsSetLocal,
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
+      /*sentinel.
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
       localNullableWithoutInitializer;
   late final int?
-      /*
+      /*is-null.
        lateIsSetLocal,
        lateLocal,
        lateLocalGetter,
        lateLocalSetter
       */
+      /*sentinel.
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
       finalLocalNullableWithoutInitializer;
   late int
       /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter,
-   lateLocalSetter
-  */
-      localNonNullableWithInitializer = 0;
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
+      localNonNullableWithInitializer = 21;
   late final int /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter
-  */
-      finalLocalNonNullableWithInitializer = 0;
+       lateLocal,
+       lateLocalGetter
+      */
+      finalLocalNonNullableWithInitializer = 22;
   late int?
-      /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter,
-   lateLocalSetter
-  */
-      localNullableWithInitializer = 0;
-  late final int? /*
-   lateIsSetLocal,
-   lateLocal,
-   lateLocalGetter
-  */
-      finalLocalNullableWithInitializer = 0;
+      /*is-null.
+       lateIsSetLocal,
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
+      /*sentinel.
+       lateLocal,
+       lateLocalGetter,
+       lateLocalSetter
+      */
+      localNullableWithInitializer = 23;
+  late final int?
+      /*is-null.
+       lateIsSetLocal,
+       lateLocal,
+       lateLocalGetter
+      */
+      /*sentinel.
+       lateLocal,
+       lateLocalGetter
+      */
+      finalLocalNullableWithInitializer = 24;
 }
diff --git a/pkg/front_end/test/predicates/data/late_names.dart b/pkg/front_end/test/predicates/data/late_names.dart
new file mode 100644
index 0000000..a67c9e9
--- /dev/null
+++ b/pkg/front_end/test/predicates/data/late_names.dart
@@ -0,0 +1,461 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*member: _#a:
+ lateField,
+ lateFieldName=a,
+ lateFieldTarget=_#a
+*/
+/*is-null.member: _#a#isSet:
+ lateFieldName=a,
+ lateFieldTarget=_#a,
+ lateIsSetField
+*/
+/*member: a:
+ lateFieldGetter,
+ lateFieldName=a,
+ lateFieldTarget=_#a
+*/
+/*member: a=:
+ lateFieldName=a,
+ lateFieldSetter,
+ lateFieldTarget=_#a
+*/
+late int? a;
+
+/*member: _#aa:
+ lateField,
+ lateFieldName=aa,
+ lateFieldTarget=_#aa
+*/
+/*is-null.member: _#aa#isSet:
+ lateFieldName=aa,
+ lateFieldTarget=_#aa,
+ lateIsSetField
+*/
+/*member: aa:
+ lateFieldGetter,
+ lateFieldName=aa,
+ lateFieldTarget=_#aa
+*/
+/*member: aa=:
+ lateFieldName=aa,
+ lateFieldSetter,
+ lateFieldTarget=_#aa
+*/
+late int? aa;
+
+/*member: _#_a:
+ lateField,
+ lateFieldName=_a,
+ lateFieldTarget=_#_a
+*/
+/*is-null.member: _#_a#isSet:
+ lateFieldName=_a,
+ lateFieldTarget=_#_a,
+ lateIsSetField
+*/
+/*member: _a:
+ lateFieldGetter,
+ lateFieldName=_a,
+ lateFieldTarget=_#_a
+*/
+/*member: _a=:
+ lateFieldName=_a,
+ lateFieldSetter,
+ lateFieldTarget=_#_a
+*/
+late int? _a;
+
+class Class {
+  /*member: Class._#Class#a:
+   lateField,
+   lateFieldName=a,
+   lateFieldTarget=Class._#Class#a
+  */
+  /*is-null.member: Class._#Class#a#isSet:
+   lateFieldName=a,
+   lateFieldTarget=Class._#Class#a,
+   lateIsSetField
+  */
+  /*member: Class.a:
+   lateFieldGetter,
+   lateFieldName=a,
+   lateFieldTarget=Class._#Class#a
+  */
+  /*member: Class.a=:
+   lateFieldName=a,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#a
+  */
+  late int? a;
+  /*member: Class._#Class#aa:
+   lateField,
+   lateFieldName=aa,
+   lateFieldTarget=Class._#Class#aa
+  */
+  /*is-null.member: Class._#Class#aa#isSet:
+   lateFieldName=aa,
+   lateFieldTarget=Class._#Class#aa,
+   lateIsSetField
+  */
+  /*member: Class.aa:
+   lateFieldGetter,
+   lateFieldName=aa,
+   lateFieldTarget=Class._#Class#aa
+  */
+  /*member: Class.aa=:
+   lateFieldName=aa,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#aa
+  */
+  late int? aa;
+  /*member: Class._#Class#_a:
+   lateField,
+   lateFieldName=_a,
+   lateFieldTarget=Class._#Class#_a
+  */
+  /*is-null.member: Class._#Class#_a#isSet:
+   lateFieldName=_a,
+   lateFieldTarget=Class._#Class#_a,
+   lateIsSetField
+  */
+  /*member: Class._a:
+   lateFieldGetter,
+   lateFieldName=_a,
+   lateFieldTarget=Class._#Class#_a
+  */
+  /*member: Class._a=:
+   lateFieldName=_a,
+   lateFieldSetter,
+   lateFieldTarget=Class._#Class#_a
+  */
+  late int? _a;
+
+  /*member: Class._#b:
+   lateField,
+   lateFieldName=b,
+   lateFieldTarget=Class._#b
+  */
+  /*is-null.member: Class._#b#isSet:
+   lateFieldName=b,
+   lateFieldTarget=Class._#b,
+   lateIsSetField
+  */
+  /*member: Class.b:
+   lateFieldGetter,
+   lateFieldName=b,
+   lateFieldTarget=Class._#b
+  */
+  /*member: Class.b=:
+   lateFieldName=b,
+   lateFieldSetter,
+   lateFieldTarget=Class._#b
+  */
+  static late int? b;
+  /*member: Class._#bb:
+   lateField,
+   lateFieldName=bb,
+   lateFieldTarget=Class._#bb
+  */
+  /*is-null.member: Class._#bb#isSet:
+   lateFieldName=bb,
+   lateFieldTarget=Class._#bb,
+   lateIsSetField
+  */
+  /*member: Class.bb:
+   lateFieldGetter,
+   lateFieldName=bb,
+   lateFieldTarget=Class._#bb
+  */
+  /*member: Class.bb=:
+   lateFieldName=bb,
+   lateFieldSetter,
+   lateFieldTarget=Class._#bb
+  */
+  static late int? bb;
+  /*member: Class._#_b:
+   lateField,
+   lateFieldName=_b,
+   lateFieldTarget=Class._#_b
+  */
+  /*is-null.member: Class._#_b#isSet:
+   lateFieldName=_b,
+   lateFieldTarget=Class._#_b,
+   lateIsSetField
+  */
+  /*member: Class._b:
+   lateFieldGetter,
+   lateFieldName=_b,
+   lateFieldTarget=Class._#_b
+  */
+  /*member: Class._b=:
+   lateFieldName=_b,
+   lateFieldSetter,
+   lateFieldTarget=Class._#_b
+  */
+  static late int? _b;
+}
+
+class _Class {
+  /*member: _Class._#_Class#a:
+   lateField,
+   lateFieldName=a,
+   lateFieldTarget=_Class._#_Class#a
+  */
+  /*is-null.member: _Class._#_Class#a#isSet:
+   lateFieldName=a,
+   lateFieldTarget=_Class._#_Class#a,
+   lateIsSetField
+  */
+  /*member: _Class.a:
+   lateFieldGetter,
+   lateFieldName=a,
+   lateFieldTarget=_Class._#_Class#a
+  */
+  /*member: _Class.a=:
+   lateFieldName=a,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#_Class#a
+  */
+  late int? a;
+  /*member: _Class._#_Class#aa:
+   lateField,
+   lateFieldName=aa,
+   lateFieldTarget=_Class._#_Class#aa
+  */
+  /*is-null.member: _Class._#_Class#aa#isSet:
+   lateFieldName=aa,
+   lateFieldTarget=_Class._#_Class#aa,
+   lateIsSetField
+  */
+  /*member: _Class.aa:
+   lateFieldGetter,
+   lateFieldName=aa,
+   lateFieldTarget=_Class._#_Class#aa
+  */
+  /*member: _Class.aa=:
+   lateFieldName=aa,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#_Class#aa
+  */
+  late int? aa;
+  /*member: _Class._#_Class#_a:
+   lateField,
+   lateFieldName=_a,
+   lateFieldTarget=_Class._#_Class#_a
+  */
+  /*is-null.member: _Class._#_Class#_a#isSet:
+   lateFieldName=_a,
+   lateFieldTarget=_Class._#_Class#_a,
+   lateIsSetField
+  */
+  /*member: _Class._a:
+   lateFieldGetter,
+   lateFieldName=_a,
+   lateFieldTarget=_Class._#_Class#_a
+  */
+  /*member: _Class._a=:
+   lateFieldName=_a,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#_Class#_a
+  */
+  late int? _a;
+
+  /*member: _Class._#b:
+   lateField,
+   lateFieldName=b,
+   lateFieldTarget=_Class._#b
+  */
+  /*is-null.member: _Class._#b#isSet:
+   lateFieldName=b,
+   lateFieldTarget=_Class._#b,
+   lateIsSetField
+  */
+  /*member: _Class.b:
+   lateFieldGetter,
+   lateFieldName=b,
+   lateFieldTarget=_Class._#b
+  */
+  /*member: _Class.b=:
+   lateFieldName=b,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#b
+  */
+  static late int? b;
+  /*member: _Class._#bb:
+   lateField,
+   lateFieldName=bb,
+   lateFieldTarget=_Class._#bb
+  */
+  /*is-null.member: _Class._#bb#isSet:
+   lateFieldName=bb,
+   lateFieldTarget=_Class._#bb,
+   lateIsSetField
+  */
+  /*member: _Class.bb:
+   lateFieldGetter,
+   lateFieldName=bb,
+   lateFieldTarget=_Class._#bb
+  */
+  /*member: _Class.bb=:
+   lateFieldName=bb,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#bb
+  */
+  static late int? bb;
+  /*member: _Class._#_b:
+   lateField,
+   lateFieldName=_b,
+   lateFieldTarget=_Class._#_b
+  */
+  /*is-null.member: _Class._#_b#isSet:
+   lateFieldName=_b,
+   lateFieldTarget=_Class._#_b,
+   lateIsSetField
+  */
+  /*member: _Class._b:
+   lateFieldGetter,
+   lateFieldName=_b,
+   lateFieldTarget=_Class._#_b
+  */
+  /*member: _Class._b=:
+   lateFieldName=_b,
+   lateFieldSetter,
+   lateFieldTarget=_Class._#_b
+  */
+  static late int? _b;
+}
+
+extension on int? {
+  /*member: _#_extension#0|a:
+   lateField,
+   lateFieldName=_extension#0|a,
+   lateFieldTarget=_#_extension#0|a
+  */
+  /*is-null.member: _#_extension#0|a#isSet:
+   lateFieldName=_extension#0|a,
+   lateFieldTarget=_#_extension#0|a,
+   lateIsSetField
+  */
+  /*member: _extension#0|a:
+   lateFieldGetter,
+   lateFieldName=_extension#0|a,
+   lateFieldTarget=_#_extension#0|a
+  */
+  /*member: _extension#0|a=:
+   lateFieldName=_extension#0|a,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|a
+  */
+  static late int? a;
+  /*member: _#_extension#0|aa:
+   lateField,
+   lateFieldName=_extension#0|aa,
+   lateFieldTarget=_#_extension#0|aa
+  */
+  /*is-null.member: _#_extension#0|aa#isSet:
+   lateFieldName=_extension#0|aa,
+   lateFieldTarget=_#_extension#0|aa,
+   lateIsSetField
+  */
+  /*member: _extension#0|aa:
+   lateFieldGetter,
+   lateFieldName=_extension#0|aa,
+   lateFieldTarget=_#_extension#0|aa
+  */
+  /*member: _extension#0|aa=:
+   lateFieldName=_extension#0|aa,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|aa
+  */
+  static late int? aa;
+  /*member: _#_extension#0|_b:
+   lateField,
+   lateFieldName=_extension#0|_b,
+   lateFieldTarget=_#_extension#0|_b
+  */
+  /*is-null.member: _#_extension#0|_b#isSet:
+   lateFieldName=_extension#0|_b,
+   lateFieldTarget=_#_extension#0|_b,
+   lateIsSetField
+  */
+  /*member: _extension#0|_b:
+   lateFieldGetter,
+   lateFieldName=_extension#0|_b,
+   lateFieldTarget=_#_extension#0|_b
+  */
+  /*member: _extension#0|_b=:
+   lateFieldName=_extension#0|_b,
+   lateFieldSetter,
+   lateFieldTarget=_#_extension#0|_b
+  */
+  static late int? _b;
+}
+
+extension _Extension on int? {
+  /*member: _#_Extension|a:
+   lateField,
+   lateFieldName=_Extension|a,
+   lateFieldTarget=_#_Extension|a
+  */
+  /*is-null.member: _#_Extension|a#isSet:
+   lateFieldName=_Extension|a,
+   lateFieldTarget=_#_Extension|a,
+   lateIsSetField
+  */
+  /*member: _Extension|a:
+   lateFieldGetter,
+   lateFieldName=_Extension|a,
+   lateFieldTarget=_#_Extension|a
+  */
+  /*member: _Extension|a=:
+   lateFieldName=_Extension|a,
+   lateFieldSetter,
+   lateFieldTarget=_#_Extension|a
+  */
+  static late int? a;
+  /*member: _#_Extension|aa:
+   lateField,
+   lateFieldName=_Extension|aa,
+   lateFieldTarget=_#_Extension|aa
+  */
+  /*is-null.member: _#_Extension|aa#isSet:
+   lateFieldName=_Extension|aa,
+   lateFieldTarget=_#_Extension|aa,
+   lateIsSetField
+  */
+  /*member: _Extension|aa:
+   lateFieldGetter,
+   lateFieldName=_Extension|aa,
+   lateFieldTarget=_#_Extension|aa
+  */
+  /*member: _Extension|aa=:
+   lateFieldName=_Extension|aa,
+   lateFieldSetter,
+   lateFieldTarget=_#_Extension|aa
+  */
+  static late int? aa;
+  /*member: _#_Extension|_b:
+   lateField,
+   lateFieldName=_Extension|_b,
+   lateFieldTarget=_#_Extension|_b
+  */
+  /*is-null.member: _#_Extension|_b#isSet:
+   lateFieldName=_Extension|_b,
+   lateFieldTarget=_#_Extension|_b,
+   lateIsSetField
+  */
+  /*member: _Extension|_b:
+   lateFieldGetter,
+   lateFieldName=_Extension|_b,
+   lateFieldTarget=_#_Extension|_b
+  */
+  /*member: _Extension|_b=:
+   lateFieldName=_Extension|_b,
+   lateFieldSetter,
+   lateFieldTarget=_#_Extension|_b
+  */
+  static late int? _b;
+}
diff --git a/pkg/front_end/test/predicates/data/marker.options b/pkg/front_end/test/predicates/data/marker.options
index afd83e5..1053541 100644
--- a/pkg/front_end/test/predicates/data/marker.options
+++ b/pkg/front_end/test/predicates/data/marker.options
@@ -1 +1,2 @@
-cfe=pkg/front_end/test/predicates/predicate_test.dart
+is-null=pkg/front_end/test/predicates/predicate_test.dart
+sentinel=pkg/front_end/test/predicates/predicate_test.dart
diff --git a/pkg/front_end/test/predicates/predicate_test.dart b/pkg/front_end/test/predicates/predicate_test.dart
index f62f803..ffe5ec2 100644
--- a/pkg/front_end/test/predicates/predicate_test.dart
+++ b/pkg/front_end/test/predicates/predicate_test.dart
@@ -9,12 +9,18 @@
 import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
 import 'package:_fe_analyzer_shared/src/testing/features.dart';
 import 'package:front_end/src/api_prototype/experimental_flags.dart';
+import 'package:front_end/src/base/nnbd_mode.dart';
 import 'package:front_end/src/testing/id_extractor.dart';
 import 'package:front_end/src/testing/id_testing_helper.dart';
+import 'package:front_end/src/testing/id_testing_utils.dart';
 import 'package:front_end/src/api_prototype/lowering_predicates.dart';
 import 'package:kernel/ast.dart';
+import 'package:kernel/src/printer.dart';
 import 'package:kernel/target/targets.dart';
 
+const String isNullMarker = 'is-null';
+const String sentinelMarker = 'sentinel';
+
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
   await runTests<Features>(dataDir,
@@ -22,20 +28,33 @@
       createUriForFileName: createUriForFileName,
       onFailure: onFailure,
       runTest: runTestFor(const PredicateDataComputer(), [
-        const TestConfig(cfeMarker, 'cfe',
+        const TestConfig(isNullMarker, 'use is-null',
             explicitExperimentalFlags: const {
               ExperimentalFlag.nonNullable: true
             },
             targetFlags: const TargetFlags(
-                forceLateLoweringsForTesting: LateLowering.all))
+                forceLateLoweringsForTesting: LateLowering.all,
+                forceLateLoweringSentinelForTesting: false),
+            nnbdMode: NnbdMode.Strong),
+        const TestConfig(sentinelMarker, 'use sentinel',
+            explicitExperimentalFlags: const {
+              ExperimentalFlag.nonNullable: true
+            },
+            targetFlags: const TargetFlags(
+                forceLateLoweringsForTesting: LateLowering.all,
+                forceLateLoweringSentinelForTesting: true),
+            nnbdMode: NnbdMode.Strong)
       ]));
 }
 
 class Tags {
   static const String lateField = 'lateField';
+  static const String lateFieldName = 'lateFieldName';
   static const String lateIsSetField = 'lateIsSetField';
   static const String lateFieldGetter = 'lateFieldGetter';
   static const String lateFieldSetter = 'lateFieldSetter';
+  static const String lateFieldTarget = 'lateFieldTarget';
+  static const String lateFieldInitializer = 'lateFieldInitializer';
 
   static const String lateLocal = 'lateLocal';
   static const String lateIsSetLocal = 'lateIsSetLocal';
@@ -95,19 +114,44 @@
       Features features = new Features();
       if (isLateLoweredField(node)) {
         features.add(Tags.lateField);
+        features[Tags.lateFieldName] =
+            extractFieldNameFromLateLoweredField(node).text;
       }
       if (isLateLoweredIsSetField(node)) {
         features.add(Tags.lateIsSetField);
+        features[Tags.lateFieldName] =
+            extractFieldNameFromLateLoweredIsSetField(node).text;
+      }
+      Field target = getLateFieldTarget(node);
+      if (target != null) {
+        features[Tags.lateFieldTarget] = getQualifiedMemberName(target);
+      }
+      Expression initializer = getLateFieldInitializer(node);
+      if (initializer != null) {
+        features[Tags.lateFieldInitializer] =
+            initializer.toText(astTextStrategyForTesting);
       }
       return features;
     } else if (node is Procedure) {
       Features features = new Features();
       if (isLateLoweredFieldGetter(node)) {
         features.add(Tags.lateFieldGetter);
+        features[Tags.lateFieldName] =
+            extractFieldNameFromLateLoweredFieldGetter(node).text;
       }
-
       if (isLateLoweredFieldSetter(node)) {
         features.add(Tags.lateFieldSetter);
+        features[Tags.lateFieldName] =
+            extractFieldNameFromLateLoweredFieldSetter(node).text;
+      }
+      Field target = getLateFieldTarget(node);
+      if (target != null) {
+        features[Tags.lateFieldTarget] = getQualifiedMemberName(target);
+      }
+      Expression initializer = getLateFieldInitializer(node);
+      if (initializer != null) {
+        features[Tags.lateFieldInitializer] =
+            initializer.toText(astTextStrategyForTesting);
       }
       return features;
     }
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 12f059f..cfb9146 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -34,6 +34,7 @@
 aligned
 alive
 allocate
+allocator
 altered
 analogous
 analogy
@@ -441,6 +442,7 @@
 foo
 foobar
 footer
+forcing
 foreign
 formed
 former
@@ -836,6 +838,7 @@
 pi
 picking
 pkg
+play
 player
 plugin
 pm
@@ -1264,6 +1267,7 @@
 unpleasant
 unreachable
 unseen
+unset
 unshadowed
 unsortable
 unsound
diff --git a/pkg/front_end/test/unit_test_suites.dart b/pkg/front_end/test/unit_test_suites.dart
index 0bd8b66..8e256f6 100644
--- a/pkg/front_end/test/unit_test_suites.dart
+++ b/pkg/front_end/test/unit_test_suites.dart
@@ -138,24 +138,30 @@
       "matches": matchedExpectations,
     }));
     if (!matchedExpectations) {
-      String failureLog = result.log;
+      StringBuffer sb = new StringBuffer();
+      sb.write(result.log);
       if (result.error != null) {
-        failureLog = "$failureLog\n\n${result.error}";
+        sb.write("\n\n${result.error}");
       }
       if (result.trace != null) {
-        failureLog = "$failureLog\n\n${result.trace}";
+        sb.write("\n\n${result.trace}");
       }
+      sb.write("\n\nTo re-run this test, run:");
+      sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
+          "$testName");
       if (result.autoFixCommand != null) {
-        failureLog = "$failureLog\n\n"
-            "To re-run this test, run:\n\n"
-            "   dart pkg/front_end/test/unit_test_suites.dart -p $testName\n\n"
-            "To automatically update the test expectations, run:\n\n"
-            "   dart pkg/front_end/test/unit_test_suites.dart -p $testName "
-            "-D${result.autoFixCommand}\n";
-      } else {
-        failureLog = "$failureLog\n\nRe-run this test: dart "
-            "pkg/front_end/test/unit_test_suites.dart -p $testName";
+        sb.write("\n\nTo automatically update the test expectations, run:");
+        sb.write("\n\n   dart pkg/front_end/test/unit_test_suites.dart -p "
+            "$testName -D${result.autoFixCommand}");
+        if (result.canBeFixWithUpdateExpectations) {
+          sb.write('\n\nTo update test expectations for all tests at once, '
+              'run:');
+          sb.write('\n\n  dart pkg/front_end/tool/update_expectations.dart');
+          sb.write('\n\nNote that this takes a long time and should only be '
+              'used when many tests need updating.\n');
+        }
       }
+      String failureLog = sb.toString();
       String outcome = "${result.outcome}";
       logsPort.send(jsonEncode({
         "name": testName,
diff --git a/pkg/front_end/test/utils/kernel_chain.dart b/pkg/front_end/test/utils/kernel_chain.dart
index 397879a..b76a823 100644
--- a/pkg/front_end/test/utils/kernel_chain.dart
+++ b/pkg/front_end/test/utils/kernel_chain.dart
@@ -66,6 +66,8 @@
 
   String get updateExpectationsOption;
 
+  bool get canBeFixWithUpdateExpectations;
+
   ExpectationSet get expectationSet;
 
   Expectation get expectationFileMismatch =>
@@ -96,7 +98,10 @@
             output, onMismatch, "$uri doesn't match ${expectedFile.uri}\n$diff",
             autoFixCommand: onMismatch == expectationFileMismatch
                 ? updateExpectationsOption
-                : null);
+                : null,
+            canBeFixWithUpdateExpectations:
+                onMismatch == expectationFileMismatch &&
+                    canBeFixWithUpdateExpectations);
       } else {
         return new Result<O>.pass(output);
       }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
index 97b91dd..a424674 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
@@ -20,8 +20,9 @@
 
   Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate( 
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline.expect
index e4af729..299f784 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline.expect
@@ -8,7 +8,8 @@
   @Double()
   double y;
   Pointer<Coordinate> next;
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {}
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
index a7af7c2..2f99722 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
@@ -8,7 +8,8 @@
   double x;
   @Double()
   double y;
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {}
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.expect
index 7121f54..3d65f9e 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:ffi" as ffi;
 import "dart:core" as core;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -13,8 +12,8 @@
   @#C1
   field core::double* y = null;
   field ffi::Pointer<self::Coordinate*>* next = null;
-  static factory allocate(core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
-    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(all::allocate<self::Coordinate*>()) in block {
+  static factory allocate(ffi::Allocator* allocator, core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
+    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(ffi::AllocatorAlloc|call<self::Coordinate*>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -41,4 +40,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
index 906fb3f..ce1ae9d 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:core" as core;
 import "dart:ffi" as ffi;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -16,8 +15,8 @@
   constructor #fromTypedDataBase(dynamic #pointer) → dynamic
     : super ffi::Struct::_fromPointer(#pointer)
     ;
-  static factory allocate(core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
-    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(all::allocate<self::Coordinate*>()) in block {
+  static factory allocate(ffi::Allocator* allocator, core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
+    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(ffi::AllocatorAlloc|call<self::Coordinate*>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -72,4 +71,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart b/pkg/front_end/testcases/nnbd/ffi_sample.dart
index 0c7f870..c45b492 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart
@@ -18,8 +18,9 @@
 
   external Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.outline.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.outline.expect
index 915c142..ad4664a 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.outline.expect
@@ -17,7 +17,7 @@
   external set y(core::double #externalFieldValue) → void;
   external get next() → ffi::Pointer<self::Coordinate>;
   external set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void;
-  static factory allocate(core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate
+  static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate
     ;
 }
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.expect
index 0b6b078..ff96753 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:ffi" as ffi;
 import "dart:core" as core;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -18,8 +17,8 @@
   external set y(core::double #externalFieldValue) → void;
   external get next() → ffi::Pointer<self::Coordinate>;
   external set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void;
-  static factory allocate(core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
-    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(all::allocate<self::Coordinate>()) in block {
+  static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
+    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(ffi::AllocatorAlloc|call<self::Coordinate>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -35,4 +34,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
index 92815a2..601d9fb 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:core" as core;
 import "dart:ffi" as ffi;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -32,8 +31,8 @@
     return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
   set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
     return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
-  static factory allocate(core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
-    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(all::allocate<self::Coordinate>()) in block {
+  static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
+    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(ffi::AllocatorAlloc|call<self::Coordinate>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -66,4 +65,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline.expect
index f21ecbe..326d793 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline.expect
@@ -7,7 +7,8 @@
   @Double()
   external double y;
   external Pointer<Coordinate> next;
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {}
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline_modelled.expect
index 263267c..88e9317 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.textual_outline_modelled.expect
@@ -7,7 +7,8 @@
   external double x;
   @Double()
   external double y;
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {}
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.expect
index 0b6b078..ff96753 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:ffi" as ffi;
 import "dart:core" as core;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -18,8 +17,8 @@
   external set y(core::double #externalFieldValue) → void;
   external get next() → ffi::Pointer<self::Coordinate>;
   external set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void;
-  static factory allocate(core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
-    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(all::allocate<self::Coordinate>()) in block {
+  static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
+    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(ffi::AllocatorAlloc|call<self::Coordinate>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -35,4 +34,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
index 92815a2..601d9fb 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:core" as core;
 import "dart:ffi" as ffi;
-import "package:ffi/src/allocation.dart" as all;
 
 import "dart:ffi";
 import "package:ffi/ffi.dart";
@@ -32,8 +31,8 @@
     return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
   set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
     return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
-  static factory allocate(core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
-    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(all::allocate<self::Coordinate>()) in block {
+  static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
+    return let final self::Coordinate #t1 = ffi::StructPointer|get#ref<self::Coordinate>(ffi::AllocatorAlloc|call<self::Coordinate>(allocator)) in block {
       #t1.{self::Coordinate::x} = x;
       #t1.{self::Coordinate::y} = y;
       #t1.{self::Coordinate::next} = next;
@@ -66,4 +65,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_sample.dart:
-- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
+- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index b78e407..0d81ce0 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -141,8 +141,15 @@
       bool disableLazyClassReading = false,
       bool alwaysCreateNewNamedNodes})
       : _disableLazyReading = disableLazyReading,
-        _disableLazyClassReading =
-            disableLazyReading || disableLazyClassReading,
+        _disableLazyClassReading = disableLazyReading ||
+            disableLazyClassReading ||
+            // Disable lazy class reading when forcing the creation of new named
+            // nodes as it is a logical "relink" to the new version (overwriting
+            // the old one) - which doesn't play well with lazy loading class
+            // content as old loaded references will then potentially still
+            // point to the old content until the new class has been lazy
+            // loaded.
+            (alwaysCreateNewNamedNodes == true),
         this.alwaysCreateNewNamedNodes = alwaysCreateNewNamedNodes ?? false;
 
   fail(String message) {
diff --git a/pkg/kernel/lib/src/tool/find_referenced_libraries.dart b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart
new file mode 100644
index 0000000..e95c7df
--- /dev/null
+++ b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/visitor.dart';
+
+Set<Library> findAllReferencedLibraries(List<Library> from) {
+  _LibraryCollector collector = new _LibraryCollector();
+  for (Library library in from) {
+    collector.visitLibrary(library);
+  }
+  return collector.allSeenLibraries;
+}
+
+bool duplicateLibrariesReachable(List<Library> from) {
+  Set<Uri> seenUris = {};
+  for (Library lib in findAllReferencedLibraries(from)) {
+    if (!seenUris.add(lib.importUri)) return true;
+  }
+  return false;
+}
+
+class _LibraryCollector extends RecursiveVisitor<Null> {
+  Set<Library> allSeenLibraries = {};
+
+  Null defaultNode(Node node) {
+    if (node is NamedNode) {
+      // Named nodes can be linked to.
+      seen(node);
+    } else if (node is Name) {
+      if (node.library != null) {
+        seen(node.library);
+      }
+    }
+    super.defaultNode(node);
+  }
+
+  Null defaultMemberReference(Member node) {
+    seen(node);
+    super.defaultMemberReference(node);
+  }
+
+  void seen(TreeNode node) {
+    TreeNode parent = node;
+    while (parent != null && parent is! Library) {
+      parent = parent.parent;
+    }
+    allSeenLibraries.add(parent);
+  }
+}
diff --git a/pkg/kernel/test/binary/lazy_reading_test.dart b/pkg/kernel/test/binary/lazy_reading_test.dart
new file mode 100644
index 0000000..601cb4e
--- /dev/null
+++ b/pkg/kernel/test/binary/lazy_reading_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/binary/ast_from_binary.dart';
+import 'package:kernel/src/tool/find_referenced_libraries.dart';
+import 'utils.dart';
+
+main() {
+  Library lib;
+  {
+    /// Create a library with two classes (A and B) where class A - in its
+    /// constructor - invokes the constructor for B.
+    lib = new Library(Uri.parse('org-dartlang:///lib.dart'));
+    final Class classA = new Class(name: "A");
+    lib.addClass(classA);
+    final Class classB = new Class(name: "B");
+    lib.addClass(classB);
+
+    final Constructor classBConstructor = new Constructor(
+        new FunctionNode(new EmptyStatement()),
+        name: new Name(""));
+    classB.addConstructor(classBConstructor);
+
+    final Constructor classAConstructor = new Constructor(
+        new FunctionNode(new ExpressionStatement(new ConstructorInvocation(
+            classBConstructor, new Arguments.empty()))),
+        name: new Name(""));
+    classA.addConstructor(classAConstructor);
+  }
+  Component c = new Component(libraries: [lib]);
+  c.setMainMethodAndMode(null, false, NonNullableByDefaultCompiledMode.Weak);
+  List<int> loadMe = serializeComponent(c);
+
+  // Load and make sure we can get at class B from class A (i.e. that it's
+  // loaded correctly!).
+  Component loadedComponent = new Component();
+  new BinaryBuilder(loadMe,
+          disableLazyReading: false, disableLazyClassReading: false)
+      .readSingleFileComponent(loadedComponent);
+  {
+    final Library loadedLib = loadedComponent.libraries.single;
+    final Class loadedClassA = loadedLib.classes.first;
+    final ExpressionStatement loadedConstructorA =
+        loadedClassA.constructors.single.function.body;
+    final ConstructorInvocation loadedConstructorInvocation =
+        loadedConstructorA.expression;
+    final Class pointedToClass =
+        loadedConstructorInvocation.target.enclosingClass;
+    final Library pointedToLib =
+        loadedConstructorInvocation.target.enclosingLibrary;
+
+    Set<Library> reachable = findAllReferencedLibraries([loadedLib]);
+    if (reachable.length != 1 || reachable.single != loadedLib) {
+      throw "Expected only the single library to be reachable, "
+          "but found $reachable";
+    }
+
+    final Class loadedClassB = loadedLib.classes[1];
+    if (loadedClassB != pointedToClass) {
+      throw "Doesn't point to the right class";
+    }
+    if (pointedToLib != loadedLib) {
+      throw "Doesn't point to the right library";
+    }
+  }
+  // Attempt to load again, overwriting the old stuff. This should logically
+  // "relink" to the newly loaded version.
+  Component loadedComponent2 = new Component(nameRoot: loadedComponent.root);
+  new BinaryBuilder(loadMe,
+          disableLazyReading: false,
+          disableLazyClassReading: false,
+          alwaysCreateNewNamedNodes: true)
+      .readSingleFileComponent(loadedComponent2);
+  {
+    final Library loadedLib = loadedComponent2.libraries.single;
+    final Class loadedClassA = loadedLib.classes.first;
+    final ExpressionStatement loadedConstructorA =
+        loadedClassA.constructors.single.function.body;
+    final ConstructorInvocation loadedConstructorInvocation =
+        loadedConstructorA.expression;
+    final Class pointedToClass =
+        loadedConstructorInvocation.target.enclosingClass;
+    final Library pointedToLib =
+        loadedConstructorInvocation.target.enclosingLibrary;
+
+    Set<Library> reachable = findAllReferencedLibraries([loadedLib]);
+    if (reachable.length != 1 || reachable.single != loadedLib) {
+      throw "Expected only the single library to be reachable, "
+          "but found $reachable";
+    }
+
+    final Class loadedClassB = loadedLib.classes[1];
+    if (loadedClassB != pointedToClass) {
+      throw "Doesn't point to the right class";
+    }
+    if (pointedToLib != loadedLib) {
+      throw "Doesn't point to the right library";
+    }
+  }
+}
diff --git a/pkg/kernel/test/convert_field_to_setter_getter.dart b/pkg/kernel/test/convert_field_to_setter_getter.dart
index 6e0b797..d449735 100644
--- a/pkg/kernel/test/convert_field_to_setter_getter.dart
+++ b/pkg/kernel/test/convert_field_to_setter_getter.dart
@@ -2,11 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
-
-import 'package:kernel/ast.dart';
 import 'package:kernel/binary/ast_from_binary.dart';
 import 'package:kernel/binary/ast_to_binary.dart';
+import 'binary/utils.dart';
 
 main() {
   final Library lib1 = new Library(Uri.parse('org-dartlang:///lib.dart'));
@@ -180,14 +178,3 @@
   StaticGet staticGet = setterStatement.expression;
   return staticGet.target;
 }
-
-/// A [Sink] that directly writes data into a byte builder.
-class ByteSink implements Sink<List<int>> {
-  final BytesBuilder builder = new BytesBuilder();
-
-  void add(List<int> data) {
-    builder.add(data);
-  }
-
-  void close() {}
-}
diff --git a/pkg/kernel/test/relink_test.dart b/pkg/kernel/test/relink_test.dart
index ed51ee6..37b0f7d 100644
--- a/pkg/kernel/test/relink_test.dart
+++ b/pkg/kernel/test/relink_test.dart
@@ -2,16 +2,26 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
-
-import 'package:kernel/ast.dart';
 import 'package:kernel/binary/ast_from_binary.dart';
 import 'package:kernel/binary/ast_to_binary.dart';
+import 'package:kernel/src/tool/find_referenced_libraries.dart';
+import 'binary/utils.dart';
 
 main() {
   Component component1 = createComponent(42);
   Component component2 = createComponent(43);
 
+  expectReachable(
+      findAllReferencedLibraries(component1.libraries), component1.libraries);
+  if (duplicateLibrariesReachable(component1.libraries)) {
+    throw "Didn't expect duplicates libraries!";
+  }
+  expectReachable(
+      findAllReferencedLibraries(component2.libraries), component2.libraries);
+  if (duplicateLibrariesReachable(component2.libraries)) {
+    throw "Didn't expect duplicates libraries!";
+  }
+
   ByteSink sink = new ByteSink();
   new BinaryPrinter(sink).writeComponentFile(component1);
   List<int> writtenBytes1 = sink.builder.takeBytes();
@@ -25,6 +35,11 @@
   Procedure target1 = getMainTarget(component1Prime);
   Procedure procedureLib1 = getLibProcedure(component1Prime);
   if (target1 != procedureLib1) throw "Unexpected target.";
+  expectReachable(findAllReferencedLibraries(component1Prime.libraries),
+      component1Prime.libraries);
+  if (duplicateLibrariesReachable(component1Prime.libraries)) {
+    throw "Didn't expect duplicates libraries!";
+  }
 
   // Loading another one saying it should overwrite works as one would expect
   // for this component: It gives a component that is linked to itself that is
@@ -36,6 +51,11 @@
   Procedure procedureLib2 = getLibProcedure(component2Prime);
   if (procedureLib2 == procedureLib1) throw "Unexpected procedure.";
   if (target2 != procedureLib2) throw "Unexpected target.";
+  expectReachable(findAllReferencedLibraries(component2Prime.libraries),
+      component2Prime.libraries);
+  if (duplicateLibrariesReachable(component2Prime.libraries)) {
+    throw "Didn't expect duplicates libraries!";
+  }
 
   // The old one that was loaded on top of was re-linked so it also points to
   // procedureLib2.
@@ -44,17 +64,48 @@
 
   // Relink back and forth a number of times: It keeps working as expected.
   for (int i = 0; i < 6; i++) {
+    // Before the relink the lib from component2Prime is also reachable!
+    expectReachable(
+        findAllReferencedLibraries(component1Prime.libraries),
+        []
+          ..addAll(component1Prime.libraries)
+          ..add(procedureLib2.enclosingLibrary));
+    if (!duplicateLibrariesReachable(component1Prime.libraries)) {
+      throw "Expected duplicates libraries!";
+    }
+
     // Relinking component1Prime works as one would expected: Both components
     // main now points to procedureLib1.
     component1Prime.relink();
+    // After the relink only the libs from component1Prime are reachable!
+    expectReachable(findAllReferencedLibraries(component1Prime.libraries),
+        component1Prime.libraries);
+    if (duplicateLibrariesReachable(component1Prime.libraries)) {
+      throw "Didn't expect duplicates libraries!";
+    }
     target1 = getMainTarget(component1Prime);
     if (target1 != procedureLib1) throw "Unexpected target.";
     target2 = getMainTarget(component2Prime);
     if (target2 != procedureLib1) throw "Unexpected target.";
 
+    // Before the relink the lib from component1Prime is also reachable!
+    expectReachable(
+        findAllReferencedLibraries(component2Prime.libraries),
+        []
+          ..addAll(component2Prime.libraries)
+          ..add(procedureLib1.enclosingLibrary));
+    if (!duplicateLibrariesReachable(component2Prime.libraries)) {
+      throw "Expected duplicates libraries!";
+    }
     // Relinking component2Prime works as one would expected: Both components
     // main now points to procedureLib2.
     component2Prime.relink();
+    // After the relink only the libs from component1Prime are reachable!
+    expectReachable(findAllReferencedLibraries(component2Prime.libraries),
+        component2Prime.libraries);
+    if (duplicateLibrariesReachable(component2Prime.libraries)) {
+      throw "Didn't expect duplicates libraries!";
+    }
     target1 = getMainTarget(component1Prime);
     if (target1 != procedureLib2) throw "Unexpected target.";
     target2 = getMainTarget(component2Prime);
@@ -62,6 +113,18 @@
   }
 }
 
+void expectReachable(
+    Set<Library> findAllReferencedLibraries, List<Library> libraries) {
+  Set<Library> onlyInReferenced = findAllReferencedLibraries.toSet()
+    ..removeAll(libraries);
+  Set<Library> onlyInLibraries = libraries.toSet()
+    ..removeAll(findAllReferencedLibraries);
+  if (onlyInReferenced.isNotEmpty || onlyInLibraries.isNotEmpty) {
+    throw "Expected to be the same, but ${onlyInReferenced} was only in "
+        "reachable and ${onlyInLibraries} was only in libraries";
+  }
+}
+
 Procedure getLibProcedure(Component component1Prime) {
   if (component1Prime.libraries[1].importUri !=
       Uri.parse('org-dartlang:///lib.dart')) {
@@ -106,14 +169,3 @@
   return new Component(libraries: [main, lib])
     ..setMainMethodAndMode(null, false, NonNullableByDefaultCompiledMode.Weak);
 }
-
-/// A [Sink] that directly writes data into a byte builder.
-class ByteSink implements Sink<List<int>> {
-  final BytesBuilder builder = new BytesBuilder();
-
-  void add(List<int> data) {
-    builder.add(data);
-  }
-
-  void close() {}
-}
diff --git a/pkg/kernel/test/round_trip.dart b/pkg/kernel/test/round_trip.dart
index b94ae42..271293a 100644
--- a/pkg/kernel/test/round_trip.dart
+++ b/pkg/kernel/test/round_trip.dart
@@ -6,7 +6,7 @@
 import 'dart:io';
 import 'package:kernel/binary/ast_from_binary.dart';
 import 'package:kernel/binary/ast_to_binary.dart';
-import 'package:kernel/kernel.dart';
+import 'binary/utils.dart';
 
 const String usage = '''
 Usage: round_trip.dart FILE.dill [sdk.dill]
@@ -52,14 +52,3 @@
 String show(int byte) {
   return '$byte (0x${byte.toRadixString(16).padLeft(2, "0")})';
 }
-
-/// A [Sink] that directly writes data into a byte builder.
-class ByteSink implements Sink<List<int>> {
-  final BytesBuilder builder = new BytesBuilder();
-
-  void add(List<int> data) {
-    builder.add(data);
-  }
-
-  void close() {}
-}
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 6d682de..7c51016 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -828,6 +828,7 @@
     }
 
     // Expand runtimes.
+    var configurationNumber = 1;
     for (var runtime in runtimes) {
       // Expand architectures.
       var architectures = data["arch"] as String;
@@ -852,8 +853,13 @@
             }
             for (var sanitizerName in sanitizers.split(",")) {
               var sanitizer = Sanitizer.find(sanitizerName);
-              var configuration = Configuration("custom configuration",
-                  architecture, compiler, mode, runtime, system,
+              var configuration = Configuration(
+                  "custom configuration_${configurationNumber++}",
+                  architecture,
+                  compiler,
+                  mode,
+                  runtime,
+                  system,
                   nnbdMode: nnbdMode,
                   sanitizer: sanitizer,
                   timeout: data["timeout"] as int,
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 9c1baf2..96f273a 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -221,26 +221,13 @@
   /// Create a directories for generated assets (tests, html files,
   /// pubspec checkouts ...).
   String createOutputDirectory(Path testPath) {
-    var checked = configuration.isChecked ? '-checked' : '';
-    var minified = configuration.isMinified ? '-minified' : '';
-    var sdk = configuration.useSdk ? '-sdk' : '';
-    var dirName = "${configuration.compiler.name}-${configuration.runtime.name}"
-        "$checked$minified$sdk";
-    return createGeneratedTestDirectoryHelper("tests", dirName, testPath);
+    return createGeneratedTestDirectoryHelper(
+        "tests", configuration.configuration.name, testPath);
   }
 
   String createCompilationOutputDirectory(Path testPath) {
-    var checked = configuration.isChecked ? '-checked' : '';
-    var minified = configuration.isMinified ? '-minified' : '';
-    var csp = configuration.isCsp ? '-csp' : '';
-    var sdk = configuration.useSdk ? '-sdk' : '';
-    var isLegacyModule = configuration.compiler == Compiler.dartdevk &&
-        configuration.runtime == Runtime.d8;
-    var module = isLegacyModule ? '-legacy' : '';
-    var dirName = "${configuration.compiler.name}"
-        "$checked$minified$csp$sdk$module";
     return createGeneratedTestDirectoryHelper(
-        "compilations", dirName, testPath);
+        "compilations", configuration.configuration.name, testPath);
   }
 
   String createPubspecCheckoutDirectory(Path directoryOfPubspecYaml) {
diff --git a/pkg/test_runner/lib/src/utils.dart b/pkg/test_runner/lib/src/utils.dart
index b1c41171..fc27e18 100644
--- a/pkg/test_runner/lib/src/utils.dart
+++ b/pkg/test_runner/lib/src/utils.dart
@@ -414,13 +414,11 @@
   static void deleteTempSnapshotDirectory(TestConfiguration configuration) {
     if (configuration.compiler == Compiler.dartk ||
         configuration.compiler == Compiler.dartkp) {
-      var checked = configuration.isChecked ? '-checked' : '';
-      var minified = configuration.isMinified ? '-minified' : '';
-      var csp = configuration.isCsp ? '-csp' : '';
-      var sdk = configuration.useSdk ? '-sdk' : '';
-      var dirName = "${configuration.compiler.name}$checked$minified$csp$sdk";
-      var generatedPath =
-          configuration.buildDirectory + "/generated_compilations/$dirName";
+      var generatedPath = [
+        configuration.buildDirectory,
+        "generated_compilations",
+        configuration.configuration.name
+      ].join('/');
       if (FileSystemEntity.isDirectorySync(generatedPath)) {
         TestUtils.deleteDirectory(generatedPath);
       }
diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart
index c6f6c16..1f7fc84 100644
--- a/pkg/testing/lib/src/chain.dart
+++ b/pkg/testing/lib/src/chain.dart
@@ -358,8 +358,16 @@
   /// update the test to match new expectations.
   final String autoFixCommand;
 
+  /// If set, the test can be fixed by running
+  ///
+  ///     dart pkg/front_end/tool/update_expectations.dart
+  ///
+  final bool canBeFixWithUpdateExpectations;
+
   Result(this.output, this.outcome, this.error,
-      {this.trace, this.autoFixCommand});
+      {this.trace,
+      this.autoFixCommand,
+      this.canBeFixWithUpdateExpectations: false});
 
   Result.pass(O output) : this(output, Expectation.Pass, null);
 
@@ -384,7 +392,9 @@
 
   Result<O2> copyWithOutput<O2>(O2 output) {
     return new Result<O2>(output, outcome, error,
-        trace: trace, autoFixCommand: autoFixCommand)
+        trace: trace,
+        autoFixCommand: autoFixCommand,
+        canBeFixWithUpdateExpectations: canBeFixWithUpdateExpectations)
       ..logs.addAll(logs);
   }
 }
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index f8b473f..17ad5f5 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -34,6 +34,7 @@
   kFloat,
   kDouble,
   kVoid,
+  kOpaque,
   kStruct,
   kHandle,
 }
@@ -60,6 +61,7 @@
   'Float',
   'Double',
   'Void',
+  'Opaque',
   'Struct',
   'Handle'
 ];
@@ -86,6 +88,7 @@
   4, // Float
   8, // Double
   UNKNOWN, // Void
+  UNKNOWN, // Opaque
   UNKNOWN, // Struct
   WORD_SIZE, // Handle
 ];
@@ -205,9 +208,13 @@
   final Procedure numAddition;
 
   final Library ffiLibrary;
+  final Class allocatorClass;
   final Class nativeFunctionClass;
+  final Class opaqueClass;
   final Class pointerClass;
   final Class structClass;
+  final Procedure allocateMethod;
+  final Procedure allocatorAllocateMethod;
   final Procedure castMethod;
   final Procedure offsetByMethod;
   final Procedure elementAtMethod;
@@ -228,6 +235,7 @@
   final Map<NativeType, Procedure> elementAtMethods;
   final Procedure loadStructMethod;
   final Procedure memCopy;
+  final Procedure allocationTearoff;
   final Procedure asFunctionTearoff;
   final Procedure lookupFunctionTearoff;
 
@@ -257,9 +265,14 @@
         listElementAt = coreTypes.index.getMember('dart:core', 'List', '[]'),
         numAddition = coreTypes.index.getMember('dart:core', 'num', '+'),
         ffiLibrary = index.getLibrary('dart:ffi'),
+        allocatorClass = index.getClass('dart:ffi', 'Allocator'),
         nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
+        opaqueClass = index.getClass('dart:ffi', 'Opaque'),
         pointerClass = index.getClass('dart:ffi', 'Pointer'),
         structClass = index.getClass('dart:ffi', 'Struct'),
+        allocateMethod = index.getMember('dart:ffi', 'AllocatorAlloc', 'call'),
+        allocatorAllocateMethod =
+            index.getMember('dart:ffi', 'Allocator', 'allocate'),
         castMethod = index.getMember('dart:ffi', 'Pointer', 'cast'),
         offsetByMethod = index.getMember('dart:ffi', 'Pointer', '_offsetBy'),
         elementAtMethod = index.getMember('dart:ffi', 'Pointer', 'elementAt'),
@@ -301,6 +314,8 @@
         }),
         loadStructMethod = index.getTopLevelMember('dart:ffi', '_loadStruct'),
         memCopy = index.getTopLevelMember('dart:ffi', '_memCopy'),
+        allocationTearoff = index.getMember(
+            'dart:ffi', 'AllocatorAlloc', LibraryIndex.tearoffPrefix + 'call'),
         asFunctionTearoff = index.getMember('dart:ffi', 'NativeFunctionPointer',
             LibraryIndex.tearoffPrefix + 'asFunction'),
         lookupFunctionTearoff = index.getMember(
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 3260c0a..7bfd6a2 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -128,7 +128,9 @@
   @override
   visitProcedure(Procedure node) {
     if (isFfiLibrary && node.isExtensionMember) {
-      if (node == asFunctionTearoff || node == lookupFunctionTearoff) {
+      if (node == allocationTearoff ||
+          node == asFunctionTearoff ||
+          node == lookupFunctionTearoff) {
         // Skip static checks and transformation for the tearoffs.
         return node;
       }
@@ -279,6 +281,13 @@
           }
         }
         return _replaceFromFunction(node);
+      } else if (target == allocateMethod) {
+        final DartType nativeType = node.arguments.types[0];
+
+        _ensureNativeTypeValid(nativeType, node);
+
+        // TODO(http://dartbug.com/38721): Inline the body to get rid of a
+        // generic invocation of sizeOf.
       }
     } on _FfiStaticTypeError {
       // It's OK to swallow the exception because the diagnostics issued will
@@ -479,10 +488,15 @@
   Class _extendsOrImplementsSealedClass(Class klass) {
     final Class superClass = klass.supertype?.classNode;
 
-    // The Struct class can be extended, but subclasses of Struct cannot be (nor
-    // implemented).
-    if (klass != structClass && hierarchy.isSubtypeOf(klass, structClass)) {
-      return superClass != structClass ? superClass : null;
+    // The Opaque and Struct classes can be extended, but subclasses
+    // cannot be (nor implemented).
+    if (klass != opaqueClass &&
+        klass != structClass &&
+        (hierarchy.isSubtypeOf(klass, opaqueClass) ||
+            hierarchy.isSubtypeOf(klass, structClass))) {
+      return superClass != opaqueClass && superClass != structClass
+          ? superClass
+          : null;
     }
 
     if (!nativeTypesClasses.contains(klass)) {
diff --git a/runtime/tests/vm/dart/isolates/dart_api_create_lightweight_isolate_test.dart b/runtime/tests/vm/dart/isolates/dart_api_create_lightweight_isolate_test.dart
index f2e8a70..25e0199 100644
--- a/runtime/tests/vm/dart/isolates/dart_api_create_lightweight_isolate_test.dart
+++ b/runtime/tests/vm/dart/isolates/dart_api_create_lightweight_isolate_test.dart
@@ -14,6 +14,7 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../../tests/ffi/calloc.dart';
 import '../../../../../tests/ffi/dylib_utils.dart';
 
 final bool isAOT = Platform.executable.contains('dart_precompiled_runtime');
@@ -62,7 +63,7 @@
       Expect.isTrue(isolate.address != 0);
       return isolate;
     } finally {
-      free(cname);
+      calloc.free(cname);
     }
   }
 
@@ -86,8 +87,8 @@
         onError != null ? onError.nativePort : 0,
         onExit != null ? onExit.nativePort : 0);
 
-    free(libraryUri);
-    free(functionName);
+    calloc.free(libraryUri);
+    calloc.free(functionName);
   }
 }
 
@@ -120,7 +121,7 @@
     // wait a little here to ensure the write of the callback has arrived.
     await Future.delayed(const Duration(milliseconds: 100));
     Expect.equals('xbz', Utf8.fromUtf8(peer.cast()));
-    free(peer);
+    calloc.free(peer);
   }
 }
 
diff --git a/runtime/tests/vm/dart/regress_41971_test.dart b/runtime/tests/vm/dart/regress_41971_test.dart
index 28f63ad..7979d0d 100644
--- a/runtime/tests/vm/dart/regress_41971_test.dart
+++ b/runtime/tests/vm/dart/regress_41971_test.dart
@@ -11,6 +11,8 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../tests/ffi/calloc.dart';
+
 class X {
   int field;
   X(this.field);
@@ -35,8 +37,8 @@
 }
 
 void main() {
-  final p = allocate<Int32>(count: 128);
+  final p = calloc<Int32>(128);
   p[0] = 42;
   Expect.equals(42, loadFrom(p));
-  free(p);
+  calloc.free(p);
 }
diff --git a/runtime/tests/vm/dart/thread_priority_macos_test.dart b/runtime/tests/vm/dart/thread_priority_macos_test.dart
index b7c8280..473c1ce 100644
--- a/runtime/tests/vm/dart/thread_priority_macos_test.dart
+++ b/runtime/tests/vm/dart/thread_priority_macos_test.dart
@@ -10,6 +10,8 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../tests/ffi/calloc.dart';
+
 // pthread_t pthread_self()
 typedef PthreadSelfFT = int Function();
 typedef PthreadSelfNFT = IntPtr Function();
@@ -34,11 +36,11 @@
 
 main(args) {
   if (Platform.isMacOS) {
-    final policy = allocate<Int32>(count: 1);
-    final param = allocate<SchedParam>(count: 1);
+    final policy = calloc<Int32>(1);
+    final param = calloc<SchedParam>(1);
     Expect.equals(0, pthreadGetSchedParam(pthreadSelf(), policy, param));
     Expect.equals(15, param.ref.schedPriority);
-    free(policy);
-    free(param);
+    calloc.free(policy);
+    calloc.free(param);
   }
 }
diff --git a/runtime/tests/vm/dart_2/isolates/dart_api_create_lightweight_isolate_test.dart b/runtime/tests/vm/dart_2/isolates/dart_api_create_lightweight_isolate_test.dart
index 0daead0..d35474e 100644
--- a/runtime/tests/vm/dart_2/isolates/dart_api_create_lightweight_isolate_test.dart
+++ b/runtime/tests/vm/dart_2/isolates/dart_api_create_lightweight_isolate_test.dart
@@ -14,6 +14,7 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../../tests/ffi/calloc.dart';
 import '../../../../../tests/ffi/dylib_utils.dart';
 
 final bool isAOT = Platform.executable.contains('dart_precompiled_runtime');
@@ -62,7 +63,7 @@
       Expect.isTrue(isolate.address != 0);
       return isolate;
     } finally {
-      free(cname);
+      calloc.free(cname);
     }
   }
 
@@ -86,8 +87,8 @@
         onError != null ? onError.nativePort : 0,
         onExit != null ? onExit.nativePort : 0);
 
-    free(libraryUri);
-    free(functionName);
+    calloc.free(libraryUri);
+    calloc.free(functionName);
   }
 }
 
@@ -120,7 +121,7 @@
     // wait a little here to ensure the write of the callback has arrived.
     await Future.delayed(const Duration(milliseconds: 100));
     Expect.equals('xbz', Utf8.fromUtf8(peer.cast()));
-    free(peer);
+    calloc.free(peer);
   }
 }
 
diff --git a/runtime/tests/vm/dart_2/regress_41971_test.dart b/runtime/tests/vm/dart_2/regress_41971_test.dart
index 28f63ad..7979d0d 100644
--- a/runtime/tests/vm/dart_2/regress_41971_test.dart
+++ b/runtime/tests/vm/dart_2/regress_41971_test.dart
@@ -11,6 +11,8 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../tests/ffi/calloc.dart';
+
 class X {
   int field;
   X(this.field);
@@ -35,8 +37,8 @@
 }
 
 void main() {
-  final p = allocate<Int32>(count: 128);
+  final p = calloc<Int32>(128);
   p[0] = 42;
   Expect.equals(42, loadFrom(p));
-  free(p);
+  calloc.free(p);
 }
diff --git a/runtime/tests/vm/dart_2/thread_priority_macos_test.dart b/runtime/tests/vm/dart_2/thread_priority_macos_test.dart
index b466eb0..fdce726 100644
--- a/runtime/tests/vm/dart_2/thread_priority_macos_test.dart
+++ b/runtime/tests/vm/dart_2/thread_priority_macos_test.dart
@@ -10,6 +10,8 @@
 import 'package:expect/expect.dart';
 import 'package:ffi/ffi.dart';
 
+import '../../../../tests/ffi/calloc.dart';
+
 // pthread_t pthread_self()
 typedef PthreadSelfFT = int Function();
 typedef PthreadSelfNFT = IntPtr Function();
@@ -34,11 +36,11 @@
 
 main(args) {
   if (Platform.isMacOS) {
-    final policy = allocate<Int32>(count: 1);
-    final param = allocate<SchedParam>(count: 1);
+    final policy = calloc<Int32>(1);
+    final param = calloc<SchedParam>(1);
     Expect.equals(0, pthreadGetSchedParam(pthreadSelf(), policy, param));
     Expect.equals(15, param.ref.schedPriority);
-    free(policy);
-    free(param);
+    calloc.free(policy);
+    calloc.free(param);
   }
 }
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index bfff86b..2836127 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -243,7 +243,7 @@
     }
     s->WriteCid(class_id);
     if (s->kind() == Snapshot::kFullCore &&
-        RequireLegacyErasureOfConstants(cls)) {
+        RequireCanonicalTypeErasureOfConstants(cls)) {
       s->UnexpectedObject(cls, "Class with non mode agnostic constants");
     }
     if (s->kind() != Snapshot::kFullAOT) {
@@ -268,10 +268,10 @@
   GrowableArray<ClassPtr> predefined_;
   GrowableArray<ClassPtr> objects_;
 
-  bool RequireLegacyErasureOfConstants(ClassPtr cls) {
+  bool RequireCanonicalTypeErasureOfConstants(ClassPtr cls) {
     // Do not generate a core snapshot containing constants that would require
-    // a legacy erasure of their types if loaded in an isolate running in weak
-    // mode.
+    // a canonical erasure of their types if loaded in an isolate running in
+    // unsound nullability mode.
     if (cls->ptr()->host_type_arguments_field_offset_in_words_ ==
             Class::kNoTypeArguments ||
         cls->ptr()->constants_ == Array::null()) {
@@ -279,7 +279,7 @@
     }
     Zone* zone = Thread::Current()->zone();
     const Class& clazz = Class::Handle(zone, cls);
-    return clazz.RequireLegacyErasureOfConstants(zone);
+    return clazz.RequireCanonicalTypeErasureOfConstants(zone);
   }
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/frontend/constant_reader.cc b/runtime/vm/compiler/frontend/constant_reader.cc
index eab7f31..af38fcf 100644
--- a/runtime/vm/compiler/frontend/constant_reader.cc
+++ b/runtime/vm/compiler/frontend/constant_reader.cc
@@ -199,7 +199,7 @@
       // Build type from the raw bytes (needs temporary translator).
       TypeTranslator type_translator(
           &reader, this, active_class_, true,
-          active_class_->RequireLegacyErasure(null_safety));
+          active_class_->RequireConstCanonicalTypeErasure(null_safety));
       auto& type_arguments =
           TypeArguments::Handle(Z, TypeArguments::New(1, Heap::kOld));
       AbstractType& type = type_translator.BuildType();
@@ -242,7 +242,7 @@
       // Build type from the raw bytes (needs temporary translator).
       TypeTranslator type_translator(
           &reader, this, active_class_, true,
-          active_class_->RequireLegacyErasure(null_safety));
+          active_class_->RequireConstCanonicalTypeErasure(null_safety));
       const intptr_t number_of_type_arguments = reader.ReadUInt();
       if (klass.NumTypeArguments() > 0) {
         auto& type_arguments = TypeArguments::Handle(
@@ -285,7 +285,7 @@
       // Build type from the raw bytes (needs temporary translator).
       TypeTranslator type_translator(
           &reader, this, active_class_, true,
-          active_class_->RequireLegacyErasure(null_safety));
+          active_class_->RequireConstCanonicalTypeErasure(null_safety));
       const intptr_t number_of_type_arguments = reader.ReadUInt();
       ASSERT(number_of_type_arguments > 0);
       auto& type_arguments = TypeArguments::Handle(
@@ -318,7 +318,11 @@
     }
     case kTypeLiteralConstant: {
       // Build type from the raw bytes (needs temporary translator).
-      // Legacy erasure is not applied to type literals. See issue #42262.
+      // Const canonical type erasure is not applied to constant type literals.
+      // However, CFE must ensure that constant type literals can be
+      // canonicalized to an identical representant independently of the null
+      // safety mode currently in use (sound or unsound) or migration state of
+      // the declaring library (legacy or opted-in).
       TypeTranslator type_translator(&reader, this, active_class_, true);
       instance = type_translator.BuildType().raw();
       break;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 6e6216e..ae03f6e 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2925,7 +2925,7 @@
                                ConstantReader* constant_reader,
                                ActiveClass* active_class,
                                bool finalize,
-                               bool apply_legacy_erasure)
+                               bool apply_canonical_type_erasure)
     : helper_(helper),
       constant_reader_(constant_reader),
       translation_helper_(helper->translation_helper_),
@@ -2936,7 +2936,7 @@
       zone_(translation_helper_.zone()),
       result_(AbstractType::Handle(translation_helper_.zone())),
       finalize_(finalize),
-      apply_legacy_erasure_(apply_legacy_erasure) {}
+      apply_canonical_type_erasure_(apply_canonical_type_erasure) {}
 
 AbstractType& TypeTranslator::BuildType() {
   BuildTypeInternal();
@@ -2968,13 +2968,13 @@
       result_ = Object::void_type().raw();
       break;
     case kNeverType: {
-      const Nullability nullability = helper_->ReadNullability();
-      if (apply_legacy_erasure_) {
-        result_ = IG->object_store()->null_type();
-      } else {
-        result_ = Type::Handle(Z, IG->object_store()->never_type())
-                      .ToNullability(nullability, Heap::kOld);
+      Nullability nullability = helper_->ReadNullability();
+      if (apply_canonical_type_erasure_ &&
+          nullability != Nullability::kNullable) {
+        nullability = Nullability::kLegacy;
       }
+      result_ = Type::Handle(Z, IG->object_store()->never_type())
+                    .ToNullability(nullability, Heap::kOld);
       break;
     }
     case kBottomType:
@@ -3009,7 +3009,7 @@
   //   => We therefore ignore errors in `A` or `B`.
 
   Nullability nullability = helper_->ReadNullability();
-  if (apply_legacy_erasure_) {
+  if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
     nullability = Nullability::kLegacy;
   }
 
@@ -3050,7 +3050,7 @@
           ? active_class_->enclosing->NumTypeArguments()
           : 0;
   Nullability nullability = helper_->ReadNullability();
-  if (apply_legacy_erasure_) {
+  if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
     nullability = Nullability::kLegacy;
   }
   FunctionType& signature = FunctionType::ZoneHandle(
@@ -3120,8 +3120,7 @@
       const uint8_t flags = helper_->ReadFlags();  // read flags
       signature.SetParameterTypeAt(pos, result_);
       signature.SetParameterNameAt(pos, name);
-      if (!apply_legacy_erasure_ &&
-          (flags & static_cast<uint8_t>(NamedTypeFlags::kIsRequired)) != 0) {
+      if ((flags & static_cast<uint8_t>(NamedTypeFlags::kIsRequired)) != 0) {
         signature.SetIsRequiredAt(pos);
       }
     }
@@ -3146,7 +3145,7 @@
 
 void TypeTranslator::BuildTypeParameterType() {
   Nullability nullability = helper_->ReadNullability();
-  if (apply_legacy_erasure_) {
+  if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
     nullability = Nullability::kLegacy;
   }
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 52454ac..044e034 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -1330,7 +1330,7 @@
     return member->IsFactory();
   }
 
-  bool RequireLegacyErasure(bool null_safety) const {
+  bool RequireConstCanonicalTypeErasure(bool null_safety) const {
     return klass != nullptr && !null_safety &&
            Library::Handle(klass->library()).nnbd_compiled_mode() ==
                NNBDCompiledMode::kAgnostic;
@@ -1459,7 +1459,7 @@
                  ConstantReader* constant_reader,
                  ActiveClass* active_class,
                  bool finalize = false,
-                 bool apply_legacy_erasure = false);
+                 bool apply_canonical_type_erasure = false);
 
   AbstractType& BuildType();
   AbstractType& BuildTypeWithoutFinalization();
@@ -1533,7 +1533,7 @@
   Zone* zone_;
   AbstractType& result_;
   bool finalize_;
-  const bool apply_legacy_erasure_;
+  const bool apply_canonical_type_erasure_;
 
   friend class ScopeBuilder;
   friend class KernelLoader;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index dfa5bba..129d71f 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5828,38 +5828,29 @@
   set.Release();
 }
 
-bool Class::RequireLegacyErasureOfConstants(Zone* zone) const {
+bool Class::RequireCanonicalTypeErasureOfConstants(Zone* zone) const {
   const intptr_t num_type_params = NumTypeParameters();
   const intptr_t num_type_args = NumTypeArguments();
   const intptr_t from_index = num_type_args - num_type_params;
   Instance& constant = Instance::Handle(zone);
   TypeArguments& type_arguments = TypeArguments::Handle(zone);
-  AbstractType& type = AbstractType::Handle(zone);
   CanonicalInstancesSet set(zone, constants());
   CanonicalInstancesSet::Iterator it(&set);
+  bool result = false;
   while (it.MoveNext()) {
     constant ^= set.GetKey(it.Current());
     ASSERT(!constant.IsNull());
     ASSERT(!constant.IsTypeArguments());
     ASSERT(!constant.IsType());
     type_arguments = constant.GetTypeArguments();
-    if (type_arguments.IsNull()) {
-      continue;
-    }
-    for (intptr_t i = 0; i < num_type_params; i++) {
-      type = type_arguments.TypeAt(from_index + i);
-      if (!type.IsLegacy() && !type.IsVoidType() && !type.IsDynamicType() &&
-          !type.IsNullType()) {
-        set.Release();
-        return true;
-      }
-      // It is not possible for a legacy type to have non-legacy type
-      // arguments or for a legacy function type to have non-legacy parameter
-      // types, non-legacy type parameters, or required named parameters.
+    if (type_arguments.RequireConstCanonicalTypeErasure(zone, from_index,
+                                                        num_type_params)) {
+      result = true;
+      break;
     }
   }
   set.Release();
-  return false;
+  return result;
 }
 
 intptr_t TypeArguments::ComputeNullability() const {
@@ -6067,6 +6058,27 @@
   return false;
 }
 
+bool TypeArguments::RequireConstCanonicalTypeErasure(Zone* zone,
+                                                     intptr_t from_index,
+                                                     intptr_t len,
+                                                     TrailPtr trail) const {
+  if (IsNull()) return false;
+  ASSERT(Length() >= (from_index + len));
+  AbstractType& type = AbstractType::Handle(zone);
+  for (intptr_t i = 0; i < len; i++) {
+    type = TypeAt(from_index + i);
+    if (type.IsNonNullable() ||
+        (type.IsNullable() &&
+         type.RequireConstCanonicalTypeErasure(zone, trail))) {
+      // It is not possible for a legacy type to have non-nullable type
+      // arguments or for a legacy function type to have non-nullable type in
+      // its signature.
+      return true;
+    }
+  }
+  return false;
+}
+
 bool TypeArguments::IsDynamicTypes(bool raw_instantiated,
                                    intptr_t from_index,
                                    intptr_t len) const {
@@ -19060,6 +19072,13 @@
   return false;
 }
 
+bool AbstractType::RequireConstCanonicalTypeErasure(Zone* zone,
+                                                    TrailPtr trail) const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+  return false;
+}
+
 AbstractTypePtr AbstractType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
@@ -20059,6 +20078,24 @@
   return TypeArguments::Handle(arguments()).IsRecursive(trail);
 }
 
+bool Type::RequireConstCanonicalTypeErasure(Zone* zone, TrailPtr trail) const {
+  if (IsNonNullable()) {
+    return true;
+  }
+  if (IsLegacy()) {
+    // It is not possible for a legacy type parameter to have a non-nullable
+    // bound or non-nullable default argument.
+    return false;
+  }
+  const Class& cls = Class::Handle(zone, type_class());
+  const intptr_t num_type_params = cls.NumTypeParameters();
+  const intptr_t num_type_args = cls.NumTypeArguments();
+  const intptr_t from_index = num_type_args - num_type_params;
+  return TypeArguments::Handle(zone, arguments())
+      .RequireConstCanonicalTypeErasure(zone, from_index, num_type_params,
+                                        trail);
+}
+
 bool Type::IsDeclarationTypeOf(const Class& cls) const {
   ASSERT(type_class() == cls.raw());
   if (cls.IsNullClass()) {
@@ -20413,6 +20450,47 @@
   return false;
 }
 
+bool FunctionType::RequireConstCanonicalTypeErasure(Zone* zone,
+                                                    TrailPtr trail) const {
+  if (IsNonNullable()) {
+    return true;
+  }
+  if (IsLegacy()) {
+    // It is not possible for a function type to have a non-nullable type in
+    // its signature.
+    return false;
+  }
+  AbstractType& type = AbstractType::Handle(zone);
+  const intptr_t num_type_params = NumTypeParameters();
+  if (num_type_params > 0) {
+    const TypeArguments& type_params = TypeArguments::Handle(type_parameters());
+    TypeParameter& type_param = TypeParameter::Handle(zone);
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type_param ^= type_params.TypeAt(i);
+      type = type_param.bound();
+      if (type.RequireConstCanonicalTypeErasure(zone, trail)) {
+        return true;
+      }
+      type = type_param.default_argument();
+      if (type.RequireConstCanonicalTypeErasure(zone, trail)) {
+        return true;
+      }
+    }
+  }
+  type = result_type();
+  if (type.RequireConstCanonicalTypeErasure(zone, trail)) {
+    return true;
+  }
+  const intptr_t num_params = NumParameters();
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = ParameterTypeAt(i);
+    if (type.RequireConstCanonicalTypeErasure(zone, trail)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 AbstractTypePtr FunctionType::Canonicalize(Thread* thread,
                                            TrailPtr trail) const {
   ASSERT(IsFinalized());
@@ -20552,6 +20630,16 @@
   type.EnumerateURIs(uris);
 }
 
+bool TypeRef::RequireConstCanonicalTypeErasure(Zone* zone,
+                                               TrailPtr trail) const {
+  if (TestAndAddToTrail(&trail)) {
+    return false;
+  }
+  const AbstractType& ref_type = AbstractType::Handle(zone, type());
+  return !ref_type.IsNull() &&
+         ref_type.RequireConstCanonicalTypeErasure(zone, trail);
+}
+
 bool TypeRef::IsInstantiated(Genericity genericity,
                              intptr_t num_free_fun_type_params,
                              TrailPtr trail) const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 1b8150e..ec29673 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1328,7 +1328,7 @@
 
   void RehashConstants(Zone* zone) const;
 
-  bool RequireLegacyErasureOfConstants(Zone* zone) const;
+  bool RequireCanonicalTypeErasureOfConstants(Zone* zone) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(ClassLayout));
@@ -7404,6 +7404,15 @@
     return IsDynamicTypes(true, 0, len);
   }
 
+  // Return true if this vector contains a TypeRef.
+  bool IsRecursive(TrailPtr trail = nullptr) const;
+
+  // Return true if this vector contains a non-nullable type.
+  bool RequireConstCanonicalTypeErasure(Zone* zone,
+                                        intptr_t from_index,
+                                        intptr_t len,
+                                        TrailPtr trail = nullptr) const;
+
   TypeArgumentsPtr Prepend(Zone* zone,
                            const TypeArguments& other,
                            intptr_t other_length,
@@ -7461,9 +7470,6 @@
   // Return true if all types of this vector are finalized.
   bool IsFinalized() const;
 
-  // Return true if this vector contains a recursive type argument.
-  bool IsRecursive(TrailPtr trail = nullptr) const;
-
   // Caller must hold Isolate::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const {
     return Canonicalize(thread, nullptr);
@@ -7633,6 +7639,8 @@
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
   virtual bool IsRecursive(TrailPtr trail = nullptr) const;
+  virtual bool RequireConstCanonicalTypeErasure(Zone* zone,
+                                                TrailPtr trail = nullptr) const;
 
   // Instantiate this type using the given type argument vectors.
   //
@@ -7890,6 +7898,8 @@
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
   virtual bool IsRecursive(TrailPtr trail = nullptr) const;
+  virtual bool RequireConstCanonicalTypeErasure(Zone* zone,
+                                                TrailPtr trail = nullptr) const;
 
   // Return true if this type can be used as the declaration type of cls after
   // canonicalization (passed-in cls must match type_class()).
@@ -8034,6 +8044,8 @@
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
   virtual bool IsRecursive(TrailPtr trail = nullptr) const;
+  virtual bool RequireConstCanonicalTypeErasure(Zone* zone,
+                                                TrailPtr trail = nullptr) const;
 
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
@@ -8277,6 +8289,8 @@
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
   virtual bool IsRecursive(TrailPtr trail = nullptr) const { return true; }
+  virtual bool RequireConstCanonicalTypeErasure(Zone* zone,
+                                                TrailPtr trail = nullptr) const;
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
@@ -8386,6 +8400,11 @@
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
   virtual bool IsRecursive(TrailPtr trail = nullptr) const;
+  virtual bool RequireConstCanonicalTypeErasure(
+      Zone* zone,
+      TrailPtr trail = nullptr) const {
+    return IsNonNullable();
+  }
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index e5b845a..a660f5c 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -2064,7 +2064,8 @@
     Type& type = Type::Handle();
     type ^= Api::UnwrapHandle(cls);  // Dart_GetClass actually returns a Type.
     const Class& clazz = Class::Handle(type.type_class());
-    const bool required = clazz.RequireLegacyErasureOfConstants(zone.GetZone());
+    const bool required =
+        clazz.RequireCanonicalTypeErasureOfConstants(zone.GetZone());
     EXPECT(required == isolate->group()->null_safety());
 
     // Verify that snapshot writing succeeds if erasure is not required.
diff --git a/samples/ffi/async/sample_async_callback.dart b/samples/ffi/async/sample_async_callback.dart
index 59ae31b..4901c55 100644
--- a/samples/ffi/async/sample_async_callback.dart
+++ b/samples/ffi/async/sample_async_callback.dart
@@ -105,7 +105,7 @@
 final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
     void Function(Pointer<Work>)>('ExecuteCallback');
 
-class Work extends Struct {}
+class Work extends Opaque {}
 
 Future asyncSleep(int ms) {
   return new Future.delayed(Duration(milliseconds: ms));
diff --git a/samples/ffi/calloc.dart b/samples/ffi/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/samples/ffi/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/samples/ffi/coordinate.dart b/samples/ffi/coordinate.dart
index 8a54ba9..01f8ec3 100644
--- a/samples/ffi/coordinate.dart
+++ b/samples/ffi/coordinate.dart
@@ -16,8 +16,9 @@
 
   external Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/samples/ffi/resource_management/pool.dart b/samples/ffi/resource_management/pool.dart
index 7064f9f..3bc0e2a 100644
--- a/samples/ffi/resource_management/pool.dart
+++ b/samples/ffi/resource_management/pool.dart
@@ -5,48 +5,36 @@
 // Explicit pool used for managing resources.
 
 import "dart:async";
-import 'dart:convert';
 import 'dart:ffi';
-import 'dart:typed_data';
 
-import 'package:ffi/ffi.dart' as packageFfi;
-import 'package:ffi/ffi.dart' show Utf8;
+import 'package:ffi/ffi.dart';
 
-/// Manages native resources.
+import '../calloc.dart';
+
+/// Keeps track of all allocated memory and frees all allocated memory on
+/// [releaseAll].
 ///
-/// Primary implementations are [Pool] and [Unmanaged].
-abstract class ResourceManager {
-  /// Allocates memory on the native heap.
-  ///
-  /// The native memory is under management by this [ResourceManager].
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count: 1});
-}
+/// Wraps an [Allocator] to do the actual allocation and freeing.
+class Pool implements Allocator {
+  /// The [Allocator] used for allocation and freeing.
+  final Allocator _wrappedAllocator;
 
-/// Manages native resources.
-class Pool implements ResourceManager {
+  Pool(this._wrappedAllocator);
+
   /// Native memory under management by this [Pool].
   final List<Pointer<NativeType>> _managedMemoryPointers = [];
 
   /// Callbacks for releasing native resources under management by this [Pool].
   final List<Function()> _managedResourceReleaseCallbacks = [];
 
-  /// Allocates memory on the native heap.
+  /// Allocates memory on the native heap by using the allocator supplied to
+  /// the constructor.
   ///
-  /// The native memory is under management by this [Pool].
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count: 1}) {
-    final p = Unmanaged().allocate<T>(count: count);
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int numBytes, {int? alignment}) {
+    final p = _wrappedAllocator.allocate<T>(numBytes, alignment: alignment);
     _managedMemoryPointers.add(p);
     return p;
   }
@@ -71,17 +59,21 @@
     }
     _managedResourceReleaseCallbacks.clear();
     for (final p in _managedMemoryPointers) {
-      Unmanaged().free(p);
+      _wrappedAllocator.free(p);
     }
     _managedMemoryPointers.clear();
   }
+
+  @override
+  void free(Pointer<NativeType> pointer) => throw UnsupportedError(
+      "Individually freeing Pool allocated memory is not allowed");
 }
 
 /// Creates a [Pool] to manage native resources.
 ///
 /// If the isolate is shut down, through `Isolate.kill()`, resources are _not_ cleaned up.
-R using<R>(R Function(Pool) f) {
-  final p = Pool();
+R using<R>(R Function(Pool) f, [Allocator wrappedAllocator = calloc]) {
+  final p = Pool(wrappedAllocator);
   try {
     return f(p);
   } finally {
@@ -96,8 +88,8 @@
 /// Please note that all throws are caught and packaged in [RethrownError].
 ///
 /// If the isolate is shut down, through `Isolate.kill()`, resources are _not_ cleaned up.
-R usePool<R>(R Function() f) {
-  final p = Pool();
+R usePool<R>(R Function() f, [Allocator wrappedAllocator = calloc]) {
+  final p = Pool(wrappedAllocator);
   try {
     return runZoned(() => f(),
         zoneValues: {#_pool: p},
@@ -117,78 +109,3 @@
   toString() => """RethrownError(${original})
 ${originalStackTrace}""";
 }
-
-/// Does not manage it's resources.
-class Unmanaged implements ResourceManager {
-  /// Allocates memory on the native heap.
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count = 1}) =>
-      packageFfi.allocate(count: count);
-
-  /// Releases memory on the native heap.
-  ///
-  /// For POSIX-based systems, this uses free. On Windows, it uses HeapFree
-  /// against the default public heap. It may only be used against pointers
-  /// allocated in a manner equivalent to [allocate].
-  ///
-  /// Throws an ArgumentError on failure to free.
-  ///
-  void free(Pointer pointer) => packageFfi.free(pointer);
-}
-
-/// Does not manage it's resources.
-final Unmanaged unmanaged = Unmanaged();
-
-extension Utf8InPool on String {
-  /// Convert a [String] to a Utf8-encoded null-terminated C string.
-  ///
-  /// If 'string' contains NULL bytes, the converted string will be truncated
-  /// prematurely. Unpaired surrogate code points in [string] will be preserved
-  /// in the UTF-8 encoded result. See [Utf8Encoder] for details on encoding.
-  ///
-  /// Returns a malloc-allocated pointer to the result.
-  ///
-  /// The memory is managed by the [Pool] passed in as [pool].
-  Pointer<Utf8> toUtf8(ResourceManager pool) {
-    final units = utf8.encode(this);
-    final Pointer<Uint8> result = pool.allocate<Uint8>(count: units.length + 1);
-    final Uint8List nativeString = result.asTypedList(units.length + 1);
-    nativeString.setAll(0, units);
-    nativeString[units.length] = 0;
-    return result.cast();
-  }
-}
-
-extension Utf8Helpers on Pointer<Utf8> {
-  /// Returns the length of a null-terminated string -- the number of (one-byte)
-  /// characters before the first null byte.
-  int strlen() {
-    final Pointer<Uint8> array = this.cast<Uint8>();
-    final Uint8List nativeString = array.asTypedList(_maxSize);
-    return nativeString.indexWhere((char) => char == 0);
-  }
-
-  /// Creates a [String] containing the characters UTF-8 encoded in [this].
-  ///
-  /// [this] must be a zero-terminated byte sequence of valid UTF-8
-  /// encodings of Unicode code points. It may also contain UTF-8 encodings of
-  /// unpaired surrogate code points, which is not otherwise valid UTF-8, but
-  /// which may be created when encoding a Dart string containing an unpaired
-  /// surrogate. See [Utf8Decoder] for details on decoding.
-  ///
-  /// Returns a Dart string containing the decoded code points.
-  String contents() {
-    final int length = strlen();
-    return utf8.decode(Uint8List.view(
-        this.cast<Uint8>().asTypedList(length).buffer, 0, length));
-  }
-}
-
-const int _kMaxSmi64 = (1 << 62) - 1;
-const int _kMaxSmi32 = (1 << 30) - 1;
-final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
diff --git a/samples/ffi/resource_management/pool_isolate_shutdown_sample.dart b/samples/ffi/resource_management/pool_isolate_shutdown_sample.dart
index cab2cb0..39de01d 100644
--- a/samples/ffi/resource_management/pool_isolate_shutdown_sample.dart
+++ b/samples/ffi/resource_management/pool_isolate_shutdown_sample.dart
@@ -86,4 +86,4 @@
     void Function(Pointer<SomeResource>)>("ReleaseResource");
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples/ffi/resource_management/pool_sample.dart b/samples/ffi/resource_management/pool_sample.dart
index 00ee1ae..ef8b415 100644
--- a/samples/ffi/resource_management/pool_sample.dart
+++ b/samples/ffi/resource_management/pool_sample.dart
@@ -9,6 +9,7 @@
 import 'package:expect/expect.dart';
 
 import 'pool.dart';
+import 'utf8_helpers.dart';
 import '../dylib_utils.dart';
 
 main() {
@@ -21,7 +22,7 @@
 
   // To ensure resources are freed, wrap them in a [using] call.
   using((Pool pool) {
-    final p = pool.allocate<Int64>(count: 2);
+    final p = pool<Int64>(2);
     p[0] = 24;
     MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
     print(p[1]);
@@ -31,14 +32,14 @@
   // Resources are freed also when abnormal control flow occurs.
   try {
     using((Pool pool) {
-      final p = pool.allocate<Int64>(count: 2);
+      final p = pool<Int64>(2);
       p[0] = 25;
       MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), 8);
       print(p[1]);
       Expect.equals(25, p[1]);
       throw Exception("Some random exception");
     });
-    // `free(p)` has been called.
+    // `calloc.free(p)` has been called.
   } on Exception catch (e) {
     print("Caught exception: $e");
   }
@@ -46,8 +47,8 @@
   // In a pool multiple resources can be allocated, which will all be freed
   // at the end of the scope.
   using((Pool pool) {
-    final p = pool.allocate<Int64>(count: 2);
-    final p2 = pool.allocate<Int64>(count: 2);
+    final p = pool<Int64>(2);
+    final p2 = pool<Int64>(2);
     p[0] = 1;
     p[1] = 2;
     MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
@@ -58,7 +59,7 @@
   // If the resource allocation happens in a different scope, then one either
   // needs to pass the pool to that scope.
   f1(Pool pool) {
-    return pool.allocate<Int64>(count: 2);
+    return pool<Int64>(2);
   }
 
   using((Pool pool) {
@@ -110,4 +111,4 @@
 }
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples/ffi/resource_management/pool_zoned_sample.dart b/samples/ffi/resource_management/pool_zoned_sample.dart
index 05f1794..4c99fdc 100644
--- a/samples/ffi/resource_management/pool_zoned_sample.dart
+++ b/samples/ffi/resource_management/pool_zoned_sample.dart
@@ -9,6 +9,7 @@
 import 'package:expect/expect.dart';
 
 import 'pool.dart';
+import 'utf8_helpers.dart';
 import '../dylib_utils.dart';
 
 main() {
@@ -21,7 +22,7 @@
 
   // To ensure resources are freed, wrap them in a [using] call.
   usePool(() {
-    final p = currentPool.allocate<Int64>(count: 2);
+    final p = currentPool<Int64>(2);
     p[0] = 24;
     MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
     print(p[1]);
@@ -31,7 +32,7 @@
   // Resources are freed also when abnormal control flow occurs.
   try {
     usePool(() {
-      final p = currentPool.allocate<Int64>(count: 2);
+      final p = currentPool<Int64>(2);
       p[0] = 25;
       MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), 8);
       print(p[1]);
@@ -46,8 +47,8 @@
   // In a pool multiple resources can be allocated, which will all be freed
   // at the end of the scope.
   usePool(() {
-    final p = currentPool.allocate<Int64>(count: 2);
-    final p2 = currentPool.allocate<Int64>(count: 2);
+    final p = currentPool<Int64>(2);
+    final p2 = currentPool<Int64>(2);
     p[0] = 1;
     p[1] = 2;
     MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
@@ -58,7 +59,7 @@
   // If the resource allocation happens in a different scope, it is in the
   // same zone, so it's lifetime is automatically managed by the pool.
   f1() {
-    return currentPool.allocate<Int64>(count: 2);
+    return currentPool<Int64>(2);
   }
 
   usePool(() {
@@ -111,4 +112,4 @@
 }
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples/ffi/resource_management/unmanaged_sample.dart b/samples/ffi/resource_management/unmanaged_sample.dart
index 9c3e0f0..04c20cb 100644
--- a/samples/ffi/resource_management/unmanaged_sample.dart
+++ b/samples/ffi/resource_management/unmanaged_sample.dart
@@ -7,30 +7,32 @@
 import 'dart:ffi';
 
 import 'package:expect/expect.dart';
+import 'package:ffi/ffi.dart';
 
-import 'pool.dart';
+import 'utf8_helpers.dart';
+import '../calloc.dart';
 import '../dylib_utils.dart';
 
 main() {
   final ffiTestDynamicLibrary =
       dlopenPlatformSpecific("ffi_test_dynamic_library");
 
-  final MemMove = ffiTestDynamicLibrary.lookupFunction<
+  final memMove = ffiTestDynamicLibrary.lookupFunction<
       Void Function(Pointer<Void>, Pointer<Void>, IntPtr),
       void Function(Pointer<Void>, Pointer<Void>, int)>("MemMove");
 
   // To ensure resources are freed, call free manually.
   //
   // For automatic management use a Pool.
-  final p = unmanaged.allocate<Int64>(count: 2);
+  final p = calloc<Int64>(2);
   p[0] = 24;
-  MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
+  memMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
   print(p[1]);
   Expect.equals(24, p[1]);
-  unmanaged.free(p);
+  calloc.free(p);
 
   // Using Strings.
-  final p2 = "Hello world!".toUtf8(unmanaged);
+  final p2 = "Hello world!".toUtf8(calloc);
   print(p2.contents());
-  unmanaged.free(p2);
+  calloc.free(p2);
 }
diff --git a/samples/ffi/resource_management/utf8_helpers.dart b/samples/ffi/resource_management/utf8_helpers.dart
new file mode 100644
index 0000000..ed7b4a1
--- /dev/null
+++ b/samples/ffi/resource_management/utf8_helpers.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:ffi';
+import 'dart:typed_data';
+
+import 'package:ffi/ffi.dart';
+
+extension Utf8InPool on String {
+  /// Convert a [String] to a Utf8-encoded null-terminated C string.
+  ///
+  /// If 'string' contains NULL bytes, the converted string will be truncated
+  /// prematurely. See [Utf8Encoder] for details on encoding.
+  ///
+  /// Returns a [allocator]-allocated pointer to the result.
+  Pointer<Utf8> toUtf8(Allocator allocator) {
+    final units = utf8.encode(this);
+    final Pointer<Uint8> result = allocator<Uint8>(units.length + 1);
+    final Uint8List nativeString = result.asTypedList(units.length + 1);
+    nativeString.setAll(0, units);
+    nativeString[units.length] = 0;
+    return result.cast();
+  }
+}
+
+extension Utf8Helpers on Pointer<Utf8> {
+  /// The length of a null-terminated string — the number of (one-byte)
+  /// characters before the first null byte.
+  int get strlen {
+    final Pointer<Uint8> array = this.cast<Uint8>();
+    final Uint8List nativeString = array.asTypedList(_maxSize);
+    return nativeString.indexWhere((char) => char == 0);
+  }
+
+  /// Creates a [String] containing the characters UTF-8 encoded in [this].
+  ///
+  /// [this] must be a zero-terminated byte sequence of valid UTF-8
+  /// encodings of Unicode code points. See [Utf8Decoder] for details on
+  /// decoding.
+  ///
+  /// Returns a Dart string containing the decoded code points.
+  String contents() {
+    final int length = strlen;
+    return utf8.decode(Uint8List.view(
+        this.cast<Uint8>().asTypedList(length).buffer, 0, length));
+  }
+}
+
+const int _kMaxSmi64 = (1 << 62) - 1;
+const int _kMaxSmi32 = (1 << 30) - 1;
+final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
diff --git a/samples/ffi/sample_ffi_bitfield.dart b/samples/ffi/sample_ffi_bitfield.dart
index cc10a2d..67ce69e 100644
--- a/samples/ffi/sample_ffi_bitfield.dart
+++ b/samples/ffi/sample_ffi_bitfield.dart
@@ -7,6 +7,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:expect/expect.dart';
 
+import 'calloc.dart';
+
 /// typedef struct {
 ///     unsigned int bold      : 1;
 ///     unsigned int underline : 2;
@@ -93,7 +95,7 @@
 }
 
 main() {
-  final p = allocate<ScreenCellAttrs>(count: 3);
+  final p = calloc<ScreenCellAttrs>(3);
 
   // Zeroes out all fields.
   p.ref.bits = 0;
@@ -119,5 +121,5 @@
   // A check for automated testing.
   Expect.equals(1933, p.ref.bits);
 
-  free(p);
+  calloc.free(p);
 }
diff --git a/samples/ffi/sample_ffi_data.dart b/samples/ffi/sample_ffi_data.dart
index 8e713d0..e5b0497 100644
--- a/samples/ffi/sample_ffi_data.dart
+++ b/samples/ffi/sample_ffi_data.dart
@@ -5,29 +5,31 @@
 import 'dart:ffi';
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
+
 main() {
   print('start main');
 
   {
     // Basic operation: allocate, get, set, and free.
-    Pointer<Int64> p = allocate();
+    Pointer<Int64> p = calloc();
     p.value = 42;
     int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Undefined behavior before set.
-    Pointer<Int64> p = allocate();
+    Pointer<Int64> p = calloc();
     int pValue = p.value;
     print('If not set, returns garbage: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Pointers can be created from an address.
-    Pointer<Int64> pHelper = allocate();
+    Pointer<Int64> pHelper = calloc();
     pHelper.value = 1337;
 
     int address = pHelper.address;
@@ -36,13 +38,13 @@
     Pointer<Int64> p = Pointer.fromAddress(address);
     print('${p.runtimeType} value: ${p.value}');
 
-    free(pHelper);
+    calloc.free(pHelper);
   }
 
   {
     // Address is zeroed out after free.
-    Pointer<Int64> p = allocate();
-    free(p);
+    Pointer<Int64> p = calloc();
+    calloc.free(p);
     print('After free, address is zero: ${p.address}');
   }
 
@@ -50,13 +52,13 @@
     // Allocating too much throws an exception.
     try {
       int maxMint = 9223372036854775807; // 2^63 - 1
-      allocate<Int64>(count: maxMint);
+      calloc<Int64>(maxMint);
     } on Error {
       print('Expected exception on allocating too much');
     }
     try {
       int maxInt1_8 = 1152921504606846975; // 2^60 -1
-      allocate<Int64>(count: maxInt1_8);
+      calloc<Int64>(maxInt1_8);
     } on Error {
       print('Expected exception on allocating too much');
     }
@@ -65,7 +67,7 @@
   {
     // Pointers can be cast into another type,
     // resulting in the corresponding bits read.
-    Pointer<Int64> p1 = allocate();
+    Pointer<Int64> p1 = calloc();
     p1.value = 9223372036854775807; // 2^63 - 1
 
     Pointer<Int32> p2 = p1.cast();
@@ -74,61 +76,61 @@
     Pointer<Int32> p3 = p2.elementAt(1);
     print('${p3.runtimeType} value: ${p3.value}'); // 2^31 - 1
 
-    free(p1);
+    calloc.free(p1);
   }
 
   {
     // Data can be tightly packed in memory.
-    Pointer<Int8> p = allocate(count: 8);
+    Pointer<Int8> p = calloc(8);
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
       p.elementAt(i).value = i * 3;
     }
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
       print('p.elementAt($i) value: ${p.elementAt(i).value}');
     }
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Values that don't fit are truncated.
-    Pointer<Int32> p11 = allocate();
+    Pointer<Int32> p11 = calloc();
 
     p11.value = 9223372036854775807;
 
     print(p11);
 
-    free(p11);
+    calloc.free(p11);
   }
 
   {
     // Doubles.
-    Pointer<Double> p = allocate();
+    Pointer<Double> p = calloc();
     p.value = 3.14159265359;
     print('${p.runtimeType} value: ${p.value}');
     p.value = 3.14;
     print('${p.runtimeType} value: ${p.value}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Floats.
-    Pointer<Float> p = allocate();
+    Pointer<Float> p = calloc();
     p.value = 3.14159265359;
     print('${p.runtimeType} value: ${p.value}');
     p.value = 3.14;
     print('${p.runtimeType} value: ${p.value}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // IntPtr varies in size based on whether the platform is 32 or 64 bit.
     // Addresses of pointers fit in this size.
-    Pointer<IntPtr> p = allocate();
+    Pointer<IntPtr> p = calloc();
     int p14addr = p.address;
     p.value = p14addr;
     int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
@@ -136,19 +138,19 @@
     // The size of the element it is pointing to is undefined,
     // they cannot be allocated, read, or written.
 
-    Pointer<IntPtr> p1 = allocate();
+    Pointer<IntPtr> p1 = calloc();
     Pointer<Void> p2 = p1.cast();
     print('${p2.runtimeType} address: ${p2.address}');
 
-    free(p1);
+    calloc.free(p1);
   }
 
   {
     // Pointer to a pointer to something.
-    Pointer<Int16> pHelper = allocate();
+    Pointer<Int16> pHelper = calloc();
     pHelper.value = 17;
 
-    Pointer<Pointer<Int16>> p = allocate();
+    Pointer<Pointer<Int16>> p = calloc();
 
     // Storing into a pointer pointer automatically unboxes.
     p.value = pHelper;
@@ -160,31 +162,31 @@
     int pValue = p.value.value;
     print('${p.runtimeType} value\'s value: ${pValue}');
 
-    free(p);
-    free(pHelper);
+    calloc.free(p);
+    calloc.free(pHelper);
   }
 
   {
     // The pointer to pointer types must match up.
-    Pointer<Int8> pHelper = allocate();
+    Pointer<Int8> pHelper = calloc();
     pHelper.value = 123;
 
-    Pointer<Pointer<Int16>> p = allocate();
+    Pointer<Pointer<Int16>> p = calloc();
 
     // Trying to store `pHelper` into `p.val` would result in a type mismatch.
 
-    free(pHelper);
-    free(p);
+    calloc.free(pHelper);
+    calloc.free(p);
   }
 
   {
     // `nullptr` points to address 0 in c++.
-    Pointer<Pointer<Int8>> pointerToPointer = allocate();
+    Pointer<Pointer<Int8>> pointerToPointer = calloc();
     Pointer<Int8> value = nullptr;
     pointerToPointer.value = value;
     value = pointerToPointer.value;
     print("Loading a pointer to the 0 address is null: ${value}");
-    free(pointerToPointer);
+    calloc.free(pointerToPointer);
   }
 
   {
@@ -205,7 +207,7 @@
         head.value = value;
         return;
       }
-      Pointer<IntPtr> next = allocate<IntPtr>();
+      Pointer<IntPtr> next = calloc<IntPtr>();
       head.value = next.address;
       createChain(next, length - 1, value);
     }
@@ -220,7 +222,7 @@
 
     void freeChain(Pointer<IntPtr> head, int length) {
       Pointer<IntPtr> next = Pointer.fromAddress(head.value);
-      free(head);
+      calloc.free(head);
       if (length == 0) {
         return;
       }
@@ -228,7 +230,7 @@
     }
 
     int length = 10;
-    Pointer<IntPtr> head = allocate();
+    Pointer<IntPtr> head = calloc();
     createChain(head, length, 512);
     int tailValue = getChainValue(head, length);
     print('tailValue: ${tailValue}');
diff --git a/samples/ffi/sample_ffi_functions.dart b/samples/ffi/sample_ffi_functions.dart
index bff74eb..5038ba8 100644
--- a/samples/ffi/sample_ffi_functions.dart
+++ b/samples/ffi/sample_ffi_functions.dart
@@ -6,6 +6,7 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 typedef NativeUnaryOp = Int32 Function(Int32);
@@ -184,7 +185,7 @@
     // pass an array / pointer as argument
     Int64PointerUnOp assign1337Index1 = ffiTestFunctions
         .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
-    Pointer<Int64> p2 = allocate(count: 2);
+    Pointer<Int64> p2 = calloc(2);
     p2.value = 42;
     p2[1] = 1000;
     print(p2.elementAt(1).address.toRadixString(16));
@@ -209,11 +210,11 @@
     print(result);
     print(result.runtimeType);
 
-    Pointer<Int64> p2 = allocate(count: 2);
+    Pointer<Int64> p2 = calloc(2);
     result = nullableInt64ElemAt1(p2);
     print(result);
     print(result.runtimeType);
-    free(p2);
+    calloc.free(p2);
   }
 
   print("end main");
diff --git a/samples/ffi/sample_ffi_functions_callbacks.dart b/samples/ffi/sample_ffi_functions_callbacks.dart
index affdcef..de6d05a 100644
--- a/samples/ffi/sample_ffi_functions_callbacks.dart
+++ b/samples/ffi/sample_ffi_functions_callbacks.dart
@@ -4,6 +4,9 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
+
+import 'calloc.dart';
 import 'coordinate.dart';
 import 'dylib_utils.dart';
 
@@ -43,7 +46,7 @@
     Pointer<NativeFunction<CoordinateTrice>> p2 =
         ffiTestFunctions.lookup("CoordinateUnOpTrice");
     CoordinateTrice coordinateUnOpTrice = p2.asFunction();
-    Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 20.0, nullptr);
     c1.next = c1.addressOf;
     Coordinate result =
         coordinateUnOpTrice(transposeCoordinatePointer, c1.addressOf).ref;
diff --git a/samples/ffi/sample_ffi_functions_structs.dart b/samples/ffi/sample_ffi_functions_structs.dart
index 9aefb57..9185040 100644
--- a/samples/ffi/sample_ffi_functions_structs.dart
+++ b/samples/ffi/sample_ffi_functions_structs.dart
@@ -4,11 +4,12 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
+
+import 'calloc.dart';
 import 'coordinate.dart';
 import 'dylib_utils.dart';
 
-import 'package:ffi/ffi.dart';
-
 typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
 
 main() {
@@ -23,8 +24,8 @@
         ffiTestFunctions.lookup("TransposeCoordinate");
     NativeCoordinateOp f1 = p1.asFunction();
 
-    Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
-    Coordinate c2 = Coordinate.allocate(42.0, 84.0, c1.addressOf);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 20.0, nullptr);
+    Coordinate c2 = Coordinate.allocate(calloc, 42.0, 84.0, c1.addressOf);
     c1.next = c2.addressOf;
 
     Coordinate result = f1(c1.addressOf).ref;
@@ -44,7 +45,7 @@
         ffiTestFunctions.lookup("CoordinateElemAt1");
     NativeCoordinateOp f1 = p1.asFunction();
 
-    Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
+    Pointer<Coordinate> c1 = calloc<Coordinate>(3);
     Pointer<Coordinate> c2 = c1.elementAt(1);
     Pointer<Coordinate> c3 = c1.elementAt(2);
     c1.ref.x = 10.0;
diff --git a/samples/ffi/sample_ffi_structs.dart b/samples/ffi/sample_ffi_structs.dart
index bd6d7c7..f6de82c 100644
--- a/samples/ffi/sample_ffi_structs.dart
+++ b/samples/ffi/sample_ffi_structs.dart
@@ -6,6 +6,7 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'coordinate.dart';
 
 main() {
@@ -13,9 +14,9 @@
 
   {
     // Allocates each coordinate separately in c memory.
-    Coordinate c1 = Coordinate.allocate(10.0, 10.0, nullptr);
-    Coordinate c2 = Coordinate.allocate(20.0, 20.0, c1.addressOf);
-    Coordinate c3 = Coordinate.allocate(30.0, 30.0, c2.addressOf);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 10.0, nullptr);
+    Coordinate c2 = Coordinate.allocate(calloc, 20.0, 20.0, c1.addressOf);
+    Coordinate c3 = Coordinate.allocate(calloc, 30.0, 30.0, c2.addressOf);
     c1.next = c3.addressOf;
 
     Coordinate currentCoordinate = c1;
@@ -24,14 +25,14 @@
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    free(c1.addressOf);
-    free(c2.addressOf);
-    free(c3.addressOf);
+    calloc.free(c1.addressOf);
+    calloc.free(c2.addressOf);
+    calloc.free(c3.addressOf);
   }
 
   {
     // Allocates coordinates consecutively in c memory.
-    Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
+    Pointer<Coordinate> c1 = calloc<Coordinate>(3);
     Pointer<Coordinate> c2 = c1.elementAt(1);
     Pointer<Coordinate> c3 = c1.elementAt(2);
     c1.ref.x = 10.0;
@@ -50,15 +51,15 @@
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    free(c1);
+    calloc.free(c1);
   }
 
   {
-    Coordinate c = Coordinate.allocate(10, 10, nullptr);
+    Coordinate c = Coordinate.allocate(calloc, 10, 10, nullptr);
     print(c is Coordinate);
     print(c is Pointer<Void>);
     print(c is Pointer);
-    free(c.addressOf);
+    calloc.free(c.addressOf);
   }
 
   print("end main");
diff --git a/samples/ffi/sqlite/lib/sqlite.dart b/samples/ffi/sqlite/lib/sqlite.dart
index d6bac5b..1e60f9f 100644
--- a/samples/ffi/sqlite/lib/sqlite.dart
+++ b/samples/ffi/sqlite/lib/sqlite.dart
@@ -8,3 +8,5 @@
 library sqlite;
 
 export "src/database.dart";
+
+export "src/ffi/calloc.dart" show calloc;
diff --git a/samples/ffi/sqlite/lib/src/bindings/types.dart b/samples/ffi/sqlite/lib/src/bindings/types.dart
index 494cdef..40edc87 100644
--- a/samples/ffi/sqlite/lib/src/bindings/types.dart
+++ b/samples/ffi/sqlite/lib/src/bindings/types.dart
@@ -13,7 +13,7 @@
 /// is its destructor.  There are many other interfaces (such as
 /// [sqlite3_prepare_v2()], [sqlite3_create_function()], and
 /// [sqlite3_busy_timeout()] to name but three) that are methods on an
-class Database extends Struct {}
+class Database extends Opaque {}
 
 /// SQL Statement Object
 ///
@@ -36,7 +36,7 @@
 ///
 /// Refer to documentation on individual methods above for additional
 /// information.
-class Statement extends Struct {}
+class Statement extends Opaque {}
 
 /// Dynamically Typed Value Object
 ///
@@ -72,4 +72,4 @@
 /// [sqlite3_result_value()] and [sqlite3_bind_value()].
 /// The [sqlite3_value_blob | sqlite3_value_type()] family of
 /// interfaces require protected sqlite3_value objects.
-class Value extends Struct {}
+class Value extends Opaque {}
diff --git a/samples/ffi/sqlite/lib/src/database.dart b/samples/ffi/sqlite/lib/src/database.dart
index 7725609..59da929 100644
--- a/samples/ffi/sqlite/lib/src/database.dart
+++ b/samples/ffi/sqlite/lib/src/database.dart
@@ -15,6 +15,8 @@
 import "bindings/constants.dart";
 import "collections/closable_iterator.dart";
 
+import 'ffi/calloc.dart';
+
 /// [Database] represents an open connection to a SQLite database.
 ///
 /// All functions against a database may throw [SQLiteError].
@@ -27,13 +29,13 @@
   /// Open a database located at the file [path].
   Database(String path,
       [int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
-    Pointer<Pointer<types.Database>> dbOut = allocate();
+    Pointer<Pointer<types.Database>> dbOut = calloc();
     final pathC = Utf8.toUtf8(path);
     final int resultCode =
         bindings.sqlite3_open_v2(pathC, dbOut, flags, nullptr);
     _database = dbOut.value;
-    free(dbOut);
-    free(pathC);
+    calloc.free(dbOut);
+    calloc.free(pathC);
 
     if (resultCode == Errors.SQLITE_OK) {
       _open = true;
@@ -63,13 +65,13 @@
 
   /// Execute a query, discarding any returned rows.
   void execute(String query) {
-    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Pointer<Statement>> statementOut = calloc();
     Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
         _database, queryC, -1, statementOut, nullptr);
     Pointer<Statement> statement = statementOut.value;
-    free(statementOut);
-    free(queryC);
+    calloc.free(statementOut);
+    calloc.free(queryC);
 
     while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
       resultCode = bindings.sqlite3_step(statement);
@@ -82,13 +84,13 @@
 
   /// Evaluate a query and return the resulting rows as an iterable.
   Result query(String query) {
-    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Pointer<Statement>> statementOut = calloc();
     Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
         _database, queryC, -1, statementOut, nullptr);
     Pointer<Statement> statement = statementOut.value;
-    free(statementOut);
-    free(queryC);
+    calloc.free(statementOut);
+    calloc.free(queryC);
 
     if (resultCode != Errors.SQLITE_OK) {
       bindings.sqlite3_finalize(statement);
diff --git a/samples/ffi/sqlite/lib/src/ffi/arena.dart b/samples/ffi/sqlite/lib/src/ffi/arena.dart
index d01b64f..5369a22 100644
--- a/samples/ffi/sqlite/lib/src/ffi/arena.dart
+++ b/samples/ffi/sqlite/lib/src/ffi/arena.dart
@@ -7,6 +7,8 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
+
 /// [Arena] manages allocated C memory.
 ///
 /// Arenas are zoned.
@@ -24,7 +26,7 @@
   /// Frees all memory pointed to by [Pointer]s in this arena.
   void finalize() {
     for (final ptr in _allocations) {
-      free(ptr);
+      calloc.free(ptr);
     }
   }
 
diff --git a/samples/ffi/sqlite/lib/src/ffi/calloc.dart b/samples/ffi/sqlite/lib/src/ffi/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/samples/ffi/sqlite/lib/src/ffi/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/samples/ffi/sqlite/test/sqlite_test.dart b/samples/ffi/sqlite/test/sqlite_test.dart
index 130c95f..fedc9e5 100644
--- a/samples/ffi/sqlite/test/sqlite_test.dart
+++ b/samples/ffi/sqlite/test/sqlite_test.dart
@@ -168,6 +168,6 @@
     final String test = 'Hasta Mañana';
     final medium = Utf8.toUtf8(test);
     expect(test, medium.ref.toString());
-    free(medium);
+    calloc.free(medium);
   });
 }
diff --git a/samples_2/ffi/async/sample_async_callback.dart b/samples_2/ffi/async/sample_async_callback.dart
index 5e6d79a..2405a8a 100644
--- a/samples_2/ffi/async/sample_async_callback.dart
+++ b/samples_2/ffi/async/sample_async_callback.dart
@@ -107,7 +107,7 @@
 final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
     void Function(Pointer<Work>)>('ExecuteCallback');
 
-class Work extends Struct {}
+class Work extends Opaque {}
 
 Future asyncSleep(int ms) {
   return new Future.delayed(Duration(milliseconds: ms));
diff --git a/samples_2/ffi/calloc.dart b/samples_2/ffi/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/samples_2/ffi/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/samples_2/ffi/coordinate.dart b/samples_2/ffi/coordinate.dart
index 4ff34f5..4d9d300 100644
--- a/samples_2/ffi/coordinate.dart
+++ b/samples_2/ffi/coordinate.dart
@@ -18,8 +18,9 @@
 
   Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/samples_2/ffi/resource_management/pool.dart b/samples_2/ffi/resource_management/pool.dart
index 776c331..477a78e 100644
--- a/samples_2/ffi/resource_management/pool.dart
+++ b/samples_2/ffi/resource_management/pool.dart
@@ -7,48 +7,36 @@
 // @dart = 2.9
 
 import "dart:async";
-import 'dart:convert';
 import 'dart:ffi';
-import 'dart:typed_data';
 
-import 'package:ffi/ffi.dart' as packageFfi;
-import 'package:ffi/ffi.dart' show Utf8;
+import 'package:ffi/ffi.dart';
 
-/// Manages native resources.
+import '../calloc.dart';
+
+/// Keeps track of all allocated memory and frees all allocated memory on
+/// [releaseAll].
 ///
-/// Primary implementations are [Pool] and [Unmanaged].
-abstract class ResourceManager {
-  /// Allocates memory on the native heap.
-  ///
-  /// The native memory is under management by this [ResourceManager].
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count: 1});
-}
+/// Wraps an [Allocator] to do the actual allocation and freeing.
+class Pool implements Allocator {
+  /// The [Allocator] used for allocation and freeing.
+  final Allocator _wrappedAllocator;
 
-/// Manages native resources.
-class Pool implements ResourceManager {
+  Pool(this._wrappedAllocator);
+
   /// Native memory under management by this [Pool].
   final List<Pointer<NativeType>> _managedMemoryPointers = [];
 
   /// Callbacks for releasing native resources under management by this [Pool].
   final List<Function()> _managedResourceReleaseCallbacks = [];
 
-  /// Allocates memory on the native heap.
+  /// Allocates memory on the native heap by using the allocator supplied to
+  /// the constructor.
   ///
-  /// The native memory is under management by this [Pool].
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count: 1}) {
-    final p = Unmanaged().allocate<T>(count: count);
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int numBytes, {int alignment}) {
+    final p = _wrappedAllocator.allocate<T>(numBytes, alignment: alignment);
     _managedMemoryPointers.add(p);
     return p;
   }
@@ -73,17 +61,21 @@
     }
     _managedResourceReleaseCallbacks.clear();
     for (final p in _managedMemoryPointers) {
-      Unmanaged().free(p);
+      _wrappedAllocator.free(p);
     }
     _managedMemoryPointers.clear();
   }
+
+  @override
+  void free(Pointer<NativeType> pointer) => throw UnsupportedError(
+      "Individually freeing Pool allocated memory is not allowed");
 }
 
 /// Creates a [Pool] to manage native resources.
 ///
 /// If the isolate is shut down, through `Isolate.kill()`, resources are _not_ cleaned up.
-R using<R>(R Function(Pool) f) {
-  final p = Pool();
+R using<R>(R Function(Pool) f, [Allocator wrappedAllocator = calloc]) {
+  final p = Pool(wrappedAllocator);
   try {
     return f(p);
   } finally {
@@ -98,8 +90,8 @@
 /// Please note that all throws are caught and packaged in [RethrownError].
 ///
 /// If the isolate is shut down, through `Isolate.kill()`, resources are _not_ cleaned up.
-R usePool<R>(R Function() f) {
-  final p = Pool();
+R usePool<R>(R Function() f, [Allocator wrappedAllocator = calloc]) {
+  final p = Pool(wrappedAllocator);
   try {
     return runZoned(() => f(),
         zoneValues: {#_pool: p},
@@ -119,78 +111,3 @@
   toString() => """RethrownError(${original})
 ${originalStackTrace}""";
 }
-
-/// Does not manage it's resources.
-class Unmanaged implements ResourceManager {
-  /// Allocates memory on the native heap.
-  ///
-  /// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
-  /// against the default public heap. Allocation of either element size or count
-  /// of 0 is undefined.
-  ///
-  /// Throws an ArgumentError on failure to allocate.
-  Pointer<T> allocate<T extends NativeType>({int count = 1}) =>
-      packageFfi.allocate(count: count);
-
-  /// Releases memory on the native heap.
-  ///
-  /// For POSIX-based systems, this uses free. On Windows, it uses HeapFree
-  /// against the default public heap. It may only be used against pointers
-  /// allocated in a manner equivalent to [allocate].
-  ///
-  /// Throws an ArgumentError on failure to free.
-  ///
-  void free(Pointer pointer) => packageFfi.free(pointer);
-}
-
-/// Does not manage it's resources.
-final Unmanaged unmanaged = Unmanaged();
-
-extension Utf8InPool on String {
-  /// Convert a [String] to a Utf8-encoded null-terminated C string.
-  ///
-  /// If 'string' contains NULL bytes, the converted string will be truncated
-  /// prematurely. Unpaired surrogate code points in [string] will be preserved
-  /// in the UTF-8 encoded result. See [Utf8Encoder] for details on encoding.
-  ///
-  /// Returns a malloc-allocated pointer to the result.
-  ///
-  /// The memory is managed by the [Pool] passed in as [pool].
-  Pointer<Utf8> toUtf8(ResourceManager pool) {
-    final units = utf8.encode(this);
-    final Pointer<Uint8> result = pool.allocate<Uint8>(count: units.length + 1);
-    final Uint8List nativeString = result.asTypedList(units.length + 1);
-    nativeString.setAll(0, units);
-    nativeString[units.length] = 0;
-    return result.cast();
-  }
-}
-
-extension Utf8Helpers on Pointer<Utf8> {
-  /// Returns the length of a null-terminated string -- the number of (one-byte)
-  /// characters before the first null byte.
-  int strlen() {
-    final Pointer<Uint8> array = this.cast<Uint8>();
-    final Uint8List nativeString = array.asTypedList(_maxSize);
-    return nativeString.indexWhere((char) => char == 0);
-  }
-
-  /// Creates a [String] containing the characters UTF-8 encoded in [this].
-  ///
-  /// [this] must be a zero-terminated byte sequence of valid UTF-8
-  /// encodings of Unicode code points. It may also contain UTF-8 encodings of
-  /// unpaired surrogate code points, which is not otherwise valid UTF-8, but
-  /// which may be created when encoding a Dart string containing an unpaired
-  /// surrogate. See [Utf8Decoder] for details on decoding.
-  ///
-  /// Returns a Dart string containing the decoded code points.
-  String contents() {
-    final int length = strlen();
-    return utf8.decode(Uint8List.view(
-        this.cast<Uint8>().asTypedList(length).buffer, 0, length));
-  }
-}
-
-const int _kMaxSmi64 = (1 << 62) - 1;
-const int _kMaxSmi32 = (1 << 30) - 1;
-final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
diff --git a/samples_2/ffi/resource_management/pool_isolate_shutdown_sample.dart b/samples_2/ffi/resource_management/pool_isolate_shutdown_sample.dart
index 8d3401b..4c8eb0f 100644
--- a/samples_2/ffi/resource_management/pool_isolate_shutdown_sample.dart
+++ b/samples_2/ffi/resource_management/pool_isolate_shutdown_sample.dart
@@ -88,4 +88,4 @@
     void Function(Pointer<SomeResource>)>("ReleaseResource");
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples_2/ffi/resource_management/pool_sample.dart b/samples_2/ffi/resource_management/pool_sample.dart
index 87c5e39..c794a40 100644
--- a/samples_2/ffi/resource_management/pool_sample.dart
+++ b/samples_2/ffi/resource_management/pool_sample.dart
@@ -11,6 +11,7 @@
 import 'package:expect/expect.dart';
 
 import 'pool.dart';
+import 'utf8_helpers.dart';
 import '../dylib_utils.dart';
 
 main() {
@@ -23,7 +24,7 @@
 
   // To ensure resources are freed, wrap them in a [using] call.
   using((Pool pool) {
-    final p = pool.allocate<Int64>(count: 2);
+    final p = pool<Int64>(2);
     p[0] = 24;
     MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
     print(p[1]);
@@ -33,14 +34,14 @@
   // Resources are freed also when abnormal control flow occurs.
   try {
     using((Pool pool) {
-      final p = pool.allocate<Int64>(count: 2);
+      final p = pool<Int64>(2);
       p[0] = 25;
       MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), 8);
       print(p[1]);
       Expect.equals(25, p[1]);
       throw Exception("Some random exception");
     });
-    // `free(p)` has been called.
+    // `calloc.free(p)` has been called.
   } on Exception catch (e) {
     print("Caught exception: $e");
   }
@@ -48,8 +49,8 @@
   // In a pool multiple resources can be allocated, which will all be freed
   // at the end of the scope.
   using((Pool pool) {
-    final p = pool.allocate<Int64>(count: 2);
-    final p2 = pool.allocate<Int64>(count: 2);
+    final p = pool<Int64>(2);
+    final p2 = pool<Int64>(2);
     p[0] = 1;
     p[1] = 2;
     MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
@@ -60,7 +61,7 @@
   // If the resource allocation happens in a different scope, then one either
   // needs to pass the pool to that scope.
   f1(Pool pool) {
-    return pool.allocate<Int64>(count: 2);
+    return pool<Int64>(2);
   }
 
   using((Pool pool) {
@@ -112,4 +113,4 @@
 }
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples_2/ffi/resource_management/pool_zoned_sample.dart b/samples_2/ffi/resource_management/pool_zoned_sample.dart
index 0b4e8ff..a1dc9c1 100644
--- a/samples_2/ffi/resource_management/pool_zoned_sample.dart
+++ b/samples_2/ffi/resource_management/pool_zoned_sample.dart
@@ -11,6 +11,7 @@
 import 'package:expect/expect.dart';
 
 import 'pool.dart';
+import 'utf8_helpers.dart';
 import '../dylib_utils.dart';
 
 main() {
@@ -23,7 +24,7 @@
 
   // To ensure resources are freed, wrap them in a [using] call.
   usePool(() {
-    final p = currentPool.allocate<Int64>(count: 2);
+    final p = currentPool<Int64>(2);
     p[0] = 24;
     MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
     print(p[1]);
@@ -33,7 +34,7 @@
   // Resources are freed also when abnormal control flow occurs.
   try {
     usePool(() {
-      final p = currentPool.allocate<Int64>(count: 2);
+      final p = currentPool<Int64>(2);
       p[0] = 25;
       MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), 8);
       print(p[1]);
@@ -48,8 +49,8 @@
   // In a pool multiple resources can be allocated, which will all be freed
   // at the end of the scope.
   usePool(() {
-    final p = currentPool.allocate<Int64>(count: 2);
-    final p2 = currentPool.allocate<Int64>(count: 2);
+    final p = currentPool<Int64>(2);
+    final p2 = currentPool<Int64>(2);
     p[0] = 1;
     p[1] = 2;
     MemMove(p2.cast<Void>(), p.cast<Void>(), 2 * sizeOf<Int64>());
@@ -60,7 +61,7 @@
   // If the resource allocation happens in a different scope, it is in the
   // same zone, so it's lifetime is automatically managed by the pool.
   f1() {
-    return currentPool.allocate<Int64>(count: 2);
+    return currentPool<Int64>(2);
   }
 
   usePool(() {
@@ -113,4 +114,4 @@
 }
 
 /// Represents some opaque resource being managed by a library.
-class SomeResource extends Struct {}
+class SomeResource extends Opaque {}
diff --git a/samples_2/ffi/resource_management/unmanaged_sample.dart b/samples_2/ffi/resource_management/unmanaged_sample.dart
index b8c9971..e73f7cc 100644
--- a/samples_2/ffi/resource_management/unmanaged_sample.dart
+++ b/samples_2/ffi/resource_management/unmanaged_sample.dart
@@ -9,8 +9,10 @@
 import 'dart:ffi';
 
 import 'package:expect/expect.dart';
+import 'package:ffi/ffi.dart';
 
-import 'pool.dart';
+import 'utf8_helpers.dart';
+import '../calloc.dart';
 import '../dylib_utils.dart';
 
 main() {
@@ -24,15 +26,15 @@
   // To ensure resources are freed, call free manually.
   //
   // For automatic management use a Pool.
-  final p = unmanaged.allocate<Int64>(count: 2);
+  final p = calloc<Int64>(2);
   p[0] = 24;
   MemMove(p.elementAt(1).cast<Void>(), p.cast<Void>(), sizeOf<Int64>());
   print(p[1]);
   Expect.equals(24, p[1]);
-  unmanaged.free(p);
+  calloc.free(p);
 
   // Using Strings.
-  final p2 = "Hello world!".toUtf8(unmanaged);
+  final p2 = "Hello world!".toUtf8(calloc);
   print(p2.contents());
-  unmanaged.free(p2);
+  calloc.free(p2);
 }
diff --git a/samples_2/ffi/resource_management/utf8_helpers.dart b/samples_2/ffi/resource_management/utf8_helpers.dart
new file mode 100644
index 0000000..e1d555b
--- /dev/null
+++ b/samples_2/ffi/resource_management/utf8_helpers.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Explicit pool used for managing resources.
+
+// @dart = 2.9
+
+import 'dart:convert';
+import 'dart:ffi';
+import 'dart:typed_data';
+
+import 'package:ffi/ffi.dart';
+
+extension Utf8InPool on String {
+  /// Convert a [String] to a Utf8-encoded null-terminated C string.
+  ///
+  /// If 'string' contains NULL bytes, the converted string will be truncated
+  /// prematurely. See [Utf8Encoder] for details on encoding.
+  ///
+  /// Returns a [allocator]-allocated pointer to the result.
+  Pointer<Utf8> toUtf8(Allocator allocator) {
+    final units = utf8.encode(this);
+    final Pointer<Uint8> result = allocator<Uint8>(units.length + 1);
+    final Uint8List nativeString = result.asTypedList(units.length + 1);
+    nativeString.setAll(0, units);
+    nativeString[units.length] = 0;
+    return result.cast();
+  }
+}
+
+extension Utf8Helpers on Pointer<Utf8> {
+  /// The length of a null-terminated string — the number of (one-byte)
+  /// characters before the first null byte.
+  int get strlen {
+    final Pointer<Uint8> array = this.cast<Uint8>();
+    final Uint8List nativeString = array.asTypedList(_maxSize);
+    return nativeString.indexWhere((char) => char == 0);
+  }
+
+  /// Creates a [String] containing the characters UTF-8 encoded in [this].
+  ///
+  /// [this] must be a zero-terminated byte sequence of valid UTF-8
+  /// encodings of Unicode code points.See [Utf8Decoder] for details on
+  /// decoding.
+  ///
+  /// Returns a Dart string containing the decoded code points.
+  String contents() {
+    final int length = strlen;
+    return utf8.decode(Uint8List.view(
+        this.cast<Uint8>().asTypedList(length).buffer, 0, length));
+  }
+}
+
+const int _kMaxSmi64 = (1 << 62) - 1;
+const int _kMaxSmi32 = (1 << 30) - 1;
+final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
diff --git a/samples_2/ffi/sample_ffi_bitfield.dart b/samples_2/ffi/sample_ffi_bitfield.dart
index 91bb65d..78c41df 100644
--- a/samples_2/ffi/sample_ffi_bitfield.dart
+++ b/samples_2/ffi/sample_ffi_bitfield.dart
@@ -9,6 +9,8 @@
 import 'package:ffi/ffi.dart';
 import 'package:expect/expect.dart';
 
+import 'calloc.dart';
+
 /// typedef struct {
 ///     unsigned int bold      : 1;
 ///     unsigned int underline : 2;
@@ -95,7 +97,7 @@
 }
 
 main() {
-  final p = allocate<ScreenCellAttrs>(count: 3);
+  final p = calloc<ScreenCellAttrs>(3);
 
   // Zeroes out all fields.
   p.ref.bits = 0;
@@ -121,5 +123,5 @@
   // A check for automated testing.
   Expect.equals(1933, p.ref.bits);
 
-  free(p);
+  calloc.free(p);
 }
diff --git a/samples_2/ffi/sample_ffi_data.dart b/samples_2/ffi/sample_ffi_data.dart
index 09dba76..2d22011 100644
--- a/samples_2/ffi/sample_ffi_data.dart
+++ b/samples_2/ffi/sample_ffi_data.dart
@@ -7,29 +7,31 @@
 import 'dart:ffi';
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
+
 main() {
   print('start main');
 
   {
     // Basic operation: allocate, get, set, and free.
-    Pointer<Int64> p = allocate();
+    Pointer<Int64> p = calloc();
     p.value = 42;
     int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Undefined behavior before set.
-    Pointer<Int64> p = allocate();
+    Pointer<Int64> p = calloc();
     int pValue = p.value;
     print('If not set, returns garbage: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Pointers can be created from an address.
-    Pointer<Int64> pHelper = allocate();
+    Pointer<Int64> pHelper = calloc();
     pHelper.value = 1337;
 
     int address = pHelper.address;
@@ -38,13 +40,13 @@
     Pointer<Int64> p = Pointer.fromAddress(address);
     print('${p.runtimeType} value: ${p.value}');
 
-    free(pHelper);
+    calloc.free(pHelper);
   }
 
   {
     // Address is zeroed out after free.
-    Pointer<Int64> p = allocate();
-    free(p);
+    Pointer<Int64> p = calloc();
+    calloc.free(p);
     print('After free, address is zero: ${p.address}');
   }
 
@@ -52,13 +54,13 @@
     // Allocating too much throws an exception.
     try {
       int maxMint = 9223372036854775807; // 2^63 - 1
-      allocate<Int64>(count: maxMint);
+      calloc<Int64>(maxMint);
     } on Error {
       print('Expected exception on allocating too much');
     }
     try {
       int maxInt1_8 = 1152921504606846975; // 2^60 -1
-      allocate<Int64>(count: maxInt1_8);
+      calloc<Int64>(maxInt1_8);
     } on Error {
       print('Expected exception on allocating too much');
     }
@@ -67,7 +69,7 @@
   {
     // Pointers can be cast into another type,
     // resulting in the corresponding bits read.
-    Pointer<Int64> p1 = allocate();
+    Pointer<Int64> p1 = calloc();
     p1.value = 9223372036854775807; // 2^63 - 1
 
     Pointer<Int32> p2 = p1.cast();
@@ -76,61 +78,61 @@
     Pointer<Int32> p3 = p2.elementAt(1);
     print('${p3.runtimeType} value: ${p3.value}'); // 2^31 - 1
 
-    free(p1);
+    calloc.free(p1);
   }
 
   {
     // Data can be tightly packed in memory.
-    Pointer<Int8> p = allocate(count: 8);
+    Pointer<Int8> p = calloc(8);
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
       p.elementAt(i).value = i * 3;
     }
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
       print('p.elementAt($i) value: ${p.elementAt(i).value}');
     }
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Values that don't fit are truncated.
-    Pointer<Int32> p11 = allocate();
+    Pointer<Int32> p11 = calloc();
 
     p11.value = 9223372036854775807;
 
     print(p11);
 
-    free(p11);
+    calloc.free(p11);
   }
 
   {
     // Doubles.
-    Pointer<Double> p = allocate();
+    Pointer<Double> p = calloc();
     p.value = 3.14159265359;
     print('${p.runtimeType} value: ${p.value}');
     p.value = 3.14;
     print('${p.runtimeType} value: ${p.value}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // Floats.
-    Pointer<Float> p = allocate();
+    Pointer<Float> p = calloc();
     p.value = 3.14159265359;
     print('${p.runtimeType} value: ${p.value}');
     p.value = 3.14;
     print('${p.runtimeType} value: ${p.value}');
-    free(p);
+    calloc.free(p);
   }
 
   {
     // IntPtr varies in size based on whether the platform is 32 or 64 bit.
     // Addresses of pointers fit in this size.
-    Pointer<IntPtr> p = allocate();
+    Pointer<IntPtr> p = calloc();
     int p14addr = p.address;
     p.value = p14addr;
     int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    free(p);
+    calloc.free(p);
   }
 
   {
@@ -138,19 +140,19 @@
     // The size of the element it is pointing to is undefined,
     // they cannot be allocated, read, or written.
 
-    Pointer<IntPtr> p1 = allocate();
+    Pointer<IntPtr> p1 = calloc();
     Pointer<Void> p2 = p1.cast();
     print('${p2.runtimeType} address: ${p2.address}');
 
-    free(p1);
+    calloc.free(p1);
   }
 
   {
     // Pointer to a pointer to something.
-    Pointer<Int16> pHelper = allocate();
+    Pointer<Int16> pHelper = calloc();
     pHelper.value = 17;
 
-    Pointer<Pointer<Int16>> p = allocate();
+    Pointer<Pointer<Int16>> p = calloc();
 
     // Storing into a pointer pointer automatically unboxes.
     p.value = pHelper;
@@ -162,31 +164,31 @@
     int pValue = p.value.value;
     print('${p.runtimeType} value\'s value: ${pValue}');
 
-    free(p);
-    free(pHelper);
+    calloc.free(p);
+    calloc.free(pHelper);
   }
 
   {
     // The pointer to pointer types must match up.
-    Pointer<Int8> pHelper = allocate();
+    Pointer<Int8> pHelper = calloc();
     pHelper.value = 123;
 
-    Pointer<Pointer<Int16>> p = allocate();
+    Pointer<Pointer<Int16>> p = calloc();
 
     // Trying to store `pHelper` into `p.val` would result in a type mismatch.
 
-    free(pHelper);
-    free(p);
+    calloc.free(pHelper);
+    calloc.free(p);
   }
 
   {
     // `nullptr` points to address 0 in c++.
-    Pointer<Pointer<Int8>> pointerToPointer = allocate();
+    Pointer<Pointer<Int8>> pointerToPointer = calloc();
     Pointer<Int8> value = nullptr;
     pointerToPointer.value = value;
     value = pointerToPointer.value;
     print("Loading a pointer to the 0 address is null: ${value}");
-    free(pointerToPointer);
+    calloc.free(pointerToPointer);
   }
 
   {
@@ -207,7 +209,7 @@
         head.value = value;
         return;
       }
-      Pointer<IntPtr> next = allocate<IntPtr>();
+      Pointer<IntPtr> next = calloc<IntPtr>();
       head.value = next.address;
       createChain(next, length - 1, value);
     }
@@ -222,7 +224,7 @@
 
     void freeChain(Pointer<IntPtr> head, int length) {
       Pointer<IntPtr> next = Pointer.fromAddress(head.value);
-      free(head);
+      calloc.free(head);
       if (length == 0) {
         return;
       }
@@ -230,7 +232,7 @@
     }
 
     int length = 10;
-    Pointer<IntPtr> head = allocate();
+    Pointer<IntPtr> head = calloc();
     createChain(head, length, 512);
     int tailValue = getChainValue(head, length);
     print('tailValue: ${tailValue}');
diff --git a/samples_2/ffi/sample_ffi_functions.dart b/samples_2/ffi/sample_ffi_functions.dart
index 4cd30b0..1bf8ecc 100644
--- a/samples_2/ffi/sample_ffi_functions.dart
+++ b/samples_2/ffi/sample_ffi_functions.dart
@@ -8,6 +8,7 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 typedef NativeUnaryOp = Int32 Function(Int32);
@@ -186,7 +187,7 @@
     // pass an array / pointer as argument
     Int64PointerUnOp assign1337Index1 = ffiTestFunctions
         .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
-    Pointer<Int64> p2 = allocate(count: 2);
+    Pointer<Int64> p2 = calloc(2);
     p2.value = 42;
     p2[1] = 1000;
     print(p2.elementAt(1).address.toRadixString(16));
@@ -251,11 +252,11 @@
     print(result);
     print(result.runtimeType);
 
-    Pointer<Int64> p2 = allocate(count: 2);
+    Pointer<Int64> p2 = calloc(2);
     result = nullableInt64ElemAt1(p2);
     print(result);
     print(result.runtimeType);
-    free(p2);
+    calloc.free(p2);
   }
 
   print("end main");
diff --git a/samples_2/ffi/sample_ffi_functions_callbacks.dart b/samples_2/ffi/sample_ffi_functions_callbacks.dart
index 79f9a41..1d9dc12 100644
--- a/samples_2/ffi/sample_ffi_functions_callbacks.dart
+++ b/samples_2/ffi/sample_ffi_functions_callbacks.dart
@@ -6,6 +6,9 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
+
+import 'calloc.dart';
 import 'coordinate.dart';
 import 'dylib_utils.dart';
 
@@ -45,7 +48,7 @@
     Pointer<NativeFunction<CoordinateTrice>> p2 =
         ffiTestFunctions.lookup("CoordinateUnOpTrice");
     CoordinateTrice coordinateUnOpTrice = p2.asFunction();
-    Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 20.0, nullptr);
     c1.next = c1.addressOf;
     Coordinate result =
         coordinateUnOpTrice(transposeCoordinatePointer, c1.addressOf).ref;
diff --git a/samples_2/ffi/sample_ffi_functions_structs.dart b/samples_2/ffi/sample_ffi_functions_structs.dart
index 7129658..41b608d 100644
--- a/samples_2/ffi/sample_ffi_functions_structs.dart
+++ b/samples_2/ffi/sample_ffi_functions_structs.dart
@@ -6,11 +6,12 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
+
+import 'calloc.dart';
 import 'coordinate.dart';
 import 'dylib_utils.dart';
 
-import 'package:ffi/ffi.dart';
-
 typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
 
 main() {
@@ -25,8 +26,8 @@
         ffiTestFunctions.lookup("TransposeCoordinate");
     NativeCoordinateOp f1 = p1.asFunction();
 
-    Coordinate c1 = Coordinate.allocate(10.0, 20.0, nullptr);
-    Coordinate c2 = Coordinate.allocate(42.0, 84.0, c1.addressOf);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 20.0, nullptr);
+    Coordinate c2 = Coordinate.allocate(calloc, 42.0, 84.0, c1.addressOf);
     c1.next = c2.addressOf;
 
     Coordinate result = f1(c1.addressOf).ref;
@@ -46,7 +47,7 @@
         ffiTestFunctions.lookup("CoordinateElemAt1");
     NativeCoordinateOp f1 = p1.asFunction();
 
-    Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
+    Pointer<Coordinate> c1 = calloc<Coordinate>(3);
     Pointer<Coordinate> c2 = c1.elementAt(1);
     Pointer<Coordinate> c3 = c1.elementAt(2);
     c1.ref.x = 10.0;
diff --git a/samples_2/ffi/sample_ffi_structs.dart b/samples_2/ffi/sample_ffi_structs.dart
index d5af59e..94b19cc 100644
--- a/samples_2/ffi/sample_ffi_structs.dart
+++ b/samples_2/ffi/sample_ffi_structs.dart
@@ -8,6 +8,7 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
 import 'coordinate.dart';
 
 main() {
@@ -15,9 +16,9 @@
 
   {
     // Allocates each coordinate separately in c memory.
-    Coordinate c1 = Coordinate.allocate(10.0, 10.0, nullptr);
-    Coordinate c2 = Coordinate.allocate(20.0, 20.0, c1.addressOf);
-    Coordinate c3 = Coordinate.allocate(30.0, 30.0, c2.addressOf);
+    Coordinate c1 = Coordinate.allocate(calloc, 10.0, 10.0, nullptr);
+    Coordinate c2 = Coordinate.allocate(calloc, 20.0, 20.0, c1.addressOf);
+    Coordinate c3 = Coordinate.allocate(calloc, 30.0, 30.0, c2.addressOf);
     c1.next = c3.addressOf;
 
     Coordinate currentCoordinate = c1;
@@ -26,14 +27,14 @@
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    free(c1.addressOf);
-    free(c2.addressOf);
-    free(c3.addressOf);
+    calloc.free(c1.addressOf);
+    calloc.free(c2.addressOf);
+    calloc.free(c3.addressOf);
   }
 
   {
     // Allocates coordinates consecutively in c memory.
-    Pointer<Coordinate> c1 = allocate<Coordinate>(count: 3);
+    Pointer<Coordinate> c1 = calloc<Coordinate>(3);
     Pointer<Coordinate> c2 = c1.elementAt(1);
     Pointer<Coordinate> c3 = c1.elementAt(2);
     c1.ref.x = 10.0;
@@ -52,15 +53,15 @@
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    free(c1);
+    calloc.free(c1);
   }
 
   {
-    Coordinate c = Coordinate.allocate(10, 10, nullptr);
+    Coordinate c = Coordinate.allocate(calloc, 10, 10, nullptr);
     print(c is Coordinate);
     print(c is Pointer<Void>);
     print(c is Pointer);
-    free(c.addressOf);
+    calloc.free(c.addressOf);
   }
 
   print("end main");
diff --git a/samples_2/ffi/sqlite/lib/sqlite.dart b/samples_2/ffi/sqlite/lib/sqlite.dart
index 825e434..0e0669b 100644
--- a/samples_2/ffi/sqlite/lib/sqlite.dart
+++ b/samples_2/ffi/sqlite/lib/sqlite.dart
@@ -10,3 +10,5 @@
 library sqlite;
 
 export "src/database.dart";
+
+export "src/ffi/calloc.dart" show calloc;
diff --git a/samples_2/ffi/sqlite/lib/src/bindings/types.dart b/samples_2/ffi/sqlite/lib/src/bindings/types.dart
index f6a1736..763f47e 100644
--- a/samples_2/ffi/sqlite/lib/src/bindings/types.dart
+++ b/samples_2/ffi/sqlite/lib/src/bindings/types.dart
@@ -15,7 +15,7 @@
 /// is its destructor.  There are many other interfaces (such as
 /// [sqlite3_prepare_v2()], [sqlite3_create_function()], and
 /// [sqlite3_busy_timeout()] to name but three) that are methods on an
-class Database extends Struct {}
+class Database extends Opaque {}
 
 /// SQL Statement Object
 ///
@@ -38,7 +38,7 @@
 ///
 /// Refer to documentation on individual methods above for additional
 /// information.
-class Statement extends Struct {}
+class Statement extends Opaque {}
 
 /// Dynamically Typed Value Object
 ///
@@ -74,4 +74,4 @@
 /// [sqlite3_result_value()] and [sqlite3_bind_value()].
 /// The [sqlite3_value_blob | sqlite3_value_type()] family of
 /// interfaces require protected sqlite3_value objects.
-class Value extends Struct {}
+class Value extends Opaque {}
diff --git a/samples_2/ffi/sqlite/lib/src/database.dart b/samples_2/ffi/sqlite/lib/src/database.dart
index 38121a9..49f229f 100644
--- a/samples_2/ffi/sqlite/lib/src/database.dart
+++ b/samples_2/ffi/sqlite/lib/src/database.dart
@@ -17,6 +17,8 @@
 import "bindings/constants.dart";
 import "collections/closable_iterator.dart";
 
+import 'ffi/calloc.dart';
+
 /// [Database] represents an open connection to a SQLite database.
 ///
 /// All functions against a database may throw [SQLiteError].
@@ -29,13 +31,13 @@
   /// Open a database located at the file [path].
   Database(String path,
       [int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
-    Pointer<Pointer<types.Database>> dbOut = allocate();
+    Pointer<Pointer<types.Database>> dbOut = calloc();
     final pathC = Utf8.toUtf8(path);
     final int resultCode =
         bindings.sqlite3_open_v2(pathC, dbOut, flags, nullptr);
     _database = dbOut.value;
-    free(dbOut);
-    free(pathC);
+    calloc.free(dbOut);
+    calloc.free(pathC);
 
     if (resultCode == Errors.SQLITE_OK) {
       _open = true;
@@ -65,13 +67,13 @@
 
   /// Execute a query, discarding any returned rows.
   void execute(String query) {
-    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Pointer<Statement>> statementOut = calloc();
     Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
         _database, queryC, -1, statementOut, nullptr);
     Pointer<Statement> statement = statementOut.value;
-    free(statementOut);
-    free(queryC);
+    calloc.free(statementOut);
+    calloc.free(queryC);
 
     while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
       resultCode = bindings.sqlite3_step(statement);
@@ -84,13 +86,13 @@
 
   /// Evaluate a query and return the resulting rows as an iterable.
   Result query(String query) {
-    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Pointer<Statement>> statementOut = calloc();
     Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
         _database, queryC, -1, statementOut, nullptr);
     Pointer<Statement> statement = statementOut.value;
-    free(statementOut);
-    free(queryC);
+    calloc.free(statementOut);
+    calloc.free(queryC);
 
     if (resultCode != Errors.SQLITE_OK) {
       bindings.sqlite3_finalize(statement);
diff --git a/samples_2/ffi/sqlite/lib/src/ffi/arena.dart b/samples_2/ffi/sqlite/lib/src/ffi/arena.dart
index a26e807..39e3035 100644
--- a/samples_2/ffi/sqlite/lib/src/ffi/arena.dart
+++ b/samples_2/ffi/sqlite/lib/src/ffi/arena.dart
@@ -9,6 +9,8 @@
 
 import 'package:ffi/ffi.dart';
 
+import 'calloc.dart';
+
 /// [Arena] manages allocated C memory.
 ///
 /// Arenas are zoned.
@@ -26,7 +28,7 @@
   /// Frees all memory pointed to by [Pointer]s in this arena.
   void finalize() {
     for (final ptr in _allocations) {
-      free(ptr);
+      calloc.free(ptr);
     }
   }
 
diff --git a/samples_2/ffi/sqlite/lib/src/ffi/calloc.dart b/samples_2/ffi/sqlite/lib/src/ffi/calloc.dart
new file mode 100644
index 0000000..c6be280
--- /dev/null
+++ b/samples_2/ffi/sqlite/lib/src/ffi/calloc.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/samples_2/ffi/sqlite/test/sqlite_test.dart b/samples_2/ffi/sqlite/test/sqlite_test.dart
index f7d3744..f27336bd 100644
--- a/samples_2/ffi/sqlite/test/sqlite_test.dart
+++ b/samples_2/ffi/sqlite/test/sqlite_test.dart
@@ -172,6 +172,6 @@
     final String test = 'Hasta Mañana';
     final medium = Utf8.toUtf8(test);
     expect(test, medium.ref.toString());
-    free(medium);
+    calloc.free(medium);
   });
 }
diff --git a/sdk/lib/_internal/vm/lib/ffi_allocation_patch.dart b/sdk/lib/_internal/vm/lib/ffi_allocation_patch.dart
new file mode 100644
index 0000000..5b794e6
--- /dev/null
+++ b/sdk/lib/_internal/vm/lib/ffi_allocation_patch.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// All imports must be in all FFI patch files to not depend on the order
+// the patches are applied.
+import "dart:_internal" show patch;
+import 'dart:typed_data';
+import 'dart:isolate';
+
+extension AllocatorAlloc on Allocator {
+  // TODO(http://dartbug.com/38721): Implement this in the CFE to remove the
+  // invocation of sizeOf<T> to enable tree shaking.
+  // TODO(http://dartbug.com/39964): Add `alignmentOf<T>()` call.
+  @patch
+  Pointer<T> call<T extends NativeType>([int count = 1]) {
+    return this.allocate(sizeOf<T>() * count);
+  }
+}
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index b050a48..ce3d87f 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.dart
@@ -5,9 +5,9 @@
 /// Classes and utilities that supplement the collection support in dart:core.
 ///
 /// To use this library in your code:
-///
-///     import 'dart:collection';
-///
+/// ```dart
+/// import 'dart:collection';
+/// ```
 /// {@category Core}
 library dart.collection;
 
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 3990cd2..c9c9d8e 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -24,8 +24,6 @@
 /// symmetric, transitive, and consistent over time), and that `hashCode`
 /// must be the same for objects that are considered equal by `==`.
 ///
-/// The map allows `null` as a key.
-///
 /// Iterating the map's keys, values or entries (through [forEach])
 /// may happen in any order.
 /// The iteration order only changes when the map is modified.
@@ -56,10 +54,10 @@
   /// [K] instance.
   ///
   /// Example:
-  ///
-  ///     new HashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
-  ///                          hashCode: (int e) => e % 5)
-  ///
+  /// ```dart
+  /// HashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+  ///                  hashCode: (int e) => e % 5)
+  /// ```
   /// This example map does not need an `isValidKey` function to be passed.
   /// The default function accepts only `int` values, which can safely be
   /// passed to both the `equals` and `hashCode` functions.
@@ -90,9 +88,10 @@
   /// Creates an unordered identity-based map.
   ///
   /// Effectively a shorthand for:
-  ///
-  ///     new HashMap<K, V>(equals: identical,
-  ///                       hashCode: identityHashCode)
+  /// ```dart
+  /// HashMap<K, V>(equals: identical,
+  ///               hashCode: identityHashCode)
+  /// ```
   external factory HashMap.identity();
 
   /// Creates a [HashMap] that contains all key/value pairs of [other].
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index 6ebb04e..075627f 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -13,8 +13,6 @@
 /// must consistent with equality, so that the same for objects that are
 /// considered equal.
 ///
-/// The set allows `null` as an element.
-///
 /// Most simple operations on `HashSet` are done in (potentially amortized)
 /// constant time: [add], [contains], [remove], and [length], provided the hash
 /// codes of objects are well distributed.
@@ -47,10 +45,10 @@
   ///
   /// If [isValidKey] is omitted, it defaults to testing if the object is an
   /// [E] instance. That means that:
-  ///
-  ///     new HashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
-  ///                      hashCode: (int e) => e % 5)
-  ///
+  /// ```dart
+  /// HashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+  ///              hashCode: (int e) => e % 5)
+  /// ```
   /// does not need an `isValidKey` argument, because it defaults to only
   /// accepting `int` values which are accepted by both `equals` and `hashCode`.
   ///
@@ -71,9 +69,10 @@
   /// Creates an unordered identity-based set.
   ///
   /// Effectively a shorthand for:
-  ///
-  ///     new HashSet<E>(equals: identical,
-  ///                    hashCode: identityHashCode)
+  /// ```dart
+  /// HashSet<E>(equals: identical,
+  ///                hashCode: identityHashCode)
+  /// ```
   external factory HashSet.identity();
 
   /// Create a hash set containing all [elements].
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 9dfdb99..872248e 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -19,8 +19,6 @@
 /// must define a stable equivalence relation on the keys (reflexive,
 /// symmetric, transitive, and consistent over time), and that `hashCode`
 /// must be the same for objects that are considered equal by `==`.
-///
-/// The map allows `null` as a key.
 abstract class LinkedHashMap<K, V> implements Map<K, V> {
   /// Creates an insertion-ordered hash-table based [Map].
   ///
@@ -41,10 +39,10 @@
   /// [K] instance.
   ///
   /// Example:
-  ///
-  ///     new LinkedHashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
-  ///                                hashCode: (int e) => e % 5)
-  ///
+  /// ```dart
+  /// LinkedHashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+  ///                        hashCode: (int e) => e % 5)
+  /// ```
   /// This example map does not need an `isValidKey` function to be passed.
   /// The default function accepts only `int` values, which can safely be
   /// passed to both the `equals` and `hashCode` functions.
@@ -74,9 +72,10 @@
   /// Creates an insertion-ordered identity-based map.
   ///
   /// Effectively a shorthand for:
-  ///
-  ///     new LinkedHashMap<K, V>(equals: identical,
-  ///                             hashCode: identityHashCode)
+  /// ```dart
+  /// LinkedHashMap<K, V>(equals: identical,
+  ///                     hashCode: identityHashCode)
+  /// ```
   external factory LinkedHashMap.identity();
 
   /// Creates a [LinkedHashMap] that contains all key value pairs of [other].
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index c4f6818..a27a89b 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -15,8 +15,6 @@
 /// symmetric, transitive, and consistent over time), and that `hashCode`
 /// must be the same for objects that are considered equal by `==`.
 ///
-/// The set allows `null` as an element.
-///
 /// Iteration of elements is done in element insertion order.
 /// An element that was added after another will occur later in the iteration.
 /// Adding an element that is already in the set
@@ -54,10 +52,10 @@
   ///
   /// If [isValidKey] is omitted, it defaults to testing if the object is an
   /// [E] instance. That means that:
-  ///
-  ///     new LinkedHashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
-  ///                            hashCode: (int e) => e % 5)
-  ///
+  /// ```dart
+  /// LinkedHashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+  ///                    hashCode: (int e) => e % 5)
+  /// ```
   /// does not need an `isValidKey` argument, because it defaults to only
   /// accepting `int` values which are accepted by both `equals` and `hashCode`.
   ///
@@ -78,9 +76,10 @@
   /// Creates an insertion-ordered identity-based set.
   ///
   /// Effectively a shorthand for:
-  ///
-  ///     new LinkedHashSet<E>(equals: identical,
-  ///                          hashCode: identityHashCode)
+  /// ```dart
+  /// LinkedHashSet<E>(equals: identical,
+  ///                      hashCode: identityHashCode)
+  /// ```
   external factory LinkedHashSet.identity();
 
   /// Create a linked hash set containing all [elements].
@@ -91,10 +90,11 @@
   /// All the [elements] should be instances of [E].
   /// The `elements` iterable itself may have any element type,
   /// so this constructor can be used to down-cast a `Set`, for example as:
-  ///
-  ///     Set<SuperType> superSet = ...;
-  ///     Iterable<SuperType> tmp = superSet.where((e) => e is SubType);
-  ///     Set<SubType> subSet = new LinkedHashSet<SubType>.from(tmp);
+  /// ```dart
+  /// Set<SuperType> superSet = ...;
+  /// Iterable<SuperType> tmp = superSet.where((e) => e is SubType);
+  /// Set<SubType> subSet = LinkedHashSet<SubType>.from(tmp);
+  /// ```
   factory LinkedHashSet.from(Iterable<dynamic> elements) {
     LinkedHashSet<E> result = LinkedHashSet<E>();
     for (final element in elements) {
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
index 0445807..3e77646 100644
--- a/sdk/lib/collection/linked_list.dart
+++ b/sdk/lib/collection/linked_list.dart
@@ -33,16 +33,16 @@
   int _length = 0;
   E? _first;
 
-  /// Construct a new empty linked list.
+  /// Constructs a new empty linked list.
   LinkedList();
 
-  /// Add [entry] to the beginning of the linked list.
+  /// Adds [entry] to the beginning of the linked list.
   void addFirst(E entry) {
     _insertBefore(_first, entry, updateFirst: true);
     _first = entry;
   }
 
-  /// Add [entry] to the end of the linked list.
+  /// Adds [entry] to the end of the linked list.
   void add(E entry) {
     _insertBefore(_first, entry, updateFirst: false);
   }
@@ -52,7 +52,7 @@
     entries.forEach(add);
   }
 
-  /// Remove [entry] from the linked list.
+  /// Removes [entry] from the linked list.
   ///
   /// Returns false and does nothing if [entry] is not in this linked list.
   ///
@@ -225,9 +225,9 @@
   E? _next;
   E? _previous;
 
-  /// Get the linked list containing this element.
+  /// The linked list containing this element.
   ///
-  /// Returns `null` if this entry is not currently in any list.
+  /// The value is `null` if this entry is not currently in any list.
   LinkedList<E>? get list => _list;
 
   /// Unlink the element from its linked list.
@@ -237,19 +237,19 @@
     _list!._unlink(this as E);
   }
 
-  /// Return the successor of this element in its linked list.
+  /// The successor of this element in its linked list.
   ///
-  /// Returns `null` if there is no successor in the linked list, or if this
-  /// entry is not currently in any list.
+  /// The value is  `null` if there is no successor in the linked list,
+  /// or if this entry is not currently in any list.
   E? get next {
     if (_list == null || identical(_list!.first, _next)) return null;
     return _next;
   }
 
-  /// Return the predecessor of this element in its linked list.
+  /// The predecessor of this element in its linked list.
   ///
-  /// Returns `null` if there is no predecessor in the linked list, or if this
-  /// entry is not currently in any list.
+  /// The value is `null` if there is no predecessor in the linked list,
+  /// or if this entry is not currently in any list.
   E? get previous {
     if (_list == null || identical(this, _list!.first)) return null;
     return _previous;
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index c238840..bb545b9 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.dart
@@ -30,7 +30,7 @@
   /// ```dart
   /// Queue<SuperType> superQueue = ...;
   /// Queue<SubType> subQueue =
-  ///     new Queue<SubType>.from(superQueue.whereType<SubType>());
+  ///     Queue<SubType>.from(superQueue.whereType<SubType>());
   /// ```
   factory Queue.from(Iterable elements) = ListQueue<E>.from;
 
@@ -286,7 +286,7 @@
   /// ```dart
   /// Queue<SuperType> superQueue = ...;
   /// Queue<SubType> subQueue =
-  ///     new DoubleLinkedQueue<SubType>.from(superQueue.whereType<SubType>());
+  ///     DoubleLinkedQueue<SubType>.from(superQueue.whereType<SubType>());
   /// ```
   factory DoubleLinkedQueue.from(Iterable<dynamic> elements) {
     DoubleLinkedQueue<E> list = DoubleLinkedQueue<E>();
@@ -565,7 +565,7 @@
   /// ```dart
   /// Queue<SuperType> superQueue = ...;
   /// Queue<SubType> subQueue =
-  ///     new ListQueue<SubType>.from(superQueue.whereType<SubType>());
+  ///     ListQueue<SubType>.from(superQueue.whereType<SubType>());
   /// ```
   factory ListQueue.from(Iterable<dynamic> elements) {
     if (elements is List<dynamic>) {
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index a019b64..2ad35f6 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -474,20 +474,25 @@
 
   Iterable<V> get values => _SplayTreeValueIterable<K, V>(this);
 
-  /// Get the first key in the map. Returns `null` if the map is empty.
+  /// The first key in the map.
+  ///
+  /// Returns `null` if the map is empty.
   K? firstKey() {
     if (_root == null) return null;
     return _first!.key;
   }
 
-  /// Get the last key in the map. Returns `null` if the map is empty.
+  /// The last key in the map.
+  ///
+  /// Returns `null` if the map is empty.
   K? lastKey() {
     if (_root == null) return null;
     return _last!.key;
   }
 
-  /// Get the last key in the map that is strictly smaller than [key]. Returns
-  /// `null` if no key was not found.
+  /// The last key in the map that is strictly smaller than [key].
+  ///
+  /// Returns `null` if no key was not found.
   K? lastKeyBefore(K key) {
     if (key == null) throw ArgumentError(key);
     if (_root == null) return null;
@@ -729,7 +734,7 @@
   /// ```dart
   /// Set<SuperType> superSet = ...;
   /// Set<SubType> subSet =
-  ///     new SplayTreeSet<SubType>.from(superSet.whereType<SubType>());
+  ///     SplayTreeSet<SubType>.from(superSet.whereType<SubType>());
   /// ```
   factory SplayTreeSet.from(Iterable elements,
       [int Function(E key1, E key2)? compare,
diff --git a/sdk/lib/ffi/allocation.dart b/sdk/lib/ffi/allocation.dart
new file mode 100644
index 0000000..fc5fce4
--- /dev/null
+++ b/sdk/lib/ffi/allocation.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+/// Manages memory on the native heap.
+abstract class Allocator {
+  /// This interface is meant to be implemented, not extended or mixed in.
+  Allocator._() {
+    throw UnsupportedError("Cannot be instantiated");
+  }
+
+  /// Allocates [byteCount] bytes of memory on the native heap.
+  ///
+  /// If [alignment] is provided, the allocated memory will be at least aligned
+  /// to [alignment] bytes.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment});
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  void free(Pointer pointer);
+}
+
+/// Extension on [Allocator] to provide allocation with [NativeType].
+extension AllocatorAlloc on Allocator {
+  /// Allocates `sizeOf<T>() * count` bytes of memory using
+  /// `allocator.allocate`.
+  ///
+  /// This extension method must be invoked with a compile-time constant [T].
+  external Pointer<T> call<T extends NativeType>([int count = 1]);
+}
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 68424f8..bce5feb 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -17,6 +17,7 @@
 import 'dart:typed_data';
 
 part "native_type.dart";
+part "allocation.dart";
 part "annotations.dart";
 part "dynamic_library.dart";
 part "struct.dart";
@@ -558,7 +559,7 @@
 }
 
 /// Opaque, not exposing it's members.
-class Dart_CObject extends Struct {}
+class Dart_CObject extends Opaque {}
 
 typedef Dart_NativeMessageHandler = Void Function(Int64, Pointer<Dart_CObject>);
 
diff --git a/sdk/lib/ffi/ffi_sources.gni b/sdk/lib/ffi/ffi_sources.gni
index 5b34b9c..db03071 100644
--- a/sdk/lib/ffi/ffi_sources.gni
+++ b/sdk/lib/ffi/ffi_sources.gni
@@ -6,6 +6,7 @@
   "ffi.dart",
 
   # The above file needs to be first as it lists the parts below.
+  "allocation.dart",
   "annotations.dart",
   "dynamic_library.dart",
   "native_type.dart",
diff --git a/sdk/lib/ffi/native_type.dart b/sdk/lib/ffi/native_type.dart
index e319342..31e4b72 100644
--- a/sdk/lib/ffi/native_type.dart
+++ b/sdk/lib/ffi/native_type.dart
@@ -12,6 +12,12 @@
   const NativeType();
 }
 
+/// [Opaque]'s subtypes represent opaque types in C.
+///
+/// [Opaque]'s subtypes are not constructible in the Dart code and serve purely
+/// as markers in type signatures.
+abstract class Opaque extends NativeType {}
+
 /// [_NativeInteger]'s subtypes represent a native integer in C.
 ///
 /// [_NativeInteger]'s subtypes are not constructible in the Dart code and serve
diff --git a/sdk/lib/isolate/capability.dart b/sdk/lib/isolate/capability.dart
index a51eec2..6678fc4 100644
--- a/sdk/lib/isolate/capability.dart
+++ b/sdk/lib/isolate/capability.dart
@@ -4,31 +4,26 @@
 
 part of dart.isolate;
 
-/**
- * An unforgeable object that comes back as equal when passed through other
- * isolates.
- *
- * Sending a capability object to another isolate, and getting it back,
- * will produce an object that is equal to the original.
- * There is no other way to create objects equal to a capability object.
- *
- * Capabilities can be used as access guards: A remote isolate can send
- * a request for an operation, but it is only allowed if the request contains
- * the correct capability object.
- *
- * This allows exposing the same interface to multiple clients,
- * but restricting some operations to only those clients
- * that have also been given the corresponding capability.
- *
- * Capabilities can be used inside a single isolate,
- * but they have no advantage over
- * just using `new Object` to create a unique object,
- * and it offers no real security against other code
- * running in the same isolate.
- */
+/// An unforgeable object that comes back as equal when passed through other
+/// isolates.
+///
+/// Sending a capability object to another isolate, and getting it back,
+/// will produce an object that is equal to the original.
+/// There is no other way to create objects equal to a capability object.
+///
+/// Capabilities can be used as access guards.
+/// An isolate can receive requests for operations from other isolates,
+/// but only allow them if the request contains the correct capability object.
+/// This allows exposing the same interface to multiple clients,
+/// but restricting some operations to only those clients
+/// that have also been given the corresponding capability.
+///
+/// Capabilities can be used inside a single isolate,
+/// but they have no advantage over
+/// just using `Object()` to create a unique object,
+/// and it offers no real security against other code
+/// running in the same isolate.
 class Capability {
-  /**
-   * Create a new unforgeable capability object.
-   */
+  /// Create a new unforgeable capability object.
   external factory Capability();
 }
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index b7650dd..7a15d7b 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -2,18 +2,16 @@
 // 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.
 
-/**
- * Concurrent programming using _isolates_:
- * independent workers that are similar to threads
- * but don't share memory,
- * communicating only via messages.
- *
- * To use this library in your code:
- *
- *     import 'dart:isolate';
- *
- * {@category VM}
- */
+/// Concurrent programming using _isolates_:
+/// independent workers that are similar to threads
+/// but don't share memory,
+/// communicating only via messages.
+///
+/// To use this library in your code:
+/// ```dart
+/// import 'dart:isolate';
+/// ```
+/// {@category VM}
 library dart.isolate;
 
 import "dart:async";
@@ -22,230 +20,207 @@
 
 part "capability.dart";
 
-/**
- * Thrown when an isolate cannot be created.
- */
+/// Thrown when an isolate cannot be created.
 class IsolateSpawnException implements Exception {
-  /** Error message reported by the spawn operation. */
+  /// Error message reported by the spawn operation.
   final String message;
   @pragma("vm:entry-point")
   IsolateSpawnException(this.message);
   String toString() => "IsolateSpawnException: $message";
 }
 
-/**
- * An isolated Dart execution context.
- *
- * All Dart code runs in an isolate, and code can access classes and values
- * only from the same isolate. Different isolates can communicate by sending
- * values through ports (see [ReceivePort], [SendPort]).
- *
- * An `Isolate` object is a reference to an isolate, usually different from
- * the current isolate.
- * It represents, and can be used to control, the other isolate.
- *
- * When spawning a new isolate, the spawning isolate receives an `Isolate`
- * object representing the new isolate when the spawn operation succeeds.
- *
- * Isolates run code in its own event loop, and each event may run smaller tasks
- * in a nested microtask queue.
- *
- * An `Isolate` object allows other isolates to control the event loop
- * of the isolate that it represents, and to inspect the isolate,
- * for example by pausing the isolate or by getting events when the isolate
- * has an uncaught error.
- *
- * The [controlPort] identifies and gives access to controlling the isolate,
- * and the [pauseCapability] and [terminateCapability] guard access
- * to some control operations.
- * For example, calling [pause] on an `Isolate` object created without a
- * [pauseCapability], has no effect.
- *
- * The `Isolate` object provided by a spawn operation will have the
- * control port and capabilities needed to control the isolate.
- * New isolate objects can be created without some of these capabilities
- * if necessary, using the [Isolate.Isolate] constructor.
- *
- * An `Isolate` object cannot be sent over a `SendPort`, but the control port
- * and capabilities can be sent, and can be used to create a new functioning
- * `Isolate` object in the receiving port's isolate.
- */
+/// An isolated Dart execution context.
+///
+/// All Dart code runs in an isolate, and code can access classes and values
+/// only from the same isolate. Different isolates can communicate by sending
+/// values through ports (see [ReceivePort], [SendPort]).
+///
+/// An `Isolate` object is a reference to an isolate, usually different from
+/// the current isolate.
+/// It represents, and can be used to control, the other isolate.
+///
+/// When spawning a new isolate, the spawning isolate receives an `Isolate`
+/// object representing the new isolate when the spawn operation succeeds.
+///
+/// Isolates run code in its own event loop, and each event may run smaller tasks
+/// in a nested microtask queue.
+///
+/// An `Isolate` object allows other isolates to control the event loop
+/// of the isolate that it represents, and to inspect the isolate,
+/// for example by pausing the isolate or by getting events when the isolate
+/// has an uncaught error.
+///
+/// The [controlPort] identifies and gives access to controlling the isolate,
+/// and the [pauseCapability] and [terminateCapability] guard access
+/// to some control operations.
+/// For example, calling [pause] on an `Isolate` object created without a
+/// [pauseCapability], has no effect.
+///
+/// The `Isolate` object provided by a spawn operation will have the
+/// control port and capabilities needed to control the isolate.
+/// New isolate objects can be created without some of these capabilities
+/// if necessary, using the [Isolate.Isolate] constructor.
+///
+/// An `Isolate` object cannot be sent over a `SendPort`, but the control port
+/// and capabilities can be sent, and can be used to create a new functioning
+/// `Isolate` object in the receiving port's isolate.
 class Isolate {
-  /** Argument to `ping` and `kill`: Ask for immediate action. */
+  /// Argument to `ping` and `kill`: Ask for immediate action.
   static const int immediate = 0;
-  /** Argument to `ping` and `kill`: Ask for action before the next event. */
+
+  /// Argument to `ping` and `kill`: Ask for action before the next event.
   static const int beforeNextEvent = 1;
 
-  /**
-   * Control port used to send control messages to the isolate.
-   *
-   * The control port identifies the isolate.
-   *
-   * An `Isolate` object allows sending control messages
-   * through the control port.
-   *
-   * Some control messages require a specific capability to be passed along
-   * with the message (see [pauseCapability] and [terminateCapability]),
-   * otherwise the message is ignored by the isolate.
-   */
+  /// Control port used to send control messages to the isolate.
+  ///
+  /// The control port identifies the isolate.
+  ///
+  /// An `Isolate` object allows sending control messages
+  /// through the control port.
+  ///
+  /// Some control messages require a specific capability to be passed along
+  /// with the message (see [pauseCapability] and [terminateCapability]),
+  /// otherwise the message is ignored by the isolate.
   final SendPort controlPort;
 
-  /**
-   * Capability granting the ability to pause the isolate.
-   *
-   * This capability is required by [pause].
-   * If the capability is `null`, or if it is not the correct pause capability
-   * of the isolate identified by [controlPort],
-   * then calls to [pause] will have no effect.
-   *
-   * If the isolate is spawned in a paused state, use this capability as
-   * argument to the [resume] method in order to resume the paused isolate.
-   */
+  /// Capability granting the ability to pause the isolate.
+  ///
+  /// This capability is required by [pause].
+  /// If the capability is `null`, or if it is not the correct pause capability
+  /// of the isolate identified by [controlPort],
+  /// then calls to [pause] will have no effect.
+  ///
+  /// If the isolate is spawned in a paused state, use this capability as
+  /// argument to the [resume] method in order to resume the paused isolate.
   final Capability? pauseCapability;
 
-  /**
-   * Capability granting the ability to terminate the isolate.
-   *
-   * This capability is required by [kill] and [setErrorsFatal].
-   * If the capability is `null`, or if it is not the correct termination
-   * capability of the isolate identified by [controlPort],
-   * then calls to those methods will have no effect.
-   */
+  /// Capability granting the ability to terminate the isolate.
+  ///
+  /// This capability is required by [kill] and [setErrorsFatal].
+  /// If the capability is `null`, or if it is not the correct termination
+  /// capability of the isolate identified by [controlPort],
+  /// then calls to those methods will have no effect.
   final Capability? terminateCapability;
 
-  /**
-   * The name of the [Isolate] displayed for debug purposes.
-   *
-   * This can be set using the `debugName` parameter in [spawn] and [spawnUri].
-   *
-   * This name does not uniquely identify an isolate. Multiple isolates in the
-   * same process may have the same `debugName`.
-   *
-   * For a given isolate, this value will be the same as the values returned by
-   * `Dart_DebugName` in the C embedding API and the `debugName` property in
-   * [IsolateMirror].
-   */
+  /// The name of the [Isolate] displayed for debug purposes.
+  ///
+  /// This can be set using the `debugName` parameter in [spawn] and [spawnUri].
+  ///
+  /// This name does not uniquely identify an isolate. Multiple isolates in the
+  /// same process may have the same `debugName`.
+  ///
+  /// For a given isolate, this value will be the same as the values returned by
+  /// `Dart_DebugName` in the C embedding API and the `debugName` property in
+  /// [IsolateMirror].
   @Since("2.3")
   external String? get debugName;
 
-  /**
-   * Create a new [Isolate] object with a restricted set of capabilities.
-   *
-   * The port should be a control port for an isolate, as taken from
-   * another `Isolate` object.
-   *
-   * The capabilities should be the subset of the capabilities that are
-   * available to the original isolate.
-   * Capabilities of an isolate are locked to that isolate, and have no effect
-   * anywhere else, so the capabilities should come from the same isolate as
-   * the control port.
-   *
-   * Can also be used to create an [Isolate] object from a control port, and
-   * any available capabilities, that have been sent through a [SendPort].
-   *
-   * Example:
-   * ```dart
-   * Isolate isolate = findSomeIsolate();
-   * Isolate restrictedIsolate = new Isolate(isolate.controlPort);
-   * untrustedCode(restrictedIsolate);
-   * ```
-   * This example creates a new `Isolate` object that cannot be used to
-   * pause or terminate the isolate. All the untrusted code can do is to
-   * inspect the isolate and see uncaught errors or when it terminates.
-   */
+  /// Creates a new [Isolate] object with a restricted set of capabilities.
+  ///
+  /// The port should be a control port for an isolate, as taken from
+  /// another `Isolate` object.
+  ///
+  /// The capabilities should be the subset of the capabilities that are
+  /// available to the original isolate.
+  /// Capabilities of an isolate are locked to that isolate, and have no effect
+  /// anywhere else, so the capabilities should come from the same isolate as
+  /// the control port.
+  ///
+  /// Can also be used to create an [Isolate] object from a control port, and
+  /// any available capabilities, that have been sent through a [SendPort].
+  ///
+  /// Example:
+  /// ```dart
+  /// Isolate isolate = findSomeIsolate();
+  /// Isolate restrictedIsolate = Isolate(isolate.controlPort);
+  /// untrustedCode(restrictedIsolate);
+  /// ```
+  /// This example creates a new `Isolate` object that cannot be used to
+  /// pause or terminate the isolate. All the untrusted code can do is to
+  /// inspect the isolate and see uncaught errors or when it terminates.
   Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});
 
-  /**
-   * Return an [Isolate] object representing the current isolate.
-   *
-   * The current isolate for code using [current]
-   * is the isolate running the code.
-   *
-   * The isolate object provides the capabilities required to inspect,
-   * pause or kill the isolate, and allows granting these capabilities
-   * to others.
-   *
-   * It is possible to pause the current isolate, but doing so *without*
-   * first passing the ability to resume it again to another isolate,
-   * is a sure way to hang your program.
-   */
+  /// An [Isolate] object representing the current isolate.
+  ///
+  /// The current isolate for code using [current]
+  /// is the isolate running the code.
+  ///
+  /// The isolate object provides the capabilities required to inspect,
+  /// pause or kill the isolate, and allows granting these capabilities
+  /// to others.
+  ///
+  /// It is possible to pause the current isolate, but doing so *without*
+  /// first passing the ability to resume it again to another isolate,
+  /// is a sure way to hang your program.
   external static Isolate get current;
 
-  /**
-   * The location of the package configuration of the current isolate, if any.
-   *
-   * This getter returns `null`, as the `packages/` directory is not supported
-   * in Dart 2.
-   */
+  /// The package root of the current isolate, if any.
+  ///
+  /// This getter returns `null`, as the `packages/` directory is not supported
+  /// in Dart 2.
   @Deprecated('packages/ directory resolution is not supported in Dart 2.')
   external static Future<Uri?> get packageRoot;
 
-  /**
-   * The package root of the current isolate, if any.
-   *
-   * If the isolate is using a [packageRoot] or the isolate has not been
-   * setup for package resolution, this getter returns `null`, otherwise it
-   * returns the package config URI.
-   */
+  /// The location of the package configuration of the current isolate, if any.
+  ///
+  /// If the isolate has not been setup for package resolution,
+  /// this location is `null`,
+  /// otherwise it is a URI referencing the package config file.
   external static Future<Uri?> get packageConfig;
 
-  /**
-   * Maps a package: URI to a non-package Uri.
-   *
-   * If there is no valid mapping from the package: URI in the current
-   * isolate, then this call returns `null`. Non-package: URIs are
-   * returned unmodified.
-   */
+  /// Maps a `package:` URI to a non-package Uri.
+  ///
+  /// If there is no valid mapping from the `package:` URI in the current
+  /// isolate, then this call returns `null`. Non-`package:` URIs are
+  /// returned unmodified.
   external static Future<Uri?> resolvePackageUri(Uri packageUri);
 
-  /**
-   * Creates and spawns an isolate that shares the same code as the current
-   * isolate.
-   *
-   * The argument [entryPoint] specifies the initial function to call
-   * in the spawned isolate.
-   * The entry-point function is invoked in the new isolate with [message]
-   * as the only argument.
-   *
-   * The function must be a top-level function or a static method
-   * that can be called with a single argument,
-   * that is, a compile-time constant function value
-   * which accepts at least one positional parameter
-   * and has at most one required positional parameter.
-   * The function may accept any number of optional parameters,
-   * as long as it *can* be called with just a single argument.
-   * The function must not be the value of a function expression
-   * or an instance method tear-off.
-   *
-   * Usually the initial [message] contains a [SendPort] so
-   * that the spawner and spawnee can communicate with each other.
-   *
-   * If the [paused] parameter is set to `true`,
-   * the isolate will start up in a paused state,
-   * just before calling the [entryPoint] function with the [message],
-   * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
-   * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
-   *
-   * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
-   * the isolate will act as if, respectively, [setErrorsFatal],
-   * [addOnExitListener] and [addErrorListener] were called with the
-   * corresponding parameter and was processed before the isolate starts
-   * running.
-   *
-   * If [debugName] is provided, the spawned [Isolate] will be identifiable by
-   * this name in debuggers and logging.
-   *
-   * If [errorsAreFatal] is omitted, the platform may choose a default behavior
-   * or inherit the current isolate's behavior.
-   *
-   * You can also call the [setErrorsFatal], [addOnExitListener] and
-   * [addErrorListener] methods on the returned isolate, but unless the
-   * isolate was started as [paused], it may already have terminated
-   * before those methods can complete.
-   *
-   * Returns a future which will complete with an [Isolate] instance if the
-   * spawning succeeded. It will complete with an error otherwise.
-   */
+  /// Creates and spawns an isolate that shares the same code as the current
+  /// isolate.
+  ///
+  /// The argument [entryPoint] specifies the initial function to call
+  /// in the spawned isolate.
+  /// The entry-point function is invoked in the new isolate with [message]
+  /// as the only argument.
+  ///
+  /// The function must be a top-level function or a static method
+  /// that can be called with a single argument,
+  /// that is, a compile-time constant function value
+  /// which accepts at least one positional parameter
+  /// and has at most one required positional parameter.
+  /// The function may accept any number of optional parameters,
+  /// as long as it *can* be called with just a single argument.
+  /// The function must not be the value of a function expression
+  /// or an instance method tear-off.
+  ///
+  /// Usually the initial [message] contains a [SendPort] so
+  /// that the spawner and spawnee can communicate with each other.
+  ///
+  /// If the [paused] parameter is set to `true`,
+  /// the isolate will start up in a paused state,
+  /// just before calling the [entryPoint] function with the [message],
+  /// as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+  /// To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+  ///
+  /// If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+  /// the isolate will act as if, respectively, [setErrorsFatal],
+  /// [addOnExitListener] and [addErrorListener] were called with the
+  /// corresponding parameter and was processed before the isolate starts
+  /// running.
+  ///
+  /// If [debugName] is provided, the spawned [Isolate] will be identifiable by
+  /// this name in debuggers and logging.
+  ///
+  /// If [errorsAreFatal] is omitted, the platform may choose a default behavior
+  /// or inherit the current isolate's behavior.
+  ///
+  /// You can also call the [setErrorsFatal], [addOnExitListener] and
+  /// [addErrorListener] methods on the returned isolate, but unless the
+  /// isolate was started as [paused], it may already have terminated
+  /// before those methods can complete.
+  ///
+  /// Returns a future which will complete with an [Isolate] instance if the
+  /// spawning succeeded. It will complete with an error otherwise.
   external static Future<Isolate> spawn<T>(
       void entryPoint(T message), T message,
       {bool paused = false,
@@ -254,78 +229,76 @@
       SendPort? onError,
       @Since("2.3") String? debugName});
 
-  /**
-   * Creates and spawns an isolate that runs the code from the library with
-   * the specified URI.
-   *
-   * The isolate starts executing the top-level `main` function of the library
-   * with the given URI.
-   *
-   * The target `main` must be callable with zero, one or two arguments.
-   * Examples:
-   *
-   * * `main()`
-   * * `main(args)`
-   * * `main(args, message)`
-   *
-   * When present, the parameter `args` is set to the provided [args] list.
-   * When present, the parameter `message` is set to the initial [message].
-   *
-   * If the [paused] parameter is set to `true`,
-   * the isolate will start up in a paused state,
-   * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
-   * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
-   *
-   * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
-   * the isolate will act as if, respectively, [setErrorsFatal],
-   * [addOnExitListener] and [addErrorListener] were called with the
-   * corresponding parameter and was processed before the isolate starts
-   * running.
-   *
-   * You can also call the [setErrorsFatal], [addOnExitListener] and
-   * [addErrorListener] methods on the returned isolate, but unless the
-   * isolate was started as [paused], it may already have terminated
-   * before those methods can complete.
-   *
-   * If the [checked] parameter is set to `true` or `false`,
-   * the new isolate will run code in checked mode (enabling asserts and type
-   * checks), respectively in production mode (disabling asserts and type
-   * checks), if possible. If the parameter is omitted, the new isolate will
-   * inherit the value from the current isolate.
-   *
-   * In Dart2 strong mode, the `checked` parameter only controls asserts, but
-   * not type checks.
-   *
-   * It may not always be possible to honor the `checked` parameter.
-   * If the isolate code was pre-compiled, it may not be possible to change
-   * the checked mode setting dynamically.
-   * In that case, the `checked` parameter is ignored.
-   *
-   * WARNING: The [checked] parameter is not implemented on all platforms yet.
-   *
-   * If the [packageConfig] parameter is provided, then it is used to find the
-   * location of a package resolution configuration file for the spawned
-   * isolate.
-   *
-   * If the [automaticPackageResolution] parameter is provided, then the
-   * location of the package sources in the spawned isolate is automatically
-   * determined.
-   *
-   * The [environment] is a mapping from strings to strings which the
-   * spawned isolate uses when looking up [String.fromEnvironment] values.
-   * The system may add its own entries to environment as well.
-   * If `environment` is omitted, the spawned isolate has the same environment
-   * declarations as the spawning isolate.
-   *
-   * WARNING: The [environment] parameter is not implemented on all
-   * platforms yet.
-   *
-   * If [debugName] is provided, the spawned [Isolate] will be identifiable by
-   * this name in debuggers and logging.
-   *
-   * Returns a future that will complete with an [Isolate] instance if the
-   * spawning succeeded. It will complete with an error otherwise.
-   */
+  /// Creates and spawns an isolate that runs the code from the library with
+  /// the specified URI.
+  ///
+  /// The isolate starts executing the top-level `main` function of the library
+  /// with the given URI.
+  ///
+  /// The target `main` must be callable with zero, one or two arguments.
+  /// Examples:
+  ///
+  /// * `main()`
+  /// * `main(args)`
+  /// * `main(args, message)`
+  ///
+  /// When present, the parameter `args` is set to the provided [args] list.
+  /// When present, the parameter `message` is set to the initial [message].
+  ///
+  /// If the [paused] parameter is set to `true`,
+  /// the isolate will start up in a paused state,
+  /// as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+  /// To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+  ///
+  /// If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+  /// the isolate will act as if, respectively, [setErrorsFatal],
+  /// [addOnExitListener] and [addErrorListener] were called with the
+  /// corresponding parameter and was processed before the isolate starts
+  /// running.
+  ///
+  /// You can also call the [setErrorsFatal], [addOnExitListener] and
+  /// [addErrorListener] methods on the returned isolate, but unless the
+  /// isolate was started as [paused], it may already have terminated
+  /// before those methods can complete.
+  ///
+  /// If the [checked] parameter is set to `true` or `false`,
+  /// the new isolate will run code in checked mode (enabling asserts and type
+  /// checks), respectively in production mode (disabling asserts and type
+  /// checks), if possible. If the parameter is omitted, the new isolate will
+  /// inherit the value from the current isolate.
+  ///
+  /// In Dart2 strong mode, the `checked` parameter only controls asserts, but
+  /// not type checks.
+  ///
+  /// It may not always be possible to honor the `checked` parameter.
+  /// If the isolate code was pre-compiled, it may not be possible to change
+  /// the checked mode setting dynamically.
+  /// In that case, the `checked` parameter is ignored.
+  ///
+  /// WARNING: The [checked] parameter is not implemented on all platforms yet.
+  ///
+  /// If the [packageConfig] parameter is provided, then it is used to find the
+  /// location of a package resolution configuration file for the spawned
+  /// isolate.
+  ///
+  /// If the [automaticPackageResolution] parameter is provided, then the
+  /// location of the package sources in the spawned isolate is automatically
+  /// determined.
+  ///
+  /// The [environment] is a mapping from strings to strings which the
+  /// spawned isolate uses when looking up [String.fromEnvironment] values.
+  /// The system may add its own entries to environment as well.
+  /// If `environment` is omitted, the spawned isolate has the same environment
+  /// declarations as the spawning isolate.
+  ///
+  /// WARNING: The [environment] parameter is not implemented on all
+  /// platforms yet.
+  ///
+  /// If [debugName] is provided, the spawned [Isolate] will be identifiable by
+  /// this name in debuggers and logging.
+  ///
+  /// Returns a future that will complete with an [Isolate] instance if the
+  /// spawning succeeded. It will complete with an error otherwise.
   external static Future<Isolate> spawnUri(
       Uri uri,
       List<String> args,
@@ -343,239 +316,219 @@
       @Since("2.3")
           String? debugName});
 
-  /**
-   * Requests the isolate to pause.
-   *
-   * When the isolate receives the pause command, it stops
-   * processing events from the event loop queue.
-   * It may still add new events to the queue in response to, e.g., timers
-   * or receive-port messages. When the isolate is resumed,
-   * it starts handling the already enqueued events.
-   *
-   * The pause request is sent through the isolate's command port,
-   * which bypasses the receiving isolate's event loop.
-   * The pause takes effect when it is received, pausing the event loop
-   * as it is at that time.
-   *
-   * The [resumeCapability] is used to identity the pause,
-   * and must be used again to end the pause using [resume].
-   * If [resumeCapability] is omitted, a new capability object is created
-   * and used instead.
-   *
-   * If an isolate is paused more than once using the same capability,
-   * only one resume with that capability is needed to end the pause.
-   *
-   * If an isolate is paused using more than one capability,
-   * each pause must be individually ended before the isolate resumes.
-   *
-   * Returns the capability that must be used to end the pause.
-   * This is either [resumeCapability], or a new capability when
-   * [resumeCapability] is omitted.
-   *
-   * If [pauseCapability] is `null`, or it's not the pause capability
-   * of the isolate identified by [controlPort],
-   * the pause request is ignored by the receiving isolate.
-   */
+  /// Requests the isolate to pause.
+  ///
+  /// When the isolate receives the pause command, it stops
+  /// processing events from the event loop queue.
+  /// It may still add new events to the queue in response to, e.g., timers
+  /// or receive-port messages. When the isolate is resumed,
+  /// it starts handling the already enqueued events.
+  ///
+  /// The pause request is sent through the isolate's command port,
+  /// which bypasses the receiving isolate's event loop.
+  /// The pause takes effect when it is received, pausing the event loop
+  /// as it is at that time.
+  ///
+  /// The [resumeCapability] is used to identity the pause,
+  /// and must be used again to end the pause using [resume].
+  /// If [resumeCapability] is omitted, a new capability object is created
+  /// and used instead.
+  ///
+  /// If an isolate is paused more than once using the same capability,
+  /// only one resume with that capability is needed to end the pause.
+  ///
+  /// If an isolate is paused using more than one capability,
+  /// each pause must be individually ended before the isolate resumes.
+  ///
+  /// Returns the capability that must be used to end the pause.
+  /// This is either [resumeCapability], or a new capability when
+  /// [resumeCapability] is omitted.
+  ///
+  /// If [pauseCapability] is `null`, or it's not the pause capability
+  /// of the isolate identified by [controlPort],
+  /// the pause request is ignored by the receiving isolate.
   Capability pause([Capability? resumeCapability]) {
     resumeCapability ??= new Capability();
     _pause(resumeCapability);
     return resumeCapability;
   }
 
-  /** Internal implementation of [pause]. */
+  /// Internal implementation of [pause].
   external void _pause(Capability resumeCapability);
 
-  /**
-   * Resumes a paused isolate.
-   *
-   * Sends a message to an isolate requesting that it ends a pause
-   * that was previously requested.
-   *
-   * When all active pause requests have been cancelled, the isolate
-   * will continue processing events and handling normal messages.
-   *
-   * If the [resumeCapability] is not one that has previously been used
-   * to pause the isolate, or it has already been used to resume from
-   * that pause, the resume call has no effect.
-   */
+  /// Resumes a paused isolate.
+  ///
+  /// Sends a message to an isolate requesting that it ends a pause
+  /// that was previously requested.
+  ///
+  /// When all active pause requests have been cancelled, the isolate
+  /// will continue processing events and handling normal messages.
+  ///
+  /// If the [resumeCapability] is not one that has previously been used
+  /// to pause the isolate, or it has already been used to resume from
+  /// that pause, the resume call has no effect.
   external void resume(Capability resumeCapability);
 
-  /**
-   * Requests an exit message on [responsePort] when the isolate terminates.
-   *
-   * The isolate will send [response] as a message on [responsePort] as the last
-   * thing before it terminates. It will run no further code after the message
-   * has been sent.
-   *
-   * Adding the same port more than once will only cause it to receive one exit
-   * message, using the last response value that was added,
-   * and it only needs to be removed once using [removeOnExitListener].
-   *
-   * If the isolate has terminated before it can receive this request,
-   * no exit message will be sent.
-   *
-   * The [response] object must follow the same restrictions as enforced by
-   * [SendPort.send].
-   * It is recommended to only use simple values that can be sent to all
-   * isolates, like `null`, booleans, numbers or strings.
-   *
-   * Since isolates run concurrently, it's possible for it to exit before the
-   * exit listener is established, and in that case no response will be
-   * sent on [responsePort].
-   * To avoid this, either use the corresponding parameter to the spawn
-   * function, or start the isolate paused, add the listener and
-   * then resume the isolate.
-   */
+  /// Requests an exit message on [responsePort] when the isolate terminates.
+  ///
+  /// The isolate will send [response] as a message on [responsePort] as the last
+  /// thing before it terminates. It will run no further code after the message
+  /// has been sent.
+  ///
+  /// Adding the same port more than once will only cause it to receive one exit
+  /// message, using the last response value that was added,
+  /// and it only needs to be removed once using [removeOnExitListener].
+  ///
+  /// If the isolate has terminated before it can receive this request,
+  /// no exit message will be sent.
+  ///
+  /// The [response] object must follow the same restrictions as enforced by
+  /// [SendPort.send].
+  /// It is recommended to only use simple values that can be sent to all
+  /// isolates, like `null`, booleans, numbers or strings.
+  ///
+  /// Since isolates run concurrently, it's possible for it to exit before the
+  /// exit listener is established, and in that case no response will be
+  /// sent on [responsePort].
+  /// To avoid this, either use the corresponding parameter to the spawn
+  /// function, or start the isolate paused, add the listener and
+  /// then resume the isolate.
   /* TODO(lrn): Can we do better? Can the system recognize this message and
    * send a reply if the receiving isolate is dead?
    */
   external void addOnExitListener(SendPort responsePort, {Object? response});
 
-  /**
-   * Stops listening for exit messages from the isolate.
-   *
-   * Requests for the isolate to not send exit messages on [responsePort].
-   * If the isolate isn't expecting to send exit messages on [responsePort],
-   * because the port hasn't been added using [addOnExitListener],
-   * or because it has already been removed, the request is ignored.
-   *
-   * If the same port has been passed via [addOnExitListener] more than once,
-   * only one call to `removeOnExitListener` is needed to stop it from receiving
-   * exit messages.
-   *
-   * Closing the receive port that is associated with the [responsePort] does
-   * not stop the isolate from sending uncaught errors, they are just going to
-   * be lost.
-   *
-   * An exit message may still be sent if the isolate terminates
-   * before this request is received and processed.
-   */
+  /// Stops listening for exit messages from the isolate.
+  ///
+  /// Requests for the isolate to not send exit messages on [responsePort].
+  /// If the isolate isn't expecting to send exit messages on [responsePort],
+  /// because the port hasn't been added using [addOnExitListener],
+  /// or because it has already been removed, the request is ignored.
+  ///
+  /// If the same port has been passed via [addOnExitListener] more than once,
+  /// only one call to `removeOnExitListener` is needed to stop it from receiving
+  /// exit messages.
+  ///
+  /// Closing the receive port that is associated with the [responsePort] does
+  /// not stop the isolate from sending uncaught errors, they are just going to
+  /// be lost.
+  ///
+  /// An exit message may still be sent if the isolate terminates
+  /// before this request is received and processed.
   external void removeOnExitListener(SendPort responsePort);
 
-  /**
-   * Sets whether uncaught errors will terminate the isolate.
-   *
-   * If errors are fatal, any uncaught error will terminate the isolate
-   * event loop and shut down the isolate.
-   *
-   * This call requires the [terminateCapability] for the isolate.
-   * If the capability is absent or incorrect, no change is made.
-   *
-   * Since isolates run concurrently, it's possible for the receiving isolate
-   * to exit due to an error, before a request, using this method, has been
-   * received and processed.
-   * To avoid this, either use the corresponding parameter to the spawn
-   * function, or start the isolate paused, set errors non-fatal and
-   * then resume the isolate.
-   */
+  /// Sets whether uncaught errors will terminate the isolate.
+  ///
+  /// If errors are fatal, any uncaught error will terminate the isolate
+  /// event loop and shut down the isolate.
+  ///
+  /// This call requires the [terminateCapability] for the isolate.
+  /// If the capability is absent or incorrect, no change is made.
+  ///
+  /// Since isolates run concurrently, it's possible for the receiving isolate
+  /// to exit due to an error, before a request, using this method, has been
+  /// received and processed.
+  /// To avoid this, either use the corresponding parameter to the spawn
+  /// function, or start the isolate paused, set errors non-fatal and
+  /// then resume the isolate.
   external void setErrorsFatal(bool errorsAreFatal);
 
-  /**
-   * Requests the isolate to shut down.
-   *
-   * The isolate is requested to terminate itself.
-   * The [priority] argument specifies when this must happen.
-   *
-   * The [priority], when provided, must be one of [immediate] or
-   * [beforeNextEvent] (the default).
-   * The shutdown is performed at different times depending on the priority:
-   *
-   * * `immediate`: The isolate shuts down as soon as possible.
-   *     Control messages are handled in order, so all previously sent control
-   *     events from this isolate will all have been processed.
-   *     The shutdown should happen no later than if sent with
-   *     `beforeNextEvent`.
-   *     It may happen earlier if the system has a way to shut down cleanly
-   *     at an earlier time, even during the execution of another event.
-   * * `beforeNextEvent`: The shutdown is scheduled for the next time
-   *     control returns to the event loop of the receiving isolate,
-   *     after the current event, and any already scheduled control events,
-   *     are completed.
-   *
-   * If [terminateCapability] is `null`, or it's not the terminate capability
-   * of the isolate identified by [controlPort],
-   * the kill request is ignored by the receiving isolate.
-   */
+  /// Requests the isolate to shut down.
+  ///
+  /// The isolate is requested to terminate itself.
+  /// The [priority] argument specifies when this must happen.
+  ///
+  /// The [priority], when provided, must be one of [immediate] or
+  /// [beforeNextEvent] (the default).
+  /// The shutdown is performed at different times depending on the priority:
+  ///
+  /// * `immediate`: The isolate shuts down as soon as possible.
+  ///     Control messages are handled in order, so all previously sent control
+  ///     events from this isolate will all have been processed.
+  ///     The shutdown should happen no later than if sent with
+  ///     `beforeNextEvent`.
+  ///     It may happen earlier if the system has a way to shut down cleanly
+  ///     at an earlier time, even during the execution of another event.
+  /// * `beforeNextEvent`: The shutdown is scheduled for the next time
+  ///     control returns to the event loop of the receiving isolate,
+  ///     after the current event, and any already scheduled control events,
+  ///     are completed.
+  ///
+  /// If [terminateCapability] is `null`, or it's not the terminate capability
+  /// of the isolate identified by [controlPort],
+  /// the kill request is ignored by the receiving isolate.
   external void kill({int priority = beforeNextEvent});
 
-  /**
-   * Requests that the isolate send [response] on the [responsePort].
-   *
-   * The [response] object must follow the same restrictions as enforced by
-   * [SendPort.send].
-   * It is recommended to only use simple values that can be sent to all
-   * isolates, like `null`, booleans, numbers or strings.
-   *
-   * If the isolate is alive, it will eventually send `response`
-   * (defaulting to `null`) on the response port.
-   *
-   * The [priority] must be one of [immediate] or [beforeNextEvent].
-   * The response is sent at different times depending on the ping type:
-   *
-   * * `immediate`: The isolate responds as soon as it receives the
-   *     control message. This is after any previous control message
-   *     from the same isolate has been received and processed,
-   *     but may be during execution of another event.
-   * * `beforeNextEvent`: The response is scheduled for the next time
-   *     control returns to the event loop of the receiving isolate,
-   *     after the current event, and any already scheduled control events,
-   *     are completed.
-   */
+  /// Requests that the isolate send [response] on the [responsePort].
+  ///
+  /// The [response] object must follow the same restrictions as enforced by
+  /// [SendPort.send].
+  /// It is recommended to only use simple values that can be sent to all
+  /// isolates, like `null`, booleans, numbers or strings.
+  ///
+  /// If the isolate is alive, it will eventually send `response`
+  /// (defaulting to `null`) on the response port.
+  ///
+  /// The [priority] must be one of [immediate] or [beforeNextEvent].
+  /// The response is sent at different times depending on the ping type:
+  ///
+  /// * `immediate`: The isolate responds as soon as it receives the
+  ///     control message. This is after any previous control message
+  ///     from the same isolate has been received and processed,
+  ///     but may be during execution of another event.
+  /// * `beforeNextEvent`: The response is scheduled for the next time
+  ///     control returns to the event loop of the receiving isolate,
+  ///     after the current event, and any already scheduled control events,
+  ///     are completed.
   external void ping(SendPort responsePort,
       {Object? response, int priority = immediate});
 
-  /**
-   * Requests that uncaught errors of the isolate are sent back to [port].
-   *
-   * The errors are sent back as two elements lists.
-   * The first element is a `String` representation of the error, usually
-   * created by calling `toString` on the error.
-   * The second element is a `String` representation of an accompanying
-   * stack trace, or `null` if no stack trace was provided.
-   * To convert this back to a [StackTrace] object, use [StackTrace.fromString].
-   *
-   * Listening using the same port more than once does nothing.
-   * A port will only receive each error once,
-   * and will only need to be removed once using [removeErrorListener].
-
-   * Closing the receive port that is associated with the port does not stop
-   * the isolate from sending uncaught errors, they are just going to be lost.
-   * Instead use [removeErrorListener] to stop receiving errors on [port].
-   *
-   * Since isolates run concurrently, it's possible for it to exit before the
-   * error listener is established. To avoid this, start the isolate paused,
-   * add the listener and then resume the isolate.
-   */
+  /// Requests that uncaught errors of the isolate are sent back to [port].
+  ///
+  /// The errors are sent back as two-element lists.
+  /// The first element is a `String` representation of the error, usually
+  /// created by calling `toString` on the error.
+  /// The second element is a `String` representation of an accompanying
+  /// stack trace, or `null` if no stack trace was provided.
+  /// To convert this back to a [StackTrace] object, use [StackTrace.fromString].
+  ///
+  /// Listening using the same port more than once does nothing.
+  /// A port will only receive each error once,
+  /// and will only need to be removed once using [removeErrorListener].
+  ///
+  /// Closing the receive port that is associated with the port does not stop
+  /// the isolate from sending uncaught errors, they are just going to be lost.
+  /// Instead use [removeErrorListener] to stop receiving errors on [port].
+  ///
+  /// Since isolates run concurrently, it's possible for it to exit before the
+  /// error listener is established. To avoid this, start the isolate paused,
+  /// add the listener and then resume the isolate.
   external void addErrorListener(SendPort port);
 
-  /**
-   * Stops listening for uncaught errors from the isolate.
-   *
-   * Requests for the isolate to not send uncaught errors on [port].
-   * If the isolate isn't expecting to send uncaught errors on [port],
-   * because the port hasn't been added using [addErrorListener],
-   * or because it has already been removed, the request is ignored.
-   *
-   * If the same port has been passed via [addErrorListener] more than once,
-   * only one call to `removeErrorListener` is needed to stop it from receiving
-   * uncaught errors.
-   *
-   * Uncaught errors message may still be sent by the isolate
-   * until this request is received and processed.
-   */
+  /// Stops listening for uncaught errors from the isolate.
+  ///
+  /// Requests for the isolate to not send uncaught errors on [port].
+  /// If the isolate isn't expecting to send uncaught errors on [port],
+  /// because the port hasn't been added using [addErrorListener],
+  /// or because it has already been removed, the request is ignored.
+  ///
+  /// If the same port has been passed via [addErrorListener] more than once,
+  /// only one call to `removeErrorListener` is needed to stop it from receiving
+  /// uncaught errors.
+  ///
+  /// Uncaught errors message may still be sent by the isolate
+  /// until this request is received and processed.
   external void removeErrorListener(SendPort port);
 
-  /**
-   * Returns a broadcast stream of uncaught errors from the isolate.
-   *
-   * Each error is provided as an error event on the stream.
-   *
-   * The actual error object and stackTraces will not necessarily
-   * be the same object types as in the actual isolate, but they will
-   * always have the same [Object.toString] result.
-   *
-   * This stream is based on [addErrorListener] and [removeErrorListener].
-   */
+  /// Returns a broadcast stream of uncaught errors from the isolate.
+  ///
+  /// Each error is provided as an error event on the stream.
+  ///
+  /// The actual error object and stackTraces will not necessarily
+  /// be the same object types as in the actual isolate, but they will
+  /// always have the same [Object.toString] result.
+  ///
+  /// This stream is based on [addErrorListener] and [removeErrorListener].
   Stream get errors {
     StreamController controller = StreamController.broadcast(sync: true);
     RawReceivePort? port;
@@ -602,158 +555,159 @@
   }
 }
 
-/**
- * Sends messages to its [ReceivePort]s.
- *
- * [SendPort]s are created from [ReceivePort]s. Any message sent through
- * a [SendPort] is delivered to its corresponding [ReceivePort]. There might be
- * many [SendPort]s for the same [ReceivePort].
- *
- * [SendPort]s can be transmitted to other isolates, and they preserve equality
- * when sent.
- */
+/// Sends messages to its [ReceivePort]s.
+///
+/// [SendPort]s are created from [ReceivePort]s. Any message sent through
+/// a [SendPort] is delivered to its corresponding [ReceivePort]. There might be
+/// many [SendPort]s for the same [ReceivePort].
+///
+/// [SendPort]s can be transmitted to other isolates, and they preserve equality
+/// when sent.
 abstract class SendPort implements Capability {
-  /**
-   * Sends an asynchronous [message] through this send port, to its
-   * corresponding `ReceivePort`.
-   *
-   * The content of [message] can be: primitive values (null, num, bool, double,
-   * String), instances of [SendPort], and lists and maps whose elements are any
-   * of these. List and maps are also allowed to be cyclic.
-   *
-   * In the special circumstances when two isolates share the same code and are
-   * running in the same process (e.g. isolates created via [Isolate.spawn]), it
-   * is also possible to send object instances (which would be copied in the
-   * process). This is currently only supported by the
-   * [Dart Native](https://dart.dev/platforms#dart-native-vm-jit-and-aot)
-   * platform.
-   *
-   * The send happens immediately and doesn't block.  The corresponding receive
-   * port can receive the message as soon as its isolate's event loop is ready
-   * to deliver it, independently of what the sending isolate is doing.
-   */
+  /// Sends an asynchronous [message] through this send port, to its
+  /// corresponding `ReceivePort`.
+  ///
+  /// The content of [message] can be: primitive values
+  /// (null, num, bool, double, String), instances of [SendPort],
+  /// and lists and maps whose elements are any of these.
+  /// List and maps are also allowed to contain cyclic references.
+  ///
+  /// In the special circumstances when two isolates share the same code and are
+  /// running in the same process (e.g. isolates created via [Isolate.spawn]),
+  /// it is also possible to send object instances (which would be copied in the
+  /// process). This is currently only supported by the
+  /// [Dart Native](https://dart.dev/platforms#dart-native-vm-jit-and-aot)
+  /// platform.
+  ///
+  /// The send happens immediately and doesn't block.  The corresponding receive
+  /// port can receive the message as soon as its isolate's event loop is ready
+  /// to deliver it, independently of what the sending isolate is doing.
   void send(Object? message);
 
-  /**
-   * Tests whether [other] is a [SendPort] pointing to the same
-   * [ReceivePort] as this one.
-   */
+  /// Tests whether [other] is a [SendPort] pointing to the same
+  /// [ReceivePort] as this one.
   bool operator ==(var other);
 
-  /**
-   * Returns an immutable hash code for this send port that is
-   * consistent with the == operator.
-   */
+  /// A hash code for this send port that is consistent with the == operator.
   int get hashCode;
 }
 
-/**
- * Together with [SendPort], the only means of communication between isolates.
- *
- * [ReceivePort]s have a `sendPort` getter which returns a [SendPort].
- * Any message that is sent through this [SendPort]
- * is delivered to the [ReceivePort] it has been created from. There, the
- * message is dispatched to the `ReceivePort`'s listener.
- *
- * A [ReceivePort] is a non-broadcast stream. This means that it buffers
- * incoming messages until a listener is registered. Only one listener can
- * receive messages. See [Stream.asBroadcastStream] for transforming the port
- * to a broadcast stream.
- *
- * A [ReceivePort] may have many [SendPort]s.
- */
+/// Together with [SendPort], the only means of communication between isolates.
+///
+/// [ReceivePort]s have a `sendPort` getter which returns a [SendPort].
+/// Any message that is sent through this [SendPort]
+/// is delivered to the [ReceivePort] it has been created from. There, the
+/// message is dispatched to the `ReceivePort`'s listener.
+///
+/// A [ReceivePort] is a non-broadcast stream. This means that it buffers
+/// incoming messages until a listener is registered. Only one listener can
+/// receive messages. See [Stream.asBroadcastStream] for transforming the port
+/// to a broadcast stream.
+///
+/// A [ReceivePort] may have many [SendPort]s.
 abstract class ReceivePort implements Stream<dynamic> {
-  /**
-   * Opens a long-lived port for receiving messages.
-   *
-   * A [ReceivePort] is a non-broadcast stream. This means that it buffers
-   * incoming messages until a listener is registered. Only one listener can
-   * receive messages. See [Stream.asBroadcastStream] for transforming the port
-   * to a broadcast stream.
-   *
-   * The optional `debugName` parameter can be set to associate a name with
-   * this port that can be displayed in tooling.
-   *
-   * A receive port is closed by canceling its subscription.
-   */
+  /// Opens a long-lived port for receiving messages.
+  ///
+  /// A [ReceivePort] is a non-broadcast stream. This means that it buffers
+  /// incoming messages until a listener is registered. Only one listener can
+  /// receive messages. See [Stream.asBroadcastStream] for transforming the port
+  /// to a broadcast stream.
+  ///
+  /// The optional `debugName` parameter can be set to associate a name with
+  /// this port that can be displayed in tooling.
+  ///
+  /// A receive port is closed by canceling its subscription.
   external factory ReceivePort([String debugName = '']);
 
-  /**
-   * Creates a [ReceivePort] from a [RawReceivePort].
-   *
-   * The handler of the given [rawPort] is overwritten during the construction
-   * of the result.
-   */
+  /// Creates a [ReceivePort] from a [RawReceivePort].
+  ///
+  /// The handler of the given [rawPort] is overwritten during the construction
+  /// of the result.
   external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);
 
-  /**
-   * Inherited from [Stream].
-   *
-   * Note that [onError] and [cancelOnError] are ignored since a ReceivePort
-   * will never receive an error.
-   *
-   * The [onDone] handler will be called when the stream closes.
-   * The stream closes when [close] is called.
-   */
+  /// Listen for events from [Stream].
+  ///
+  /// See [Stream.listen].
+  ///
+  /// Note that [onError] and [cancelOnError] are ignored since a [ReceivePort]
+  /// will never receive an error.
+  ///
+  /// The [onDone] handler will be called when the stream closes.
+  /// The stream closes when [close] is called.
   StreamSubscription<dynamic> listen(void onData(var message)?,
       {Function? onError, void onDone()?, bool? cancelOnError});
 
-  /**
-   * Closes `this`.
-   *
-   * If the stream has not been canceled yet, adds a close-event to the event
-   * queue and discards any further incoming messages.
-   *
-   * If the stream has already been canceled this method has no effect.
-   */
+  /// Closes the receive port.
+  ///
+  /// No further events will be received by the receive port,
+  /// or emitted as stream events.
+  ///
+  /// If [listen] has been called and the [StreamSubscription] has not
+  /// been canceled yet, the subscription will be closed with a "done"
+  /// event.
+  ///
+  /// If the stream has already been canceled this method has no effect.
   void close();
 
-  /**
-   * Returns a [SendPort] that sends to this receive port.
-   */
+  /// A [SendPort] which sends messages to this receive port.
   SendPort get sendPort;
 }
 
+/// A low-level asynchronous message receiver.
+///
+/// A [RawReceivePort] is low level feature, and is not [Zone] aware.
+/// The [handler] will always be invoked  in the [Zone.root] zone.
+///
+/// The port cannot be paused. The data-handler must be set before the first
+/// messsage is received, otherwise the message is lost.
+///
+/// Messages can be sent to this port using [sendPort].
 abstract class RawReceivePort {
-  /**
-   * Opens a long-lived port for receiving messages.
-   *
-   * A [RawReceivePort] is low level and does not work with [Zone]s. It
-   * can not be paused. The data-handler must be set before the first
-   * event is received.
-   *
-   * The optional `debugName` parameter can be set to associate a name with
-   * this port that can be displayed in tooling.
-   *
-   */
+  /// Opens a long-lived port for receiving messages.
+  ///
+  /// A [RawReceivePort] is low level and does not work with [Zone]s. It
+  /// cannot be paused. The data-handler must be set before the first
+  /// messsage is received, otherwise the message is lost.
+  ///
+  /// If [handler] is provided, it's set as the [RawReceivePort.handler].
+  ///
+  /// The optional `debugName` parameter can be set to associate a name with
+  /// this port that can be displayed in tooling.
   external factory RawReceivePort([Function? handler, String debugName = '']);
 
-  /**
-   * Sets the handler that is invoked for every incoming message.
-   *
-   * The handler is invoked in the root-zone ([Zone.root]).
-   */
+  /// Sets the handler that is invoked for every incoming message.
+  ///
+  /// The handler is invoked in the [Zone.root] zone.
+  /// If the handler should be invoked in the current zone, do:
+  /// ```dart
+  /// rawPort.handler = Zone.current.bind(actualHandler);
+  /// ```
+  ///
+  /// The handler must be a function which can accept one argument
+  /// of the type of the messages sent to this port.
+  /// This means that if it is known that messages will all be [String]s,
+  /// a handler of type `void Function(String)` can be used.
+  /// The function is invoked dynamically with the actual messages,
+  /// and if this invocation fails,
+  /// the error becomes a top-level uncaught error in the [Zone.root] zone.
+  // TODO(44659): Change parameter type to `void Function(Never)` to only
+  // accept functions which can be called with one argument.
   void set handler(Function? newHandler);
 
-  /**
-   * Closes the port.
-   *
-   * After a call to this method any incoming message is silently dropped.
-   */
+  /// Closes the port.
+  ///
+  /// After a call to this method, any incoming message is silently dropped.
+  /// The [handler] will never be called again.
   void close();
 
-  /**
-   * Returns a [SendPort] that sends to this raw receive port.
-   */
+  /// Returns a [SendPort] that sends messages to this raw receive port.
   SendPort get sendPort;
 }
 
-/**
- * Description of an error from another isolate.
- *
- * This error has the same `toString()` and `stackTrace.toString()` behavior
- * as the original error, but has no other features of the original error.
- */
+/// Description of an error from another isolate.
+///
+/// This error has the same `toString()` and `stackTrace.toString()` behavior
+/// as the original error, but has no other features of the original error.
 class RemoteError implements Error {
   final String _description;
   final StackTrace stackTrace;
@@ -763,35 +717,29 @@
   String toString() => _description;
 }
 
-/**
- * An efficiently transferable sequence of byte values.
- *
- * A [TransferableTypedData] is created from a number of bytes.
- * This will take time proportional to the number of bytes.
- *
- * The [TransferableTypedData] can be moved between isolates, so
- * sending it through a send port will only take constant time.
- *
- * When sent this way, the local transferable can no longer be materialized,
- * and the received object is now the only way to materialize the data.
- */
+/// An efficiently transferable sequence of byte values.
+///
+/// A [TransferableTypedData] is created from a number of bytes.
+/// This will take time proportional to the number of bytes.
+///
+/// The [TransferableTypedData] can be moved between isolates, so
+/// sending it through a send port will only take constant time.
+///
+/// When sent this way, the local transferable can no longer be materialized,
+/// and the received object is now the only way to materialize the data.
 @Since("2.3.2")
 abstract class TransferableTypedData {
-  /**
-   * Creates a new [TransferableTypedData] containing the bytes of [list].
-   *
-   * It must be possible to create a single [Uint8List] containing the
-   * bytes, so if there are more bytes than what the platform allows in
-   * a single [Uint8List], then creation fails.
-   */
+  /// Creates a new [TransferableTypedData] containing the bytes of [list].
+  ///
+  /// It must be possible to create a single [Uint8List] containing the
+  /// bytes, so if there are more bytes than what the platform allows in
+  /// a single [Uint8List], then creation fails.
   external factory TransferableTypedData.fromList(List<TypedData> list);
 
-  /**
-   * Creates a new [ByteBuffer] containing the bytes stored in this [TransferableTypedData].
-   *
-   * The [TransferableTypedData] is a cross-isolate single-use resource.
-   * This method must not be called more than once on the same underlying
-   * transferable bytes, even if the calls occur in different isolates.
-   */
+  /// Creates a new [ByteBuffer] containing the bytes stored in this [TransferableTypedData].
+  ///
+  /// The [TransferableTypedData] is a cross-isolate single-use resource.
+  /// This method must not be called more than once on the same underlying
+  /// transferable bytes, even if the calls occur in different isolates.
   ByteBuffer materialize();
 }
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 0b9d207..8f584e2 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -86,6 +86,7 @@
         "uri": "ffi/ffi.dart",
         "patches": [
           "_internal/vm/lib/ffi_patch.dart",
+          "_internal/vm/lib/ffi_allocation_patch.dart",
           "_internal/vm/lib/ffi_dynamic_library_patch.dart",
           "_internal/vm/lib/ffi_native_type_patch.dart",
           "_internal/vm/lib/ffi_struct_patch.dart"
@@ -470,4 +471,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index f6cb8c3..89e3640 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -91,6 +91,7 @@
       uri: "ffi/ffi.dart"
       patches:
         - "_internal/vm/lib/ffi_patch.dart"
+        - "_internal/vm/lib/ffi_allocation_patch.dart"
         - "_internal/vm/lib/ffi_dynamic_library_patch.dart"
         - "_internal/vm/lib/ffi_native_type_patch.dart"
         - "_internal/vm/lib/ffi_struct_patch.dart"
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 8f847b1..ad1da4d 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -5,9 +5,9 @@
 /// Mathematical constants and functions, plus a random number generator.
 ///
 /// To use this library in your code:
-///
-///     import 'dart:math';
-///
+/// ```dart
+/// import 'dart:math';
+/// ```
 /// {@category Core}
 library dart.math;
 
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index f092fc8..b3e9432 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -9,6 +9,7 @@
   final T x;
   final T y;
 
+  /// Creates a point with the provided [x] and [y] coordinates.
   const Point(T x, T y)
       : this.x = x,
         this.y = y;
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index c796465..20d17f8 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -6,9 +6,9 @@
 /// (for example, unsigned 8 byte integers) and SIMD numeric types.
 ///
 /// To use this library in your code:
-///
-///     import 'dart:typed_data';
-///
+/// ```dart
+/// import 'dart:typed_data';
+/// ```
 /// {@category Core}
 library dart.typed_data;
 
@@ -18,407 +18,357 @@
 
 part "unmodifiable_typed_data.dart";
 
-/**
- * A sequence of bytes underlying a typed data object.
- *
- * Used to process large quantities of binary or numerical data
- * more efficiently using a typed view.
- */
+/// A sequence of bytes underlying a typed data object.
+///
+/// Used to process large quantities of binary or numerical data
+/// more efficiently using a typed view.
 abstract class ByteBuffer {
-  /**
-   * Returns the length of this byte buffer, in bytes.
-   */
+  /// Returns the length of this byte buffer, in bytes.
   int get lengthInBytes;
 
-  /**
-   * Creates a [Uint8List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Uint8List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes] and contains [length] bytes.
-   * If [length] is omitted, the range extends to the end of the buffer.
-   *
-   * The start index and length must describe a valid range of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Uint8List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Uint8List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes] and contains [length] bytes.
+  /// If [length] is omitted, the range extends to the end of the buffer.
+  ///
+  /// The start index and length must describe a valid range of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length` must not be greater than [lengthInBytes].
   Uint8List asUint8List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Int8List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Int8List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes] and contains [length] bytes.
-   * If [length] is omitted, the range extends to the end of the buffer.
-   *
-   * The start index and length must describe a valid range of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Int8List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Int8List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes] and contains [length] bytes.
+  /// If [length] is omitted, the range extends to the end of the buffer.
+  ///
+  /// The start index and length must describe a valid range of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length` must not be greater than [lengthInBytes].
   Int8List asInt8List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Uint8ClampedList] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Uint8ClampedList` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes] and contains [length] bytes.
-   * If [length] is omitted, the range extends to the end of the buffer.
-   *
-   * The start index and length must describe a valid range of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Uint8ClampedList] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Uint8ClampedList` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes] and contains [length] bytes.
+  /// If [length] is omitted, the range extends to the end of the buffer.
+  ///
+  /// The start index and length must describe a valid range of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length` must not be greater than [lengthInBytes].
   Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Uint16List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Uint16List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
-   * and contains [length] 16-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not even, the last byte can't be part of the view.
-   *
-   * The start index and length must describe a valid 16-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by two,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Uint16List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Uint16List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+  /// and contains [length] 16-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not even, the last byte can't be part of the view.
+  ///
+  /// The start index and length must describe a valid 16-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by two,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
   Uint16List asUint16List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Int16List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Int16List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
-   * and contains [length] 16-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not even, the last byte can't be part of the view.
-   *
-   * The start index and length must describe a valid 16-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by two,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Int16List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Int16List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+  /// and contains [length] 16-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not even, the last byte can't be part of the view.
+  ///
+  /// The start index and length must describe a valid 16-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by two,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
   Int16List asInt16List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Uint32List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Uint32List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
-   * and contains [length] 32-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 32-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by four,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Uint32List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Uint32List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+  /// and contains [length] 32-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by four, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 32-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by four,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
   Uint32List asUint32List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Int32List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Int32List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
-   * and contains [length] 32-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 32-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by four,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Int32List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Int32List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+  /// and contains [length] 32-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by four, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 32-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by four,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
   Int32List asInt32List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Uint64List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Uint64List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
-   * and contains [length] 64-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 64-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by eight,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Uint64List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Uint64List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+  /// and contains [length] 64-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 64-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by eight,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
   Uint64List asUint64List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Int64List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Int64List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
-   * and contains [length] 64-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 64-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by eight,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Int64List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Int64List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+  /// and contains [length] 64-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 64-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by eight,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
   Int64List asInt64List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Int32x4List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Int32x4List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
-   * and contains [length] 128-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 128-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by sixteen,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Int32x4List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Int32x4List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+  /// and contains [length] 128-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 128-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by sixteen,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
   Int32x4List asInt32x4List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Float32List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Float32List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
-   * and contains [length] 32-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 32-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by four,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Float32List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Float32List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+  /// and contains [length] 32-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by four, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 32-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by four,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
   Float32List asFloat32List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Float64List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Float64List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
-   * and contains [length] 64-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 64-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by eight,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Float64List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Float64List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+  /// and contains [length] 64-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 64-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by eight,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
   Float64List asFloat64List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Float32x4List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Float32x4List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
-   * and contains [length] 128-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 128-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by sixteen,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Float32x4List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Float32x4List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+  /// and contains [length] 128-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 128-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by sixteen,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
   Float32x4List asFloat32x4List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [Float64x2List] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `Float64x2List` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
-   * and contains [length] 128-bit integers.
-   * If [length] is omitted, the range extends as far towards the end of
-   * the buffer as possible -
-   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
-   * of the view.
-   *
-   * The start index and length must describe a valid 128-bit aligned range
-   * of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `offsetInBytes` must be divisible by sixteen,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [Float64x2List] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `Float64x2List` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+  /// and contains [length] 128-bit integers.
+  /// If [length] is omitted, the range extends as far towards the end of
+  /// the buffer as possible -
+  /// if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+  /// of the view.
+  ///
+  /// The start index and length must describe a valid 128-bit aligned range
+  /// of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `offsetInBytes` must be divisible by sixteen,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
   Float64x2List asFloat64x2List([int offsetInBytes = 0, int? length]);
 
-  /**
-   * Creates a [ByteData] _view_ of a region of this byte buffer.
-   *
-   * The view is backed by the bytes of this byte buffer.
-   * Any changes made to the `ByteData` will also change the buffer,
-   * and vice versa.
-   *
-   * The viewed region start at [offsetInBytes] and contains [length] bytes.
-   * If [length] is omitted, the range extends to the end of the buffer.
-   *
-   * The start index and length must describe a valid range of the buffer:
-   *
-   * * `offsetInBytes` must not be negative,
-   * * `length` must not be negative, and
-   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
-   */
+  /// Creates a [ByteData] _view_ of a region of this byte buffer.
+  ///
+  /// The view is backed by the bytes of this byte buffer.
+  /// Any changes made to the `ByteData` will also change the buffer,
+  /// and vice versa.
+  ///
+  /// The viewed region start at [offsetInBytes] and contains [length] bytes.
+  /// If [length] is omitted, the range extends to the end of the buffer.
+  ///
+  /// The start index and length must describe a valid range of the buffer:
+  ///
+  /// * `offsetInBytes` must not be negative,
+  /// * `length` must not be negative, and
+  /// * `offsetInBytes + length` must not be greater than [lengthInBytes].
   ByteData asByteData([int offsetInBytes = 0, int? length]);
 }
 
-/**
- * A typed view of a sequence of bytes.
- */
+/// A typed view of a sequence of bytes.
 abstract class TypedData {
-  /**
-   * Returns the number of bytes in the representation of each element in this
-   * list.
-   */
+  /// Returns the number of bytes in the representation of each element in this
+  /// list.
   int get elementSizeInBytes;
 
-  /**
-   * Returns the offset in bytes into the underlying byte buffer of this view.
-   */
+  /// Returns the offset in bytes into the underlying byte buffer of this view.
   int get offsetInBytes;
 
-  /**
-   * Returns the length of this view, in bytes.
-   */
+  /// Returns the length of this view, in bytes.
   int get lengthInBytes;
 
-  /**
-   * Returns the byte buffer associated with this object.
-   */
+  /// Returns the byte buffer associated with this object.
   ByteBuffer get buffer;
 }
 
 abstract class _TypedIntList extends TypedData {
-  /**
-   * Returns the concatenation of this list and [other].
-   *
-   * If other is also a typed-data integer list, the returned list will
-   * be a type-data integer list capable of containing all the elements of
-   * this list and of [other].
-   * Otherwise the returned list will be a normal growable `List<int>`.
-   */
+  /// Returns the concatenation of this list and [other].
+  ///
+  /// If other is also a typed-data integer list, the returned list will
+  /// be a type-data integer list capable of containing all the elements of
+  /// this list and of [other].
+  /// Otherwise the returned list will be a normal growable `List<int>`.
   List<int> operator +(List<int> other);
 }
 
 abstract class _TypedFloatList extends TypedData {
-  /**
-   * Returns the concatenation of this list and [other].
-   *
-   * If other is also a typed-data floating point number list,
-   * the returned list will be a type-data float list capable of containing
-   * all the elements of this list and of [other].
-   * Otherwise the returned list will be a normal growable `List<double>`.
-   */
+  /// Returns the concatenation of this list and [other].
+  ///
+  /// If other is also a typed-data floating point number list,
+  /// the returned list will be a type-data float list capable of containing
+  /// all the elements of this list and of [other].
+  /// Otherwise the returned list will be a normal growable `List<double>`.
   List<double> operator +(List<double> other);
 }
 
-/**
- * Describes endianness to be used when accessing or updating a
- * sequence of bytes.
- */
+/// Describes endianness to be used when accessing or updating a
+/// sequence of bytes.
 class Endian {
   final bool _littleEndian;
   const Endian._(this._littleEndian);
@@ -431,102 +381,94 @@
           : big;
 }
 
-/**
- * A fixed-length, random-access sequence of bytes that also provides random
- * and unaligned access to the fixed-width integers and floating point
- * numbers represented by those bytes.
- *
- * `ByteData` may be used to pack and unpack data from external sources
- * (such as networks or files systems), and to process large quantities
- * of numerical data more efficiently than would be possible
- * with ordinary [List] implementations.
- * `ByteData` can save space, by eliminating the need for object headers,
- * and time, by eliminating the need for data copies.
- *
- * If data comes in as bytes, they can be converted to `ByteData` by
- * sharing the same buffer.
- * ```dart
- * Uint8List bytes = ...;
- * var blob = ByteData.sublistView(bytes);
- * if (blob.getUint32(0, Endian.little) == 0x04034b50) { // Zip file marker
- *   ...
- * }
- *
- * ```
- *
- * Finally, `ByteData` may be used to intentionally reinterpret the bytes
- * representing one arithmetic type as another.
- * For example this code fragment determine what 32-bit signed integer
- * is represented by the bytes of a 32-bit floating point number
- * (both stored as big endian):
- * ```dart
- * var bdata = new ByteData(8);
- * bdata.setFloat32(0, 3.04);
- * int huh = bdata.getInt32(0); // 0x40428f5c
- * ```
- */
+/// A fixed-length, random-access sequence of bytes that also provides random
+/// and unaligned access to the fixed-width integers and floating point
+/// numbers represented by those bytes.
+///
+/// `ByteData` may be used to pack and unpack data from external sources
+/// (such as networks or files systems), and to process large quantities
+/// of numerical data more efficiently than would be possible
+/// with ordinary [List] implementations.
+/// `ByteData` can save space, by eliminating the need for object headers,
+/// and time, by eliminating the need for data copies.
+///
+/// If data comes in as bytes, they can be converted to `ByteData` by
+/// sharing the same buffer.
+/// ```dart
+/// Uint8List bytes = ...;
+/// var blob = ByteData.sublistView(bytes);
+/// if (blob.getUint32(0, Endian.little) == 0x04034b50) { // Zip file marker
+///   ...
+/// }
+///
+/// ```
+///
+/// Finally, `ByteData` may be used to intentionally reinterpret the bytes
+/// representing one arithmetic type as another.
+/// For example this code fragment determine what 32-bit signed integer
+/// is represented by the bytes of a 32-bit floating point number
+/// (both stored as big endian):
+/// ```dart
+/// var bdata = ByteData(8);
+/// bdata.setFloat32(0, 3.04);
+/// int huh = bdata.getInt32(0); // 0x40428f5c
+/// ```
 abstract class ByteData implements TypedData {
-  /**
-   * Creates a [ByteData] of the specified length (in elements), all of
-   * whose bytes are initially zero.
-   */
+  /// Creates a [ByteData] of the specified length (in elements), all of
+  /// whose bytes are initially zero.
   @pragma("vm:entry-point")
   external factory ByteData(int length);
 
-  /**
-   * Creates an [ByteData] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [ByteData] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `ByteData.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * ByteData.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [ByteData.sublistView]
-   * which includes this computation:
-   * ```dart
-   * ByteData.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [ByteData] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [ByteData] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + [length] must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `ByteData.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// ByteData.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [ByteData.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// ByteData.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory ByteData.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asByteData(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [ByteData] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   */
+  /// Creates a [ByteData] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
   @Since("2.8")
   factory ByteData.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -538,341 +480,291 @@
         data.offsetInBytes + start * elementSize, (end - start) * elementSize);
   }
 
-  /**
-   * Returns the (possibly negative) integer represented by the byte at the
-   * specified [byteOffset] in this object, in two's complement binary
-   * representation.
-   *
-   * The return value will be between -128 and 127, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * less than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the byte at the
+  /// specified [byteOffset] in this object, in two's complement binary
+  /// representation.
+  ///
+  /// The return value will be between -128 and 127, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// less than the length of this object.
   int getInt8(int byteOffset);
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * two's complement binary representation of the specified [value], which
-   * must fit in a single byte.
-   *
-   * In other words, [value] must be between -128 and 127, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * less than the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// two's complement binary representation of the specified [value], which
+  /// must fit in a single byte.
+  ///
+  /// In other words, [value] must be between -128 and 127, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// less than the length of this object.
   void setInt8(int byteOffset, int value);
 
-  /**
-   * Returns the positive integer represented by the byte at the specified
-   * [byteOffset] in this object, in unsigned binary form.
-   *
-   * The return value will be between 0 and 255, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * less than the length of this object.
-   */
+  /// Returns the positive integer represented by the byte at the specified
+  /// [byteOffset] in this object, in unsigned binary form.
+  ///
+  /// The return value will be between 0 and 255, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// less than the length of this object.
   int getUint8(int byteOffset);
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * unsigned binary representation of the specified [value], which must fit
-   * in a single byte.
-   *
-   * In other words, [value] must be between 0 and 255, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * less than the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// unsigned binary representation of the specified [value], which must fit
+  /// in a single byte.
+  ///
+  /// In other words, [value] must be between 0 and 255, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// less than the length of this object.
   void setUint8(int byteOffset, int value);
 
-  /**
-   * Returns the (possibly negative) integer represented by the two bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   *
-   * The return value will be between -2<sup>15</sup> and 2<sup>15</sup> - 1,
-   * inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 2` must be less than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the two bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  ///
+  /// The return value will be between -2<sup>15</sup> and 2<sup>15</sup> - 1,
+  /// inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 2` must be less than or equal to the length of this object.
   int getInt16(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in two bytes.
-   *
-   * In other words, [value] must lie
-   * between -2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 2` must be less than or equal to the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in two bytes.
+  ///
+  /// In other words, [value] must lie
+  /// between -2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 2` must be less than or equal to the length of this object.
   void setInt16(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the positive integer represented by the two bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   *
-   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 2` must be less than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the two bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  ///
+  /// The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 2` must be less than or equal to the length of this object.
   int getUint16(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in two bytes.
-   *
-   * In other words, [value] must be between
-   * 0 and 2<sup>16</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 2` must be less than or equal to the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in two bytes.
+  ///
+  /// In other words, [value] must be between
+  /// 0 and 2<sup>16</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 2` must be less than or equal to the length of this object.
   void setUint16(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the (possibly negative) integer represented by the four bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   *
-   * The return value will be between -2<sup>31</sup> and 2<sup>31</sup> - 1,
-   * inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the four bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  ///
+  /// The return value will be between -2<sup>31</sup> and 2<sup>31</sup> - 1,
+  /// inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   int getInt32(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in four bytes.
-   *
-   * In other words, [value] must lie
-   * between -2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in four bytes.
+  ///
+  /// In other words, [value] must lie
+  /// between -2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   void setInt32(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the positive integer represented by the four bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   *
-   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the four bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  ///
+  /// The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   int getUint32(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in four bytes.
-   *
-   * In other words, [value] must be between
-   * 0 and 2<sup>32</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in four bytes.
+  ///
+  /// In other words, [value] must be between
+  /// 0 and 2<sup>32</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   void setUint32(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the (possibly negative) integer represented by the eight bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   *
-   * The return value will be between -2<sup>63</sup> and 2<sup>63</sup> - 1,
-   * inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  ///
+  /// The return value will be between -2<sup>63</sup> and 2<sup>63</sup> - 1,
+  /// inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in eight bytes.
-   *
-   * In other words, [value] must lie
-   * between -2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in eight bytes.
+  ///
+  /// In other words, [value] must lie
+  /// between -2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the positive integer represented by the eight bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   *
-   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the eight bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  ///
+  /// The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in eight bytes.
-   *
-   * In other words, [value] must be between
-   * 0 and 2<sup>64</sup> - 1, inclusive.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in eight bytes.
+  ///
+  /// In other words, [value] must be between
+  /// 0 and 2<sup>64</sup> - 1, inclusive.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the floating point number represented by the four bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * single-precision binary floating-point format (binary32).
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Returns the floating point number represented by the four bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// single-precision binary floating-point format (binary32).
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   double getFloat32(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 single-precision binary floating-point
-   * (binary32) representation of the specified [value].
-   *
-   * **Note that this method can lose precision.** The input [value] is
-   * a 64-bit floating point value, which will be converted to 32-bit
-   * floating point value by IEEE 754 rounding rules before it is stored.
-   * If [value] cannot be represented exactly as a binary32, it will be
-   * converted to the nearest binary32 value.  If two binary32 values are
-   * equally close, the one whose least significant bit is zero will be used.
-   * Note that finite (but large) values can be converted to infinity, and
-   * small non-zero values can be converted to zero.
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 4` must be less than or equal to the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 single-precision binary floating-point
+  /// (binary32) representation of the specified [value].
+  ///
+  /// **Note that this method can lose precision.** The input [value] is
+  /// a 64-bit floating point value, which will be converted to 32-bit
+  /// floating point value by IEEE 754 rounding rules before it is stored.
+  /// If [value] cannot be represented exactly as a binary32, it will be
+  /// converted to the nearest binary32 value.  If two binary32 values are
+  /// equally close, the one whose least significant bit is zero will be used.
+  /// Note that finite (but large) values can be converted to infinity, and
+  /// small non-zero values can be converted to zero.
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 4` must be less than or equal to the length of this object.
   void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]);
 
-  /**
-   * Returns the floating point number represented by the eight bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * double-precision binary floating-point format (binary64).
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Returns the floating point number represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// double-precision binary floating-point format (binary64).
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   double getFloat64(int byteOffset, [Endian endian = Endian.big]);
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 double-precision binary floating-point
-   * (binary64) representation of the specified [value].
-   *
-   * The [byteOffset] must be non-negative, and
-   * `byteOffset + 8` must be less than or equal to the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 double-precision binary floating-point
+  /// (binary64) representation of the specified [value].
+  ///
+  /// The [byteOffset] must be non-negative, and
+  /// `byteOffset + 8` must be less than or equal to the length of this object.
   void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]);
 }
 
-/**
- * A fixed-length list of 8-bit signed integers.
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low eight bits,
- * interpreted as a signed 8-bit two's complement integer with values in the
- * range -128 to +127.
- */
+/// A fixed-length list of 8-bit signed integers.
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low eight bits,
+/// interpreted as a signed 8-bit two's complement integer with values in the
+/// range -128 to +127.
 abstract class Int8List implements List<int>, _TypedIntList {
-  /**
-   * Creates an [Int8List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely [length] bytes.
-   */
+  /// Creates an [Int8List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely [length] bytes.
   external factory Int8List(int length);
 
-  /**
-   * Creates a [Int8List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely `elements.length`
-   * bytes.
-   */
+  /// Creates a [Int8List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely `elements.length`
+  /// bytes.
   external factory Int8List.fromList(List<int> elements);
 
-  /**
-   * Creates an [Int8List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Int8List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Int8List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Int8List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Int8List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Int8List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [Int8List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Int8List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Int8List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Int8List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Int8List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Int8List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Int8List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asInt8List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Int8List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   */
+  /// Creates an [Int8List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
   @Since("2.8")
   factory Int8List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -883,119 +775,107 @@
         data.offsetInBytes + start * elementSize, (end - start) * elementSize);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is an `Int8List` containing the elements of this list at
-   * positions greater than or equal to [start] and less than [end] in the same
-   * order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Int8List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Int8List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is an `Int8List` containing the elements of this list at
+  /// positions greater than or equal to [start] and less than [end] in the same
+  /// order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Int8List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Int8List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Int8List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 1;
 }
 
-/**
- * A fixed-length list of 8-bit unsigned integers.
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low eight bits,
- * interpreted as an unsigned 8-bit integer with values in the
- * range 0 to 255.
- */
+/// A fixed-length list of 8-bit unsigned integers.
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low eight bits,
+/// interpreted as an unsigned 8-bit integer with values in the
+/// range 0 to 255.
 abstract class Uint8List implements List<int>, _TypedIntList {
-  /**
-   * Creates a [Uint8List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely [length] bytes.
-   */
+  /// Creates a [Uint8List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely [length] bytes.
   external factory Uint8List(int length);
 
-  /**
-   * Creates a [Uint8List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely `elements.length`
-   * bytes.
-   */
+  /// Creates a [Uint8List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely `elements.length`
+  /// bytes.
   external factory Uint8List.fromList(List<int> elements);
 
-  /**
-   * Creates a [Uint8List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Uint8List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Uint8List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Uint8List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Uint8List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Uint8List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Uint8List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Uint8List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Uint8List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Uint8List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Uint8List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Uint8List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Uint8List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asUint8List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Uint8List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   */
+  /// Creates a [Uint8List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
   @Since("2.8")
   factory Uint8List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1006,129 +886,115 @@
         data.offsetInBytes + start * elementSize, (end - start) * elementSize);
   }
 
-  /**
-   * Returns a concatenation of this list and [other].
-   *
-   * If [other] is also a typed-data list, then the return list will be a
-   * typed data list capable of holding both unsigned 8-bit integers and
-   * the elements of [other], otherwise it'll be a normal list of integers.
-   */
+  /// Returns a concatenation of this list and [other].
+  ///
+  /// If [other] is also a typed-data list, then the return list will be a
+  /// typed data list capable of holding both unsigned 8-bit integers and
+  /// the elements of [other], otherwise it'll be a normal list of integers.
   List<int> operator +(List<int> other);
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Uint8List` containing the elements of this list at
-   * positions greater than or equal to [start] and less than [end] in the same
-   * order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Uint8List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Uint8List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Uint8List` containing the elements of this list at
+  /// positions greater than or equal to [start] and less than [end] in the same
+  /// order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Uint8List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Uint8List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Uint8List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 1;
 }
 
-/**
- * A fixed-length list of 8-bit unsigned integers.
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are clamped to an unsigned eight bit value.
- * That is, all values below zero are stored as zero
- * and all values above 255 are stored as 255.
- */
+/// A fixed-length list of 8-bit unsigned integers.
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are clamped to an unsigned eight bit value.
+/// That is, all values below zero are stored as zero
+/// and all values above 255 are stored as 255.
 abstract class Uint8ClampedList implements List<int>, _TypedIntList {
-  /**
-   * Creates a [Uint8ClampedList] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely [length] bytes.
-   */
+  /// Creates a [Uint8ClampedList] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely [length] bytes.
   external factory Uint8ClampedList(int length);
 
-  /**
-   * Creates a [Uint8ClampedList] of the same size as the [elements]
-   * list and copies over the values clamping when needed.
-   *
-   * Values are clamped to fit in the list when they are copied,
-   * the same way storing values clamps them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely `elements.length`
-   * bytes.
-   */
+  /// Creates a [Uint8ClampedList] of the same size as the [elements]
+  /// list and copies over the values clamping when needed.
+  ///
+  /// Values are clamped to fit in the list when they are copied,
+  /// the same way storing values clamps them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely `elements.length`
+  /// bytes.
   external factory Uint8ClampedList.fromList(List<int> elements);
 
-  /**
-   * Creates a [Uint8ClampedList] _view_ of the specified region in the
-   * specified byte [buffer].
-   *
-   * Changes in the [Uint8List] will be visible in the byte buffer
-   * and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Uint8ClampedList.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Uint8ClampedList.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Uint8ClampedList.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Uint8ClampedList.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Uint8ClampedList] _view_ of the specified region in the
+  /// specified byte [buffer].
+  ///
+  /// Changes in the [Uint8List] will be visible in the byte buffer
+  /// and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Uint8ClampedList.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Uint8ClampedList.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Uint8ClampedList.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Uint8ClampedList.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Uint8ClampedList.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asUint8ClampedList(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Uint8ClampedList] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   */
+  /// Creates a [Uint8ClampedList] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
   @Since("2.8")
   factory Uint8ClampedList.sublistView(TypedData data,
       [int start = 0, int? end]) {
@@ -1140,126 +1006,114 @@
         data.offsetInBytes + start * elementSize, (end - start) * elementSize);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Uint8ClampedList` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Uint8ClampedList.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Uint8ClampedList
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Uint8ClampedList` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Uint8ClampedList.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Uint8ClampedList
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Uint8ClampedList sublist(int start, [int? end]);
 
   static const int bytesPerElement = 1;
 }
 
-/**
- * A fixed-length list of 16-bit signed integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 16 bits,
- * interpreted as a signed 16-bit two's complement integer with values in the
- * range -32768 to +32767.
- */
+/// A fixed-length list of 16-bit signed integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 16 bits,
+/// interpreted as a signed 16-bit two's complement integer with values in the
+/// range -32768 to +32767.
 abstract class Int16List implements List<int>, _TypedIntList {
-  /**
-   * Creates an [Int16List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 2 bytes.
-   */
+  /// Creates an [Int16List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 2 bytes.
   external factory Int16List(int length);
 
-  /**
-   * Creates a [Int16List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 2 bytes.
-   */
+  /// Creates a [Int16List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 2 bytes.
   external factory Int16List.fromList(List<int> elements);
 
-  /**
-   * Creates an [Int16List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Int16List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Int16List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Int16List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Int16List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Int16List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [Int16List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Int16List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Int16List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Int16List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Int16List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Int16List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Int16List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asInt16List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Int16List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of two.
-   */
+  /// Creates an [Int16List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of two.
   @Since("2.8")
   factory Int16List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1275,127 +1129,115 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is an `Int16List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Int16List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Int16List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is an `Int16List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Int16List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Int16List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Int16List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 2;
 }
 
-/**
- * A fixed-length list of 16-bit unsigned integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 16 bits,
- * interpreted as an unsigned 16-bit integer with values in the
- * range 0 to 65535.
- */
+/// A fixed-length list of 16-bit unsigned integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 16 bits,
+/// interpreted as an unsigned 16-bit integer with values in the
+/// range 0 to 65535.
 abstract class Uint16List implements List<int>, _TypedIntList {
-  /**
-   * Creates a [Uint16List] of the specified length (in elements), all
-   * of whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 2 bytes.
-   */
+  /// Creates a [Uint16List] of the specified length (in elements), all
+  /// of whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 2 bytes.
   external factory Uint16List(int length);
 
-  /**
-   * Creates a [Uint16List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 2 bytes.
-   */
+  /// Creates a [Uint16List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 2 bytes.
   external factory Uint16List.fromList(List<int> elements);
 
-  /**
-   * Creates a [Uint16List] _view_ of the specified region in
-   * the specified byte buffer.
-   *
-   * Changes in the [Uint16List] will be visible in the byte buffer
-   * and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Uint16List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Uint16List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Uint16List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Uint16List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Uint16List] _view_ of the specified region in
+  /// the specified byte buffer.
+  ///
+  /// Changes in the [Uint16List] will be visible in the byte buffer
+  /// and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Uint16List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Uint16List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Uint16List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Uint16List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Uint16List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asUint16List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Uint16List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of two.
-   */
+  /// Creates a [Uint16List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of two.
   @Since("2.8")
   factory Uint16List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1411,126 +1253,114 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Uint16List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Uint16List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Uint16List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Uint16List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Uint16List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Uint16List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Uint16List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 2;
 }
 
-/**
- * A fixed-length list of 32-bit signed integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 32 bits,
- * interpreted as a signed 32-bit two's complement integer with values in the
- * range -2147483648 to 2147483647.
- */
+/// A fixed-length list of 32-bit signed integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 32 bits,
+/// interpreted as a signed 32-bit two's complement integer with values in the
+/// range -2147483648 to 2147483647.
 abstract class Int32List implements List<int>, _TypedIntList {
-  /**
-   * Creates an [Int32List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 4 bytes.
-   */
+  /// Creates an [Int32List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 4 bytes.
   external factory Int32List(int length);
 
-  /**
-   * Creates a [Int32List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 4 bytes.
-   */
+  /// Creates a [Int32List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 4 bytes.
   external factory Int32List.fromList(List<int> elements);
 
-  /**
-   * Creates an [Int32List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Int32List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Int32List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Int32List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Int32List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Int32List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [Int32List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Int32List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Int32List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Int32List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Int32List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Int32List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Int32List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asInt32List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Int32List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of four.
-   */
+  /// Creates an [Int32List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of four.
   @Since("2.8")
   factory Int32List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1546,127 +1376,115 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is an `Int32List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Int32List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Int32List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is an `Int32List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Int32List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Int32List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Int32List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 4;
 }
 
-/**
- * A fixed-length list of 32-bit unsigned integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 32 bits,
- * interpreted as an unsigned 32-bit integer with values in the
- * range 0 to 4294967295.
- */
+/// A fixed-length list of 32-bit unsigned integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 32 bits,
+/// interpreted as an unsigned 32-bit integer with values in the
+/// range 0 to 4294967295.
 abstract class Uint32List implements List<int>, _TypedIntList {
-  /**
-   * Creates a [Uint32List] of the specified length (in elements), all
-   * of whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 4 bytes.
-   */
+  /// Creates a [Uint32List] of the specified length (in elements), all
+  /// of whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 4 bytes.
   external factory Uint32List(int length);
 
-  /**
-   * Creates a [Uint32List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 4 bytes.
-   */
+  /// Creates a [Uint32List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 4 bytes.
   external factory Uint32List.fromList(List<int> elements);
 
-  /**
-   * Creates a [Uint32List] _view_ of the specified region in
-   * the specified byte buffer.
-   *
-   * Changes in the [Uint32List] will be visible in the byte buffer
-   * and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Uint32List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Uint32List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Uint32List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Uint32List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Uint32List] _view_ of the specified region in
+  /// the specified byte buffer.
+  ///
+  /// Changes in the [Uint32List] will be visible in the byte buffer
+  /// and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Uint32List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Uint32List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Uint32List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Uint32List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Uint32List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asUint32List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Uint32List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of four.
-   */
+  /// Creates a [Uint32List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of four.
   @Since("2.8")
   factory Uint32List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1682,126 +1500,114 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Uint32List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Uint32List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Uint32List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Uint32List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Uint32List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Uint32List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Uint32List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 4;
 }
 
-/**
- * A fixed-length list of 64-bit signed integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 64 bits,
- * interpreted as a signed 64-bit two's complement integer with values in the
- * range -9223372036854775808 to +9223372036854775807.
- */
+/// A fixed-length list of 64-bit signed integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 64 bits,
+/// interpreted as a signed 64-bit two's complement integer with values in the
+/// range -9223372036854775808 to +9223372036854775807.
 abstract class Int64List implements List<int>, _TypedIntList {
-  /**
-   * Creates an [Int64List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 8 bytes.
-   */
+  /// Creates an [Int64List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 8 bytes.
   external factory Int64List(int length);
 
-  /**
-   * Creates a [Int64List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 8 bytes.
-   */
+  /// Creates a [Int64List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 8 bytes.
   external factory Int64List.fromList(List<int> elements);
 
-  /**
-   * Creates an [Int64List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Int64List] will be visible in the byte buffer
-   * and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Int64List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Int64List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Int64List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Int64List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [Int64List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Int64List] will be visible in the byte buffer
+  /// and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Int64List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Int64List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Int64List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Int64List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Int64List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asInt64List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Int64List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of eight.
-   */
+  /// Creates an [Int64List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of eight.
   @Since("2.8")
   factory Int64List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1817,127 +1623,115 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is an `Int64List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Int64List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Int64List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is an `Int64List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Int64List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Int64List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Int64List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 8;
 }
 
-/**
- * A fixed-length list of 64-bit unsigned integers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation can be considerably
- * more space- and time-efficient than the default [List] implementation.
- *
- * Integers stored in the list are truncated to their low 64 bits,
- * interpreted as an unsigned 64-bit integer with values in the
- * range 0 to 18446744073709551615.
- */
+/// A fixed-length list of 64-bit unsigned integers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation can be considerably
+/// more space- and time-efficient than the default [List] implementation.
+///
+/// Integers stored in the list are truncated to their low 64 bits,
+/// interpreted as an unsigned 64-bit integer with values in the
+/// range 0 to 18446744073709551615.
 abstract class Uint64List implements List<int>, _TypedIntList {
-  /**
-   * Creates a [Uint64List] of the specified length (in elements), all
-   * of whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 8 bytes.
-   */
+  /// Creates a [Uint64List] of the specified length (in elements), all
+  /// of whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 8 bytes.
   external factory Uint64List(int length);
 
-  /**
-   * Creates a [Uint64List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 8 bytes.
-   */
+  /// Creates a [Uint64List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 8 bytes.
   external factory Uint64List.fromList(List<int> elements);
 
-  /**
-   * Creates an [Uint64List] _view_ of the specified region in
-   * the specified byte buffer.
-   *
-   * Changes in the [Uint64List] will be visible in the byte buffer
-   * and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Uint64List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Uint64List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Uint64List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Uint64List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates an [Uint64List] _view_ of the specified region in
+  /// the specified byte buffer.
+  ///
+  /// Changes in the [Uint64List] will be visible in the byte buffer
+  /// and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Uint64List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Uint64List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Uint64List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Uint64List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Uint64List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asUint64List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Uint64List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of eight.
-   */
+  /// Creates a [Uint64List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of eight.
   @Since("2.8")
   factory Uint64List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -1953,127 +1747,115 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Uint64List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Uint64List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Uint64List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Uint64List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Uint64List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Uint64List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Uint64List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 8;
 }
 
-/**
- * A fixed-length list of IEEE 754 single-precision binary floating-point
- * numbers that is viewable as a [TypedData].
- *
- * For long lists, this
- * implementation can be considerably more space- and time-efficient than
- * the default [List] implementation.
- *
- * Double values stored in the list are converted to the nearest
- * single-precision value. Values read are converted to a double
- * value with the same value.
- */
+/// A fixed-length list of IEEE 754 single-precision binary floating-point
+/// numbers that is viewable as a [TypedData].
+///
+/// For long lists, this
+/// implementation can be considerably more space- and time-efficient than
+/// the default [List] implementation.
+///
+/// Double values stored in the list are converted to the nearest
+/// single-precision value. Values read are converted to a double
+/// value with the same value.
 abstract class Float32List implements List<double>, _TypedFloatList {
-  /**
-   * Creates a [Float32List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 4 bytes.
-   */
+  /// Creates a [Float32List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 4 bytes.
   external factory Float32List(int length);
 
-  /**
-   * Creates a [Float32List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * Values are truncated to fit in the list when they are copied,
-   * the same way storing values truncates them.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 4 bytes.
-   */
+  /// Creates a [Float32List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// Values are truncated to fit in the list when they are copied,
+  /// the same way storing values truncates them.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 4 bytes.
   external factory Float32List.fromList(List<double> elements);
 
-  /**
-   * Creates a [Float32List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Float32List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Float32List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Float32List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Float32List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Float32List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Float32List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Float32List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Float32List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Float32List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Float32List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Float32List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Float32List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asFloat32List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Float32List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of four.
-   */
+  /// Creates an [Float32List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of four.
   @Since("2.8")
   factory Float32List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -2089,120 +1871,108 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Float32List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Float32List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Float32List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Float32List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Float32List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Float32List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Float32List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 4;
 }
 
-/**
- * A fixed-length list of IEEE 754 double-precision binary floating-point
- * numbers  that is viewable as a [TypedData].
- *
- * For long lists, this
- * implementation can be considerably more space- and time-efficient than
- * the default [List] implementation.
- */
+/// A fixed-length list of IEEE 754 double-precision binary floating-point
+/// numbers  that is viewable as a [TypedData].
+///
+/// For long lists, this
+/// implementation can be considerably more space- and time-efficient than
+/// the default [List] implementation.
 abstract class Float64List implements List<double>, _TypedFloatList {
-  /**
-   * Creates a [Float64List] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 8 bytes.
-   */
+  /// Creates a [Float64List] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 8 bytes.
   external factory Float64List(int length);
 
-  /**
-   * Creates a [Float64List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 8 bytes.
-   */
+  /// Creates a [Float64List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 8 bytes.
   external factory Float64List.fromList(List<double> elements);
 
-  /**
-   * Creates a [Float64List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Float64List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Float64List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Float64List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Float64List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Float64List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Float64List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Float64List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Float64List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Float64List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Float64List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Float64List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Float64List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asFloat64List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Float64List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of eight.
-   */
+  /// Creates a [Float64List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of eight.
   @Since("2.8")
   factory Float64List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -2218,119 +1988,107 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Float64List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Float64List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Float64List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Float64List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Float64List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Float64List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Float64List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 8;
 }
 
-/**
- * A fixed-length list of Float32x4 numbers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 abstract class Float32x4List implements List<Float32x4>, TypedData {
-  /**
-   * Creates a [Float32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 16 bytes.
-   */
+  /// Creates a [Float32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 16 bytes.
   external factory Float32x4List(int length);
 
-  /**
-   * Creates a [Float32x4List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 16 bytes.
-   */
+  /// Creates a [Float32x4List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 16 bytes.
   external factory Float32x4List.fromList(List<Float32x4> elements);
 
-  /**
-   * Creates a [Float32x4List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Float32x4List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Float32x4List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Float32x4List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Float32x4List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Float32x4List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Float32x4List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Float32x4List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Float32x4List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Float32x4List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Float32x4List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Float32x4List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Float32x4List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asFloat32x4List(offsetInBytes, length);
   }
 
-  /**
-   * Creates a [Float32x4List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of sixteen.
-   */
+  /// Creates a [Float32x4List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of sixteen.
   @Since("2.8")
   factory Float32x4List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -2346,127 +2104,113 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns the concatenation of this list and [other].
-   *
-   * If [other] is also a [Float32x4List], the result is a new [Float32x4List],
-   * otherwise the result is a normal growable `List<Float32x4>`.
-   */
+  /// Returns the concatenation of this list and [other].
+  ///
+  /// If [other] is also a [Float32x4List], the result is a new [Float32x4List],
+  /// otherwise the result is a normal growable `List<Float32x4>`.
   List<Float32x4> operator +(List<Float32x4> other);
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Float32x4List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Float32x4List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Float32x4List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Float32x4List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Float32x4List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Float32x4List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Float32x4List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 16;
 }
 
-/**
- * A fixed-length list of Int32x4 numbers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 abstract class Int32x4List implements List<Int32x4>, TypedData {
-  /**
-   * Creates a [Int32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 16 bytes.
-   */
+  /// Creates a [Int32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 16 bytes.
   external factory Int32x4List(int length);
 
-  /**
-   * Creates a [Int32x4List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 16 bytes.
-   */
+  /// Creates a [Int32x4List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 16 bytes.
   external factory Int32x4List.fromList(List<Int32x4> elements);
 
-  /**
-   * Creates a [Int32x4List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Int32x4List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Int32x4List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Int32x4List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Int32x4List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Int32x4List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Int32x4List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Int32x4List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Int32x4List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Int32x4List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Int32x4List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Int32x4List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Int32x4List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asInt32x4List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Int32x4List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of sixteen.
-   */
+  /// Creates an [Int32x4List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of sixteen.
   @Since("2.8")
   factory Int32x4List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -2482,135 +2226,119 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns the concatenation of this list and [other].
-   *
-   * If [other] is also a [Int32x4List], the result is a new [Int32x4List],
-   * otherwise the result is a normal growable `List<Int32x4>`.
-   */
+  /// Returns the concatenation of this list and [other].
+  ///
+  /// If [other] is also a [Int32x4List], the result is a new [Int32x4List],
+  /// otherwise the result is a normal growable `List<Int32x4>`.
   List<Int32x4> operator +(List<Int32x4> other);
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is an `Int32x4list` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Int32x4list.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Int32x4list
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is an `Int32x4list` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Int32x4list.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Int32x4list
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Int32x4List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 16;
 }
 
-/**
- * A fixed-length list of Float64x2 numbers that is viewable as a
- * [TypedData].
- *
- * For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData].
+///
+/// For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 abstract class Float64x2List implements List<Float64x2>, TypedData {
-  /**
-   * Creates a [Float64x2List] of the specified length (in elements),
-   * all of whose elements have all lanes set to zero.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * [length] times 16 bytes.
-   */
+  /// Creates a [Float64x2List] of the specified length (in elements),
+  /// all of whose elements have all lanes set to zero.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// [length] times 16 bytes.
   external factory Float64x2List(int length);
 
-  /**
-   * Creates a [Float64x2List] with the same length as the [elements] list
-   * and copies over the elements.
-   *
-   * The list is backed by a [ByteBuffer] containing precisely
-   * `elements.length` times 16 bytes.
-   */
+  /// Creates a [Float64x2List] with the same length as the [elements] list
+  /// and copies over the elements.
+  ///
+  /// The list is backed by a [ByteBuffer] containing precisely
+  /// `elements.length` times 16 bytes.
   external factory Float64x2List.fromList(List<Float64x2> elements);
 
-  /**
-   * Returns the concatenation of this list and [other].
-   *
-   * If [other] is also a [Float64x2List], the result is a new [Float64x2List],
-   * otherwise the result is a normal growable `List<Float64x2>`.
-   */
+  /// Returns the concatenation of this list and [other].
+  ///
+  /// If [other] is also a [Float64x2List], the result is a new [Float64x2List],
+  /// otherwise the result is a normal growable `List<Float64x2>`.
   List<Float64x2> operator +(List<Float64x2> other);
 
-  /**
-   * Creates a [Float64x2List] _view_ of the specified region in [buffer].
-   *
-   * Changes in the [Float64x2List] will be visible in the byte
-   * buffer and vice versa.
-   * If the [offsetInBytes] index of the region is not specified,
-   * it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to `null`,
-   * which indicates that the view extends to the end of the byte buffer.
-   *
-   * The [offsetInBytes] and [length] must be non-negative, and
-   * [offsetInBytes] + ([length] * elementSizeInBytes) must be less than or
-   * equal to the length of [buffer].
-   *
-   * The [offsetInBytes] must be a multiple of [bytesPerElement].
-   *
-   * Note that when creating a view from a [TypedData] list or byte data,
-   * that list or byte data may itself be a view on a larger buffer
-   * with a [TypedData.offsetInBytes] greater than zero.
-   * Merely doing `Float64x2List.view(other.buffer, 0, count)` may not
-   * point to the bytes you intended. Instead you may need to do:
-   * ```dart
-   * Float64x2List.view(other.buffer, other.offsetInBytes, count)
-   * ```
-   * Alternatively, use [Float64x2List.sublistView]
-   * which includes this computation:
-   * ```dart
-   * Float64x2List.sublistView(other, 0, count);
-   * ```
-   * (The third argument is an end index rather than a length, so if
-   * you start from a position greater than zero, you need not
-   * reduce the count correspondingly).
-   */
+  /// Creates a [Float64x2List] _view_ of the specified region in [buffer].
+  ///
+  /// Changes in the [Float64x2List] will be visible in the byte
+  /// buffer and vice versa.
+  /// If the [offsetInBytes] index of the region is not specified,
+  /// it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not provided,
+  /// the view extends to the end of the byte buffer.
+  ///
+  /// The [offsetInBytes] and [length] must be non-negative, and
+  /// [offsetInBytes] + ([length] * [bytesPerElement]) must be less than or
+  /// equal to the length of [buffer].
+  ///
+  /// The [offsetInBytes] must be a multiple of [bytesPerElement].
+  ///
+  /// Note that when creating a view from a [TypedData] list or byte data,
+  /// that list or byte data may itself be a view on a larger buffer
+  /// with a [TypedData.offsetInBytes] greater than zero.
+  /// Merely doing `Float64x2List.view(other.buffer, 0, count)` may not
+  /// point to the bytes you intended. Instead you may need to do:
+  /// ```dart
+  /// Float64x2List.view(other.buffer, other.offsetInBytes, count)
+  /// ```
+  /// Alternatively, use [Float64x2List.sublistView]
+  /// which includes this computation:
+  /// ```dart
+  /// Float64x2List.sublistView(other, 0, count);
+  /// ```
+  /// (The third argument is an end index rather than a length, so if
+  /// you start from a position greater than zero, you need not
+  /// reduce the count correspondingly).
   factory Float64x2List.view(ByteBuffer buffer,
       [int offsetInBytes = 0, int? length]) {
     return buffer.asFloat64x2List(offsetInBytes, length);
   }
 
-  /**
-   * Creates an [Float64x2List] view on a range of elements of [data].
-   *
-   * Creates a view on the range of `data.buffer` which corresponds
-   * to the elements of [data] from [start] until [end].
-   * If [data] is a typed data list, like [Uint16List], then the view is on
-   * the bytes of the elements with indices from [start] until [end].
-   * If [data] is a [ByteData], it's treated like a list of bytes.
-   *
-   * If provided, [start] and [end] must satisfy
-   *
-   * 0 &le; `start` &le; `end` &le; *elementCount*
-   *
-   * where *elementCount* is the number of elements in [data], which
-   * is the same as the [List.length] of a typed data list.
-   *
-   * If omitted, [start] defaults to zero and [end] to *elementCount*.
-   *
-   * The start and end indices of the range of bytes being viewed must be
-   * multiples of sixteen.
-   */
+  /// Creates an [Float64x2List] view on a range of elements of [data].
+  ///
+  /// Creates a view on the range of `data.buffer` which corresponds
+  /// to the elements of [data] from [start] until [end].
+  /// If [data] is a typed data list, like [Uint16List], then the view is on
+  /// the bytes of the elements with indices from [start] until [end].
+  /// If [data] is a [ByteData], it's treated like a list of bytes.
+  ///
+  /// If provided, [start] and [end] must satisfy
+  ///
+  /// 0 &le; `start` &le; `end` &le; *elementCount*
+  ///
+  /// where *elementCount* is the number of elements in [data], which
+  /// is the same as the [List.length] of a typed data list.
+  ///
+  /// If omitted, [start] defaults to zero and [end] to *elementCount*.
+  ///
+  /// The start and end indices of the range of bytes being viewed must be
+  /// multiples of sixteen.
   @Since("2.8")
   factory Float64x2List.sublistView(TypedData data, [int start = 0, int? end]) {
     int elementSize = data.elementSizeInBytes;
@@ -2626,40 +2354,36 @@
         byteLength ~/ bytesPerElement);
   }
 
-  /**
-   * Returns a new list containing the elements between [start] and [end].
-   *
-   * The new list is a `Float64x2List` containing the elements of this
-   * list at positions greater than or equal to [start] and less than [end] in
-   * the same order as they occur in this list.
-   *
-   * ```dart
-   * var numbers = Float64x2List.fromList([0, 1, 2, 3, 4]);
-   * print(numbers.sublist(1, 3)); // [1, 2]
-   * print(numbers.sublist(1, 3).runtimeType); // Float64x2List
-   * ```
-   *
-   * If [end] is omitted, it defaults to the [length] of this list.
-   *
-   * ```dart
-   * print(numbers.sublist(1)); // [1, 2, 3, 4]
-   * ```
-   *
-   * The `start` and `end` positions must satisfy the relations
-   * 0 ≤ `start` ≤ `end` ≤ `this.length`
-   * If `end` is equal to `start`, then the returned list is empty.
-   */
+  /// Returns a new list containing the elements between [start] and [end].
+  ///
+  /// The new list is a `Float64x2List` containing the elements of this
+  /// list at positions greater than or equal to [start] and less than [end] in
+  /// the same order as they occur in this list.
+  ///
+  /// ```dart
+  /// var numbers = Float64x2List.fromList([0, 1, 2, 3, 4]);
+  /// print(numbers.sublist(1, 3)); // [1, 2]
+  /// print(numbers.sublist(1, 3).runtimeType); // Float64x2List
+  /// ```
+  ///
+  /// If [end] is omitted, it defaults to the [length] of this list.
+  ///
+  /// ```dart
+  /// print(numbers.sublist(1)); // [1, 2, 3, 4]
+  /// ```
+  ///
+  /// The `start` and `end` positions must satisfy the relations
+  /// 0 ≤ `start` ≤ `end` ≤ `this.length`
+  /// If `end` is equal to `start`, then the returned list is empty.
   Float64x2List sublist(int start, [int? end]);
 
   static const int bytesPerElement = 16;
 }
 
-/**
- * Float32x4 immutable value type and operations.
- *
- * Float32x4 stores 4 32-bit floating point values in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Float32x4 immutable value type and operations.
+///
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 abstract class Float32x4 {
   external factory Float32x4(double x, double y, double z, double w);
   external factory Float32x4.splat(double v);
@@ -3026,12 +2750,10 @@
   Float32x4 reciprocalSqrt();
 }
 
-/**
- * Int32x4 and operations.
- *
- * Int32x4 stores 4 32-bit bit-masks in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Int32x4 and operations.
+///
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 abstract class Int32x4 {
   external factory Int32x4(int x, int y, int z, int w);
   external factory Int32x4.bool(bool x, bool y, bool z, bool w);
@@ -3379,12 +3101,10 @@
   Float32x4 select(Float32x4 trueValue, Float32x4 falseValue);
 }
 
-/**
- * Float64x2 immutable value type and operations.
- *
- * Float64x2 stores 2 64-bit floating point values in "lanes".
- * The lanes are "x" and "y" respectively.
- */
+/// Float64x2 immutable value type and operations.
+///
+/// Float64x2 stores 2 64-bit floating point values in "lanes".
+/// The lanes are "x" and "y" respectively.
 abstract class Float64x2 {
   external factory Float64x2(double x, double y);
   external factory Float64x2.splat(double v);
diff --git a/sdk/lib/typed_data/unmodifiable_typed_data.dart b/sdk/lib/typed_data/unmodifiable_typed_data.dart
index 30bdf51..43aaa84 100644
--- a/sdk/lib/typed_data/unmodifiable_typed_data.dart
+++ b/sdk/lib/typed_data/unmodifiable_typed_data.dart
@@ -4,9 +4,7 @@
 
 part of dart.typed_data;
 
-/**
- * A read-only view of a [ByteBuffer].
- */
+/// A read-only view of a [ByteBuffer].
 class UnmodifiableByteBufferView implements ByteBuffer {
   final ByteBuffer _data;
 
@@ -66,9 +64,7 @@
       new UnmodifiableByteDataView(_data.asByteData(offsetInBytes, length));
 }
 
-/**
- * A read-only view of a [ByteData].
- */
+/// A read-only view of a [ByteData].
 class UnmodifiableByteDataView implements ByteData {
   final ByteData _data;
 
@@ -173,9 +169,7 @@
   }
 }
 
-/**
- * View of a [Uint8List] that disallows modification.
- */
+/// View of a [Uint8List] that disallows modification.
 class UnmodifiableUint8ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Uint8List, Uint8List>
     implements Uint8List {
@@ -185,9 +179,7 @@
   Uint8List _createList(int length) => Uint8List(length);
 }
 
-/**
- * View of a [Int8List] that disallows modification.
- */
+/// View of a [Int8List] that disallows modification.
 class UnmodifiableInt8ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Int8List, Int8List>
     implements Int8List {
@@ -197,9 +189,7 @@
   Int8List _createList(int length) => Int8List(length);
 }
 
-/**
- * View of a [Uint8ClampedList] that disallows modification.
- */
+/// View of a [Uint8ClampedList] that disallows modification.
 class UnmodifiableUint8ClampedListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Uint8ClampedList, Uint8ClampedList>
     implements Uint8ClampedList {
@@ -209,9 +199,7 @@
   Uint8ClampedList _createList(int length) => Uint8ClampedList(length);
 }
 
-/**
- * View of a [Uint16List] that disallows modification.
- */
+/// View of a [Uint16List] that disallows modification.
 class UnmodifiableUint16ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Uint16List, Uint16List>
     implements Uint16List {
@@ -221,9 +209,7 @@
   Uint16List _createList(int length) => Uint16List(length);
 }
 
-/**
- * View of a [Int16List] that disallows modification.
- */
+/// View of a [Int16List] that disallows modification.
 class UnmodifiableInt16ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Int16List, Int16List>
     implements Int16List {
@@ -233,9 +219,7 @@
   Int16List _createList(int length) => Int16List(length);
 }
 
-/**
- * View of a [Uint32List] that disallows modification.
- */
+/// View of a [Uint32List] that disallows modification.
 class UnmodifiableUint32ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Uint32List, Uint32List>
     implements Uint32List {
@@ -245,9 +229,7 @@
   Uint32List _createList(int length) => Uint32List(length);
 }
 
-/**
- * View of a [Int32List] that disallows modification.
- */
+/// View of a [Int32List] that disallows modification.
 class UnmodifiableInt32ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Int32List, Int32List>
     implements Int32List {
@@ -257,9 +239,7 @@
   Int32List _createList(int length) => Int32List(length);
 }
 
-/**
- * View of a [Uint64List] that disallows modification.
- */
+/// View of a [Uint64List] that disallows modification.
 class UnmodifiableUint64ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Uint64List, Uint64List>
     implements Uint64List {
@@ -269,9 +249,7 @@
   Uint64List _createList(int length) => Uint64List(length);
 }
 
-/**
- * View of a [Int64List] that disallows modification.
- */
+/// View of a [Int64List] that disallows modification.
 class UnmodifiableInt64ListView extends UnmodifiableListBase<int>
     with _UnmodifiableListMixin<int, Int64List, Int64List>
     implements Int64List {
@@ -281,9 +259,7 @@
   Int64List _createList(int length) => Int64List(length);
 }
 
-/**
- * View of a [Int32x4List] that disallows modification.
- */
+/// View of a [Int32x4List] that disallows modification.
 class UnmodifiableInt32x4ListView extends UnmodifiableListBase<Int32x4>
     with _UnmodifiableListMixin<Int32x4, Int32x4List, Int32x4List>
     implements Int32x4List {
@@ -293,9 +269,7 @@
   Int32x4List _createList(int length) => Int32x4List(length);
 }
 
-/**
- * View of a [Float32x4List] that disallows modification.
- */
+/// View of a [Float32x4List] that disallows modification.
 class UnmodifiableFloat32x4ListView extends UnmodifiableListBase<Float32x4>
     with _UnmodifiableListMixin<Float32x4, Float32x4List, Float32x4List>
     implements Float32x4List {
@@ -305,9 +279,7 @@
   Float32x4List _createList(int length) => Float32x4List(length);
 }
 
-/**
- * View of a [Float64x2List] that disallows modification.
- */
+/// View of a [Float64x2List] that disallows modification.
 class UnmodifiableFloat64x2ListView extends UnmodifiableListBase<Float64x2>
     with _UnmodifiableListMixin<Float64x2, Float64x2List, Float64x2List>
     implements Float64x2List {
@@ -317,9 +289,7 @@
   Float64x2List _createList(int length) => Float64x2List(length);
 }
 
-/**
- * View of a [Float32List] that disallows modification.
- */
+/// View of a [Float32List] that disallows modification.
 class UnmodifiableFloat32ListView extends UnmodifiableListBase<double>
     with _UnmodifiableListMixin<double, Float32List, Float32List>
     implements Float32List {
@@ -329,9 +299,7 @@
   Float32List _createList(int length) => Float32List(length);
 }
 
-/**
- * View of a [Float64List] that disallows modification.
- */
+/// View of a [Float64List] that disallows modification.
 class UnmodifiableFloat64ListView extends UnmodifiableListBase<double>
     with _UnmodifiableListMixin<double, Float64List, Float64List>
     implements Float64List {
diff --git a/tests/ffi/aliasing_test.dart b/tests/ffi/aliasing_test.dart
index 6c2f698..946e1e4 100644
--- a/tests/ffi/aliasing_test.dart
+++ b/tests/ffi/aliasing_test.dart
@@ -13,6 +13,7 @@
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'calloc.dart';
 import 'ffi_test_helpers.dart';
 
 void main() {
@@ -35,28 +36,28 @@
 }
 
 void testNonAlias() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   source.value = 42;
   final int a = source.value;
   source.value = 1984;
   // alias.value should be re-executed, as we wrote to alias.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasCast() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = source.cast<Int8>().cast<Int64>();
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasCast2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = source.cast<Int16>().cast<Int64>();
   final alias2 = source.cast<Int8>().cast<Int64>();
   alias.value = 42;
@@ -64,22 +65,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasOffsetBy() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final alias = source.offsetBy(8).offsetBy(-8);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasOffsetBy2() {
-  final source = allocate<Int64>(count: 3);
+  final source = calloc<Int64>(3);
   final alias = source.offsetBy(16).offsetBy(-16);
   final alias2 = source.offsetBy(8).offsetBy(-8);
   alias.value = 42;
@@ -87,22 +88,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasElementAt() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final alias = source.elementAt(1).elementAt(-1);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasElementAt2() {
-  final source = allocate<Int64>(count: 3);
+  final source = calloc<Int64>(3);
   final alias = source.elementAt(2).elementAt(-2);
   final alias2 = source.elementAt(1).elementAt(-1);
   alias.value = 42;
@@ -110,22 +111,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddress() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddress2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
   final alias2 = Pointer<Int64>.fromAddress(source.address);
   alias.value = 42;
@@ -133,12 +134,12 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaMemory() {
-  final helper = allocate<IntPtr>();
-  final source = allocate<Int64>();
+  final helper = calloc<IntPtr>();
+  final source = calloc<Int64>();
   helper.value = source.address;
   final alias = Pointer<Int64>.fromAddress(helper.value);
   source.value = 42;
@@ -146,13 +147,13 @@
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(helper);
-  free(source);
+  calloc.free(helper);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaMemory2() {
-  final helper = allocate<IntPtr>();
-  final source = allocate<Int64>();
+  final helper = calloc<IntPtr>();
+  final source = calloc<Int64>();
   helper.value = source.address;
   final alias = Pointer<Int64>.fromAddress(helper.value);
   final alias2 = Pointer<Int64>.fromAddress(helper.value);
@@ -161,8 +162,8 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(helper);
-  free(source);
+  calloc.free(helper);
+  calloc.free(source);
 }
 
 typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
@@ -172,7 +173,7 @@
     .lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
 
 void testAliasFromAddressViaNativeFunction() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
   source.value = 42;
@@ -180,11 +181,11 @@
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaNativeFunction2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
   final alias2 =
@@ -194,7 +195,7 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 @pragma('vm:never-inline')
@@ -202,11 +203,11 @@
     source.offsetBy(7).cast<Int8>();
 
 testPartialOverlap() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final derived = makeDerived(source);
   source.value = 0x1122334455667788;
   final int value = source.value;
   derived.value = 0xaa;
   Expect.notEquals(value, source.value);
-  free(source);
+  calloc.free(source);
 }
diff --git a/tests/ffi/allocator_test.dart b/tests/ffi/allocator_test.dart
new file mode 100644
index 0000000..ab2e8db
--- /dev/null
+++ b/tests/ffi/allocator_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that we can implement the Allocator interface.
+
+import 'dart:ffi';
+
+class MyAllocator implements Allocator {
+  const MyAllocator();
+
+  @override
+  Pointer<T> allocate<T extends NativeType>(int numBytes, {int? alignment}) {
+    throw "Not implemented";
+  }
+
+  void free(Pointer pointer) {}
+}
+
+const myAllocator = MyAllocator();
+
+void main() {
+  print(myAllocator);
+}
diff --git a/tests/ffi/calloc.dart b/tests/ffi/calloc.dart
new file mode 100644
index 0000000..e17238a
--- /dev/null
+++ b/tests/ffi/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/tests/ffi/calloc_test.dart b/tests/ffi/calloc_test.dart
new file mode 100644
index 0000000..b8b9bbf
--- /dev/null
+++ b/tests/ffi/calloc_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+import 'calloc.dart';
+import 'coordinate.dart';
+
+void main() {
+  testZeroInt();
+  testZeroFloat();
+  testZeroStruct();
+}
+
+void testZeroInt() {
+  final p = calloc<Uint8>();
+  Expect.equals(0, p.value);
+  calloc.free(p);
+}
+
+void testZeroFloat() {
+  final p = calloc<Float>();
+  Expect.approxEquals(0.0, p.value);
+  calloc.free(p);
+}
+
+void testZeroStruct() {
+  final p = calloc<Coordinate>();
+  Expect.approxEquals(0, p.ref.x);
+  Expect.approxEquals(0, p.ref.y);
+  Expect.equals(nullptr, p.ref.next);
+  calloc.free(p);
+}
diff --git a/tests/ffi/coordinate.dart b/tests/ffi/coordinate.dart
index 9507312..abd6ecd 100644
--- a/tests/ffi/coordinate.dart
+++ b/tests/ffi/coordinate.dart
@@ -17,8 +17,9 @@
 
   external Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/tests/ffi/coordinate_nnbd_workaround.dart b/tests/ffi/coordinate_nnbd_workaround.dart
index 515badd..abd8dba 100644
--- a/tests/ffi/coordinate_nnbd_workaround.dart
+++ b/tests/ffi/coordinate_nnbd_workaround.dart
@@ -20,8 +20,9 @@
   external Pointer<Coordinate> get next;
   external set next(Pointer<Coordinate> v);
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/tests/ffi/data_not_asan_test.dart b/tests/ffi/data_not_asan_test.dart
index e95658f..69257d6 100644
--- a/tests/ffi/data_not_asan_test.dart
+++ b/tests/ffi/data_not_asan_test.dart
@@ -4,7 +4,7 @@
 //
 // Dart test program for testing dart:ffi primitive data pointers.
 //
-// These mallocs trigger an asan alarm, so these tests are in a separate file
+// These callocs trigger an asan alarm, so these tests are in a separate file
 // which is excluded in asan mode.
 
 import 'dart:ffi';
@@ -12,6 +12,8 @@
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'calloc.dart';
+
 void main() {
   testPointerAllocateTooLarge();
   testPointerAllocateNegative();
@@ -20,16 +22,16 @@
 void testPointerAllocateTooLarge() {
   // Try to allocate something that doesn't fit in 64 bit address space.
   int maxInt = 9223372036854775807; // 2^63 - 1
-  Expect.throws(() => allocate<Int64>(count: maxInt));
+  Expect.throws(() => calloc<Int64>(maxInt));
 
   // Try to allocate almost the full 64 bit address space.
   int maxInt1_8 = 1152921504606846975; // 2^60 -1
-  Expect.throws(() => allocate<Int64>(count: maxInt1_8));
+  Expect.throws(() => calloc<Int64>(maxInt1_8));
 }
 
 void testPointerAllocateNegative() {
   // Passing in -1 will be converted into an unsigned integer. So, it will try
   // to allocate SIZE_MAX - 1 + 1 bytes. This will fail as it is the max amount
   // of addressable memory on the system.
-  Expect.throws(() => allocate<Int8>(count: -1));
+  Expect.throws(() => calloc<Int8>(-1));
 }
diff --git a/tests/ffi/data_test.dart b/tests/ffi/data_test.dart
index b2d304d..47b88c5 100644
--- a/tests/ffi/data_test.dart
+++ b/tests/ffi/data_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'ffi_test_helpers.dart';
 
 void main() {
@@ -44,10 +45,8 @@
   testTypeTest();
   testToString();
   testEquality();
-  testAllocateGeneric();
   testAllocateVoid();
   testAllocateNativeFunction();
-  testAllocateNativeType();
   testSizeOfGeneric();
   testSizeOfVoid();
   testSizeOfNativeFunction();
@@ -58,66 +57,66 @@
 }
 
 void testPointerBasic() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 42;
   Expect.equals(42, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerFromPointer() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 1337;
   int ptr = p.address;
   Pointer<Int64> p2 = Pointer.fromAddress(ptr);
   Expect.equals(1337, p2.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerPointerArithmetic() {
-  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p = calloc(2);
   Pointer<Int64> p2 = p.elementAt(1);
   p2.value = 100;
   Pointer<Int64> p3 = p.offsetBy(8);
   Expect.equals(100, p3.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerPointerArithmeticSizes() {
-  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p = calloc(2);
   Pointer<Int64> p2 = p.elementAt(1);
   int addr = p.address;
   Expect.equals(addr + 8, p2.address);
-  free(p);
+  calloc.free(p);
 
-  Pointer<Int32> p3 = allocate(count: 2);
+  Pointer<Int32> p3 = calloc(2);
   Pointer<Int32> p4 = p3.elementAt(1);
   addr = p3.address;
   Expect.equals(addr + 4, p4.address);
-  free(p3);
+  calloc.free(p3);
 }
 
 void testPointerAllocateZero() {
   // > If size is 0, either a null pointer or a unique pointer that can be
-  // > successfully passed to free() shall be returned.
-  // http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html
+  // > successfully passed to calloc.free() shall be returned.
+  // http://pubs.opengroup.org/onlinepubs/009695399/functions/calloc.html
   //
   // Null pointer throws a Dart exception.
   bool returnedNullPointer = false;
   Pointer<Int8> p = nullptr;
   try {
-    p = allocate<Int8>(count: 0);
+    p = calloc<Int8>(0);
   } on Exception {
     returnedNullPointer = true;
   }
   if (!returnedNullPointer) {
-    free(p);
+    calloc.free(p);
   }
 }
 
 void testPointerCast() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.cast<Int32>(); // gets the correct type args back
-  free(p);
+  calloc.free(p);
 }
 
 void testCastGeneric() {
@@ -125,9 +124,9 @@
     return p.cast();
   }
 
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Pointer<Int64> p2 = generic(p);
-  free(p);
+  calloc.free(p);
 }
 
 void testCastGeneric2() {
@@ -135,41 +134,41 @@
     return p.cast();
   }
 
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Pointer<Int64> p2 = generic(p);
-  free(p);
+  calloc.free(p);
 }
 
 void testCastNativeType() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.cast<Pointer>();
-  free(p);
+  calloc.free(p);
 }
 
 void testCondensedNumbersInt8() {
-  Pointer<Int8> p = allocate(count: 8);
+  Pointer<Int8> p = calloc(8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     p[i] = i * 3;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     Expect.equals(i * 3, p[i]);
   }
-  free(p);
+  calloc.free(p);
 }
 
 void testCondensedNumbersFloat() {
-  Pointer<Float> p = allocate(count: 8);
+  Pointer<Float> p = calloc(8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     p[i] = 1.511366173271439e-13;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     Expect.equals(1.511366173271439e-13, p[i]);
   }
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt8() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 127;
   Expect.equals(127, p.value);
   p.value = -128;
@@ -184,11 +183,11 @@
   Expect.equals(0x000000000000007F, 127);
   p.value = -129;
   Expect.equals(127, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint8() {
-  Pointer<Uint8> p = allocate();
+  Pointer<Uint8> p = calloc();
   p.value = 255;
   Expect.equals(255, p.value);
   p.value = 0;
@@ -203,11 +202,11 @@
   Expect.equals(0x00000000000000FF, 255);
   p.value = -1;
   Expect.equals(255, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt16() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   p.value = 0x7FFF;
   Expect.equals(0x7FFF, p.value);
   p.value = -0x8000;
@@ -216,11 +215,11 @@
   Expect.equals(0xFFFFFFFFFFFF8000, p.value); // truncated and sign extended
   p.value = -0x8001;
   Expect.equals(0x7FFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint16() {
-  Pointer<Uint16> p = allocate();
+  Pointer<Uint16> p = calloc();
   p.value = 0xFFFF;
   Expect.equals(0xFFFF, p.value);
   p.value = 0;
@@ -229,11 +228,11 @@
   Expect.equals(0, p.value); // truncated
   p.value = -1;
   Expect.equals(0xFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt32() {
-  Pointer<Int32> p = allocate();
+  Pointer<Int32> p = calloc();
   p.value = 0x7FFFFFFF;
   Expect.equals(0x7FFFFFFF, p.value);
   p.value = -0x80000000;
@@ -242,11 +241,11 @@
   Expect.equals(0xFFFFFFFF80000000, p.value); // truncated and sign extended
   p.value = -0x80000001;
   Expect.equals(0x7FFFFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint32() {
-  Pointer<Uint32> p = allocate();
+  Pointer<Uint32> p = calloc();
   p.value = 0xFFFFFFFF;
   Expect.equals(0xFFFFFFFF, p.value);
   p.value = 0;
@@ -255,20 +254,20 @@
   Expect.equals(0, p.value); // truncated
   p.value = -1;
   Expect.equals(0xFFFFFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt64() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
   Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
   p.value = -0x8000000000000000; // -2 ^ 63
   Expect.equals(-0x8000000000000000, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint64() {
-  Pointer<Uint64> p = allocate();
+  Pointer<Uint64> p = calloc();
   p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
   Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
   p.value = -0x8000000000000000; // -2 ^ 63 interpreted as 2 ^ 63
@@ -279,69 +278,69 @@
   p.value = -1; // -1 interpreted as 2 ^ 64 - 1
   Expect.equals(-1, p.value);
   Expect.equals(0xFFFFFFFFFFFFFFFF, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeIntPtr() {
-  Pointer<IntPtr> p = allocate();
+  Pointer<IntPtr> p = calloc();
   int pAddr = p.address;
   p.value = pAddr; // its own address should fit
   p.value = 0x7FFFFFFF; // and 32 bit addresses should fit
   Expect.equals(0x7FFFFFFF, p.value);
   p.value = -0x80000000;
   Expect.equals(-0x80000000, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testFloat() {
-  Pointer<Float> p = allocate();
+  Pointer<Float> p = calloc();
   p.value = 1.511366173271439e-13;
   Expect.equals(1.511366173271439e-13, p.value);
   p.value = 1.4260258159703532e-105; // float does not have enough precision
   Expect.notEquals(1.4260258159703532e-105, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testDouble() {
-  Pointer<Double> p = allocate();
+  Pointer<Double> p = calloc();
   p.value = 1.4260258159703532e-105;
   Expect.equals(1.4260258159703532e-105, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast(); // make this dart pointer opaque
   p2.address; // we can print the address
-  free(p2);
+  calloc.free(p2);
 }
 
 void testPointerPointer() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   p.value = 17;
-  Pointer<Pointer<Int16>> p2 = allocate();
+  Pointer<Pointer<Int16>> p2 = calloc();
   p2.value = p;
   Expect.equals(17, p2.value.value);
-  free(p2);
-  free(p);
+  calloc.free(p2);
+  calloc.free(p);
 }
 
 void testPointerPointerNull() {
-  Pointer<Pointer<Int8>> pointerToPointer = allocate();
+  Pointer<Pointer<Int8>> pointerToPointer = calloc();
   Pointer<Int8> value = nullptr;
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.equals(value, nullptr);
-  value = allocate();
+  value = calloc();
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.isNotNull(value);
-  free(value);
+  calloc.free(value);
   value = nullptr;
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.equals(value, nullptr);
-  free(pointerToPointer);
+  calloc.free(pointerToPointer);
 }
 
 void testSizeOf() {
@@ -365,7 +364,7 @@
       head.value = value;
       return;
     }
-    Pointer<IntPtr> next = allocate();
+    Pointer<IntPtr> next = calloc();
     head.value = next.address;
     createChain(next, length - 1, value);
   }
@@ -380,14 +379,14 @@
 
   void freeChain(Pointer<IntPtr> head, int length) {
     Pointer<IntPtr> next = Pointer.fromAddress(head.value);
-    free(head);
+    calloc.free(head);
     if (length == 0) {
       return;
     }
     freeChain(next, length - 1);
   }
 
-  Pointer<IntPtr> head = allocate();
+  Pointer<IntPtr> head = calloc();
   createChain(head, length, 512);
   int tailValue = getChainValue(head, length);
   Expect.equals(512, tailValue);
@@ -395,16 +394,16 @@
 }
 
 void testTypeTest() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   Expect.isTrue(p is Pointer);
-  free(p);
+  calloc.free(p);
 }
 
 void testToString() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Expect.stringEquals(
       "Pointer<Int16>: address=0x", p.toString().substring(0, 26));
-  free(p);
+  calloc.free(p);
   Pointer<Int64> p2 = Pointer.fromAddress(0x123abc);
   Expect.stringEquals("Pointer<Int64>: address=0x123abc", p2.toString());
 }
@@ -423,32 +422,15 @@
 
 typedef Int8UnOp = Int8 Function(Int8);
 
-void testAllocateGeneric() {
-  Pointer<T> generic<T extends NativeType>() {
-    Pointer<T> pointer;
-    pointer = allocate();
-    return pointer;
-  }
-
-  Pointer p = generic<Int64>();
-  free(p);
-}
-
 void testAllocateVoid() {
   Expect.throws(() {
-    Pointer<Void> p = allocate();
+    Pointer<Void> p = calloc();
   });
 }
 
 void testAllocateNativeFunction() {
   Expect.throws(() {
-    Pointer<NativeFunction<Int8UnOp>> p = allocate();
-  });
-}
-
-void testAllocateNativeType() {
-  Expect.throws(() {
-    allocate();
+    Pointer<NativeFunction<Int8UnOp>> p = calloc();
   });
 }
 
@@ -482,7 +464,7 @@
 }
 
 void testDynamicInvocation() {
-  dynamic p = allocate<Int8>();
+  dynamic p = calloc<Int8>();
   Expect.throws(() {
     final int i = p.value;
   });
@@ -490,7 +472,7 @@
   p.elementAt(5); // Works, but is slow.
   final int addr = p.address;
   final Pointer<Int16> p2 = p.cast<Int16>();
-  free(p);
+  calloc.free(p);
 }
 
 final nullableInt64ElementAt1 = ffiTestFunctions.lookupFunction<
diff --git a/tests/ffi/extension_methods_test.dart b/tests/ffi/extension_methods_test.dart
index d4e8e4a..5c688e0e 100644
--- a/tests/ffi/extension_methods_test.dart
+++ b/tests/ffi/extension_methods_test.dart
@@ -7,6 +7,8 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 main(List<String> arguments) {
   for (int i = 0; i < 100; i++) {
     testStoreLoad();
@@ -15,7 +17,7 @@
 }
 
 testStoreLoad() {
-  final p = allocate<Int8>(count: 2);
+  final p = calloc<Int8>(2);
   p.value = 10;
   Expect.equals(10, p.value);
   p[1] = 20;
@@ -30,33 +32,33 @@
   final pUseNegative = p.elementAt(1);
   Expect.equals(10, pUseNegative[-1]);
 
-  final p1 = allocate<Double>(count: 2);
+  final p1 = calloc<Double>(2);
   p1.value = 10.0;
   Expect.approxEquals(10.0, p1.value);
   p1[1] = 20.0;
   Expect.approxEquals(20.0, p1[1]);
-  free(p1);
+  calloc.free(p1);
 
-  final p2 = allocate<Pointer<Int8>>(count: 2);
+  final p2 = calloc<Pointer<Int8>>(2);
   p2.value = p;
   Expect.equals(p, p2.value);
   p2[1] = p;
   Expect.equals(p, p2[1]);
-  free(p2);
-  free(p);
+  calloc.free(p2);
+  calloc.free(p);
 
-  final p3 = allocate<Foo>();
+  final p3 = calloc<Foo>();
   Foo foo = p3.ref;
   foo.a = 1;
   Expect.equals(1, foo.a);
-  free(p3);
+  calloc.free(p3);
 }
 
 testReifiedGeneric() {
-  final p = allocate<Pointer<Int8>>();
+  final p = calloc<Pointer<Int8>>();
   Pointer<Pointer<NativeType>> p2 = p;
   Expect.isTrue(p2.value is Pointer<Int8>);
-  free(p);
+  calloc.free(p);
 }
 
 class Foo extends Struct {
diff --git a/tests/ffi/external_typed_data_test.dart b/tests/ffi/external_typed_data_test.dart
index 2b584b4..1327dea 100644
--- a/tests/ffi/external_typed_data_test.dart
+++ b/tests/ffi/external_typed_data_test.dart
@@ -9,6 +9,8 @@
 import 'package:expect/expect.dart';
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 main() {
   testInt8Load();
   testInt8Store();
@@ -41,162 +43,162 @@
 
 void testInt8Load() {
   // Load
-  Pointer<Int8> ptr = allocate();
+  Pointer<Int8> ptr = calloc();
   ptr.value = 0xff;
   Int8List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt8Store() {
   // Store
-  Pointer<Int8> ptr = allocate();
+  Pointer<Int8> ptr = calloc();
   Int8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint8Load() {
   // Load
-  Pointer<Uint8> ptr = allocate();
+  Pointer<Uint8> ptr = calloc();
   ptr.value = 0xff;
   Uint8List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint8Store() {
   // Store
-  Pointer<Uint8> ptr = allocate();
+  Pointer<Uint8> ptr = calloc();
   Uint8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt16Load() {
   // Load
-  Pointer<Int16> ptr = allocate();
+  Pointer<Int16> ptr = calloc();
   ptr.value = 0xffff;
   Int16List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt16Store() {
   // Store
-  Pointer<Int16> ptr = allocate();
+  Pointer<Int16> ptr = calloc();
   Int16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint16Load() {
   // Load
-  Pointer<Uint16> ptr = allocate();
+  Pointer<Uint16> ptr = calloc();
   ptr.value = 0xffff;
   Uint16List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint16Store() {
   // Store
-  Pointer<Uint16> ptr = allocate();
+  Pointer<Uint16> ptr = calloc();
   Uint16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt32Load() {
   // Load
-  Pointer<Int32> ptr = allocate();
+  Pointer<Int32> ptr = calloc();
   ptr.value = 0xffffffff;
   Int32List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt32Store() {
   // Store
-  Pointer<Int32> ptr = allocate();
+  Pointer<Int32> ptr = calloc();
   Int32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint32Load() {
   // Load
-  Pointer<Uint32> ptr = allocate();
+  Pointer<Uint32> ptr = calloc();
   ptr.value = 0xffffffff;
   Uint32List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint32Store() {
   // Store
-  Pointer<Uint32> ptr = allocate();
+  Pointer<Uint32> ptr = calloc();
   Uint32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt64Load() {
   // Load
-  Pointer<Int64> ptr = allocate();
+  Pointer<Int64> ptr = calloc();
   ptr.value = 0xffffffffffffffff;
   Int64List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt64Store() {
   // Store
-  Pointer<Int64> ptr = allocate();
+  Pointer<Int64> ptr = calloc();
   Int64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint64Load() {
   // Load
-  Pointer<Uint64> ptr = allocate();
+  Pointer<Uint64> ptr = calloc();
   ptr.value = 0xffffffffffffffff;
   Uint64List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffffffffffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint64Store() {
   // Store
-  Pointer<Uint64> ptr = allocate();
+  Pointer<Uint64> ptr = calloc();
   Uint64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffffffffffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 double maxFloat = (2 - pow(2, -23)) * pow(2, 127) as double;
@@ -204,47 +206,47 @@
 
 void testFloatLoad() {
   // Load
-  Pointer<Float> ptr = allocate();
+  Pointer<Float> ptr = calloc();
   ptr.value = maxFloat;
   Float32List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxFloat);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testFloatStore() {
   // Store
-  Pointer<Float> ptr = allocate();
+  Pointer<Float> ptr = calloc();
   Float32List list = ptr.asTypedList(1);
   list[0] = maxFloat;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxFloat);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testDoubleLoad() {
   // Load
-  Pointer<Double> ptr = allocate();
+  Pointer<Double> ptr = calloc();
   ptr.value = maxDouble;
   Float64List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxDouble);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testDoubleStore() {
   // Store
-  Pointer<Double> ptr = allocate();
+  Pointer<Double> ptr = calloc();
   Float64List list = ptr.asTypedList(1);
   list[0] = maxDouble;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxDouble);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testArrayLoad() {
   const int count = 0x100;
-  Pointer<Int32> ptr = allocate(count: count);
+  Pointer<Int32> ptr = calloc(count);
   for (int i = 0; i < count; ++i) {
     ptr[i] = i;
   }
@@ -252,12 +254,12 @@
   for (int i = 0; i < count; ++i) {
     Expect.equals(array[i], i);
   }
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testArrayStore() {
   const int count = 0x100;
-  Pointer<Int32> ptr = allocate(count: count);
+  Pointer<Int32> ptr = calloc(count);
   Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     array[i] = i;
@@ -265,7 +267,7 @@
   for (int i = 0; i < count; ++i) {
     Expect.equals(ptr[i], i);
   }
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testNegativeArray() {
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 75ef76f..785f03a 100644
--- a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
@@ -16,6 +16,7 @@
 import "package:ffi/ffi.dart";
 
 import 'callback_tests_utils.dart';
+import 'calloc.dart';
 
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
@@ -5244,7 +5245,7 @@
 Struct1ByteInt returnStruct1ByteIntResult = Struct1ByteInt();
 
 Struct1ByteInt returnStruct1ByteIntCalculateResult() {
-  Struct1ByteInt result = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt result = calloc<Struct1ByteInt>().ref;
 
   result.a0 = returnStruct1ByteInt_a0;
 
@@ -5275,13 +5276,13 @@
 }
 
 void returnStruct1ByteIntAfterCallback() {
-  free(returnStruct1ByteIntResult.addressOf);
+  calloc.free(returnStruct1ByteIntResult.addressOf);
 
   final result = returnStruct1ByteIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct1ByteIntResult.addressOf);
+  calloc.free(returnStruct1ByteIntResult.addressOf);
 }
 
 typedef ReturnStruct3BytesHomogeneousUint8Type = Struct3BytesHomogeneousUint8
@@ -5299,7 +5300,7 @@
 Struct3BytesHomogeneousUint8
     returnStruct3BytesHomogeneousUint8CalculateResult() {
   Struct3BytesHomogeneousUint8 result =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
+      calloc<Struct3BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct3BytesHomogeneousUint8_a0;
   result.a1 = returnStruct3BytesHomogeneousUint8_a1;
@@ -5335,13 +5336,13 @@
 }
 
 void returnStruct3BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct3BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct3BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct3BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct3BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct3BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct3BytesInt2ByteAlignedType = Struct3BytesInt2ByteAligned
@@ -5357,7 +5358,7 @@
 
 Struct3BytesInt2ByteAligned returnStruct3BytesInt2ByteAlignedCalculateResult() {
   Struct3BytesInt2ByteAligned result =
-      allocate<Struct3BytesInt2ByteAligned>().ref;
+      calloc<Struct3BytesInt2ByteAligned>().ref;
 
   result.a0 = returnStruct3BytesInt2ByteAligned_a0;
   result.a1 = returnStruct3BytesInt2ByteAligned_a1;
@@ -5391,13 +5392,13 @@
 }
 
 void returnStruct3BytesInt2ByteAlignedAfterCallback() {
-  free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
+  calloc.free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
 
   final result = returnStruct3BytesInt2ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
+  calloc.free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct4BytesHomogeneousInt16Type = Struct4BytesHomogeneousInt16
@@ -5414,7 +5415,7 @@
 Struct4BytesHomogeneousInt16
     returnStruct4BytesHomogeneousInt16CalculateResult() {
   Struct4BytesHomogeneousInt16 result =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+      calloc<Struct4BytesHomogeneousInt16>().ref;
 
   result.a0 = returnStruct4BytesHomogeneousInt16_a0;
   result.a1 = returnStruct4BytesHomogeneousInt16_a1;
@@ -5448,13 +5449,13 @@
 }
 
 void returnStruct4BytesHomogeneousInt16AfterCallback() {
-  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+  calloc.free(returnStruct4BytesHomogeneousInt16Result.addressOf);
 
   final result = returnStruct4BytesHomogeneousInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+  calloc.free(returnStruct4BytesHomogeneousInt16Result.addressOf);
 }
 
 typedef ReturnStruct7BytesHomogeneousUint8Type = Struct7BytesHomogeneousUint8
@@ -5476,7 +5477,7 @@
 Struct7BytesHomogeneousUint8
     returnStruct7BytesHomogeneousUint8CalculateResult() {
   Struct7BytesHomogeneousUint8 result =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
+      calloc<Struct7BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct7BytesHomogeneousUint8_a0;
   result.a1 = returnStruct7BytesHomogeneousUint8_a1;
@@ -5521,13 +5522,13 @@
 }
 
 void returnStruct7BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct7BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct7BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct7BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct7BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct7BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct7BytesInt4ByteAlignedType = Struct7BytesInt4ByteAligned
@@ -5544,7 +5545,7 @@
 
 Struct7BytesInt4ByteAligned returnStruct7BytesInt4ByteAlignedCalculateResult() {
   Struct7BytesInt4ByteAligned result =
-      allocate<Struct7BytesInt4ByteAligned>().ref;
+      calloc<Struct7BytesInt4ByteAligned>().ref;
 
   result.a0 = returnStruct7BytesInt4ByteAligned_a0;
   result.a1 = returnStruct7BytesInt4ByteAligned_a1;
@@ -5581,13 +5582,13 @@
 }
 
 void returnStruct7BytesInt4ByteAlignedAfterCallback() {
-  free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
+  calloc.free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
 
   final result = returnStruct7BytesInt4ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
+  calloc.free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct8BytesIntType = Struct8BytesInt Function(
@@ -5602,7 +5603,7 @@
 Struct8BytesInt returnStruct8BytesIntResult = Struct8BytesInt();
 
 Struct8BytesInt returnStruct8BytesIntCalculateResult() {
-  Struct8BytesInt result = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt result = calloc<Struct8BytesInt>().ref;
 
   result.a0 = returnStruct8BytesInt_a0;
   result.a1 = returnStruct8BytesInt_a1;
@@ -5637,13 +5638,13 @@
 }
 
 void returnStruct8BytesIntAfterCallback() {
-  free(returnStruct8BytesIntResult.addressOf);
+  calloc.free(returnStruct8BytesIntResult.addressOf);
 
   final result = returnStruct8BytesIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesIntResult.addressOf);
+  calloc.free(returnStruct8BytesIntResult.addressOf);
 }
 
 typedef ReturnStruct8BytesHomogeneousFloatType = Struct8BytesHomogeneousFloat
@@ -5660,7 +5661,7 @@
 Struct8BytesHomogeneousFloat
     returnStruct8BytesHomogeneousFloatCalculateResult() {
   Struct8BytesHomogeneousFloat result =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+      calloc<Struct8BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct8BytesHomogeneousFloat_a0;
   result.a1 = returnStruct8BytesHomogeneousFloat_a1;
@@ -5694,13 +5695,13 @@
 }
 
 void returnStruct8BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct8BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct8BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct8BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct8BytesMixedType = Struct8BytesMixed Function(
@@ -5715,7 +5716,7 @@
 Struct8BytesMixed returnStruct8BytesMixedResult = Struct8BytesMixed();
 
 Struct8BytesMixed returnStruct8BytesMixedCalculateResult() {
-  Struct8BytesMixed result = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed result = calloc<Struct8BytesMixed>().ref;
 
   result.a0 = returnStruct8BytesMixed_a0;
   result.a1 = returnStruct8BytesMixed_a1;
@@ -5750,13 +5751,13 @@
 }
 
 void returnStruct8BytesMixedAfterCallback() {
-  free(returnStruct8BytesMixedResult.addressOf);
+  calloc.free(returnStruct8BytesMixedResult.addressOf);
 
   final result = returnStruct8BytesMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesMixedResult.addressOf);
+  calloc.free(returnStruct8BytesMixedResult.addressOf);
 }
 
 typedef ReturnStruct9BytesHomogeneousUint8Type = Struct9BytesHomogeneousUint8
@@ -5780,7 +5781,7 @@
 Struct9BytesHomogeneousUint8
     returnStruct9BytesHomogeneousUint8CalculateResult() {
   Struct9BytesHomogeneousUint8 result =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
+      calloc<Struct9BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct9BytesHomogeneousUint8_a0;
   result.a1 = returnStruct9BytesHomogeneousUint8_a1;
@@ -5831,13 +5832,13 @@
 }
 
 void returnStruct9BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct9BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct9BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct9BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct9BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct9BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct9BytesInt4Or8ByteAlignedType
@@ -5854,7 +5855,7 @@
 Struct9BytesInt4Or8ByteAligned
     returnStruct9BytesInt4Or8ByteAlignedCalculateResult() {
   Struct9BytesInt4Or8ByteAligned result =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
 
   result.a0 = returnStruct9BytesInt4Or8ByteAligned_a0;
   result.a1 = returnStruct9BytesInt4Or8ByteAligned_a1;
@@ -5890,13 +5891,13 @@
 }
 
 void returnStruct9BytesInt4Or8ByteAlignedAfterCallback() {
-  free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
+  calloc.free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
 
   final result = returnStruct9BytesInt4Or8ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
+  calloc.free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct12BytesHomogeneousFloatType = Struct12BytesHomogeneousFloat
@@ -5914,7 +5915,7 @@
 Struct12BytesHomogeneousFloat
     returnStruct12BytesHomogeneousFloatCalculateResult() {
   Struct12BytesHomogeneousFloat result =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct12BytesHomogeneousFloat_a0;
   result.a1 = returnStruct12BytesHomogeneousFloat_a1;
@@ -5951,13 +5952,13 @@
 }
 
 void returnStruct12BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct12BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct12BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct12BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct16BytesHomogeneousFloatType = Struct16BytesHomogeneousFloat
@@ -5976,7 +5977,7 @@
 Struct16BytesHomogeneousFloat
     returnStruct16BytesHomogeneousFloatCalculateResult() {
   Struct16BytesHomogeneousFloat result =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct16BytesHomogeneousFloat_a0;
   result.a1 = returnStruct16BytesHomogeneousFloat_a1;
@@ -6014,13 +6015,13 @@
 }
 
 void returnStruct16BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct16BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct16BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct16BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct16BytesMixedType = Struct16BytesMixed Function(
@@ -6034,7 +6035,7 @@
 Struct16BytesMixed returnStruct16BytesMixedResult = Struct16BytesMixed();
 
 Struct16BytesMixed returnStruct16BytesMixedCalculateResult() {
-  Struct16BytesMixed result = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed result = calloc<Struct16BytesMixed>().ref;
 
   result.a0 = returnStruct16BytesMixed_a0;
   result.a1 = returnStruct16BytesMixed_a1;
@@ -6067,13 +6068,13 @@
 }
 
 void returnStruct16BytesMixedAfterCallback() {
-  free(returnStruct16BytesMixedResult.addressOf);
+  calloc.free(returnStruct16BytesMixedResult.addressOf);
 
   final result = returnStruct16BytesMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesMixedResult.addressOf);
+  calloc.free(returnStruct16BytesMixedResult.addressOf);
 }
 
 typedef ReturnStruct16BytesMixed2Type = Struct16BytesMixed2 Function(
@@ -6089,7 +6090,7 @@
 Struct16BytesMixed2 returnStruct16BytesMixed2Result = Struct16BytesMixed2();
 
 Struct16BytesMixed2 returnStruct16BytesMixed2CalculateResult() {
-  Struct16BytesMixed2 result = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 result = calloc<Struct16BytesMixed2>().ref;
 
   result.a0 = returnStruct16BytesMixed2_a0;
   result.a1 = returnStruct16BytesMixed2_a1;
@@ -6128,13 +6129,13 @@
 }
 
 void returnStruct16BytesMixed2AfterCallback() {
-  free(returnStruct16BytesMixed2Result.addressOf);
+  calloc.free(returnStruct16BytesMixed2Result.addressOf);
 
   final result = returnStruct16BytesMixed2CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesMixed2Result.addressOf);
+  calloc.free(returnStruct16BytesMixed2Result.addressOf);
 }
 
 typedef ReturnStruct17BytesIntType = Struct17BytesInt Function(
@@ -6149,7 +6150,7 @@
 Struct17BytesInt returnStruct17BytesIntResult = Struct17BytesInt();
 
 Struct17BytesInt returnStruct17BytesIntCalculateResult() {
-  Struct17BytesInt result = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt result = calloc<Struct17BytesInt>().ref;
 
   result.a0 = returnStruct17BytesInt_a0;
   result.a1 = returnStruct17BytesInt_a1;
@@ -6186,13 +6187,13 @@
 }
 
 void returnStruct17BytesIntAfterCallback() {
-  free(returnStruct17BytesIntResult.addressOf);
+  calloc.free(returnStruct17BytesIntResult.addressOf);
 
   final result = returnStruct17BytesIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct17BytesIntResult.addressOf);
+  calloc.free(returnStruct17BytesIntResult.addressOf);
 }
 
 typedef ReturnStruct19BytesHomogeneousUint8Type
@@ -6245,7 +6246,7 @@
 Struct19BytesHomogeneousUint8
     returnStruct19BytesHomogeneousUint8CalculateResult() {
   Struct19BytesHomogeneousUint8 result =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct19BytesHomogeneousUint8_a0;
   result.a1 = returnStruct19BytesHomogeneousUint8_a1;
@@ -6334,13 +6335,13 @@
 }
 
 void returnStruct19BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct19BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct19BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct19BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct20BytesHomogeneousInt32Type = Struct20BytesHomogeneousInt32
@@ -6360,7 +6361,7 @@
 Struct20BytesHomogeneousInt32
     returnStruct20BytesHomogeneousInt32CalculateResult() {
   Struct20BytesHomogeneousInt32 result =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   result.a0 = returnStruct20BytesHomogeneousInt32_a0;
   result.a1 = returnStruct20BytesHomogeneousInt32_a1;
@@ -6401,13 +6402,13 @@
 }
 
 void returnStruct20BytesHomogeneousInt32AfterCallback() {
-  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousInt32Result.addressOf);
 
   final result = returnStruct20BytesHomogeneousInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousInt32Result.addressOf);
 }
 
 typedef ReturnStruct20BytesHomogeneousFloatType = Struct20BytesHomogeneousFloat
@@ -6427,7 +6428,7 @@
 Struct20BytesHomogeneousFloat
     returnStruct20BytesHomogeneousFloatCalculateResult() {
   Struct20BytesHomogeneousFloat result =
-      allocate<Struct20BytesHomogeneousFloat>().ref;
+      calloc<Struct20BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct20BytesHomogeneousFloat_a0;
   result.a1 = returnStruct20BytesHomogeneousFloat_a1;
@@ -6468,13 +6469,13 @@
 }
 
 void returnStruct20BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct20BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct32BytesHomogeneousDoubleType
@@ -6493,7 +6494,7 @@
 Struct32BytesHomogeneousDouble
     returnStruct32BytesHomogeneousDoubleCalculateResult() {
   Struct32BytesHomogeneousDouble result =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
 
   result.a0 = returnStruct32BytesHomogeneousDouble_a0;
   result.a1 = returnStruct32BytesHomogeneousDouble_a1;
@@ -6532,13 +6533,13 @@
 }
 
 void returnStruct32BytesHomogeneousDoubleAfterCallback() {
-  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
 
   final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
 }
 
 typedef ReturnStruct40BytesHomogeneousDoubleType
@@ -6559,7 +6560,7 @@
 Struct40BytesHomogeneousDouble
     returnStruct40BytesHomogeneousDoubleCalculateResult() {
   Struct40BytesHomogeneousDouble result =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
 
   result.a0 = returnStruct40BytesHomogeneousDouble_a0;
   result.a1 = returnStruct40BytesHomogeneousDouble_a1;
@@ -6601,13 +6602,13 @@
 }
 
 void returnStruct40BytesHomogeneousDoubleAfterCallback() {
-  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
 
   final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
 }
 
 typedef ReturnStruct1024BytesHomogeneousUint64Type
@@ -6878,7 +6879,7 @@
 Struct1024BytesHomogeneousUint64
     returnStruct1024BytesHomogeneousUint64CalculateResult() {
   Struct1024BytesHomogeneousUint64 result =
-      allocate<Struct1024BytesHomogeneousUint64>().ref;
+      calloc<Struct1024BytesHomogeneousUint64>().ref;
 
   result.a0 = returnStruct1024BytesHomogeneousUint64_a0;
   result.a1 = returnStruct1024BytesHomogeneousUint64_a1;
@@ -7293,13 +7294,13 @@
 }
 
 void returnStruct1024BytesHomogeneousUint64AfterCallback() {
-  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+  calloc.free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
 
   final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+  calloc.free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
 }
 
 typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
@@ -7618,7 +7619,7 @@
 StructAlignmentInt16 returnStructAlignmentInt16Result = StructAlignmentInt16();
 
 StructAlignmentInt16 returnStructAlignmentInt16CalculateResult() {
-  StructAlignmentInt16 result = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 result = calloc<StructAlignmentInt16>().ref;
 
   result.a0 = returnStructAlignmentInt16_a0;
   result.a1 = returnStructAlignmentInt16_a1;
@@ -7653,13 +7654,13 @@
 }
 
 void returnStructAlignmentInt16AfterCallback() {
-  free(returnStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructAlignmentInt16Result.addressOf);
 
   final result = returnStructAlignmentInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructAlignmentInt16Result.addressOf);
 }
 
 typedef ReturnStructAlignmentInt32Type = StructAlignmentInt32 Function(
@@ -7674,7 +7675,7 @@
 StructAlignmentInt32 returnStructAlignmentInt32Result = StructAlignmentInt32();
 
 StructAlignmentInt32 returnStructAlignmentInt32CalculateResult() {
-  StructAlignmentInt32 result = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 result = calloc<StructAlignmentInt32>().ref;
 
   result.a0 = returnStructAlignmentInt32_a0;
   result.a1 = returnStructAlignmentInt32_a1;
@@ -7709,13 +7710,13 @@
 }
 
 void returnStructAlignmentInt32AfterCallback() {
-  free(returnStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructAlignmentInt32Result.addressOf);
 
   final result = returnStructAlignmentInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructAlignmentInt32Result.addressOf);
 }
 
 typedef ReturnStructAlignmentInt64Type = StructAlignmentInt64 Function(
@@ -7730,7 +7731,7 @@
 StructAlignmentInt64 returnStructAlignmentInt64Result = StructAlignmentInt64();
 
 StructAlignmentInt64 returnStructAlignmentInt64CalculateResult() {
-  StructAlignmentInt64 result = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 result = calloc<StructAlignmentInt64>().ref;
 
   result.a0 = returnStructAlignmentInt64_a0;
   result.a1 = returnStructAlignmentInt64_a1;
@@ -7765,13 +7766,13 @@
 }
 
 void returnStructAlignmentInt64AfterCallback() {
-  free(returnStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructAlignmentInt64Result.addressOf);
 
   final result = returnStructAlignmentInt64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructAlignmentInt64Result.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedIntType = Struct8BytesNestedInt Function(
@@ -7788,7 +7789,7 @@
     Struct8BytesNestedInt();
 
 Struct8BytesNestedInt returnStruct8BytesNestedIntCalculateResult() {
-  Struct8BytesNestedInt result = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt result = calloc<Struct8BytesNestedInt>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedInt_a0.a0;
   result.a0.a1 = returnStruct8BytesNestedInt_a0.a1;
@@ -7824,13 +7825,13 @@
 }
 
 void returnStruct8BytesNestedIntAfterCallback() {
-  free(returnStruct8BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct8BytesNestedIntResult.addressOf);
 
   final result = returnStruct8BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct8BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedFloatType = Struct8BytesNestedFloat Function(
@@ -7845,7 +7846,7 @@
     Struct8BytesNestedFloat();
 
 Struct8BytesNestedFloat returnStruct8BytesNestedFloatCalculateResult() {
-  Struct8BytesNestedFloat result = allocate<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat result = calloc<Struct8BytesNestedFloat>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedFloat_a0.a0;
   result.a1.a0 = returnStruct8BytesNestedFloat_a1.a0;
@@ -7879,13 +7880,13 @@
 }
 
 void returnStruct8BytesNestedFloatAfterCallback() {
-  free(returnStruct8BytesNestedFloatResult.addressOf);
+  calloc.free(returnStruct8BytesNestedFloatResult.addressOf);
 
   final result = returnStruct8BytesNestedFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedFloatResult.addressOf);
+  calloc.free(returnStruct8BytesNestedFloatResult.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedFloat2Type = Struct8BytesNestedFloat2 Function(
@@ -7900,7 +7901,7 @@
     Struct8BytesNestedFloat2();
 
 Struct8BytesNestedFloat2 returnStruct8BytesNestedFloat2CalculateResult() {
-  Struct8BytesNestedFloat2 result = allocate<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 result = calloc<Struct8BytesNestedFloat2>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedFloat2_a0.a0;
   result.a1 = returnStruct8BytesNestedFloat2_a1;
@@ -7935,13 +7936,13 @@
 }
 
 void returnStruct8BytesNestedFloat2AfterCallback() {
-  free(returnStruct8BytesNestedFloat2Result.addressOf);
+  calloc.free(returnStruct8BytesNestedFloat2Result.addressOf);
 
   final result = returnStruct8BytesNestedFloat2CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedFloat2Result.addressOf);
+  calloc.free(returnStruct8BytesNestedFloat2Result.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedMixedType = Struct8BytesNestedMixed Function(
@@ -7957,7 +7958,7 @@
     Struct8BytesNestedMixed();
 
 Struct8BytesNestedMixed returnStruct8BytesNestedMixedCalculateResult() {
-  Struct8BytesNestedMixed result = allocate<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed result = calloc<Struct8BytesNestedMixed>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedMixed_a0.a0;
   result.a0.a1 = returnStruct8BytesNestedMixed_a0.a1;
@@ -7992,13 +7993,13 @@
 }
 
 void returnStruct8BytesNestedMixedAfterCallback() {
-  free(returnStruct8BytesNestedMixedResult.addressOf);
+  calloc.free(returnStruct8BytesNestedMixedResult.addressOf);
 
   final result = returnStruct8BytesNestedMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedMixedResult.addressOf);
+  calloc.free(returnStruct8BytesNestedMixedResult.addressOf);
 }
 
 typedef ReturnStruct16BytesNestedIntType = Struct16BytesNestedInt Function(
@@ -8013,7 +8014,7 @@
     Struct16BytesNestedInt();
 
 Struct16BytesNestedInt returnStruct16BytesNestedIntCalculateResult() {
-  Struct16BytesNestedInt result = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt result = calloc<Struct16BytesNestedInt>().ref;
 
   result.a0.a0.a0 = returnStruct16BytesNestedInt_a0.a0.a0;
   result.a0.a0.a1 = returnStruct16BytesNestedInt_a0.a0.a1;
@@ -8053,13 +8054,13 @@
 }
 
 void returnStruct16BytesNestedIntAfterCallback() {
-  free(returnStruct16BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct16BytesNestedIntResult.addressOf);
 
   final result = returnStruct16BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct16BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStruct32BytesNestedIntType = Struct32BytesNestedInt Function(
@@ -8076,7 +8077,7 @@
     Struct32BytesNestedInt();
 
 Struct32BytesNestedInt returnStruct32BytesNestedIntCalculateResult() {
-  Struct32BytesNestedInt result = allocate<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt result = calloc<Struct32BytesNestedInt>().ref;
 
   result.a0.a0.a0.a0 = returnStruct32BytesNestedInt_a0.a0.a0.a0;
   result.a0.a0.a0.a1 = returnStruct32BytesNestedInt_a0.a0.a0.a1;
@@ -8124,13 +8125,13 @@
 }
 
 void returnStruct32BytesNestedIntAfterCallback() {
-  free(returnStruct32BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct32BytesNestedIntResult.addressOf);
 
   final result = returnStruct32BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct32BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct32BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt16Type
@@ -8151,7 +8152,7 @@
 StructNestedIntStructAlignmentInt16
     returnStructNestedIntStructAlignmentInt16CalculateResult() {
   StructNestedIntStructAlignmentInt16 result =
-      allocate<StructNestedIntStructAlignmentInt16>().ref;
+      calloc<StructNestedIntStructAlignmentInt16>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt16_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt16_a0.a1;
@@ -8190,13 +8191,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt16AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt32Type
@@ -8217,7 +8218,7 @@
 StructNestedIntStructAlignmentInt32
     returnStructNestedIntStructAlignmentInt32CalculateResult() {
   StructNestedIntStructAlignmentInt32 result =
-      allocate<StructNestedIntStructAlignmentInt32>().ref;
+      calloc<StructNestedIntStructAlignmentInt32>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt32_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt32_a0.a1;
@@ -8256,13 +8257,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt32AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt64Type
@@ -8283,7 +8284,7 @@
 StructNestedIntStructAlignmentInt64
     returnStructNestedIntStructAlignmentInt64CalculateResult() {
   StructNestedIntStructAlignmentInt64 result =
-      allocate<StructNestedIntStructAlignmentInt64>().ref;
+      calloc<StructNestedIntStructAlignmentInt64>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt64_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt64_a0.a1;
@@ -8322,13 +8323,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt64AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
 }
 
 typedef ReturnStructNestedIrregularEvenBiggerType
@@ -8350,7 +8351,7 @@
 StructNestedIrregularEvenBigger
     returnStructNestedIrregularEvenBiggerCalculateResult() {
   StructNestedIrregularEvenBigger result =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
 
   result.a0 = returnStructNestedIrregularEvenBigger_a0;
   result.a1.a0.a0 = returnStructNestedIrregularEvenBigger_a1.a0.a0;
@@ -8419,11 +8420,11 @@
 }
 
 void returnStructNestedIrregularEvenBiggerAfterCallback() {
-  free(returnStructNestedIrregularEvenBiggerResult.addressOf);
+  calloc.free(returnStructNestedIrregularEvenBiggerResult.addressOf);
 
   final result = returnStructNestedIrregularEvenBiggerCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIrregularEvenBiggerResult.addressOf);
+  calloc.free(returnStructNestedIrregularEvenBiggerResult.addressOf);
 }
diff --git a/tests/ffi/function_callbacks_structs_by_value_test.dart b/tests/ffi/function_callbacks_structs_by_value_test.dart
index 23c9946..5e9399a 100644
--- a/tests/ffi/function_callbacks_structs_by_value_test.dart
+++ b/tests/ffi/function_callbacks_structs_by_value_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
 
@@ -23,7 +24,7 @@
 }
 
 void recursiveTest(int recursionCounter) {
-  final struct = allocate<Struct20BytesHomogeneousInt32>().ref;
+  final struct = calloc<Struct20BytesHomogeneousInt32>().ref;
   struct.a0 = 1;
   struct.a1 = 2;
   struct.a2 = 3;
@@ -35,7 +36,7 @@
   Expect.equals(struct.a2, result.a2);
   Expect.equals(struct.a3, result.a3);
   Expect.equals(struct.a4, result.a4);
-  free(struct.addressOf);
+  calloc.free(struct.addressOf);
 }
 
 Struct20BytesHomogeneousInt32 dartPassStructRecursive(
@@ -93,7 +94,7 @@
   _invokeReceiveStructByValue(_receiveStructByValuePointer);
   Expect.isTrue(typedDataBackedStructSet);
 
-  final pointerBackedStruct = allocate<Struct8BytesNestedInt>().ref;
+  final pointerBackedStruct = calloc<Struct8BytesNestedInt>().ref;
 
   void reset() {
     pointerBackedStruct.a0.a0 = 1;
@@ -130,5 +131,5 @@
   Expect.equals(5, typedDataBackedStruct.a1.a0);
   Expect.equals(6, typedDataBackedStruct.a1.a1);
 
-  free(pointerBackedStruct.addressOf);
+  calloc.free(pointerBackedStruct.addressOf);
 }
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index 8e800fc..c8b91cb 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -15,6 +15,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -1053,16 +1054,16 @@
 /// Smallest struct with data.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct1ByteIntx10() {
-  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a1 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a2 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a3 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a4 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a5 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a6 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a7 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a9 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a0 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a1 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a2 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a3 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a4 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a5 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a6 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a7 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a9 = calloc<Struct1ByteInt>().ref;
 
   a0.a0 = -1;
   a1.a0 = 2;
@@ -1081,16 +1082,16 @@
 
   Expect.equals(5, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct3BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1120,26 +1121,16 @@
 /// Not a multiple of word size, not a power of two.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct3BytesHomogeneousUint8x10() {
-  Struct3BytesHomogeneousUint8 a0 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a1 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a2 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a3 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a4 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a5 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a6 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a7 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a8 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a9 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a0 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a1 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a2 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a3 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a4 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a5 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a6 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a7 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a8 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a9 = calloc<Struct3BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1179,16 +1170,16 @@
 
   Expect.equals(465, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct3BytesInt2ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -1219,16 +1210,16 @@
 /// With alignment rules taken into account size is 4 bytes.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct3BytesInt2ByteAlignedx10() {
-  Struct3BytesInt2ByteAligned a0 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a1 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a2 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a3 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a4 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a5 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a6 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a7 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a8 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a9 = allocate<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a0 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a1 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a2 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a3 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a4 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a5 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a6 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a7 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a8 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a9 = calloc<Struct3BytesInt2ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1258,16 +1249,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct4BytesHomogeneousInt16x10 = ffiTestFunctions.lookupFunction<
@@ -1297,26 +1288,16 @@
 /// Exactly word size on 32-bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct4BytesHomogeneousInt16x10() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a2 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a3 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a4 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a5 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a6 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a7 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a8 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a9 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a2 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a3 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a4 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a5 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a6 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a7 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a8 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a9 = calloc<Struct4BytesHomogeneousInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1346,16 +1327,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct7BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1385,26 +1366,16 @@
 /// Sub word size on 64 bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct7BytesHomogeneousUint8x10() {
-  Struct7BytesHomogeneousUint8 a0 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a1 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a2 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a3 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a4 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a5 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a6 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a7 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a8 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a9 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a0 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a1 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a2 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a3 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a4 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a5 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a6 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a7 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a8 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a9 = calloc<Struct7BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1484,16 +1455,16 @@
 
   Expect.equals(2485, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct7BytesInt4ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -1524,16 +1495,16 @@
 /// With alignment rules taken into account size is 8 bytes.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct7BytesInt4ByteAlignedx10() {
-  Struct7BytesInt4ByteAligned a0 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a1 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a2 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a3 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a4 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a5 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a6 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a7 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a8 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a9 = allocate<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a0 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a1 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a2 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a3 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a4 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a5 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a6 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a7 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a8 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a9 = calloc<Struct7BytesInt4ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1573,16 +1544,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesIntx10 = ffiTestFunctions.lookupFunction<
@@ -1612,16 +1583,16 @@
 /// Exactly word size struct on 64bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesIntx10() {
-  Struct8BytesInt a0 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a1 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a2 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a3 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a4 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a5 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a6 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a7 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a8 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a9 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a0 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a1 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a2 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a3 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a4 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a5 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a6 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a7 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a8 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a9 = calloc<Struct8BytesInt>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1660,16 +1631,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesHomogeneousFloatx10 = ffiTestFunctions.lookupFunction<
@@ -1699,26 +1670,16 @@
 /// Arguments passed in FP registers as long as they fit.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesHomogeneousFloatx10() {
-  Struct8BytesHomogeneousFloat a0 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a1 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a2 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a3 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a4 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a5 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a6 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a7 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a8 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a9 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a0 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a1 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a2 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a3 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a4 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a5 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a6 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a7 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a8 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a9 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -1748,16 +1709,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesMixedx10 = ffiTestFunctions.lookupFunction<
@@ -1787,16 +1748,16 @@
 /// On x64, arguments go in int registers because it is not only float.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesMixedx10() {
-  Struct8BytesMixed a0 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a1 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a2 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a3 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a4 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a5 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a6 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a7 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a8 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a9 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a0 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a1 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a2 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a3 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a4 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a5 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a6 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a7 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a8 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a9 = calloc<Struct8BytesMixed>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2;
@@ -1836,16 +1797,16 @@
 
   Expect.approxEquals(15.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct9BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1878,26 +1839,16 @@
 /// Tests upper bytes in the integer registers that are partly filled.
 /// Tests stack alignment of non word size stack arguments.
 void testPassStruct9BytesHomogeneousUint8x10() {
-  Struct9BytesHomogeneousUint8 a0 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a1 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a2 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a3 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a4 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a5 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a6 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a7 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a8 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a9 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a0 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a1 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a2 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a3 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a4 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a5 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a6 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a7 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a8 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a9 = calloc<Struct9BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1997,16 +1948,16 @@
 
   Expect.equals(4095, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct9BytesInt4Or8ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -2040,25 +1991,25 @@
 ///
 void testPassStruct9BytesInt4Or8ByteAlignedx10() {
   Struct9BytesInt4Or8ByteAligned a0 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a1 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a2 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a3 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a4 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a5 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a6 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a7 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a8 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a9 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2088,16 +2039,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct12BytesHomogeneousFloatx6 = ffiTestFunctions.lookupFunction<
@@ -2121,17 +2072,17 @@
 /// The last argument is to test whether arguments are backfilled.
 void testPassStruct12BytesHomogeneousFloatx6() {
   Struct12BytesHomogeneousFloat a0 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a1 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a2 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a3 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a4 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a5 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2158,12 +2109,12 @@
 
   Expect.approxEquals(9.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
 }
 
 final passStruct16BytesHomogeneousFloatx5 = ffiTestFunctions.lookupFunction<
@@ -2185,15 +2136,15 @@
 /// 5 struct arguments will exhaust available registers.
 void testPassStruct16BytesHomogeneousFloatx5() {
   Struct16BytesHomogeneousFloat a0 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a1 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a2 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a3 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a4 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2222,11 +2173,11 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
 }
 
 final passStruct16BytesMixedx10 = ffiTestFunctions.lookupFunction<
@@ -2258,16 +2209,16 @@
 /// The rest goes on the stack.
 /// On arm, arguments are 8 byte aligned.
 void testPassStruct16BytesMixedx10() {
-  Struct16BytesMixed a0 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a2 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a0 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a2 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = calloc<Struct16BytesMixed>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2;
@@ -2297,16 +2248,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct16BytesMixed2x10 = ffiTestFunctions.lookupFunction<
@@ -2338,16 +2289,16 @@
 /// The rest goes on the stack.
 /// On arm, arguments are 4 byte aligned.
 void testPassStruct16BytesMixed2x10() {
-  Struct16BytesMixed2 a0 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a1 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a2 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a3 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a4 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a5 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a6 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a7 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a8 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a9 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a0 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a1 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a2 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a3 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a4 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a5 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a6 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a7 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a8 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a9 = calloc<Struct16BytesMixed2>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2397,16 +2348,16 @@
 
   Expect.approxEquals(20.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct17BytesIntx10 = ffiTestFunctions.lookupFunction<
@@ -2436,16 +2387,16 @@
 /// Arguments are passed as pointer to copy on arm64.
 /// Tests that the memory allocated for copies are rounded up to word size.
 void testPassStruct17BytesIntx10() {
-  Struct17BytesInt a0 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a1 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a2 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a3 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a4 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a5 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a6 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a7 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a8 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a9 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a0 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a1 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a2 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a3 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a4 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a5 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a6 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a7 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a8 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a9 = calloc<Struct17BytesInt>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2485,16 +2436,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct19BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -2526,25 +2477,25 @@
 ///
 void testPassStruct19BytesHomogeneousUint8x10() {
   Struct19BytesHomogeneousUint8 a0 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a1 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a2 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a3 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a4 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a5 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a6 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a7 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a8 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a9 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -2744,16 +2695,16 @@
 
   Expect.equals(18145, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct20BytesHomogeneousInt32x10 = ffiTestFunctions.lookupFunction<
@@ -2786,25 +2737,25 @@
 /// pointers to copies are also passed on the stack.
 void testPassStruct20BytesHomogeneousInt32x10() {
   Struct20BytesHomogeneousInt32 a0 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a1 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a2 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a3 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a4 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a5 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a6 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a7 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a8 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a9 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2864,16 +2815,16 @@
 
   Expect.equals(25, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
@@ -2884,7 +2835,7 @@
 /// Argument too big to go into FPU registers in hardfp and arm64.
 void testPassStruct20BytesHomogeneousFloat() {
   Struct20BytesHomogeneousFloat a0 =
-      allocate<Struct20BytesHomogeneousFloat>().ref;
+      calloc<Struct20BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2898,7 +2849,7 @@
 
   Expect.approxEquals(-3.0, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct32BytesHomogeneousDoublex5 = ffiTestFunctions.lookupFunction<
@@ -2920,15 +2871,15 @@
 /// 5 struct arguments will exhaust available registers.
 void testPassStruct32BytesHomogeneousDoublex5() {
   Struct32BytesHomogeneousDouble a0 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a1 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a2 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a3 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a4 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2957,11 +2908,11 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
 }
 
 final passStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
@@ -2972,7 +2923,7 @@
 /// Argument too big to go into FPU registers in arm64.
 void testPassStruct40BytesHomogeneousDouble() {
   Struct40BytesHomogeneousDouble a0 =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2986,7 +2937,7 @@
 
   Expect.approxEquals(-3.0, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct1024BytesHomogeneousUint64 = ffiTestFunctions.lookupFunction<
@@ -2997,7 +2948,7 @@
 /// Test 1kb struct.
 void testPassStruct1024BytesHomogeneousUint64() {
   Struct1024BytesHomogeneousUint64 a0 =
-      allocate<Struct1024BytesHomogeneousUint64>().ref;
+      calloc<Struct1024BytesHomogeneousUint64>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -3134,7 +3085,7 @@
 
   Expect.equals(8256, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passFloatStruct16BytesHomogeneousFloatFloatStruct1 =
@@ -3164,16 +3115,16 @@
 void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1() {
   double a0;
   Struct16BytesHomogeneousFloat a1 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a2;
   Struct16BytesHomogeneousFloat a3 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a4;
   Struct16BytesHomogeneousFloat a5 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a6;
   Struct16BytesHomogeneousFloat a7 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a8;
 
   a0 = -1.0;
@@ -3205,10 +3156,10 @@
 
   Expect.approxEquals(-11.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passFloatStruct32BytesHomogeneousDoubleFloatStruct =
@@ -3238,16 +3189,16 @@
 void testPassFloatStruct32BytesHomogeneousDoubleFloatStruct() {
   double a0;
   Struct32BytesHomogeneousDouble a1 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a2;
   Struct32BytesHomogeneousDouble a3 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a4;
   Struct32BytesHomogeneousDouble a5 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a6;
   Struct32BytesHomogeneousDouble a7 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a8;
 
   a0 = -1.0;
@@ -3279,10 +3230,10 @@
 
   Expect.approxEquals(-11.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passInt8Struct16BytesMixedInt8Struct16BytesMixedIn =
@@ -3307,13 +3258,13 @@
 /// Test backfilling of integer registers.
 void testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn() {
   int a0;
-  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = calloc<Struct16BytesMixed>().ref;
   int a2;
-  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = calloc<Struct16BytesMixed>().ref;
   int a4;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
   int a6;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
   int a8;
 
   a0 = -1;
@@ -3337,10 +3288,10 @@
 
   Expect.approxEquals(-7.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passDoublex6Struct16BytesMixedx4Int32 = ffiTestFunctions.lookupFunction<
@@ -3379,10 +3330,10 @@
   double a3;
   double a4;
   double a5;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = calloc<Struct16BytesMixed>().ref;
   int a10;
 
   a0 = -1.0;
@@ -3408,10 +3359,10 @@
 
   Expect.approxEquals(-8.0, result);
 
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passInt32x4Struct16BytesMixedx4Double = ffiTestFunctions.lookupFunction<
@@ -3436,10 +3387,10 @@
   int a1;
   int a2;
   int a3;
-  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
   double a8;
 
   a0 = -1;
@@ -3463,10 +3414,10 @@
 
   Expect.approxEquals(-7.0, result);
 
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passStruct40BytesHomogeneousDoubleStruct4BytesHomo =
@@ -3481,11 +3432,9 @@
 /// Check that the other two arguments are allocated on registers.
 void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo() {
   Struct40BytesHomogeneousDouble a0 =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct8BytesHomogeneousFloat a2 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct8BytesHomogeneousFloat a2 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -3503,9 +3452,9 @@
 
   Expect.approxEquals(-5.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
 }
 
 final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int =
@@ -3613,30 +3562,28 @@
   double a15;
   int a16;
   int a17;
-  Struct1ByteInt a18 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a18 = calloc<Struct1ByteInt>().ref;
   int a19;
   int a20;
-  Struct4BytesHomogeneousInt16 a21 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a21 = calloc<Struct4BytesHomogeneousInt16>().ref;
   int a22;
   int a23;
-  Struct8BytesInt a24 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a24 = calloc<Struct8BytesInt>().ref;
   int a25;
   int a26;
-  Struct8BytesHomogeneousFloat a27 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a27 = calloc<Struct8BytesHomogeneousFloat>().ref;
   int a28;
   int a29;
-  Struct8BytesMixed a30 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a30 = calloc<Struct8BytesMixed>().ref;
   int a31;
   int a32;
-  StructAlignmentInt16 a33 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a33 = calloc<StructAlignmentInt16>().ref;
   int a34;
   int a35;
-  StructAlignmentInt32 a36 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a36 = calloc<StructAlignmentInt32>().ref;
   int a37;
   int a38;
-  StructAlignmentInt64 a39 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a39 = calloc<StructAlignmentInt64>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -3737,14 +3684,14 @@
 
   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);
+  calloc.free(a18.addressOf);
+  calloc.free(a21.addressOf);
+  calloc.free(a24.addressOf);
+  calloc.free(a27.addressOf);
+  calloc.free(a30.addressOf);
+  calloc.free(a33.addressOf);
+  calloc.free(a36.addressOf);
+  calloc.free(a39.addressOf);
 }
 
 final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -3753,7 +3700,7 @@
 
 /// Test alignment and padding of 16 byte int within struct.
 void testPassStructAlignmentInt16() {
-  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a0 = calloc<StructAlignmentInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3765,7 +3712,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
@@ -3774,7 +3721,7 @@
 
 /// Test alignment and padding of 32 byte int within struct.
 void testPassStructAlignmentInt32() {
-  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a0 = calloc<StructAlignmentInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3786,7 +3733,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
@@ -3795,7 +3742,7 @@
 
 /// Test alignment and padding of 64 byte int within struct.
 void testPassStructAlignmentInt64() {
-  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a0 = calloc<StructAlignmentInt64>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3807,7 +3754,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct8BytesNestedIntx10 = ffiTestFunctions.lookupFunction<
@@ -3837,16 +3784,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust registers on all platforms.
 void testPassStruct8BytesNestedIntx10() {
-  Struct8BytesNestedInt a0 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a1 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a2 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a3 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a4 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a5 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a6 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a7 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a8 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a9 = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a0 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a1 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a2 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a3 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a4 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a5 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a6 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a7 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a8 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a9 = calloc<Struct8BytesNestedInt>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -3896,16 +3843,16 @@
 
   Expect.equals(20, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
@@ -3935,16 +3882,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust fpu registers on all platforms.
 void testPassStruct8BytesNestedFloatx10() {
-  Struct8BytesNestedFloat a0 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a1 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a2 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a3 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a4 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a5 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a6 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a7 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a8 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a9 = allocate<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a0 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a1 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a2 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a3 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a4 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a5 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a6 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a7 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a8 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a9 = calloc<Struct8BytesNestedFloat>().ref;
 
   a0.a0.a0 = -1.0;
   a0.a1.a0 = 2.0;
@@ -3974,16 +3921,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedFloat2x10 = ffiTestFunctions.lookupFunction<
@@ -4015,16 +3962,16 @@
 /// The nesting is irregular, testing homogenous float rules on arm and arm64,
 /// and the fpu register usage on x64.
 void testPassStruct8BytesNestedFloat2x10() {
-  Struct8BytesNestedFloat2 a0 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a1 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a2 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a3 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a4 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a5 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a6 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a7 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a8 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a9 = allocate<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a0 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a1 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a2 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a3 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a4 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a5 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a6 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a7 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a8 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a9 = calloc<Struct8BytesNestedFloat2>().ref;
 
   a0.a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -4054,16 +4001,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedMixedx10 = ffiTestFunctions.lookupFunction<
@@ -4093,16 +4040,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust all registers on all platforms.
 void testPassStruct8BytesNestedMixedx10() {
-  Struct8BytesNestedMixed a0 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a1 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a2 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a3 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a4 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a5 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a6 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a7 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a8 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a9 = allocate<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a0 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a1 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a2 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a3 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a4 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a5 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a6 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a7 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a8 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a9 = calloc<Struct8BytesNestedMixed>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4142,16 +4089,16 @@
 
   Expect.approxEquals(15.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct16BytesNestedIntx2 = ffiTestFunctions.lookupFunction<
@@ -4161,8 +4108,8 @@
 
 /// Deeper nested struct to test recursive member access.
 void testPassStruct16BytesNestedIntx2() {
-  Struct16BytesNestedInt a0 = allocate<Struct16BytesNestedInt>().ref;
-  Struct16BytesNestedInt a1 = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a0 = calloc<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a1 = calloc<Struct16BytesNestedInt>().ref;
 
   a0.a0.a0.a0 = -1;
   a0.a0.a0.a1 = 2;
@@ -4187,8 +4134,8 @@
 
   Expect.equals(8, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final passStruct32BytesNestedIntx2 = ffiTestFunctions.lookupFunction<
@@ -4198,8 +4145,8 @@
 
 /// Even deeper nested struct to test recursive member access.
 void testPassStruct32BytesNestedIntx2() {
-  Struct32BytesNestedInt a0 = allocate<Struct32BytesNestedInt>().ref;
-  Struct32BytesNestedInt a1 = allocate<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt a0 = calloc<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt a1 = calloc<Struct32BytesNestedInt>().ref;
 
   a0.a0.a0.a0.a0 = -1;
   a0.a0.a0.a0.a1 = 2;
@@ -4240,8 +4187,8 @@
 
   Expect.equals(16, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -4252,7 +4199,7 @@
 /// Test alignment and padding of nested struct with 16 byte int.
 void testPassStructNestedIntStructAlignmentInt16() {
   StructNestedIntStructAlignmentInt16 a0 =
-      allocate<StructNestedIntStructAlignmentInt16>().ref;
+      calloc<StructNestedIntStructAlignmentInt16>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4267,7 +4214,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
@@ -4278,7 +4225,7 @@
 /// Test alignment and padding of nested struct with 32 byte int.
 void testPassStructNestedIntStructAlignmentInt32() {
   StructNestedIntStructAlignmentInt32 a0 =
-      allocate<StructNestedIntStructAlignmentInt32>().ref;
+      calloc<StructNestedIntStructAlignmentInt32>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4293,7 +4240,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
@@ -4304,7 +4251,7 @@
 /// Test alignment and padding of nested struct with 64 byte int.
 void testPassStructNestedIntStructAlignmentInt64() {
   StructNestedIntStructAlignmentInt64 a0 =
-      allocate<StructNestedIntStructAlignmentInt64>().ref;
+      calloc<StructNestedIntStructAlignmentInt64>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4319,7 +4266,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIrregularEvenBiggerx4 = ffiTestFunctions.lookupFunction<
@@ -4338,13 +4285,13 @@
 /// Return big irregular struct as smoke test.
 void testPassStructNestedIrregularEvenBiggerx4() {
   StructNestedIrregularEvenBigger a0 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a1 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a2 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a3 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
 
   a0.a0 = 1;
   a0.a1.a0.a0 = 2;
@@ -4489,10 +4436,10 @@
 
   Expect.approxEquals(1572.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
 }
 
 final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
@@ -5922,7 +5869,7 @@
 /// Especially for ffi callbacks.
 /// Struct is passed in int registers in most ABIs.
 void testReturnStructArgumentStruct1ByteInt() {
-  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a0 = calloc<Struct1ByteInt>().ref;
 
   a0.a0 = -1;
 
@@ -5932,7 +5879,7 @@
 
   Expect.equals(a0.a0, result.a0);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentInt32x8Struct1ByteInt =
@@ -5954,7 +5901,7 @@
   int a5;
   int a6;
   int a7;
-  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = calloc<Struct1ByteInt>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -5973,7 +5920,7 @@
 
   Expect.equals(a8.a0, result.a0);
 
-  free(a8.addressOf);
+  calloc.free(a8.addressOf);
 }
 
 final returnStructArgumentStruct8BytesHomogeneousFloat =
@@ -5987,8 +5934,7 @@
 /// Especially for ffi callbacks.
 /// Struct is passed in float registers in most ABIs.
 void testReturnStructArgumentStruct8BytesHomogeneousFloat() {
-  Struct8BytesHomogeneousFloat a0 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a0 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -6000,7 +5946,7 @@
   Expect.approxEquals(a0.a0, result.a0);
   Expect.approxEquals(a0.a1, result.a1);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentStruct20BytesHomogeneousInt32 =
@@ -6015,7 +5961,7 @@
 /// On arm64, both argument and return value are passed in by pointer.
 void testReturnStructArgumentStruct20BytesHomogeneousInt32() {
   Struct20BytesHomogeneousInt32 a0 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6033,7 +5979,7 @@
   Expect.equals(a0.a3, result.a3);
   Expect.equals(a0.a4, result.a4);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentInt32x8Struct20BytesHomogeneou =
@@ -6056,7 +6002,7 @@
   int a6;
   int a7;
   Struct20BytesHomogeneousInt32 a8 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -6083,7 +6029,7 @@
   Expect.equals(a8.a3, result.a3);
   Expect.equals(a8.a4, result.a4);
 
-  free(a8.addressOf);
+  calloc.free(a8.addressOf);
 }
 
 final returnStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -6163,10 +6109,8 @@
 
 /// Simple nested struct.
 void testReturnStruct8BytesNestedInt() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6182,8 +6126,8 @@
   Expect.equals(a1.a0, result.a1.a0);
   Expect.equals(a1.a1, result.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct8BytesNestedFloat = ffiTestFunctions.lookupFunction<
@@ -6193,8 +6137,8 @@
 
 /// Simple nested struct with floats.
 void testReturnStruct8BytesNestedFloat() {
-  Struct4BytesFloat a0 = allocate<Struct4BytesFloat>().ref;
-  Struct4BytesFloat a1 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a0 = calloc<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a1 = calloc<Struct4BytesFloat>().ref;
 
   a0.a0 = -1.0;
   a1.a0 = 2.0;
@@ -6206,8 +6150,8 @@
   Expect.approxEquals(a0.a0, result.a0.a0);
   Expect.approxEquals(a1.a0, result.a1.a0);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct8BytesNestedFloat2 = ffiTestFunctions.lookupFunction<
@@ -6218,7 +6162,7 @@
 /// The nesting is irregular, testing homogenous float rules on arm and arm64,
 /// and the fpu register usage on x64.
 void testReturnStruct8BytesNestedFloat2() {
-  Struct4BytesFloat a0 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a0 = calloc<Struct4BytesFloat>().ref;
   double a1;
 
   a0.a0 = -1.0;
@@ -6231,7 +6175,7 @@
   Expect.approxEquals(a0.a0, result.a0.a0);
   Expect.approxEquals(a1, result.a1);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStruct8BytesNestedMixed = ffiTestFunctions.lookupFunction<
@@ -6242,9 +6186,8 @@
 
 /// Simple nested struct with mixed members.
 void testReturnStruct8BytesNestedMixed() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesFloat a1 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesFloat a1 = calloc<Struct4BytesFloat>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6258,8 +6201,8 @@
   Expect.equals(a0.a1, result.a0.a1);
   Expect.approxEquals(a1.a0, result.a1.a0);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct16BytesNestedInt = ffiTestFunctions.lookupFunction<
@@ -6270,8 +6213,8 @@
 
 /// Deeper nested struct to test recursive member access.
 void testReturnStruct16BytesNestedInt() {
-  Struct8BytesNestedInt a0 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a1 = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a0 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a1 = calloc<Struct8BytesNestedInt>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -6295,8 +6238,8 @@
   Expect.equals(a1.a1.a0, result.a1.a1.a0);
   Expect.equals(a1.a1.a1, result.a1.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct32BytesNestedInt = ffiTestFunctions.lookupFunction<
@@ -6307,8 +6250,8 @@
 
 /// Even deeper nested struct to test recursive member access.
 void testReturnStruct32BytesNestedInt() {
-  Struct16BytesNestedInt a0 = allocate<Struct16BytesNestedInt>().ref;
-  Struct16BytesNestedInt a1 = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a0 = calloc<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a1 = calloc<Struct16BytesNestedInt>().ref;
 
   a0.a0.a0.a0 = -1;
   a0.a0.a0.a1 = 2;
@@ -6348,8 +6291,8 @@
   Expect.equals(a1.a1.a1.a0, result.a1.a1.a1.a0);
   Expect.equals(a1.a1.a1.a1, result.a1.a1.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt16 =
@@ -6361,8 +6304,8 @@
 
 /// Test alignment and padding of nested struct with 16 byte int.
 void testReturnStructNestedIntStructAlignmentInt16() {
-  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
-  StructAlignmentInt16 a1 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a0 = calloc<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a1 = calloc<StructAlignmentInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6382,8 +6325,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt32 =
@@ -6395,8 +6338,8 @@
 
 /// Test alignment and padding of nested struct with 32 byte int.
 void testReturnStructNestedIntStructAlignmentInt32() {
-  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
-  StructAlignmentInt32 a1 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a0 = calloc<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a1 = calloc<StructAlignmentInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6416,8 +6359,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt64 =
@@ -6429,8 +6372,8 @@
 
 /// Test alignment and padding of nested struct with 64 byte int.
 void testReturnStructNestedIntStructAlignmentInt64() {
-  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
-  StructAlignmentInt64 a1 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a0 = calloc<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a1 = calloc<StructAlignmentInt64>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6450,8 +6393,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIrregularEvenBigger = ffiTestFunctions.lookupFunction<
@@ -6466,8 +6409,8 @@
 /// Return big irregular struct as smoke test.
 void testReturnStructNestedIrregularEvenBigger() {
   int a0;
-  StructNestedIrregularBigger a1 = allocate<StructNestedIrregularBigger>().ref;
-  StructNestedIrregularBigger a2 = allocate<StructNestedIrregularBigger>().ref;
+  StructNestedIrregularBigger a1 = calloc<StructNestedIrregularBigger>().ref;
+  StructNestedIrregularBigger a2 = calloc<StructNestedIrregularBigger>().ref;
   double a3;
 
   a0 = 1;
@@ -6544,6 +6487,6 @@
   Expect.approxEquals(a2.a3, result.a2.a3);
   Expect.approxEquals(a3, result.a3);
 
-  free(a1.addressOf);
-  free(a2.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
 }
diff --git a/tests/ffi/function_structs_test.dart b/tests/ffi/function_structs_test.dart
index bf9ea5f..ade55fb 100644
--- a/tests/ffi/function_structs_test.dart
+++ b/tests/ffi/function_structs_test.dart
@@ -14,6 +14,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'coordinate.dart';
 import 'very_large_struct.dart';
 
@@ -33,8 +34,10 @@
       ffiTestFunctions.lookup("TransposeCoordinate");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 20.0, nullptr).addressOf;
-  Pointer<Coordinate> c2 = Coordinate.allocate(42.0, 84.0, c1).addressOf;
+  Pointer<Coordinate> c1 =
+      Coordinate.allocate(calloc, 10.0, 20.0, nullptr).addressOf;
+  Pointer<Coordinate> c2 =
+      Coordinate.allocate(calloc, 42.0, 84.0, c1).addressOf;
   c1.ref.next = c2;
 
   Coordinate result = f1(c1).ref;
@@ -45,8 +48,8 @@
   Expect.approxEquals(42.0, result.x);
   Expect.approxEquals(84.0, result.y);
 
-  free(c1);
-  free(c2);
+  calloc.free(c1);
+  calloc.free(c2);
 }
 
 /// pass an array of structs to a c funtion
@@ -55,7 +58,7 @@
       ffiTestFunctions.lookup("CoordinateElemAt1");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Coordinate c1 = allocate<Coordinate>(count: 3).ref;
+  Coordinate c1 = calloc<Coordinate>(3).ref;
   Coordinate c2 = c1.addressOf[1];
   Coordinate c3 = c1.addressOf[2];
   c1.x = 10.0;
@@ -72,7 +75,7 @@
   Expect.approxEquals(20.0, result.x);
   Expect.approxEquals(20.0, result.y);
 
-  free(c1.addressOf);
+  calloc.free(c1.addressOf);
 }
 
 typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
@@ -83,7 +86,7 @@
       ffiTestFunctions.lookup("SumVeryLargeStruct");
   VeryLargeStructSum f = p1.asFunction();
 
-  VeryLargeStruct vls1 = allocate<VeryLargeStruct>(count: 2).ref;
+  VeryLargeStruct vls1 = calloc<VeryLargeStruct>(2).ref;
   VeryLargeStruct vls2 = vls1.addressOf[1];
   List<VeryLargeStruct> structs = [vls1, vls2];
   for (VeryLargeStruct struct in structs) {
@@ -114,5 +117,5 @@
   result = f(vls2.addressOf);
   Expect.equals(2048, result);
 
-  free(vls1.addressOf);
+  calloc.free(vls1.addressOf);
 }
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index bff456e..077be64 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -15,11 +15,12 @@
 
 import 'dart:ffi';
 
-import 'dylib_utils.dart';
-
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'calloc.dart';
+import 'dylib_utils.dart';
+
 void main() {
   for (int i = 0; i < 100; ++i) {
     testNativeFunctionFromCast();
@@ -50,11 +51,11 @@
 typedef GenericBinaryOp<T> = int Function(int, T);
 
 void testNativeFunctionFromCast() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<NativeFunction<NativeBinaryOp>> p2 = p1.cast();
   p2.asFunction<BinaryOp>();
   p2.asFunction<GenericBinaryOp<int>>();
-  free(p1);
+  calloc.free(p1);
 }
 
 typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
@@ -394,14 +395,14 @@
     .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
 
 void testNativeFunctionPointer() {
-  Pointer<Int64> p2 = allocate(count: 2);
+  Pointer<Int64> p2 = calloc(2);
   p2.value = 42;
   p2[1] = 1000;
   Pointer<Int64> result = assign1337Index1(p2);
   Expect.equals(1337, result.value);
   Expect.equals(1337, p2[1]);
   Expect.equals(p2.elementAt(1).address, result.address);
-  free(p2);
+  calloc.free(p2);
 }
 
 Int64PointerUnOp nullableInt64ElemAt1 = ffiTestFunctions
@@ -411,10 +412,10 @@
   Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
   Expect.equals(result, nullptr);
 
-  Pointer<Int64> p2 = allocate(count: 2);
+  Pointer<Int64> p2 = calloc(2);
   result = nullableInt64ElemAt1(p2);
   Expect.notEquals(result, nullptr);
-  free(p2);
+  calloc.free(p2);
 }
 
 typedef NativeFloatPointerToBool = Uint8 Function(Pointer<Float>);
@@ -424,13 +425,13 @@
     NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
 
 void testFloatRounding() {
-  Pointer<Float> p2 = allocate();
+  Pointer<Float> p2 = calloc();
   p2.value = 1337.0;
 
   int result = isRoughly1337(p2);
   Expect.equals(1, result);
 
-  free(p2);
+  calloc.free(p2);
 }
 
 typedef NativeFloatToVoid = Void Function(Float);
diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart
index f3f9f02..7bd7c83 100644
--- a/tests/ffi/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi/generator/structs_by_value_tests_generator.dart
@@ -197,7 +197,7 @@
         return "${dartType} ${variableName};\n";
 
       case StructType:
-        return "${dartType} ${variableName} = allocate<$dartType>().ref;\n";
+        return "${dartType} ${variableName} = calloc<$dartType>().ref;\n";
     }
 
     throw Exception("Not implemented for ${this.runtimeType}");
@@ -243,7 +243,7 @@
         return "";
 
       case StructType:
-        return "free($variableName.addressOf);\n";
+        return "calloc.free($variableName.addressOf);\n";
     }
 
     throw Exception("Not implemented for ${this.runtimeType}");
@@ -485,7 +485,7 @@
       case TestType.structReturn:
         // Allocate a struct.
         buildReturnValue = """
-        ${returnValue.dartType} result = allocate<${returnValue.dartType}>().ref;
+        ${returnValue.dartType} result = calloc<${returnValue.dartType}>().ref;
 
         ${arguments.copyValueStatements("${dartName}_", "result.")}
         """;
@@ -749,6 +749,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -801,6 +802,7 @@
 import "package:ffi/ffi.dart";
 
 import 'callback_tests_utils.dart';
+import 'calloc.dart';
 
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
diff --git a/tests/ffi/regress_37254_test.dart b/tests/ffi/regress_37254_test.dart
index ce696af..62c71db 100644
--- a/tests/ffi/regress_37254_test.dart
+++ b/tests/ffi/regress_37254_test.dart
@@ -65,34 +65,36 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 // ===== a.value = b ======
 // The tests follow table cells left to right, top to bottom.
 void store1() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store2() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
   final Pointer<NativeType> b =
-      allocate<Int8>(); // Reified Pointer<Int8> at runtime.
+      calloc<Int8>(); // Reified Pointer<Int8> at runtime.
 
   // Successful implicit downcast of argument at runtime.
   // Should succeed now, should statically be rejected when NNBD lands.
   a.value = b as Pointer<Int8>;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store3() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   // Failing implicit downcast of argument at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
@@ -100,124 +102,124 @@
     a.value = b as Pointer<Int8>;
   });
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store5() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   final Pointer<NativeType> b =
-      allocate<Int8>(); // Reified as Pointer<Int8> at runtime.
+      calloc<Int8>(); // Reified as Pointer<Int8> at runtime.
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store6() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   // Fails on type check of argument.
   Expect.throws(() {
     a.value = b;
   });
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store7() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store8() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   // Reified as Pointer<Int8> at runtime.
-  final Pointer<NativeType> b = allocate<Int8>();
+  final Pointer<NativeType> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store9() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 // ====== b = a.value ======
 // The tests follow table cells left to right, top to bottom.
 void load1() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
 
   Pointer<Int8> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load2() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
 
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load3() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   Pointer<Int8> b = a.value as Pointer<Int8>;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   // Return value runtime type is Pointer<Int8>.
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load5() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   // Failing implicit downcast of return value at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
@@ -225,16 +227,16 @@
     Pointer<Int8> b = a.value as Pointer<Int8>;
   });
 
-  free(a);
+  calloc.free(a);
 }
 
 void load6() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<NativeType>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void main() {
diff --git a/tests/ffi/regress_39885_test.dart b/tests/ffi/regress_39885_test.dart
index 7d960f2..ef73ca7 100644
--- a/tests/ffi/regress_39885_test.dart
+++ b/tests/ffi/regress_39885_test.dart
@@ -3,12 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:ffi';
-import "package:ffi/ffi.dart" show allocate, free;
+
+import "package:ffi/ffi.dart";
+
+import 'calloc.dart';
 
 main() {
-  final data = allocate<Uint8>(count: 3);
+  final data = calloc<Uint8>(3);
   for (int i = 0; i < 3; ++i) {
     data.elementAt(i).value = 1;
   }
-  free(data);
+  calloc.free(data);
 }
diff --git a/tests/ffi/regress_43693_test.dart b/tests/ffi/regress_43693_test.dart
index a34e8f8..64b48bf 100644
--- a/tests/ffi/regress_43693_test.dart
+++ b/tests/ffi/regress_43693_test.dart
@@ -9,6 +9,7 @@
 import 'package:ffi/ffi.dart';
 import 'package:expect/expect.dart';
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 class Struct43693 extends Struct {
@@ -27,10 +28,10 @@
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
 void main() {
-  final myStructs = allocate<Struct43693>();
+  final myStructs = calloc<Struct43693>();
   myStructs[0].somePtr = nullptr;
   myStructs[0].someValue = 0xAAAAAAAABBBBBBBB;
   final result = readMyStructSomeValue(myStructs);
   Expect.equals(0xAAAAAAAABBBBBBBB, result);
-  free(myStructs);
+  calloc.free(myStructs);
 }
diff --git a/tests/ffi/structs_nested_test.dart b/tests/ffi/structs_nested_test.dart
index ea4b6db..2d5208d 100644
--- a/tests/ffi/structs_nested_test.dart
+++ b/tests/ffi/structs_nested_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -48,16 +49,16 @@
 }
 
 void testAllocate() {
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   Expect.type<Pointer<Struct8BytesNestedInt>>(p);
   print(p);
-  free(p);
+  calloc.free(p);
 }
 
 /// Test that reading does not segfault, even uninitialized.
 void testRead() {
   print("read");
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   print(p);
   print(p.ref.runtimeType);
   print(p.ref.addressOf);
@@ -65,13 +66,13 @@
   print(p.ref.a0.runtimeType);
   print(p.ref.a0.addressOf);
   print(p.ref.a0.a0);
-  free(p);
+  calloc.free(p);
   print("read");
 }
 
 void testWrite() {
   print("write");
-  final p = allocate<Struct8BytesNestedInt>(count: 2);
+  final p = calloc<Struct8BytesNestedInt>(2);
   p[0].a0.a0 = 12;
   p[0].a0.a1 = 13;
   p[0].a1.a0 = 14;
@@ -88,18 +89,18 @@
   Expect.equals(17, p[1].a0.a1);
   Expect.equals(18, p[1].a1.a0);
   Expect.equals(19, p[1].a1.a1);
-  free(p);
+  calloc.free(p);
   print("written");
 }
 
 void testCopy() {
   print("copy");
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   p.ref.a0.a0 = 12;
   p.ref.a0.a1 = 13;
   p.ref.a1 = p.ref.a0;
   Expect.equals(12, p.ref.a1.a0);
   Expect.equals(13, p.ref.a1.a1);
-  free(p);
+  calloc.free(p);
   print("copied");
 }
diff --git a/tests/ffi/structs_nnbd_workaround_test.dart b/tests/ffi/structs_nnbd_workaround_test.dart
index 6501faf..06c6f29 100644
--- a/tests/ffi/structs_nnbd_workaround_test.dart
+++ b/tests/ffi/structs_nnbd_workaround_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'coordinate_nnbd_workaround.dart';
 
 void main() {
@@ -25,9 +26,12 @@
 
 /// allocates each coordinate separately in c memory
 void testStructAllocate() {
-  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
-  Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf;
-  Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf;
+  Pointer<Coordinate> c1 =
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
+  Pointer<Coordinate> c2 =
+      Coordinate.allocate(calloc, 20.0, 20.0, c1).addressOf;
+  Pointer<Coordinate> c3 =
+      Coordinate.allocate(calloc, 30.0, 30.0, c2).addressOf;
   c1.ref.next = c3;
 
   Coordinate currentCoordinate = c1.ref;
@@ -39,14 +43,14 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
-  free(c2);
-  free(c3);
+  calloc.free(c1);
+  calloc.free(c2);
+  calloc.free(c3);
 }
 
 /// allocates coordinates consecutively in c memory
 void testStructFromAddress() {
-  Pointer<Coordinate> c1 = allocate(count: 3);
+  Pointer<Coordinate> c1 = calloc(3);
   Pointer<Coordinate> c2 = c1.elementAt(1);
   Pointer<Coordinate> c3 = c1.elementAt(2);
   c1.ref
@@ -71,30 +75,30 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
+  calloc.free(c1);
 }
 
 void testStructWithNulls() {
   Pointer<Coordinate> coordinate =
-      Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
   Expect.equals(coordinate.ref.next, nullptr);
   coordinate.ref.next = coordinate;
   Expect.notEquals(coordinate.ref.next, nullptr);
   coordinate.ref.next = nullptr;
   Expect.equals(coordinate.ref.next, nullptr);
-  free(coordinate);
+  calloc.free(coordinate);
 }
 
 void testTypeTest() {
-  Coordinate c = Coordinate.allocate(10, 10, nullptr);
+  Coordinate c = Coordinate.allocate(calloc, 10, 10, nullptr);
   Expect.isTrue(c is Struct);
   Expect.isTrue(c.addressOf is Pointer<Coordinate>);
-  free(c.addressOf);
+  calloc.free(c.addressOf);
 }
 
 void testUtf8() {
   final String test = 'Hasta Mañana';
   final Pointer<Utf8> medium = Utf8.toUtf8(test);
   Expect.equals(test, Utf8.fromUtf8(medium));
-  free(medium);
+  calloc.free(medium);
 }
diff --git a/tests/ffi/structs_test.dart b/tests/ffi/structs_test.dart
index 83e617d..6bc1ed1 100644
--- a/tests/ffi/structs_test.dart
+++ b/tests/ffi/structs_test.dart
@@ -11,9 +11,10 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
-import 'ffi_test_helpers.dart';
+import 'calloc.dart';
 import 'coordinate_bare.dart' as bare;
 import 'coordinate.dart';
+import 'ffi_test_helpers.dart';
 
 void main() {
   for (int i = 0; i < 100; i++) {
@@ -28,9 +29,12 @@
 
 /// allocates each coordinate separately in c memory
 void testStructAllocate() {
-  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
-  Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf;
-  Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf;
+  Pointer<Coordinate> c1 =
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
+  Pointer<Coordinate> c2 =
+      Coordinate.allocate(calloc, 20.0, 20.0, c1).addressOf;
+  Pointer<Coordinate> c3 =
+      Coordinate.allocate(calloc, 30.0, 30.0, c2).addressOf;
   c1.ref.next = c3;
 
   Coordinate currentCoordinate = c1.ref;
@@ -42,14 +46,14 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
-  free(c2);
-  free(c3);
+  calloc.free(c1);
+  calloc.free(c2);
+  calloc.free(c3);
 }
 
 /// allocates coordinates consecutively in c memory
 void testStructFromAddress() {
-  Pointer<Coordinate> c1 = allocate(count: 3);
+  Pointer<Coordinate> c1 = calloc(3);
   Pointer<Coordinate> c2 = c1.elementAt(1);
   Pointer<Coordinate> c3 = c1.elementAt(2);
   c1.ref
@@ -74,24 +78,24 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
+  calloc.free(c1);
 }
 
 void testStructWithNulls() {
   Pointer<Coordinate> coordinate =
-      Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
   Expect.equals(coordinate.ref.next, nullptr);
   coordinate.ref.next = coordinate;
   Expect.notEquals(coordinate.ref.next, nullptr);
   coordinate.ref.next = nullptr;
   Expect.equals(coordinate.ref.next, nullptr);
-  free(coordinate);
+  calloc.free(coordinate);
 }
 
 void testBareStruct() {
   int structSize = sizeOf<Double>() * 2 + sizeOf<IntPtr>();
   bare.Coordinate c1 =
-      allocate<Uint8>(count: structSize * 3).cast<bare.Coordinate>().ref;
+      calloc<Uint8>(structSize * 3).cast<bare.Coordinate>().ref;
   bare.Coordinate c2 =
       c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().ref;
   bare.Coordinate c3 =
@@ -115,19 +119,19 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1.addressOf);
+  calloc.free(c1.addressOf);
 }
 
 void testTypeTest() {
-  Coordinate c = Coordinate.allocate(10, 10, nullptr);
+  Coordinate c = Coordinate.allocate(calloc, 10, 10, nullptr);
   Expect.isTrue(c is Struct);
   Expect.isTrue(c.addressOf is Pointer<Coordinate>);
-  free(c.addressOf);
+  calloc.free(c.addressOf);
 }
 
 void testUtf8() {
   final String test = 'Hasta Mañana';
   final Pointer<Utf8> medium = Utf8.toUtf8(test);
   Expect.equals(test, Utf8.fromUtf8(medium));
-  free(medium);
+  calloc.free(medium);
 }
diff --git a/tests/ffi/variance_function_test.dart b/tests/ffi/variance_function_test.dart
index 539c245..3db0147 100644
--- a/tests/ffi/variance_function_test.dart
+++ b/tests/ffi/variance_function_test.dart
@@ -12,11 +12,12 @@
 
 import 'dart:ffi';
 
-import 'dylib_utils.dart';
-
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+import 'dylib_utils.dart';
+
 typedef Int64PointerParamOpDart = void Function(Pointer<Int64>);
 typedef Int64PointerParamOp = Void Function(Pointer<Int64>);
 typedef NaTyPointerParamOpDart = void Function(Pointer<NativeType>);
@@ -38,19 +39,19 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<Int64PointerParamOp>>(paramOpName);
   final f = fp.asFunction<Int64PointerParamOpDart>();
-  final arg = allocate<Int64>();
+  final arg = calloc<Int64>();
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 void paramInvariant2() {
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final arg = allocate<Int64>().cast<NativeType>();
+  final arg = calloc<Int64>().cast<NativeType>();
   Expect.type<Pointer<NativeType>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 // Pass a statically and dynamically subtyped argument.
@@ -58,10 +59,10 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final arg = allocate<Int64>();
+  final arg = calloc<Int64>();
   Expect.type<Pointer<Int64>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 // Pass a statically subtyped but dynamically invariant argument.
@@ -69,10 +70,10 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final Pointer<NativeType> arg = allocate<Int64>();
+  final Pointer<NativeType> arg = calloc<Int64>();
   Expect.type<Pointer<Int64>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 void returnInvariant1() {
@@ -220,7 +221,7 @@
 }
 
 void fromFunctionTests() {
-  data = allocate();
+  data = calloc();
   for (int i = 0; i < 100; ++i) {
     callbackParamInvariant1(); // Pointer<Int64> invariant
     callbackParamInvariant2(); // Pointer<NativeType> invariant
@@ -229,7 +230,7 @@
     callbackReturnInvariant1(); // Pointer<Int64> invariant
     callbackReturnInvariant2(); // Pointer<NativeType> invariant
   }
-  free(data);
+  calloc.free(data);
 }
 
 void main() {
diff --git a/tests/ffi/vmspecific_enable_ffi_test.dart b/tests/ffi/vmspecific_enable_ffi_test.dart
index f44753d..ce90607 100644
--- a/tests/ffi/vmspecific_enable_ffi_test.dart
+++ b/tests/ffi/vmspecific_enable_ffi_test.dart
@@ -7,11 +7,14 @@
 // VMOptions=--enable-ffi=false
 
 import 'dart:ffi'; //# 01: compile-time error
+
 import 'package:ffi/ffi.dart'; //# 01: compile-time error
 
+import 'calloc.dart'; //# 01: compile-time error
+
 void main() {
   Pointer<Int8> p = //# 01: compile-time error
-      allocate(); //# 01: compile-time error
+      calloc(); //# 01: compile-time error
   print(p.address); //# 01: compile-time error
-  free(p); //# 01: compile-time error
+  calloc.free(p); //# 01: compile-time error
 }
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index 870de9c..cbce8e6 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -10,6 +10,7 @@
 
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 void main() {
@@ -53,6 +54,8 @@
   testEmptyStructAsFunctionReturn();
   testEmptyStructFromFunctionArgument();
   testEmptyStructFromFunctionReturn();
+  testAllocateGeneric();
+  testAllocateNativeType();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -65,20 +68,20 @@
     return result;
   }
 
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 123;
   Pointer loseType = p;
   generic(loseType);
-  free(p);
+  calloc.free(p);
 }
 
 void testGetGeneric2() {
   T? generic<T extends Object>() {
-    Pointer<Int8> p = allocate();
+    Pointer<Int8> p = calloc();
     p.value = 123;
     T? result;
     result = p.value; //# 21: compile-time error
-    free(p);
+    calloc.free(p);
     return result;
   }
 
@@ -86,12 +89,12 @@
 }
 
 void testGetVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast();
 
   p2.value; //# 22: compile-time error
 
-  free(p1);
+  calloc.free(p1);
 }
 
 void testGetNativeFunction() {
@@ -104,14 +107,14 @@
 }
 
 void testGetTypeMismatch() {
-  Pointer<Pointer<Int16>> p = allocate();
+  Pointer<Pointer<Int16>> p = calloc();
   Pointer<Int16> typedNull = nullptr;
   p.value = typedNull;
 
   // this fails to compile due to type mismatch
   Pointer<Int8> p2 = p.value; //# 25: compile-time error
 
-  free(p);
+  calloc.free(p);
 }
 
 void testSetGeneric() {
@@ -119,30 +122,30 @@
     p.value = 123; //# 26: compile-time error
   }
 
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 123;
   Pointer loseType = p;
   generic(loseType);
-  free(p);
+  calloc.free(p);
 }
 
 void testSetGeneric2() {
   void generic<T extends Object>(T arg) {
-    Pointer<Int8> p = allocate();
+    Pointer<Int8> p = calloc();
     p.value = arg; //# 27: compile-time error
-    free(p);
+    calloc.free(p);
   }
 
   generic<int>(123);
 }
 
 void testSetVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast();
 
   p2.value = 1234; //# 28: compile-time error
 
-  free(p1);
+  calloc.free(p1);
 }
 
 void testSetNativeFunction() {
@@ -157,16 +160,16 @@
 
 void testSetTypeMismatch() {
   // the pointer to pointer types must match up
-  Pointer<Int8> pHelper = allocate();
+  Pointer<Int8> pHelper = calloc();
   pHelper.value = 123;
 
-  Pointer<Pointer<Int16>> p = allocate();
+  Pointer<Pointer<Int16>> p = calloc();
 
   // this fails to compile due to type mismatch
   p.value = pHelper; //# 40: compile-time error
 
-  free(pHelper);
-  free(p);
+  calloc.free(pHelper);
+  calloc.free(p);
 }
 
 void testAsFunctionGeneric() {
@@ -475,6 +478,8 @@
 
 class IStruct implements Struct {} //# 815: compile-time error
 
+class IOpaque implements Opaque {} //# 816: compile-time error
+
 class MyClass {
   int x;
   MyClass(this.x);
@@ -550,3 +555,17 @@
 class HasNestedEmptyStruct extends Struct {
   external EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
 }
+
+void testAllocateGeneric() {
+  Pointer<T> generic<T extends NativeType>() {
+    Pointer<T> pointer = nullptr;
+    pointer = calloc(); //# 1320: compile-time error
+    return pointer;
+  }
+
+  Pointer p = generic<Int64>();
+}
+
+void testAllocateNativeType() {
+  calloc(); //# 1321: compile-time error
+}
diff --git a/tests/ffi_2/aliasing_test.dart b/tests/ffi_2/aliasing_test.dart
index 6c2f698..946e1e4 100644
--- a/tests/ffi_2/aliasing_test.dart
+++ b/tests/ffi_2/aliasing_test.dart
@@ -13,6 +13,7 @@
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'calloc.dart';
 import 'ffi_test_helpers.dart';
 
 void main() {
@@ -35,28 +36,28 @@
 }
 
 void testNonAlias() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   source.value = 42;
   final int a = source.value;
   source.value = 1984;
   // alias.value should be re-executed, as we wrote to alias.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasCast() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = source.cast<Int8>().cast<Int64>();
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasCast2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = source.cast<Int16>().cast<Int64>();
   final alias2 = source.cast<Int8>().cast<Int64>();
   alias.value = 42;
@@ -64,22 +65,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasOffsetBy() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final alias = source.offsetBy(8).offsetBy(-8);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasOffsetBy2() {
-  final source = allocate<Int64>(count: 3);
+  final source = calloc<Int64>(3);
   final alias = source.offsetBy(16).offsetBy(-16);
   final alias2 = source.offsetBy(8).offsetBy(-8);
   alias.value = 42;
@@ -87,22 +88,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasElementAt() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final alias = source.elementAt(1).elementAt(-1);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasElementAt2() {
-  final source = allocate<Int64>(count: 3);
+  final source = calloc<Int64>(3);
   final alias = source.elementAt(2).elementAt(-2);
   final alias2 = source.elementAt(1).elementAt(-1);
   alias.value = 42;
@@ -110,22 +111,22 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddress() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
   source.value = 42;
   final int a = source.value;
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddress2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
   final alias2 = Pointer<Int64>.fromAddress(source.address);
   alias.value = 42;
@@ -133,12 +134,12 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaMemory() {
-  final helper = allocate<IntPtr>();
-  final source = allocate<Int64>();
+  final helper = calloc<IntPtr>();
+  final source = calloc<Int64>();
   helper.value = source.address;
   final alias = Pointer<Int64>.fromAddress(helper.value);
   source.value = 42;
@@ -146,13 +147,13 @@
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(helper);
-  free(source);
+  calloc.free(helper);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaMemory2() {
-  final helper = allocate<IntPtr>();
-  final source = allocate<Int64>();
+  final helper = calloc<IntPtr>();
+  final source = calloc<Int64>();
   helper.value = source.address;
   final alias = Pointer<Int64>.fromAddress(helper.value);
   final alias2 = Pointer<Int64>.fromAddress(helper.value);
@@ -161,8 +162,8 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(helper);
-  free(source);
+  calloc.free(helper);
+  calloc.free(source);
 }
 
 typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
@@ -172,7 +173,7 @@
     .lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
 
 void testAliasFromAddressViaNativeFunction() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
   source.value = 42;
@@ -180,11 +181,11 @@
   alias.value = 1984;
   // source.value should be re-executed, we wrote alias which aliases source.
   Expect.notEquals(a, source.value);
-  free(source);
+  calloc.free(source);
 }
 
 void testAliasFromAddressViaNativeFunction2() {
-  final source = allocate<Int64>();
+  final source = calloc<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
   final alias2 =
@@ -194,7 +195,7 @@
   alias2.value = 1984;
   // alias.value should be re-executed, we wrote alias2 which aliases alias.
   Expect.notEquals(a, alias.value);
-  free(source);
+  calloc.free(source);
 }
 
 @pragma('vm:never-inline')
@@ -202,11 +203,11 @@
     source.offsetBy(7).cast<Int8>();
 
 testPartialOverlap() {
-  final source = allocate<Int64>(count: 2);
+  final source = calloc<Int64>(2);
   final derived = makeDerived(source);
   source.value = 0x1122334455667788;
   final int value = source.value;
   derived.value = 0xaa;
   Expect.notEquals(value, source.value);
-  free(source);
+  calloc.free(source);
 }
diff --git a/tests/ffi_2/allocator_test.dart b/tests/ffi_2/allocator_test.dart
new file mode 100644
index 0000000..396f5c9
--- /dev/null
+++ b/tests/ffi_2/allocator_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that we can implement the Allocator interface.
+
+import 'dart:ffi';
+
+class MyAllocator implements Allocator {
+  const MyAllocator();
+
+  @override
+  Pointer<T> allocate<T extends NativeType>(int numBytes, {int alignment}) {
+    throw "Not implemented";
+  }
+
+  void free(Pointer pointer) {}
+}
+
+const myAllocator = MyAllocator();
+
+void main() {
+  print(myAllocator);
+}
diff --git a/tests/ffi_2/calloc.dart b/tests/ffi_2/calloc.dart
new file mode 100644
index 0000000..a433e39
--- /dev/null
+++ b/tests/ffi_2/calloc.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
+// rolled. We need to wait until the `Allocator` interface has rolled into
+// Flutter.
+
+import 'dart:ffi';
+import 'dart:io';
+
+final DynamicLibrary stdlib = Platform.isWindows
+    ? DynamicLibrary.open('kernel32.dll')
+    : DynamicLibrary.process();
+
+typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
+typedef PosixCalloc = Pointer Function(int num, int size);
+final PosixCalloc posixCalloc =
+    stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
+
+typedef PosixFreeNative = Void Function(Pointer);
+typedef PosixFree = void Function(Pointer);
+final PosixFree posixFree =
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
+
+typedef WinGetProcessHeapFn = Pointer Function();
+final WinGetProcessHeapFn winGetProcessHeap = stdlib
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
+final Pointer processHeap = winGetProcessHeap();
+
+typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
+typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
+final WinHeapAlloc winHeapAlloc =
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
+
+typedef WinHeapFreeNative = Int32 Function(
+    Pointer heap, Uint32 flags, Pointer memory);
+typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
+final WinHeapFree winHeapFree =
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
+
+const int HEAP_ZERO_MEMORY = 8;
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+class _CallocAllocator implements Allocator {
+  const _CallocAllocator();
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  ///
+  /// For POSIX-based systems, this uses `calloc`. On Windows, it uses
+  /// `HeapAlloc` against the default public heap.
+  ///
+  /// Throws an [ArgumentError] if the number of bytes or alignment cannot be
+  /// satisfied.
+  // TODO: Stop ignoring alignment if it's large, for example for SSE data.
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
+    Pointer<T> result;
+    if (Platform.isWindows) {
+      result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
+          .cast();
+    } else {
+      result = posixCalloc(byteCount, 1).cast();
+    }
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  ///
+  /// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
+  /// against the default public heap. It may only be used against pointers
+  /// allocated in a manner equivalent to [allocate].
+  ///
+  /// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
+  /// freed.
+  ///
+  // TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
+  // of testing the return integer to be non-zero.
+  @override
+  void free(Pointer pointer) {
+    if (Platform.isWindows) {
+      if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
+        throw ArgumentError('Could not free $pointer.');
+      }
+    } else {
+      posixFree(pointer);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+///
+/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
+/// memory allocation.
+///
+/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
+/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
+/// public heap.
+const Allocator calloc = _CallocAllocator();
diff --git a/tests/ffi_2/calloc_test.dart b/tests/ffi_2/calloc_test.dart
new file mode 100644
index 0000000..b8b9bbf
--- /dev/null
+++ b/tests/ffi_2/calloc_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+import 'calloc.dart';
+import 'coordinate.dart';
+
+void main() {
+  testZeroInt();
+  testZeroFloat();
+  testZeroStruct();
+}
+
+void testZeroInt() {
+  final p = calloc<Uint8>();
+  Expect.equals(0, p.value);
+  calloc.free(p);
+}
+
+void testZeroFloat() {
+  final p = calloc<Float>();
+  Expect.approxEquals(0.0, p.value);
+  calloc.free(p);
+}
+
+void testZeroStruct() {
+  final p = calloc<Coordinate>();
+  Expect.approxEquals(0, p.ref.x);
+  Expect.approxEquals(0, p.ref.y);
+  Expect.equals(nullptr, p.ref.next);
+  calloc.free(p);
+}
diff --git a/tests/ffi_2/coordinate.dart b/tests/ffi_2/coordinate.dart
index 92dd9d4..92dfbf0 100644
--- a/tests/ffi_2/coordinate.dart
+++ b/tests/ffi_2/coordinate.dart
@@ -17,8 +17,9 @@
 
   Pointer<Coordinate> next;
 
-  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return allocate<Coordinate>().ref
+  factory Coordinate.allocate(
+      Allocator allocator, double x, double y, Pointer<Coordinate> next) {
+    return allocator<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/tests/ffi_2/data_not_asan_test.dart b/tests/ffi_2/data_not_asan_test.dart
index e95658f..69257d6 100644
--- a/tests/ffi_2/data_not_asan_test.dart
+++ b/tests/ffi_2/data_not_asan_test.dart
@@ -4,7 +4,7 @@
 //
 // Dart test program for testing dart:ffi primitive data pointers.
 //
-// These mallocs trigger an asan alarm, so these tests are in a separate file
+// These callocs trigger an asan alarm, so these tests are in a separate file
 // which is excluded in asan mode.
 
 import 'dart:ffi';
@@ -12,6 +12,8 @@
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'calloc.dart';
+
 void main() {
   testPointerAllocateTooLarge();
   testPointerAllocateNegative();
@@ -20,16 +22,16 @@
 void testPointerAllocateTooLarge() {
   // Try to allocate something that doesn't fit in 64 bit address space.
   int maxInt = 9223372036854775807; // 2^63 - 1
-  Expect.throws(() => allocate<Int64>(count: maxInt));
+  Expect.throws(() => calloc<Int64>(maxInt));
 
   // Try to allocate almost the full 64 bit address space.
   int maxInt1_8 = 1152921504606846975; // 2^60 -1
-  Expect.throws(() => allocate<Int64>(count: maxInt1_8));
+  Expect.throws(() => calloc<Int64>(maxInt1_8));
 }
 
 void testPointerAllocateNegative() {
   // Passing in -1 will be converted into an unsigned integer. So, it will try
   // to allocate SIZE_MAX - 1 + 1 bytes. This will fail as it is the max amount
   // of addressable memory on the system.
-  Expect.throws(() => allocate<Int8>(count: -1));
+  Expect.throws(() => calloc<Int8>(-1));
 }
diff --git a/tests/ffi_2/data_test.dart b/tests/ffi_2/data_test.dart
index a533ced..8fca1a1 100644
--- a/tests/ffi_2/data_test.dart
+++ b/tests/ffi_2/data_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'ffi_test_helpers.dart';
 
 void main() {
@@ -44,10 +45,8 @@
   testTypeTest();
   testToString();
   testEquality();
-  testAllocateGeneric();
   testAllocateVoid();
   testAllocateNativeFunction();
-  testAllocateNativeType();
   testSizeOfGeneric();
   testSizeOfVoid();
   testSizeOfNativeFunction();
@@ -58,66 +57,66 @@
 }
 
 void testPointerBasic() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 42;
   Expect.equals(42, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerFromPointer() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 1337;
   int ptr = p.address;
   Pointer<Int64> p2 = Pointer.fromAddress(ptr);
   Expect.equals(1337, p2.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerPointerArithmetic() {
-  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p = calloc(2);
   Pointer<Int64> p2 = p.elementAt(1);
   p2.value = 100;
   Pointer<Int64> p3 = p.offsetBy(8);
   Expect.equals(100, p3.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testPointerPointerArithmeticSizes() {
-  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p = calloc(2);
   Pointer<Int64> p2 = p.elementAt(1);
   int addr = p.address;
   Expect.equals(addr + 8, p2.address);
-  free(p);
+  calloc.free(p);
 
-  Pointer<Int32> p3 = allocate(count: 2);
+  Pointer<Int32> p3 = calloc(2);
   Pointer<Int32> p4 = p3.elementAt(1);
   addr = p3.address;
   Expect.equals(addr + 4, p4.address);
-  free(p3);
+  calloc.free(p3);
 }
 
 void testPointerAllocateZero() {
   // > If size is 0, either a null pointer or a unique pointer that can be
-  // > successfully passed to free() shall be returned.
-  // http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html
+  // > successfully passed to calloc.free() shall be returned.
+  // http://pubs.opengroup.org/onlinepubs/009695399/functions/calloc.html
   //
   // Null pointer throws a Dart exception.
   bool returnedNullPointer = false;
   Pointer<Int8> p;
   try {
-    p = allocate<Int8>(count: 0);
+    p = calloc<Int8>(0);
   } on Exception {
     returnedNullPointer = true;
   }
   if (!returnedNullPointer) {
-    free(p);
+    calloc.free(p);
   }
 }
 
 void testPointerCast() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.cast<Int32>(); // gets the correct type args back
-  free(p);
+  calloc.free(p);
 }
 
 void testCastGeneric() {
@@ -125,9 +124,9 @@
     return p.cast();
   }
 
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Pointer<Int64> p2 = generic(p);
-  free(p);
+  calloc.free(p);
 }
 
 void testCastGeneric2() {
@@ -135,41 +134,41 @@
     return p.cast();
   }
 
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Pointer<Int64> p2 = generic(p);
-  free(p);
+  calloc.free(p);
 }
 
 void testCastNativeType() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.cast<Pointer>();
-  free(p);
+  calloc.free(p);
 }
 
 void testCondensedNumbersInt8() {
-  Pointer<Int8> p = allocate(count: 8);
+  Pointer<Int8> p = calloc(8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     p[i] = i * 3;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     Expect.equals(i * 3, p[i]);
   }
-  free(p);
+  calloc.free(p);
 }
 
 void testCondensedNumbersFloat() {
-  Pointer<Float> p = allocate(count: 8);
+  Pointer<Float> p = calloc(8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     p[i] = 1.511366173271439e-13;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
     Expect.equals(1.511366173271439e-13, p[i]);
   }
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt8() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 127;
   Expect.equals(127, p.value);
   p.value = -128;
@@ -184,11 +183,11 @@
   Expect.equals(0x000000000000007F, 127);
   p.value = -129;
   Expect.equals(127, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint8() {
-  Pointer<Uint8> p = allocate();
+  Pointer<Uint8> p = calloc();
   p.value = 255;
   Expect.equals(255, p.value);
   p.value = 0;
@@ -203,11 +202,11 @@
   Expect.equals(0x00000000000000FF, 255);
   p.value = -1;
   Expect.equals(255, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt16() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   p.value = 0x7FFF;
   Expect.equals(0x7FFF, p.value);
   p.value = -0x8000;
@@ -216,11 +215,11 @@
   Expect.equals(0xFFFFFFFFFFFF8000, p.value); // truncated and sign extended
   p.value = -0x8001;
   Expect.equals(0x7FFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint16() {
-  Pointer<Uint16> p = allocate();
+  Pointer<Uint16> p = calloc();
   p.value = 0xFFFF;
   Expect.equals(0xFFFF, p.value);
   p.value = 0;
@@ -229,11 +228,11 @@
   Expect.equals(0, p.value); // truncated
   p.value = -1;
   Expect.equals(0xFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt32() {
-  Pointer<Int32> p = allocate();
+  Pointer<Int32> p = calloc();
   p.value = 0x7FFFFFFF;
   Expect.equals(0x7FFFFFFF, p.value);
   p.value = -0x80000000;
@@ -242,11 +241,11 @@
   Expect.equals(0xFFFFFFFF80000000, p.value); // truncated and sign extended
   p.value = -0x80000001;
   Expect.equals(0x7FFFFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint32() {
-  Pointer<Uint32> p = allocate();
+  Pointer<Uint32> p = calloc();
   p.value = 0xFFFFFFFF;
   Expect.equals(0xFFFFFFFF, p.value);
   p.value = 0;
@@ -255,20 +254,20 @@
   Expect.equals(0, p.value); // truncated
   p.value = -1;
   Expect.equals(0xFFFFFFFF, p.value); // truncated
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeInt64() {
-  Pointer<Int64> p = allocate();
+  Pointer<Int64> p = calloc();
   p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
   Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
   p.value = -0x8000000000000000; // -2 ^ 63
   Expect.equals(-0x8000000000000000, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeUint64() {
-  Pointer<Uint64> p = allocate();
+  Pointer<Uint64> p = calloc();
   p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
   Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
   p.value = -0x8000000000000000; // -2 ^ 63 interpreted as 2 ^ 63
@@ -279,69 +278,69 @@
   p.value = -1; // -1 interpreted as 2 ^ 64 - 1
   Expect.equals(-1, p.value);
   Expect.equals(0xFFFFFFFFFFFFFFFF, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testRangeIntPtr() {
-  Pointer<IntPtr> p = allocate();
+  Pointer<IntPtr> p = calloc();
   int pAddr = p.address;
   p.value = pAddr; // its own address should fit
   p.value = 0x7FFFFFFF; // and 32 bit addresses should fit
   Expect.equals(0x7FFFFFFF, p.value);
   p.value = -0x80000000;
   Expect.equals(-0x80000000, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testFloat() {
-  Pointer<Float> p = allocate();
+  Pointer<Float> p = calloc();
   p.value = 1.511366173271439e-13;
   Expect.equals(1.511366173271439e-13, p.value);
   p.value = 1.4260258159703532e-105; // float does not have enough precision
   Expect.notEquals(1.4260258159703532e-105, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testDouble() {
-  Pointer<Double> p = allocate();
+  Pointer<Double> p = calloc();
   p.value = 1.4260258159703532e-105;
   Expect.equals(1.4260258159703532e-105, p.value);
-  free(p);
+  calloc.free(p);
 }
 
 void testVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast(); // make this dart pointer opaque
   p2.address; // we can print the address
-  free(p2);
+  calloc.free(p2);
 }
 
 void testPointerPointer() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   p.value = 17;
-  Pointer<Pointer<Int16>> p2 = allocate();
+  Pointer<Pointer<Int16>> p2 = calloc();
   p2.value = p;
   Expect.equals(17, p2.value.value);
-  free(p2);
-  free(p);
+  calloc.free(p2);
+  calloc.free(p);
 }
 
 void testPointerPointerNull() {
-  Pointer<Pointer<Int8>> pointerToPointer = allocate();
+  Pointer<Pointer<Int8>> pointerToPointer = calloc();
   Pointer<Int8> value = nullptr;
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.equals(value, nullptr);
-  value = allocate();
+  value = calloc();
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.isNotNull(value);
-  free(value);
+  calloc.free(value);
   value = nullptr;
   pointerToPointer.value = value;
   value = pointerToPointer.value;
   Expect.equals(value, nullptr);
-  free(pointerToPointer);
+  calloc.free(pointerToPointer);
 }
 
 void testSizeOf() {
@@ -365,7 +364,7 @@
       head.value = value;
       return;
     }
-    Pointer<IntPtr> next = allocate();
+    Pointer<IntPtr> next = calloc();
     head.value = next.address;
     createChain(next, length - 1, value);
   }
@@ -380,14 +379,14 @@
 
   void freeChain(Pointer<IntPtr> head, int length) {
     Pointer<IntPtr> next = Pointer.fromAddress(head.value);
-    free(head);
+    calloc.free(head);
     if (length == 0) {
       return;
     }
     freeChain(next, length - 1);
   }
 
-  Pointer<IntPtr> head = allocate();
+  Pointer<IntPtr> head = calloc();
   createChain(head, length, 512);
   int tailValue = getChainValue(head, length);
   Expect.equals(512, tailValue);
@@ -395,16 +394,16 @@
 }
 
 void testTypeTest() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   Expect.isTrue(p is Pointer);
-  free(p);
+  calloc.free(p);
 }
 
 void testToString() {
-  Pointer<Int16> p = allocate();
+  Pointer<Int16> p = calloc();
   Expect.stringEquals(
       "Pointer<Int16>: address=0x", p.toString().substring(0, 26));
-  free(p);
+  calloc.free(p);
   Pointer<Int64> p2 = Pointer.fromAddress(0x123abc);
   Expect.stringEquals("Pointer<Int64>: address=0x123abc", p2.toString());
 }
@@ -423,32 +422,15 @@
 
 typedef Int8UnOp = Int8 Function(Int8);
 
-void testAllocateGeneric() {
-  Pointer<T> generic<T extends NativeType>() {
-    Pointer<T> pointer;
-    pointer = allocate();
-    return pointer;
-  }
-
-  Pointer p = generic<Int64>();
-  free(p);
-}
-
 void testAllocateVoid() {
   Expect.throws(() {
-    Pointer<Void> p = allocate();
+    Pointer<Void> p = calloc();
   });
 }
 
 void testAllocateNativeFunction() {
   Expect.throws(() {
-    Pointer<NativeFunction<Int8UnOp>> p = allocate();
-  });
-}
-
-void testAllocateNativeType() {
-  Expect.throws(() {
-    allocate();
+    Pointer<NativeFunction<Int8UnOp>> p = calloc();
   });
 }
 
@@ -482,7 +464,7 @@
 }
 
 void testDynamicInvocation() {
-  dynamic p = allocate<Int8>();
+  dynamic p = calloc<Int8>();
   Expect.throws(() {
     final int i = p.value;
   });
@@ -490,7 +472,7 @@
   p.elementAt(5); // Works, but is slow.
   final int addr = p.address;
   final Pointer<Int16> p2 = p.cast<Int16>();
-  free(p);
+  calloc.free(p);
 }
 
 final nullableInt64ElementAt1 = ffiTestFunctions.lookupFunction<
diff --git a/tests/ffi_2/extension_methods_test.dart b/tests/ffi_2/extension_methods_test.dart
index 19bc44b..3524a7f 100644
--- a/tests/ffi_2/extension_methods_test.dart
+++ b/tests/ffi_2/extension_methods_test.dart
@@ -7,6 +7,8 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 main(List<String> arguments) {
   for (int i = 0; i < 100; i++) {
     testStoreLoad();
@@ -15,7 +17,7 @@
 }
 
 testStoreLoad() {
-  final p = allocate<Int8>(count: 2);
+  final p = calloc<Int8>(2);
   p.value = 10;
   Expect.equals(10, p.value);
   p[1] = 20;
@@ -30,33 +32,33 @@
   final pUseNegative = p.elementAt(1);
   Expect.equals(10, pUseNegative[-1]);
 
-  final p1 = allocate<Double>(count: 2);
+  final p1 = calloc<Double>(2);
   p1.value = 10.0;
   Expect.approxEquals(10.0, p1.value);
   p1[1] = 20.0;
   Expect.approxEquals(20.0, p1[1]);
-  free(p1);
+  calloc.free(p1);
 
-  final p2 = allocate<Pointer<Int8>>(count: 2);
+  final p2 = calloc<Pointer<Int8>>(2);
   p2.value = p;
   Expect.equals(p, p2.value);
   p2[1] = p;
   Expect.equals(p, p2[1]);
-  free(p2);
-  free(p);
+  calloc.free(p2);
+  calloc.free(p);
 
-  final p3 = allocate<Foo>();
+  final p3 = calloc<Foo>();
   Foo foo = p3.ref;
   foo.a = 1;
   Expect.equals(1, foo.a);
-  free(p3);
+  calloc.free(p3);
 }
 
 testReifiedGeneric() {
-  final p = allocate<Pointer<Int8>>();
+  final p = calloc<Pointer<Int8>>();
   Pointer<Pointer<NativeType>> p2 = p;
   Expect.isTrue(p2.value is Pointer<Int8>);
-  free(p);
+  calloc.free(p);
 }
 
 class Foo extends Struct {
diff --git a/tests/ffi_2/external_typed_data_test.dart b/tests/ffi_2/external_typed_data_test.dart
index 8d19f79..18e8e3c 100644
--- a/tests/ffi_2/external_typed_data_test.dart
+++ b/tests/ffi_2/external_typed_data_test.dart
@@ -9,6 +9,8 @@
 import 'package:expect/expect.dart';
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 main() {
   testInt8Load();
   testInt8Store();
@@ -41,162 +43,162 @@
 
 void testInt8Load() {
   // Load
-  Pointer<Int8> ptr = allocate();
+  Pointer<Int8> ptr = calloc();
   ptr.value = 0xff;
   Int8List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt8Store() {
   // Store
-  Pointer<Int8> ptr = allocate();
+  Pointer<Int8> ptr = calloc();
   Int8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint8Load() {
   // Load
-  Pointer<Uint8> ptr = allocate();
+  Pointer<Uint8> ptr = calloc();
   ptr.value = 0xff;
   Uint8List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint8Store() {
   // Store
-  Pointer<Uint8> ptr = allocate();
+  Pointer<Uint8> ptr = calloc();
   Uint8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt16Load() {
   // Load
-  Pointer<Int16> ptr = allocate();
+  Pointer<Int16> ptr = calloc();
   ptr.value = 0xffff;
   Int16List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt16Store() {
   // Store
-  Pointer<Int16> ptr = allocate();
+  Pointer<Int16> ptr = calloc();
   Int16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint16Load() {
   // Load
-  Pointer<Uint16> ptr = allocate();
+  Pointer<Uint16> ptr = calloc();
   ptr.value = 0xffff;
   Uint16List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint16Store() {
   // Store
-  Pointer<Uint16> ptr = allocate();
+  Pointer<Uint16> ptr = calloc();
   Uint16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt32Load() {
   // Load
-  Pointer<Int32> ptr = allocate();
+  Pointer<Int32> ptr = calloc();
   ptr.value = 0xffffffff;
   Int32List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt32Store() {
   // Store
-  Pointer<Int32> ptr = allocate();
+  Pointer<Int32> ptr = calloc();
   Int32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint32Load() {
   // Load
-  Pointer<Uint32> ptr = allocate();
+  Pointer<Uint32> ptr = calloc();
   ptr.value = 0xffffffff;
   Uint32List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint32Store() {
   // Store
-  Pointer<Uint32> ptr = allocate();
+  Pointer<Uint32> ptr = calloc();
   Uint32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt64Load() {
   // Load
-  Pointer<Int64> ptr = allocate();
+  Pointer<Int64> ptr = calloc();
   ptr.value = 0xffffffffffffffff;
   Int64List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testInt64Store() {
   // Store
-  Pointer<Int64> ptr = allocate();
+  Pointer<Int64> ptr = calloc();
   Int64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint64Load() {
   // Load
-  Pointer<Uint64> ptr = allocate();
+  Pointer<Uint64> ptr = calloc();
   ptr.value = 0xffffffffffffffff;
   Uint64List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffffffffffff);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testUint64Store() {
   // Store
-  Pointer<Uint64> ptr = allocate();
+  Pointer<Uint64> ptr = calloc();
   Uint64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffffffffffff);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 double maxFloat = (2 - pow(2, -23)) * pow(2, 127);
@@ -204,47 +206,47 @@
 
 void testFloatLoad() {
   // Load
-  Pointer<Float> ptr = allocate();
+  Pointer<Float> ptr = calloc();
   ptr.value = maxFloat;
   Float32List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxFloat);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testFloatStore() {
   // Store
-  Pointer<Float> ptr = allocate();
+  Pointer<Float> ptr = calloc();
   Float32List list = ptr.asTypedList(1);
   list[0] = maxFloat;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxFloat);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testDoubleLoad() {
   // Load
-  Pointer<Double> ptr = allocate();
+  Pointer<Double> ptr = calloc();
   ptr.value = maxDouble;
   Float64List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxDouble);
   Expect.equals(list.length, 1);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testDoubleStore() {
   // Store
-  Pointer<Double> ptr = allocate();
+  Pointer<Double> ptr = calloc();
   Float64List list = ptr.asTypedList(1);
   list[0] = maxDouble;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxDouble);
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testArrayLoad() {
   const int count = 0x100;
-  Pointer<Int32> ptr = allocate(count: count);
+  Pointer<Int32> ptr = calloc(count);
   for (int i = 0; i < count; ++i) {
     ptr[i] = i;
   }
@@ -252,12 +254,12 @@
   for (int i = 0; i < count; ++i) {
     Expect.equals(array[i], i);
   }
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testArrayStore() {
   const int count = 0x100;
-  Pointer<Int32> ptr = allocate(count: count);
+  Pointer<Int32> ptr = calloc(count);
   Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     array[i] = i;
@@ -265,7 +267,7 @@
   for (int i = 0; i < count; ++i) {
     Expect.equals(ptr[i], i);
   }
-  free(ptr);
+  calloc.free(ptr);
 }
 
 void testNegativeArray() {
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 bebd119..e11d962 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
@@ -16,6 +16,7 @@
 import "package:ffi/ffi.dart";
 
 import 'callback_tests_utils.dart';
+import 'calloc.dart';
 
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
@@ -5412,7 +5413,7 @@
 Struct1ByteInt returnStruct1ByteIntResult = Struct1ByteInt();
 
 Struct1ByteInt returnStruct1ByteIntCalculateResult() {
-  Struct1ByteInt result = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt result = calloc<Struct1ByteInt>().ref;
 
   result.a0 = returnStruct1ByteInt_a0;
 
@@ -5447,13 +5448,13 @@
 }
 
 void returnStruct1ByteIntAfterCallback() {
-  free(returnStruct1ByteIntResult.addressOf);
+  calloc.free(returnStruct1ByteIntResult.addressOf);
 
   final result = returnStruct1ByteIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct1ByteIntResult.addressOf);
+  calloc.free(returnStruct1ByteIntResult.addressOf);
 }
 
 typedef ReturnStruct3BytesHomogeneousUint8Type = Struct3BytesHomogeneousUint8
@@ -5471,7 +5472,7 @@
 Struct3BytesHomogeneousUint8
     returnStruct3BytesHomogeneousUint8CalculateResult() {
   Struct3BytesHomogeneousUint8 result =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
+      calloc<Struct3BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct3BytesHomogeneousUint8_a0;
   result.a1 = returnStruct3BytesHomogeneousUint8_a1;
@@ -5511,13 +5512,13 @@
 }
 
 void returnStruct3BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct3BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct3BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct3BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct3BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct3BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct3BytesInt2ByteAlignedType = Struct3BytesInt2ByteAligned
@@ -5533,7 +5534,7 @@
 
 Struct3BytesInt2ByteAligned returnStruct3BytesInt2ByteAlignedCalculateResult() {
   Struct3BytesInt2ByteAligned result =
-      allocate<Struct3BytesInt2ByteAligned>().ref;
+      calloc<Struct3BytesInt2ByteAligned>().ref;
 
   result.a0 = returnStruct3BytesInt2ByteAligned_a0;
   result.a1 = returnStruct3BytesInt2ByteAligned_a1;
@@ -5571,13 +5572,13 @@
 }
 
 void returnStruct3BytesInt2ByteAlignedAfterCallback() {
-  free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
+  calloc.free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
 
   final result = returnStruct3BytesInt2ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
+  calloc.free(returnStruct3BytesInt2ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct4BytesHomogeneousInt16Type = Struct4BytesHomogeneousInt16
@@ -5594,7 +5595,7 @@
 Struct4BytesHomogeneousInt16
     returnStruct4BytesHomogeneousInt16CalculateResult() {
   Struct4BytesHomogeneousInt16 result =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+      calloc<Struct4BytesHomogeneousInt16>().ref;
 
   result.a0 = returnStruct4BytesHomogeneousInt16_a0;
   result.a1 = returnStruct4BytesHomogeneousInt16_a1;
@@ -5632,13 +5633,13 @@
 }
 
 void returnStruct4BytesHomogeneousInt16AfterCallback() {
-  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+  calloc.free(returnStruct4BytesHomogeneousInt16Result.addressOf);
 
   final result = returnStruct4BytesHomogeneousInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct4BytesHomogeneousInt16Result.addressOf);
+  calloc.free(returnStruct4BytesHomogeneousInt16Result.addressOf);
 }
 
 typedef ReturnStruct7BytesHomogeneousUint8Type = Struct7BytesHomogeneousUint8
@@ -5660,7 +5661,7 @@
 Struct7BytesHomogeneousUint8
     returnStruct7BytesHomogeneousUint8CalculateResult() {
   Struct7BytesHomogeneousUint8 result =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
+      calloc<Struct7BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct7BytesHomogeneousUint8_a0;
   result.a1 = returnStruct7BytesHomogeneousUint8_a1;
@@ -5709,13 +5710,13 @@
 }
 
 void returnStruct7BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct7BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct7BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct7BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct7BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct7BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct7BytesInt4ByteAlignedType = Struct7BytesInt4ByteAligned
@@ -5732,7 +5733,7 @@
 
 Struct7BytesInt4ByteAligned returnStruct7BytesInt4ByteAlignedCalculateResult() {
   Struct7BytesInt4ByteAligned result =
-      allocate<Struct7BytesInt4ByteAligned>().ref;
+      calloc<Struct7BytesInt4ByteAligned>().ref;
 
   result.a0 = returnStruct7BytesInt4ByteAligned_a0;
   result.a1 = returnStruct7BytesInt4ByteAligned_a1;
@@ -5773,13 +5774,13 @@
 }
 
 void returnStruct7BytesInt4ByteAlignedAfterCallback() {
-  free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
+  calloc.free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
 
   final result = returnStruct7BytesInt4ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
+  calloc.free(returnStruct7BytesInt4ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct8BytesIntType = Struct8BytesInt Function(
@@ -5794,7 +5795,7 @@
 Struct8BytesInt returnStruct8BytesIntResult = Struct8BytesInt();
 
 Struct8BytesInt returnStruct8BytesIntCalculateResult() {
-  Struct8BytesInt result = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt result = calloc<Struct8BytesInt>().ref;
 
   result.a0 = returnStruct8BytesInt_a0;
   result.a1 = returnStruct8BytesInt_a1;
@@ -5833,13 +5834,13 @@
 }
 
 void returnStruct8BytesIntAfterCallback() {
-  free(returnStruct8BytesIntResult.addressOf);
+  calloc.free(returnStruct8BytesIntResult.addressOf);
 
   final result = returnStruct8BytesIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesIntResult.addressOf);
+  calloc.free(returnStruct8BytesIntResult.addressOf);
 }
 
 typedef ReturnStruct8BytesHomogeneousFloatType = Struct8BytesHomogeneousFloat
@@ -5856,7 +5857,7 @@
 Struct8BytesHomogeneousFloat
     returnStruct8BytesHomogeneousFloatCalculateResult() {
   Struct8BytesHomogeneousFloat result =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+      calloc<Struct8BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct8BytesHomogeneousFloat_a0;
   result.a1 = returnStruct8BytesHomogeneousFloat_a1;
@@ -5894,13 +5895,13 @@
 }
 
 void returnStruct8BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct8BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct8BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct8BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct8BytesMixedType = Struct8BytesMixed Function(
@@ -5915,7 +5916,7 @@
 Struct8BytesMixed returnStruct8BytesMixedResult = Struct8BytesMixed();
 
 Struct8BytesMixed returnStruct8BytesMixedCalculateResult() {
-  Struct8BytesMixed result = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed result = calloc<Struct8BytesMixed>().ref;
 
   result.a0 = returnStruct8BytesMixed_a0;
   result.a1 = returnStruct8BytesMixed_a1;
@@ -5954,13 +5955,13 @@
 }
 
 void returnStruct8BytesMixedAfterCallback() {
-  free(returnStruct8BytesMixedResult.addressOf);
+  calloc.free(returnStruct8BytesMixedResult.addressOf);
 
   final result = returnStruct8BytesMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesMixedResult.addressOf);
+  calloc.free(returnStruct8BytesMixedResult.addressOf);
 }
 
 typedef ReturnStruct9BytesHomogeneousUint8Type = Struct9BytesHomogeneousUint8
@@ -5984,7 +5985,7 @@
 Struct9BytesHomogeneousUint8
     returnStruct9BytesHomogeneousUint8CalculateResult() {
   Struct9BytesHomogeneousUint8 result =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
+      calloc<Struct9BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct9BytesHomogeneousUint8_a0;
   result.a1 = returnStruct9BytesHomogeneousUint8_a1;
@@ -6039,13 +6040,13 @@
 }
 
 void returnStruct9BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct9BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct9BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct9BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct9BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct9BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct9BytesInt4Or8ByteAlignedType
@@ -6062,7 +6063,7 @@
 Struct9BytesInt4Or8ByteAligned
     returnStruct9BytesInt4Or8ByteAlignedCalculateResult() {
   Struct9BytesInt4Or8ByteAligned result =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
 
   result.a0 = returnStruct9BytesInt4Or8ByteAligned_a0;
   result.a1 = returnStruct9BytesInt4Or8ByteAligned_a1;
@@ -6102,13 +6103,13 @@
 }
 
 void returnStruct9BytesInt4Or8ByteAlignedAfterCallback() {
-  free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
+  calloc.free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
 
   final result = returnStruct9BytesInt4Or8ByteAlignedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
+  calloc.free(returnStruct9BytesInt4Or8ByteAlignedResult.addressOf);
 }
 
 typedef ReturnStruct12BytesHomogeneousFloatType = Struct12BytesHomogeneousFloat
@@ -6126,7 +6127,7 @@
 Struct12BytesHomogeneousFloat
     returnStruct12BytesHomogeneousFloatCalculateResult() {
   Struct12BytesHomogeneousFloat result =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct12BytesHomogeneousFloat_a0;
   result.a1 = returnStruct12BytesHomogeneousFloat_a1;
@@ -6167,13 +6168,13 @@
 }
 
 void returnStruct12BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct12BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct12BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct12BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct12BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct16BytesHomogeneousFloatType = Struct16BytesHomogeneousFloat
@@ -6192,7 +6193,7 @@
 Struct16BytesHomogeneousFloat
     returnStruct16BytesHomogeneousFloatCalculateResult() {
   Struct16BytesHomogeneousFloat result =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct16BytesHomogeneousFloat_a0;
   result.a1 = returnStruct16BytesHomogeneousFloat_a1;
@@ -6234,13 +6235,13 @@
 }
 
 void returnStruct16BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct16BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct16BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct16BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct16BytesMixedType = Struct16BytesMixed Function(
@@ -6254,7 +6255,7 @@
 Struct16BytesMixed returnStruct16BytesMixedResult = Struct16BytesMixed();
 
 Struct16BytesMixed returnStruct16BytesMixedCalculateResult() {
-  Struct16BytesMixed result = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed result = calloc<Struct16BytesMixed>().ref;
 
   result.a0 = returnStruct16BytesMixed_a0;
   result.a1 = returnStruct16BytesMixed_a1;
@@ -6291,13 +6292,13 @@
 }
 
 void returnStruct16BytesMixedAfterCallback() {
-  free(returnStruct16BytesMixedResult.addressOf);
+  calloc.free(returnStruct16BytesMixedResult.addressOf);
 
   final result = returnStruct16BytesMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesMixedResult.addressOf);
+  calloc.free(returnStruct16BytesMixedResult.addressOf);
 }
 
 typedef ReturnStruct16BytesMixed2Type = Struct16BytesMixed2 Function(
@@ -6313,7 +6314,7 @@
 Struct16BytesMixed2 returnStruct16BytesMixed2Result = Struct16BytesMixed2();
 
 Struct16BytesMixed2 returnStruct16BytesMixed2CalculateResult() {
-  Struct16BytesMixed2 result = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 result = calloc<Struct16BytesMixed2>().ref;
 
   result.a0 = returnStruct16BytesMixed2_a0;
   result.a1 = returnStruct16BytesMixed2_a1;
@@ -6356,13 +6357,13 @@
 }
 
 void returnStruct16BytesMixed2AfterCallback() {
-  free(returnStruct16BytesMixed2Result.addressOf);
+  calloc.free(returnStruct16BytesMixed2Result.addressOf);
 
   final result = returnStruct16BytesMixed2CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesMixed2Result.addressOf);
+  calloc.free(returnStruct16BytesMixed2Result.addressOf);
 }
 
 typedef ReturnStruct17BytesIntType = Struct17BytesInt Function(
@@ -6377,7 +6378,7 @@
 Struct17BytesInt returnStruct17BytesIntResult = Struct17BytesInt();
 
 Struct17BytesInt returnStruct17BytesIntCalculateResult() {
-  Struct17BytesInt result = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt result = calloc<Struct17BytesInt>().ref;
 
   result.a0 = returnStruct17BytesInt_a0;
   result.a1 = returnStruct17BytesInt_a1;
@@ -6418,13 +6419,13 @@
 }
 
 void returnStruct17BytesIntAfterCallback() {
-  free(returnStruct17BytesIntResult.addressOf);
+  calloc.free(returnStruct17BytesIntResult.addressOf);
 
   final result = returnStruct17BytesIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct17BytesIntResult.addressOf);
+  calloc.free(returnStruct17BytesIntResult.addressOf);
 }
 
 typedef ReturnStruct19BytesHomogeneousUint8Type
@@ -6477,7 +6478,7 @@
 Struct19BytesHomogeneousUint8
     returnStruct19BytesHomogeneousUint8CalculateResult() {
   Struct19BytesHomogeneousUint8 result =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
 
   result.a0 = returnStruct19BytesHomogeneousUint8_a0;
   result.a1 = returnStruct19BytesHomogeneousUint8_a1;
@@ -6570,13 +6571,13 @@
 }
 
 void returnStruct19BytesHomogeneousUint8AfterCallback() {
-  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct19BytesHomogeneousUint8Result.addressOf);
 
   final result = returnStruct19BytesHomogeneousUint8CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct19BytesHomogeneousUint8Result.addressOf);
+  calloc.free(returnStruct19BytesHomogeneousUint8Result.addressOf);
 }
 
 typedef ReturnStruct20BytesHomogeneousInt32Type = Struct20BytesHomogeneousInt32
@@ -6596,7 +6597,7 @@
 Struct20BytesHomogeneousInt32
     returnStruct20BytesHomogeneousInt32CalculateResult() {
   Struct20BytesHomogeneousInt32 result =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   result.a0 = returnStruct20BytesHomogeneousInt32_a0;
   result.a1 = returnStruct20BytesHomogeneousInt32_a1;
@@ -6641,13 +6642,13 @@
 }
 
 void returnStruct20BytesHomogeneousInt32AfterCallback() {
-  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousInt32Result.addressOf);
 
   final result = returnStruct20BytesHomogeneousInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct20BytesHomogeneousInt32Result.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousInt32Result.addressOf);
 }
 
 typedef ReturnStruct20BytesHomogeneousFloatType = Struct20BytesHomogeneousFloat
@@ -6667,7 +6668,7 @@
 Struct20BytesHomogeneousFloat
     returnStruct20BytesHomogeneousFloatCalculateResult() {
   Struct20BytesHomogeneousFloat result =
-      allocate<Struct20BytesHomogeneousFloat>().ref;
+      calloc<Struct20BytesHomogeneousFloat>().ref;
 
   result.a0 = returnStruct20BytesHomogeneousFloat_a0;
   result.a1 = returnStruct20BytesHomogeneousFloat_a1;
@@ -6712,13 +6713,13 @@
 }
 
 void returnStruct20BytesHomogeneousFloatAfterCallback() {
-  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousFloatResult.addressOf);
 
   final result = returnStruct20BytesHomogeneousFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct20BytesHomogeneousFloatResult.addressOf);
+  calloc.free(returnStruct20BytesHomogeneousFloatResult.addressOf);
 }
 
 typedef ReturnStruct32BytesHomogeneousDoubleType
@@ -6737,7 +6738,7 @@
 Struct32BytesHomogeneousDouble
     returnStruct32BytesHomogeneousDoubleCalculateResult() {
   Struct32BytesHomogeneousDouble result =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
 
   result.a0 = returnStruct32BytesHomogeneousDouble_a0;
   result.a1 = returnStruct32BytesHomogeneousDouble_a1;
@@ -6780,13 +6781,13 @@
 }
 
 void returnStruct32BytesHomogeneousDoubleAfterCallback() {
-  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
 
   final result = returnStruct32BytesHomogeneousDoubleCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct32BytesHomogeneousDoubleResult.addressOf);
 }
 
 typedef ReturnStruct40BytesHomogeneousDoubleType
@@ -6807,7 +6808,7 @@
 Struct40BytesHomogeneousDouble
     returnStruct40BytesHomogeneousDoubleCalculateResult() {
   Struct40BytesHomogeneousDouble result =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
 
   result.a0 = returnStruct40BytesHomogeneousDouble_a0;
   result.a1 = returnStruct40BytesHomogeneousDouble_a1;
@@ -6853,13 +6854,13 @@
 }
 
 void returnStruct40BytesHomogeneousDoubleAfterCallback() {
-  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
 
   final result = returnStruct40BytesHomogeneousDoubleCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
+  calloc.free(returnStruct40BytesHomogeneousDoubleResult.addressOf);
 }
 
 typedef ReturnStruct1024BytesHomogeneousUint64Type
@@ -7130,7 +7131,7 @@
 Struct1024BytesHomogeneousUint64
     returnStruct1024BytesHomogeneousUint64CalculateResult() {
   Struct1024BytesHomogeneousUint64 result =
-      allocate<Struct1024BytesHomogeneousUint64>().ref;
+      calloc<Struct1024BytesHomogeneousUint64>().ref;
 
   result.a0 = returnStruct1024BytesHomogeneousUint64_a0;
   result.a1 = returnStruct1024BytesHomogeneousUint64_a1;
@@ -7549,13 +7550,13 @@
 }
 
 void returnStruct1024BytesHomogeneousUint64AfterCallback() {
-  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+  calloc.free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
 
   final result = returnStruct1024BytesHomogeneousUint64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
+  calloc.free(returnStruct1024BytesHomogeneousUint64Result.addressOf);
 }
 
 typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
@@ -7894,7 +7895,7 @@
 StructAlignmentInt16 returnStructAlignmentInt16Result = StructAlignmentInt16();
 
 StructAlignmentInt16 returnStructAlignmentInt16CalculateResult() {
-  StructAlignmentInt16 result = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 result = calloc<StructAlignmentInt16>().ref;
 
   result.a0 = returnStructAlignmentInt16_a0;
   result.a1 = returnStructAlignmentInt16_a1;
@@ -7933,13 +7934,13 @@
 }
 
 void returnStructAlignmentInt16AfterCallback() {
-  free(returnStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructAlignmentInt16Result.addressOf);
 
   final result = returnStructAlignmentInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructAlignmentInt16Result.addressOf);
 }
 
 typedef ReturnStructAlignmentInt32Type = StructAlignmentInt32 Function(
@@ -7954,7 +7955,7 @@
 StructAlignmentInt32 returnStructAlignmentInt32Result = StructAlignmentInt32();
 
 StructAlignmentInt32 returnStructAlignmentInt32CalculateResult() {
-  StructAlignmentInt32 result = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 result = calloc<StructAlignmentInt32>().ref;
 
   result.a0 = returnStructAlignmentInt32_a0;
   result.a1 = returnStructAlignmentInt32_a1;
@@ -7993,13 +7994,13 @@
 }
 
 void returnStructAlignmentInt32AfterCallback() {
-  free(returnStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructAlignmentInt32Result.addressOf);
 
   final result = returnStructAlignmentInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructAlignmentInt32Result.addressOf);
 }
 
 typedef ReturnStructAlignmentInt64Type = StructAlignmentInt64 Function(
@@ -8014,7 +8015,7 @@
 StructAlignmentInt64 returnStructAlignmentInt64Result = StructAlignmentInt64();
 
 StructAlignmentInt64 returnStructAlignmentInt64CalculateResult() {
-  StructAlignmentInt64 result = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 result = calloc<StructAlignmentInt64>().ref;
 
   result.a0 = returnStructAlignmentInt64_a0;
   result.a1 = returnStructAlignmentInt64_a1;
@@ -8053,13 +8054,13 @@
 }
 
 void returnStructAlignmentInt64AfterCallback() {
-  free(returnStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructAlignmentInt64Result.addressOf);
 
   final result = returnStructAlignmentInt64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructAlignmentInt64Result.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedIntType = Struct8BytesNestedInt Function(
@@ -8076,7 +8077,7 @@
     Struct8BytesNestedInt();
 
 Struct8BytesNestedInt returnStruct8BytesNestedIntCalculateResult() {
-  Struct8BytesNestedInt result = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt result = calloc<Struct8BytesNestedInt>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedInt_a0.a0;
   result.a0.a1 = returnStruct8BytesNestedInt_a0.a1;
@@ -8116,13 +8117,13 @@
 }
 
 void returnStruct8BytesNestedIntAfterCallback() {
-  free(returnStruct8BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct8BytesNestedIntResult.addressOf);
 
   final result = returnStruct8BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct8BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedFloatType = Struct8BytesNestedFloat Function(
@@ -8137,7 +8138,7 @@
     Struct8BytesNestedFloat();
 
 Struct8BytesNestedFloat returnStruct8BytesNestedFloatCalculateResult() {
-  Struct8BytesNestedFloat result = allocate<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat result = calloc<Struct8BytesNestedFloat>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedFloat_a0.a0;
   result.a1.a0 = returnStruct8BytesNestedFloat_a1.a0;
@@ -8175,13 +8176,13 @@
 }
 
 void returnStruct8BytesNestedFloatAfterCallback() {
-  free(returnStruct8BytesNestedFloatResult.addressOf);
+  calloc.free(returnStruct8BytesNestedFloatResult.addressOf);
 
   final result = returnStruct8BytesNestedFloatCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedFloatResult.addressOf);
+  calloc.free(returnStruct8BytesNestedFloatResult.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedFloat2Type = Struct8BytesNestedFloat2 Function(
@@ -8196,7 +8197,7 @@
     Struct8BytesNestedFloat2();
 
 Struct8BytesNestedFloat2 returnStruct8BytesNestedFloat2CalculateResult() {
-  Struct8BytesNestedFloat2 result = allocate<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 result = calloc<Struct8BytesNestedFloat2>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedFloat2_a0.a0;
   result.a1 = returnStruct8BytesNestedFloat2_a1;
@@ -8235,13 +8236,13 @@
 }
 
 void returnStruct8BytesNestedFloat2AfterCallback() {
-  free(returnStruct8BytesNestedFloat2Result.addressOf);
+  calloc.free(returnStruct8BytesNestedFloat2Result.addressOf);
 
   final result = returnStruct8BytesNestedFloat2CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedFloat2Result.addressOf);
+  calloc.free(returnStruct8BytesNestedFloat2Result.addressOf);
 }
 
 typedef ReturnStruct8BytesNestedMixedType = Struct8BytesNestedMixed Function(
@@ -8257,7 +8258,7 @@
     Struct8BytesNestedMixed();
 
 Struct8BytesNestedMixed returnStruct8BytesNestedMixedCalculateResult() {
-  Struct8BytesNestedMixed result = allocate<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed result = calloc<Struct8BytesNestedMixed>().ref;
 
   result.a0.a0 = returnStruct8BytesNestedMixed_a0.a0;
   result.a0.a1 = returnStruct8BytesNestedMixed_a0.a1;
@@ -8296,13 +8297,13 @@
 }
 
 void returnStruct8BytesNestedMixedAfterCallback() {
-  free(returnStruct8BytesNestedMixedResult.addressOf);
+  calloc.free(returnStruct8BytesNestedMixedResult.addressOf);
 
   final result = returnStruct8BytesNestedMixedCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct8BytesNestedMixedResult.addressOf);
+  calloc.free(returnStruct8BytesNestedMixedResult.addressOf);
 }
 
 typedef ReturnStruct16BytesNestedIntType = Struct16BytesNestedInt Function(
@@ -8317,7 +8318,7 @@
     Struct16BytesNestedInt();
 
 Struct16BytesNestedInt returnStruct16BytesNestedIntCalculateResult() {
-  Struct16BytesNestedInt result = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt result = calloc<Struct16BytesNestedInt>().ref;
 
   result.a0.a0.a0 = returnStruct16BytesNestedInt_a0.a0.a0;
   result.a0.a0.a1 = returnStruct16BytesNestedInt_a0.a0.a1;
@@ -8361,13 +8362,13 @@
 }
 
 void returnStruct16BytesNestedIntAfterCallback() {
-  free(returnStruct16BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct16BytesNestedIntResult.addressOf);
 
   final result = returnStruct16BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct16BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct16BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStruct32BytesNestedIntType = Struct32BytesNestedInt Function(
@@ -8384,7 +8385,7 @@
     Struct32BytesNestedInt();
 
 Struct32BytesNestedInt returnStruct32BytesNestedIntCalculateResult() {
-  Struct32BytesNestedInt result = allocate<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt result = calloc<Struct32BytesNestedInt>().ref;
 
   result.a0.a0.a0.a0 = returnStruct32BytesNestedInt_a0.a0.a0.a0;
   result.a0.a0.a0.a1 = returnStruct32BytesNestedInt_a0.a0.a0.a1;
@@ -8436,13 +8437,13 @@
 }
 
 void returnStruct32BytesNestedIntAfterCallback() {
-  free(returnStruct32BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct32BytesNestedIntResult.addressOf);
 
   final result = returnStruct32BytesNestedIntCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStruct32BytesNestedIntResult.addressOf);
+  calloc.free(returnStruct32BytesNestedIntResult.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt16Type
@@ -8463,7 +8464,7 @@
 StructNestedIntStructAlignmentInt16
     returnStructNestedIntStructAlignmentInt16CalculateResult() {
   StructNestedIntStructAlignmentInt16 result =
-      allocate<StructNestedIntStructAlignmentInt16>().ref;
+      calloc<StructNestedIntStructAlignmentInt16>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt16_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt16_a0.a1;
@@ -8506,13 +8507,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt16AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt16CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt16Result.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt32Type
@@ -8533,7 +8534,7 @@
 StructNestedIntStructAlignmentInt32
     returnStructNestedIntStructAlignmentInt32CalculateResult() {
   StructNestedIntStructAlignmentInt32 result =
-      allocate<StructNestedIntStructAlignmentInt32>().ref;
+      calloc<StructNestedIntStructAlignmentInt32>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt32_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt32_a0.a1;
@@ -8576,13 +8577,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt32AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt32CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt32Result.addressOf);
 }
 
 typedef ReturnStructNestedIntStructAlignmentInt64Type
@@ -8603,7 +8604,7 @@
 StructNestedIntStructAlignmentInt64
     returnStructNestedIntStructAlignmentInt64CalculateResult() {
   StructNestedIntStructAlignmentInt64 result =
-      allocate<StructNestedIntStructAlignmentInt64>().ref;
+      calloc<StructNestedIntStructAlignmentInt64>().ref;
 
   result.a0.a0 = returnStructNestedIntStructAlignmentInt64_a0.a0;
   result.a0.a1 = returnStructNestedIntStructAlignmentInt64_a0.a1;
@@ -8646,13 +8647,13 @@
 }
 
 void returnStructNestedIntStructAlignmentInt64AfterCallback() {
-  free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
 
   final result = returnStructNestedIntStructAlignmentInt64CalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
+  calloc.free(returnStructNestedIntStructAlignmentInt64Result.addressOf);
 }
 
 typedef ReturnStructNestedIrregularEvenBiggerType
@@ -8674,7 +8675,7 @@
 StructNestedIrregularEvenBigger
     returnStructNestedIrregularEvenBiggerCalculateResult() {
   StructNestedIrregularEvenBigger result =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
 
   result.a0 = returnStructNestedIrregularEvenBigger_a0;
   result.a1.a0.a0 = returnStructNestedIrregularEvenBigger_a1.a0.a0;
@@ -8747,11 +8748,11 @@
 }
 
 void returnStructNestedIrregularEvenBiggerAfterCallback() {
-  free(returnStructNestedIrregularEvenBiggerResult.addressOf);
+  calloc.free(returnStructNestedIrregularEvenBiggerResult.addressOf);
 
   final result = returnStructNestedIrregularEvenBiggerCalculateResult();
 
   print("after callback result = $result");
 
-  free(returnStructNestedIrregularEvenBiggerResult.addressOf);
+  calloc.free(returnStructNestedIrregularEvenBiggerResult.addressOf);
 }
diff --git a/tests/ffi_2/function_callbacks_structs_by_value_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_test.dart
index 23c9946..5e9399a 100644
--- a/tests/ffi_2/function_callbacks_structs_by_value_test.dart
+++ b/tests/ffi_2/function_callbacks_structs_by_value_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
 
@@ -23,7 +24,7 @@
 }
 
 void recursiveTest(int recursionCounter) {
-  final struct = allocate<Struct20BytesHomogeneousInt32>().ref;
+  final struct = calloc<Struct20BytesHomogeneousInt32>().ref;
   struct.a0 = 1;
   struct.a1 = 2;
   struct.a2 = 3;
@@ -35,7 +36,7 @@
   Expect.equals(struct.a2, result.a2);
   Expect.equals(struct.a3, result.a3);
   Expect.equals(struct.a4, result.a4);
-  free(struct.addressOf);
+  calloc.free(struct.addressOf);
 }
 
 Struct20BytesHomogeneousInt32 dartPassStructRecursive(
@@ -93,7 +94,7 @@
   _invokeReceiveStructByValue(_receiveStructByValuePointer);
   Expect.isTrue(typedDataBackedStructSet);
 
-  final pointerBackedStruct = allocate<Struct8BytesNestedInt>().ref;
+  final pointerBackedStruct = calloc<Struct8BytesNestedInt>().ref;
 
   void reset() {
     pointerBackedStruct.a0.a0 = 1;
@@ -130,5 +131,5 @@
   Expect.equals(5, typedDataBackedStruct.a1.a0);
   Expect.equals(6, typedDataBackedStruct.a1.a1);
 
-  free(pointerBackedStruct.addressOf);
+  calloc.free(pointerBackedStruct.addressOf);
 }
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 d8ed635..e00f3fa 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -15,6 +15,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -1053,16 +1054,16 @@
 /// Smallest struct with data.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct1ByteIntx10() {
-  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a1 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a2 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a3 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a4 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a5 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a6 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a7 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
-  Struct1ByteInt a9 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a0 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a1 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a2 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a3 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a4 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a5 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a6 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a7 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = calloc<Struct1ByteInt>().ref;
+  Struct1ByteInt a9 = calloc<Struct1ByteInt>().ref;
 
   a0.a0 = -1;
   a1.a0 = 2;
@@ -1081,16 +1082,16 @@
 
   Expect.equals(5, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct3BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1120,26 +1121,16 @@
 /// Not a multiple of word size, not a power of two.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct3BytesHomogeneousUint8x10() {
-  Struct3BytesHomogeneousUint8 a0 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a1 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a2 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a3 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a4 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a5 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a6 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a7 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a8 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
-  Struct3BytesHomogeneousUint8 a9 =
-      allocate<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a0 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a1 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a2 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a3 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a4 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a5 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a6 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a7 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a8 = calloc<Struct3BytesHomogeneousUint8>().ref;
+  Struct3BytesHomogeneousUint8 a9 = calloc<Struct3BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1179,16 +1170,16 @@
 
   Expect.equals(465, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct3BytesInt2ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -1219,16 +1210,16 @@
 /// With alignment rules taken into account size is 4 bytes.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct3BytesInt2ByteAlignedx10() {
-  Struct3BytesInt2ByteAligned a0 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a1 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a2 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a3 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a4 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a5 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a6 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a7 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a8 = allocate<Struct3BytesInt2ByteAligned>().ref;
-  Struct3BytesInt2ByteAligned a9 = allocate<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a0 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a1 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a2 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a3 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a4 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a5 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a6 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a7 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a8 = calloc<Struct3BytesInt2ByteAligned>().ref;
+  Struct3BytesInt2ByteAligned a9 = calloc<Struct3BytesInt2ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1258,16 +1249,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct4BytesHomogeneousInt16x10 = ffiTestFunctions.lookupFunction<
@@ -1297,26 +1288,16 @@
 /// Exactly word size on 32-bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct4BytesHomogeneousInt16x10() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a2 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a3 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a4 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a5 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a6 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a7 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a8 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a9 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a2 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a3 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a4 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a5 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a6 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a7 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a8 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a9 = calloc<Struct4BytesHomogeneousInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1346,16 +1327,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct7BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1385,26 +1366,16 @@
 /// Sub word size on 64 bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct7BytesHomogeneousUint8x10() {
-  Struct7BytesHomogeneousUint8 a0 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a1 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a2 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a3 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a4 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a5 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a6 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a7 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a8 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
-  Struct7BytesHomogeneousUint8 a9 =
-      allocate<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a0 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a1 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a2 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a3 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a4 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a5 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a6 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a7 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a8 = calloc<Struct7BytesHomogeneousUint8>().ref;
+  Struct7BytesHomogeneousUint8 a9 = calloc<Struct7BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1484,16 +1455,16 @@
 
   Expect.equals(2485, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct7BytesInt4ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -1524,16 +1495,16 @@
 /// With alignment rules taken into account size is 8 bytes.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct7BytesInt4ByteAlignedx10() {
-  Struct7BytesInt4ByteAligned a0 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a1 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a2 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a3 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a4 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a5 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a6 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a7 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a8 = allocate<Struct7BytesInt4ByteAligned>().ref;
-  Struct7BytesInt4ByteAligned a9 = allocate<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a0 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a1 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a2 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a3 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a4 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a5 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a6 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a7 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a8 = calloc<Struct7BytesInt4ByteAligned>().ref;
+  Struct7BytesInt4ByteAligned a9 = calloc<Struct7BytesInt4ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1573,16 +1544,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesIntx10 = ffiTestFunctions.lookupFunction<
@@ -1612,16 +1583,16 @@
 /// Exactly word size struct on 64bit architectures.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesIntx10() {
-  Struct8BytesInt a0 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a1 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a2 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a3 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a4 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a5 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a6 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a7 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a8 = allocate<Struct8BytesInt>().ref;
-  Struct8BytesInt a9 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a0 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a1 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a2 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a3 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a4 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a5 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a6 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a7 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a8 = calloc<Struct8BytesInt>().ref;
+  Struct8BytesInt a9 = calloc<Struct8BytesInt>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -1660,16 +1631,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesHomogeneousFloatx10 = ffiTestFunctions.lookupFunction<
@@ -1699,26 +1670,16 @@
 /// Arguments passed in FP registers as long as they fit.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesHomogeneousFloatx10() {
-  Struct8BytesHomogeneousFloat a0 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a1 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a2 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a3 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a4 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a5 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a6 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a7 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a8 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
-  Struct8BytesHomogeneousFloat a9 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a0 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a1 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a2 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a3 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a4 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a5 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a6 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a7 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a8 = calloc<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a9 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -1748,16 +1709,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesMixedx10 = ffiTestFunctions.lookupFunction<
@@ -1787,16 +1748,16 @@
 /// On x64, arguments go in int registers because it is not only float.
 /// 10 struct arguments will exhaust available registers.
 void testPassStruct8BytesMixedx10() {
-  Struct8BytesMixed a0 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a1 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a2 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a3 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a4 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a5 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a6 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a7 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a8 = allocate<Struct8BytesMixed>().ref;
-  Struct8BytesMixed a9 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a0 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a1 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a2 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a3 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a4 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a5 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a6 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a7 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a8 = calloc<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a9 = calloc<Struct8BytesMixed>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2;
@@ -1836,16 +1797,16 @@
 
   Expect.approxEquals(15.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct9BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -1878,26 +1839,16 @@
 /// Tests upper bytes in the integer registers that are partly filled.
 /// Tests stack alignment of non word size stack arguments.
 void testPassStruct9BytesHomogeneousUint8x10() {
-  Struct9BytesHomogeneousUint8 a0 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a1 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a2 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a3 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a4 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a5 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a6 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a7 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a8 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
-  Struct9BytesHomogeneousUint8 a9 =
-      allocate<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a0 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a1 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a2 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a3 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a4 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a5 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a6 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a7 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a8 = calloc<Struct9BytesHomogeneousUint8>().ref;
+  Struct9BytesHomogeneousUint8 a9 = calloc<Struct9BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -1997,16 +1948,16 @@
 
   Expect.equals(4095, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct9BytesInt4Or8ByteAlignedx10 = ffiTestFunctions.lookupFunction<
@@ -2040,25 +1991,25 @@
 ///
 void testPassStruct9BytesInt4Or8ByteAlignedx10() {
   Struct9BytesInt4Or8ByteAligned a0 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a1 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a2 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a3 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a4 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a5 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a6 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a7 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a8 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
   Struct9BytesInt4Or8ByteAligned a9 =
-      allocate<Struct9BytesInt4Or8ByteAligned>().ref;
+      calloc<Struct9BytesInt4Or8ByteAligned>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2088,16 +2039,16 @@
 
   Expect.equals(10, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct12BytesHomogeneousFloatx6 = ffiTestFunctions.lookupFunction<
@@ -2121,17 +2072,17 @@
 /// The last argument is to test whether arguments are backfilled.
 void testPassStruct12BytesHomogeneousFloatx6() {
   Struct12BytesHomogeneousFloat a0 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a1 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a2 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a3 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a4 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
   Struct12BytesHomogeneousFloat a5 =
-      allocate<Struct12BytesHomogeneousFloat>().ref;
+      calloc<Struct12BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2158,12 +2109,12 @@
 
   Expect.approxEquals(9.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
 }
 
 final passStruct16BytesHomogeneousFloatx5 = ffiTestFunctions.lookupFunction<
@@ -2185,15 +2136,15 @@
 /// 5 struct arguments will exhaust available registers.
 void testPassStruct16BytesHomogeneousFloatx5() {
   Struct16BytesHomogeneousFloat a0 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a1 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a2 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a3 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   Struct16BytesHomogeneousFloat a4 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2222,11 +2173,11 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
 }
 
 final passStruct16BytesMixedx10 = ffiTestFunctions.lookupFunction<
@@ -2258,16 +2209,16 @@
 /// The rest goes on the stack.
 /// On arm, arguments are 8 byte aligned.
 void testPassStruct16BytesMixedx10() {
-  Struct16BytesMixed a0 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a2 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a0 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a2 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = calloc<Struct16BytesMixed>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2;
@@ -2297,16 +2248,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct16BytesMixed2x10 = ffiTestFunctions.lookupFunction<
@@ -2338,16 +2289,16 @@
 /// The rest goes on the stack.
 /// On arm, arguments are 4 byte aligned.
 void testPassStruct16BytesMixed2x10() {
-  Struct16BytesMixed2 a0 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a1 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a2 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a3 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a4 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a5 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a6 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a7 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a8 = allocate<Struct16BytesMixed2>().ref;
-  Struct16BytesMixed2 a9 = allocate<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a0 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a1 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a2 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a3 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a4 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a5 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a6 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a7 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a8 = calloc<Struct16BytesMixed2>().ref;
+  Struct16BytesMixed2 a9 = calloc<Struct16BytesMixed2>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2397,16 +2348,16 @@
 
   Expect.approxEquals(20.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct17BytesIntx10 = ffiTestFunctions.lookupFunction<
@@ -2436,16 +2387,16 @@
 /// Arguments are passed as pointer to copy on arm64.
 /// Tests that the memory allocated for copies are rounded up to word size.
 void testPassStruct17BytesIntx10() {
-  Struct17BytesInt a0 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a1 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a2 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a3 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a4 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a5 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a6 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a7 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a8 = allocate<Struct17BytesInt>().ref;
-  Struct17BytesInt a9 = allocate<Struct17BytesInt>().ref;
+  Struct17BytesInt a0 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a1 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a2 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a3 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a4 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a5 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a6 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a7 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a8 = calloc<Struct17BytesInt>().ref;
+  Struct17BytesInt a9 = calloc<Struct17BytesInt>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2485,16 +2436,16 @@
 
   Expect.equals(15, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct19BytesHomogeneousUint8x10 = ffiTestFunctions.lookupFunction<
@@ -2526,25 +2477,25 @@
 ///
 void testPassStruct19BytesHomogeneousUint8x10() {
   Struct19BytesHomogeneousUint8 a0 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a1 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a2 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a3 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a4 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a5 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a6 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a7 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a8 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
   Struct19BytesHomogeneousUint8 a9 =
-      allocate<Struct19BytesHomogeneousUint8>().ref;
+      calloc<Struct19BytesHomogeneousUint8>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -2744,16 +2695,16 @@
 
   Expect.equals(18145, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct20BytesHomogeneousInt32x10 = ffiTestFunctions.lookupFunction<
@@ -2786,25 +2737,25 @@
 /// pointers to copies are also passed on the stack.
 void testPassStruct20BytesHomogeneousInt32x10() {
   Struct20BytesHomogeneousInt32 a0 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a1 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a2 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a3 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a4 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a5 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a6 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a7 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a8 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
   Struct20BytesHomogeneousInt32 a9 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -2864,16 +2815,16 @@
 
   Expect.equals(25, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct20BytesHomogeneousFloat = ffiTestFunctions.lookupFunction<
@@ -2884,7 +2835,7 @@
 /// Argument too big to go into FPU registers in hardfp and arm64.
 void testPassStruct20BytesHomogeneousFloat() {
   Struct20BytesHomogeneousFloat a0 =
-      allocate<Struct20BytesHomogeneousFloat>().ref;
+      calloc<Struct20BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2898,7 +2849,7 @@
 
   Expect.approxEquals(-3.0, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct32BytesHomogeneousDoublex5 = ffiTestFunctions.lookupFunction<
@@ -2920,15 +2871,15 @@
 /// 5 struct arguments will exhaust available registers.
 void testPassStruct32BytesHomogeneousDoublex5() {
   Struct32BytesHomogeneousDouble a0 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a1 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a2 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a3 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   Struct32BytesHomogeneousDouble a4 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2957,11 +2908,11 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
 }
 
 final passStruct40BytesHomogeneousDouble = ffiTestFunctions.lookupFunction<
@@ -2972,7 +2923,7 @@
 /// Argument too big to go into FPU registers in arm64.
 void testPassStruct40BytesHomogeneousDouble() {
   Struct40BytesHomogeneousDouble a0 =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -2986,7 +2937,7 @@
 
   Expect.approxEquals(-3.0, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct1024BytesHomogeneousUint64 = ffiTestFunctions.lookupFunction<
@@ -2997,7 +2948,7 @@
 /// Test 1kb struct.
 void testPassStruct1024BytesHomogeneousUint64() {
   Struct1024BytesHomogeneousUint64 a0 =
-      allocate<Struct1024BytesHomogeneousUint64>().ref;
+      calloc<Struct1024BytesHomogeneousUint64>().ref;
 
   a0.a0 = 1;
   a0.a1 = 2;
@@ -3134,7 +3085,7 @@
 
   Expect.equals(8256, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passFloatStruct16BytesHomogeneousFloatFloatStruct1 =
@@ -3164,16 +3115,16 @@
 void testPassFloatStruct16BytesHomogeneousFloatFloatStruct1() {
   double a0;
   Struct16BytesHomogeneousFloat a1 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a2;
   Struct16BytesHomogeneousFloat a3 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a4;
   Struct16BytesHomogeneousFloat a5 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a6;
   Struct16BytesHomogeneousFloat a7 =
-      allocate<Struct16BytesHomogeneousFloat>().ref;
+      calloc<Struct16BytesHomogeneousFloat>().ref;
   double a8;
 
   a0 = -1.0;
@@ -3205,10 +3156,10 @@
 
   Expect.approxEquals(-11.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passFloatStruct32BytesHomogeneousDoubleFloatStruct =
@@ -3238,16 +3189,16 @@
 void testPassFloatStruct32BytesHomogeneousDoubleFloatStruct() {
   double a0;
   Struct32BytesHomogeneousDouble a1 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a2;
   Struct32BytesHomogeneousDouble a3 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a4;
   Struct32BytesHomogeneousDouble a5 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a6;
   Struct32BytesHomogeneousDouble a7 =
-      allocate<Struct32BytesHomogeneousDouble>().ref;
+      calloc<Struct32BytesHomogeneousDouble>().ref;
   double a8;
 
   a0 = -1.0;
@@ -3279,10 +3230,10 @@
 
   Expect.approxEquals(-11.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passInt8Struct16BytesMixedInt8Struct16BytesMixedIn =
@@ -3307,13 +3258,13 @@
 /// Test backfilling of integer registers.
 void testPassInt8Struct16BytesMixedInt8Struct16BytesMixedIn() {
   int a0;
-  Struct16BytesMixed a1 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a1 = calloc<Struct16BytesMixed>().ref;
   int a2;
-  Struct16BytesMixed a3 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a3 = calloc<Struct16BytesMixed>().ref;
   int a4;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
   int a6;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
   int a8;
 
   a0 = -1;
@@ -3337,10 +3288,10 @@
 
   Expect.approxEquals(-7.0, result);
 
-  free(a1.addressOf);
-  free(a3.addressOf);
-  free(a5.addressOf);
-  free(a7.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passDoublex6Struct16BytesMixedx4Int32 = ffiTestFunctions.lookupFunction<
@@ -3379,10 +3330,10 @@
   double a3;
   double a4;
   double a5;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a8 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a9 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a8 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a9 = calloc<Struct16BytesMixed>().ref;
   int a10;
 
   a0 = -1.0;
@@ -3408,10 +3359,10 @@
 
   Expect.approxEquals(-8.0, result);
 
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passInt32x4Struct16BytesMixedx4Double = ffiTestFunctions.lookupFunction<
@@ -3436,10 +3387,10 @@
   int a1;
   int a2;
   int a3;
-  Struct16BytesMixed a4 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a5 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a6 = allocate<Struct16BytesMixed>().ref;
-  Struct16BytesMixed a7 = allocate<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a4 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a5 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a6 = calloc<Struct16BytesMixed>().ref;
+  Struct16BytesMixed a7 = calloc<Struct16BytesMixed>().ref;
   double a8;
 
   a0 = -1;
@@ -3463,10 +3414,10 @@
 
   Expect.approxEquals(-7.0, result);
 
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
 }
 
 final passStruct40BytesHomogeneousDoubleStruct4BytesHomo =
@@ -3481,11 +3432,9 @@
 /// Check that the other two arguments are allocated on registers.
 void testPassStruct40BytesHomogeneousDoubleStruct4BytesHomo() {
   Struct40BytesHomogeneousDouble a0 =
-      allocate<Struct40BytesHomogeneousDouble>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct8BytesHomogeneousFloat a2 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+      calloc<Struct40BytesHomogeneousDouble>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct8BytesHomogeneousFloat a2 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -3503,9 +3452,9 @@
 
   Expect.approxEquals(-5.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
 }
 
 final passInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int =
@@ -3613,30 +3562,28 @@
   double a15;
   int a16;
   int a17;
-  Struct1ByteInt a18 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a18 = calloc<Struct1ByteInt>().ref;
   int a19;
   int a20;
-  Struct4BytesHomogeneousInt16 a21 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a21 = calloc<Struct4BytesHomogeneousInt16>().ref;
   int a22;
   int a23;
-  Struct8BytesInt a24 = allocate<Struct8BytesInt>().ref;
+  Struct8BytesInt a24 = calloc<Struct8BytesInt>().ref;
   int a25;
   int a26;
-  Struct8BytesHomogeneousFloat a27 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a27 = calloc<Struct8BytesHomogeneousFloat>().ref;
   int a28;
   int a29;
-  Struct8BytesMixed a30 = allocate<Struct8BytesMixed>().ref;
+  Struct8BytesMixed a30 = calloc<Struct8BytesMixed>().ref;
   int a31;
   int a32;
-  StructAlignmentInt16 a33 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a33 = calloc<StructAlignmentInt16>().ref;
   int a34;
   int a35;
-  StructAlignmentInt32 a36 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a36 = calloc<StructAlignmentInt32>().ref;
   int a37;
   int a38;
-  StructAlignmentInt64 a39 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a39 = calloc<StructAlignmentInt64>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -3737,14 +3684,14 @@
 
   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);
+  calloc.free(a18.addressOf);
+  calloc.free(a21.addressOf);
+  calloc.free(a24.addressOf);
+  calloc.free(a27.addressOf);
+  calloc.free(a30.addressOf);
+  calloc.free(a33.addressOf);
+  calloc.free(a36.addressOf);
+  calloc.free(a39.addressOf);
 }
 
 final passStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -3753,7 +3700,7 @@
 
 /// Test alignment and padding of 16 byte int within struct.
 void testPassStructAlignmentInt16() {
-  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a0 = calloc<StructAlignmentInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3765,7 +3712,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
@@ -3774,7 +3721,7 @@
 
 /// Test alignment and padding of 32 byte int within struct.
 void testPassStructAlignmentInt32() {
-  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a0 = calloc<StructAlignmentInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3786,7 +3733,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
@@ -3795,7 +3742,7 @@
 
 /// Test alignment and padding of 64 byte int within struct.
 void testPassStructAlignmentInt64() {
-  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a0 = calloc<StructAlignmentInt64>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -3807,7 +3754,7 @@
 
   Expect.equals(-2, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStruct8BytesNestedIntx10 = ffiTestFunctions.lookupFunction<
@@ -3837,16 +3784,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust registers on all platforms.
 void testPassStruct8BytesNestedIntx10() {
-  Struct8BytesNestedInt a0 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a1 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a2 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a3 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a4 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a5 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a6 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a7 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a8 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a9 = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a0 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a1 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a2 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a3 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a4 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a5 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a6 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a7 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a8 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a9 = calloc<Struct8BytesNestedInt>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -3896,16 +3843,16 @@
 
   Expect.equals(20, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
@@ -3935,16 +3882,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust fpu registers on all platforms.
 void testPassStruct8BytesNestedFloatx10() {
-  Struct8BytesNestedFloat a0 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a1 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a2 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a3 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a4 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a5 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a6 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a7 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a8 = allocate<Struct8BytesNestedFloat>().ref;
-  Struct8BytesNestedFloat a9 = allocate<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a0 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a1 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a2 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a3 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a4 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a5 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a6 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a7 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a8 = calloc<Struct8BytesNestedFloat>().ref;
+  Struct8BytesNestedFloat a9 = calloc<Struct8BytesNestedFloat>().ref;
 
   a0.a0.a0 = -1.0;
   a0.a1.a0 = 2.0;
@@ -3974,16 +3921,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedFloat2x10 = ffiTestFunctions.lookupFunction<
@@ -4015,16 +3962,16 @@
 /// The nesting is irregular, testing homogenous float rules on arm and arm64,
 /// and the fpu register usage on x64.
 void testPassStruct8BytesNestedFloat2x10() {
-  Struct8BytesNestedFloat2 a0 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a1 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a2 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a3 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a4 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a5 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a6 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a7 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a8 = allocate<Struct8BytesNestedFloat2>().ref;
-  Struct8BytesNestedFloat2 a9 = allocate<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a0 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a1 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a2 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a3 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a4 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a5 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a6 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a7 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a8 = calloc<Struct8BytesNestedFloat2>().ref;
+  Struct8BytesNestedFloat2 a9 = calloc<Struct8BytesNestedFloat2>().ref;
 
   a0.a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -4054,16 +4001,16 @@
 
   Expect.approxEquals(10.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct8BytesNestedMixedx10 = ffiTestFunctions.lookupFunction<
@@ -4093,16 +4040,16 @@
 /// Simple nested struct. No alignment gaps on any architectures.
 /// 10 arguments exhaust all registers on all platforms.
 void testPassStruct8BytesNestedMixedx10() {
-  Struct8BytesNestedMixed a0 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a1 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a2 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a3 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a4 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a5 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a6 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a7 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a8 = allocate<Struct8BytesNestedMixed>().ref;
-  Struct8BytesNestedMixed a9 = allocate<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a0 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a1 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a2 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a3 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a4 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a5 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a6 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a7 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a8 = calloc<Struct8BytesNestedMixed>().ref;
+  Struct8BytesNestedMixed a9 = calloc<Struct8BytesNestedMixed>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4142,16 +4089,16 @@
 
   Expect.approxEquals(15.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
-  free(a4.addressOf);
-  free(a5.addressOf);
-  free(a6.addressOf);
-  free(a7.addressOf);
-  free(a8.addressOf);
-  free(a9.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
+  calloc.free(a4.addressOf);
+  calloc.free(a5.addressOf);
+  calloc.free(a6.addressOf);
+  calloc.free(a7.addressOf);
+  calloc.free(a8.addressOf);
+  calloc.free(a9.addressOf);
 }
 
 final passStruct16BytesNestedIntx2 = ffiTestFunctions.lookupFunction<
@@ -4161,8 +4108,8 @@
 
 /// Deeper nested struct to test recursive member access.
 void testPassStruct16BytesNestedIntx2() {
-  Struct16BytesNestedInt a0 = allocate<Struct16BytesNestedInt>().ref;
-  Struct16BytesNestedInt a1 = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a0 = calloc<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a1 = calloc<Struct16BytesNestedInt>().ref;
 
   a0.a0.a0.a0 = -1;
   a0.a0.a0.a1 = 2;
@@ -4187,8 +4134,8 @@
 
   Expect.equals(8, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final passStruct32BytesNestedIntx2 = ffiTestFunctions.lookupFunction<
@@ -4198,8 +4145,8 @@
 
 /// Even deeper nested struct to test recursive member access.
 void testPassStruct32BytesNestedIntx2() {
-  Struct32BytesNestedInt a0 = allocate<Struct32BytesNestedInt>().ref;
-  Struct32BytesNestedInt a1 = allocate<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt a0 = calloc<Struct32BytesNestedInt>().ref;
+  Struct32BytesNestedInt a1 = calloc<Struct32BytesNestedInt>().ref;
 
   a0.a0.a0.a0.a0 = -1;
   a0.a0.a0.a0.a1 = 2;
@@ -4240,8 +4187,8 @@
 
   Expect.equals(16, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -4252,7 +4199,7 @@
 /// Test alignment and padding of nested struct with 16 byte int.
 void testPassStructNestedIntStructAlignmentInt16() {
   StructNestedIntStructAlignmentInt16 a0 =
-      allocate<StructNestedIntStructAlignmentInt16>().ref;
+      calloc<StructNestedIntStructAlignmentInt16>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4267,7 +4214,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt32 = ffiTestFunctions.lookupFunction<
@@ -4278,7 +4225,7 @@
 /// Test alignment and padding of nested struct with 32 byte int.
 void testPassStructNestedIntStructAlignmentInt32() {
   StructNestedIntStructAlignmentInt32 a0 =
-      allocate<StructNestedIntStructAlignmentInt32>().ref;
+      calloc<StructNestedIntStructAlignmentInt32>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4293,7 +4240,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIntStructAlignmentInt64 = ffiTestFunctions.lookupFunction<
@@ -4304,7 +4251,7 @@
 /// Test alignment and padding of nested struct with 64 byte int.
 void testPassStructNestedIntStructAlignmentInt64() {
   StructNestedIntStructAlignmentInt64 a0 =
-      allocate<StructNestedIntStructAlignmentInt64>().ref;
+      calloc<StructNestedIntStructAlignmentInt64>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -4319,7 +4266,7 @@
 
   Expect.equals(3, result);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final passStructNestedIrregularEvenBiggerx4 = ffiTestFunctions.lookupFunction<
@@ -4338,13 +4285,13 @@
 /// Return big irregular struct as smoke test.
 void testPassStructNestedIrregularEvenBiggerx4() {
   StructNestedIrregularEvenBigger a0 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a1 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a2 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
   StructNestedIrregularEvenBigger a3 =
-      allocate<StructNestedIrregularEvenBigger>().ref;
+      calloc<StructNestedIrregularEvenBigger>().ref;
 
   a0.a0 = 1;
   a0.a1.a0.a0 = 2;
@@ -4489,10 +4436,10 @@
 
   Expect.approxEquals(1572.0, result);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
-  free(a2.addressOf);
-  free(a3.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
+  calloc.free(a3.addressOf);
 }
 
 final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
@@ -5922,7 +5869,7 @@
 /// Especially for ffi callbacks.
 /// Struct is passed in int registers in most ABIs.
 void testReturnStructArgumentStruct1ByteInt() {
-  Struct1ByteInt a0 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a0 = calloc<Struct1ByteInt>().ref;
 
   a0.a0 = -1;
 
@@ -5932,7 +5879,7 @@
 
   Expect.equals(a0.a0, result.a0);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentInt32x8Struct1ByteInt =
@@ -5954,7 +5901,7 @@
   int a5;
   int a6;
   int a7;
-  Struct1ByteInt a8 = allocate<Struct1ByteInt>().ref;
+  Struct1ByteInt a8 = calloc<Struct1ByteInt>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -5973,7 +5920,7 @@
 
   Expect.equals(a8.a0, result.a0);
 
-  free(a8.addressOf);
+  calloc.free(a8.addressOf);
 }
 
 final returnStructArgumentStruct8BytesHomogeneousFloat =
@@ -5987,8 +5934,7 @@
 /// Especially for ffi callbacks.
 /// Struct is passed in float registers in most ABIs.
 void testReturnStructArgumentStruct8BytesHomogeneousFloat() {
-  Struct8BytesHomogeneousFloat a0 =
-      allocate<Struct8BytesHomogeneousFloat>().ref;
+  Struct8BytesHomogeneousFloat a0 = calloc<Struct8BytesHomogeneousFloat>().ref;
 
   a0.a0 = -1.0;
   a0.a1 = 2.0;
@@ -6000,7 +5946,7 @@
   Expect.approxEquals(a0.a0, result.a0);
   Expect.approxEquals(a0.a1, result.a1);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentStruct20BytesHomogeneousInt32 =
@@ -6015,7 +5961,7 @@
 /// On arm64, both argument and return value are passed in by pointer.
 void testReturnStructArgumentStruct20BytesHomogeneousInt32() {
   Struct20BytesHomogeneousInt32 a0 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6033,7 +5979,7 @@
   Expect.equals(a0.a3, result.a3);
   Expect.equals(a0.a4, result.a4);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStructArgumentInt32x8Struct20BytesHomogeneou =
@@ -6056,7 +6002,7 @@
   int a6;
   int a7;
   Struct20BytesHomogeneousInt32 a8 =
-      allocate<Struct20BytesHomogeneousInt32>().ref;
+      calloc<Struct20BytesHomogeneousInt32>().ref;
 
   a0 = -1;
   a1 = 2;
@@ -6083,7 +6029,7 @@
   Expect.equals(a8.a3, result.a3);
   Expect.equals(a8.a4, result.a4);
 
-  free(a8.addressOf);
+  calloc.free(a8.addressOf);
 }
 
 final returnStructAlignmentInt16 = ffiTestFunctions.lookupFunction<
@@ -6163,10 +6109,8 @@
 
 /// Simple nested struct.
 void testReturnStruct8BytesNestedInt() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesHomogeneousInt16 a1 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesHomogeneousInt16 a1 = calloc<Struct4BytesHomogeneousInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6182,8 +6126,8 @@
   Expect.equals(a1.a0, result.a1.a0);
   Expect.equals(a1.a1, result.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct8BytesNestedFloat = ffiTestFunctions.lookupFunction<
@@ -6193,8 +6137,8 @@
 
 /// Simple nested struct with floats.
 void testReturnStruct8BytesNestedFloat() {
-  Struct4BytesFloat a0 = allocate<Struct4BytesFloat>().ref;
-  Struct4BytesFloat a1 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a0 = calloc<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a1 = calloc<Struct4BytesFloat>().ref;
 
   a0.a0 = -1.0;
   a1.a0 = 2.0;
@@ -6206,8 +6150,8 @@
   Expect.approxEquals(a0.a0, result.a0.a0);
   Expect.approxEquals(a1.a0, result.a1.a0);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct8BytesNestedFloat2 = ffiTestFunctions.lookupFunction<
@@ -6218,7 +6162,7 @@
 /// The nesting is irregular, testing homogenous float rules on arm and arm64,
 /// and the fpu register usage on x64.
 void testReturnStruct8BytesNestedFloat2() {
-  Struct4BytesFloat a0 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesFloat a0 = calloc<Struct4BytesFloat>().ref;
   double a1;
 
   a0.a0 = -1.0;
@@ -6231,7 +6175,7 @@
   Expect.approxEquals(a0.a0, result.a0.a0);
   Expect.approxEquals(a1, result.a1);
 
-  free(a0.addressOf);
+  calloc.free(a0.addressOf);
 }
 
 final returnStruct8BytesNestedMixed = ffiTestFunctions.lookupFunction<
@@ -6242,9 +6186,8 @@
 
 /// Simple nested struct with mixed members.
 void testReturnStruct8BytesNestedMixed() {
-  Struct4BytesHomogeneousInt16 a0 =
-      allocate<Struct4BytesHomogeneousInt16>().ref;
-  Struct4BytesFloat a1 = allocate<Struct4BytesFloat>().ref;
+  Struct4BytesHomogeneousInt16 a0 = calloc<Struct4BytesHomogeneousInt16>().ref;
+  Struct4BytesFloat a1 = calloc<Struct4BytesFloat>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6258,8 +6201,8 @@
   Expect.equals(a0.a1, result.a0.a1);
   Expect.approxEquals(a1.a0, result.a1.a0);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct16BytesNestedInt = ffiTestFunctions.lookupFunction<
@@ -6270,8 +6213,8 @@
 
 /// Deeper nested struct to test recursive member access.
 void testReturnStruct16BytesNestedInt() {
-  Struct8BytesNestedInt a0 = allocate<Struct8BytesNestedInt>().ref;
-  Struct8BytesNestedInt a1 = allocate<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a0 = calloc<Struct8BytesNestedInt>().ref;
+  Struct8BytesNestedInt a1 = calloc<Struct8BytesNestedInt>().ref;
 
   a0.a0.a0 = -1;
   a0.a0.a1 = 2;
@@ -6295,8 +6238,8 @@
   Expect.equals(a1.a1.a0, result.a1.a1.a0);
   Expect.equals(a1.a1.a1, result.a1.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStruct32BytesNestedInt = ffiTestFunctions.lookupFunction<
@@ -6307,8 +6250,8 @@
 
 /// Even deeper nested struct to test recursive member access.
 void testReturnStruct32BytesNestedInt() {
-  Struct16BytesNestedInt a0 = allocate<Struct16BytesNestedInt>().ref;
-  Struct16BytesNestedInt a1 = allocate<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a0 = calloc<Struct16BytesNestedInt>().ref;
+  Struct16BytesNestedInt a1 = calloc<Struct16BytesNestedInt>().ref;
 
   a0.a0.a0.a0 = -1;
   a0.a0.a0.a1 = 2;
@@ -6348,8 +6291,8 @@
   Expect.equals(a1.a1.a1.a0, result.a1.a1.a1.a0);
   Expect.equals(a1.a1.a1.a1, result.a1.a1.a1.a1);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt16 =
@@ -6361,8 +6304,8 @@
 
 /// Test alignment and padding of nested struct with 16 byte int.
 void testReturnStructNestedIntStructAlignmentInt16() {
-  StructAlignmentInt16 a0 = allocate<StructAlignmentInt16>().ref;
-  StructAlignmentInt16 a1 = allocate<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a0 = calloc<StructAlignmentInt16>().ref;
+  StructAlignmentInt16 a1 = calloc<StructAlignmentInt16>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6382,8 +6325,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt32 =
@@ -6395,8 +6338,8 @@
 
 /// Test alignment and padding of nested struct with 32 byte int.
 void testReturnStructNestedIntStructAlignmentInt32() {
-  StructAlignmentInt32 a0 = allocate<StructAlignmentInt32>().ref;
-  StructAlignmentInt32 a1 = allocate<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a0 = calloc<StructAlignmentInt32>().ref;
+  StructAlignmentInt32 a1 = calloc<StructAlignmentInt32>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6416,8 +6359,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIntStructAlignmentInt64 =
@@ -6429,8 +6372,8 @@
 
 /// Test alignment and padding of nested struct with 64 byte int.
 void testReturnStructNestedIntStructAlignmentInt64() {
-  StructAlignmentInt64 a0 = allocate<StructAlignmentInt64>().ref;
-  StructAlignmentInt64 a1 = allocate<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a0 = calloc<StructAlignmentInt64>().ref;
+  StructAlignmentInt64 a1 = calloc<StructAlignmentInt64>().ref;
 
   a0.a0 = -1;
   a0.a1 = 2;
@@ -6450,8 +6393,8 @@
   Expect.equals(a1.a1, result.a1.a1);
   Expect.equals(a1.a2, result.a1.a2);
 
-  free(a0.addressOf);
-  free(a1.addressOf);
+  calloc.free(a0.addressOf);
+  calloc.free(a1.addressOf);
 }
 
 final returnStructNestedIrregularEvenBigger = ffiTestFunctions.lookupFunction<
@@ -6466,8 +6409,8 @@
 /// Return big irregular struct as smoke test.
 void testReturnStructNestedIrregularEvenBigger() {
   int a0;
-  StructNestedIrregularBigger a1 = allocate<StructNestedIrregularBigger>().ref;
-  StructNestedIrregularBigger a2 = allocate<StructNestedIrregularBigger>().ref;
+  StructNestedIrregularBigger a1 = calloc<StructNestedIrregularBigger>().ref;
+  StructNestedIrregularBigger a2 = calloc<StructNestedIrregularBigger>().ref;
   double a3;
 
   a0 = 1;
@@ -6544,6 +6487,6 @@
   Expect.approxEquals(a2.a3, result.a2.a3);
   Expect.approxEquals(a3, result.a3);
 
-  free(a1.addressOf);
-  free(a2.addressOf);
+  calloc.free(a1.addressOf);
+  calloc.free(a2.addressOf);
 }
diff --git a/tests/ffi_2/function_structs_test.dart b/tests/ffi_2/function_structs_test.dart
index bf9ea5f..6bb3e56 100644
--- a/tests/ffi_2/function_structs_test.dart
+++ b/tests/ffi_2/function_structs_test.dart
@@ -9,12 +9,12 @@
 
 import 'dart:ffi';
 
-import 'dylib_utils.dart';
-
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'coordinate.dart';
+import 'dylib_utils.dart';
 import 'very_large_struct.dart';
 
 typedef NativeCoordinateOp = Pointer<Coordinate> Function(Pointer<Coordinate>);
@@ -33,8 +33,10 @@
       ffiTestFunctions.lookup("TransposeCoordinate");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 20.0, nullptr).addressOf;
-  Pointer<Coordinate> c2 = Coordinate.allocate(42.0, 84.0, c1).addressOf;
+  Pointer<Coordinate> c1 =
+      Coordinate.allocate(calloc, 10.0, 20.0, nullptr).addressOf;
+  Pointer<Coordinate> c2 =
+      Coordinate.allocate(calloc, 42.0, 84.0, c1).addressOf;
   c1.ref.next = c2;
 
   Coordinate result = f1(c1).ref;
@@ -45,8 +47,8 @@
   Expect.approxEquals(42.0, result.x);
   Expect.approxEquals(84.0, result.y);
 
-  free(c1);
-  free(c2);
+  calloc.free(c1);
+  calloc.free(c2);
 }
 
 /// pass an array of structs to a c funtion
@@ -55,7 +57,7 @@
       ffiTestFunctions.lookup("CoordinateElemAt1");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Coordinate c1 = allocate<Coordinate>(count: 3).ref;
+  Coordinate c1 = calloc<Coordinate>(3).ref;
   Coordinate c2 = c1.addressOf[1];
   Coordinate c3 = c1.addressOf[2];
   c1.x = 10.0;
@@ -72,7 +74,7 @@
   Expect.approxEquals(20.0, result.x);
   Expect.approxEquals(20.0, result.y);
 
-  free(c1.addressOf);
+  calloc.free(c1.addressOf);
 }
 
 typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
@@ -83,7 +85,7 @@
       ffiTestFunctions.lookup("SumVeryLargeStruct");
   VeryLargeStructSum f = p1.asFunction();
 
-  VeryLargeStruct vls1 = allocate<VeryLargeStruct>(count: 2).ref;
+  VeryLargeStruct vls1 = calloc<VeryLargeStruct>(2).ref;
   VeryLargeStruct vls2 = vls1.addressOf[1];
   List<VeryLargeStruct> structs = [vls1, vls2];
   for (VeryLargeStruct struct in structs) {
@@ -114,5 +116,5 @@
   result = f(vls2.addressOf);
   Expect.equals(2048, result);
 
-  free(vls1.addressOf);
+  calloc.free(vls1.addressOf);
 }
diff --git a/tests/ffi_2/function_test.dart b/tests/ffi_2/function_test.dart
index bff456e..b547ffe 100644
--- a/tests/ffi_2/function_test.dart
+++ b/tests/ffi_2/function_test.dart
@@ -15,11 +15,12 @@
 
 import 'dart:ffi';
 
-import 'dylib_utils.dart';
-
 import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
+import 'dylib_utils.dart';
+import 'calloc.dart';
+
 void main() {
   for (int i = 0; i < 100; ++i) {
     testNativeFunctionFromCast();
@@ -50,11 +51,11 @@
 typedef GenericBinaryOp<T> = int Function(int, T);
 
 void testNativeFunctionFromCast() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<NativeFunction<NativeBinaryOp>> p2 = p1.cast();
   p2.asFunction<BinaryOp>();
   p2.asFunction<GenericBinaryOp<int>>();
-  free(p1);
+  calloc.free(p1);
 }
 
 typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
@@ -394,14 +395,14 @@
     .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
 
 void testNativeFunctionPointer() {
-  Pointer<Int64> p2 = allocate(count: 2);
+  Pointer<Int64> p2 = calloc(2);
   p2.value = 42;
   p2[1] = 1000;
   Pointer<Int64> result = assign1337Index1(p2);
   Expect.equals(1337, result.value);
   Expect.equals(1337, p2[1]);
   Expect.equals(p2.elementAt(1).address, result.address);
-  free(p2);
+  calloc.free(p2);
 }
 
 Int64PointerUnOp nullableInt64ElemAt1 = ffiTestFunctions
@@ -411,10 +412,10 @@
   Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
   Expect.equals(result, nullptr);
 
-  Pointer<Int64> p2 = allocate(count: 2);
+  Pointer<Int64> p2 = calloc(2);
   result = nullableInt64ElemAt1(p2);
   Expect.notEquals(result, nullptr);
-  free(p2);
+  calloc.free(p2);
 }
 
 typedef NativeFloatPointerToBool = Uint8 Function(Pointer<Float>);
@@ -424,13 +425,13 @@
     NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
 
 void testFloatRounding() {
-  Pointer<Float> p2 = allocate();
+  Pointer<Float> p2 = calloc();
   p2.value = 1337.0;
 
   int result = isRoughly1337(p2);
   Expect.equals(1, result);
 
-  free(p2);
+  calloc.free(p2);
 }
 
 typedef NativeFloatToVoid = Void Function(Float);
diff --git a/tests/ffi_2/generator/structs_by_value_tests_generator.dart b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
index f3f9f02..7bd7c83 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
@@ -197,7 +197,7 @@
         return "${dartType} ${variableName};\n";
 
       case StructType:
-        return "${dartType} ${variableName} = allocate<$dartType>().ref;\n";
+        return "${dartType} ${variableName} = calloc<$dartType>().ref;\n";
     }
 
     throw Exception("Not implemented for ${this.runtimeType}");
@@ -243,7 +243,7 @@
         return "";
 
       case StructType:
-        return "free($variableName.addressOf);\n";
+        return "calloc.free($variableName.addressOf);\n";
     }
 
     throw Exception("Not implemented for ${this.runtimeType}");
@@ -485,7 +485,7 @@
       case TestType.structReturn:
         // Allocate a struct.
         buildReturnValue = """
-        ${returnValue.dartType} result = allocate<${returnValue.dartType}>().ref;
+        ${returnValue.dartType} result = calloc<${returnValue.dartType}>().ref;
 
         ${arguments.copyValueStatements("${dartName}_", "result.")}
         """;
@@ -749,6 +749,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -801,6 +802,7 @@
 import "package:ffi/ffi.dart";
 
 import 'callback_tests_utils.dart';
+import 'calloc.dart';
 
 // Reuse the struct classes.
 import 'function_structs_by_value_generated_test.dart';
diff --git a/tests/ffi_2/null_test.dart b/tests/ffi_2/null_test.dart
index 303499c..fb51f94 100644
--- a/tests/ffi_2/null_test.dart
+++ b/tests/ffi_2/null_test.dart
@@ -20,6 +20,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 import 'ffi_test_helpers.dart';
 
@@ -40,17 +41,17 @@
 
 void testPointerStoreNull() {
   int i = null;
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   Expect.throws(() => p.value = i);
-  free(p);
+  calloc.free(p);
   double d = null;
-  Pointer<Float> p2 = allocate();
+  Pointer<Float> p2 = calloc();
   Expect.throws(() => p2.value = d);
-  free(p2);
+  calloc.free(p2);
   Pointer<Void> x = null;
-  Pointer<Pointer<Void>> p3 = allocate();
+  Pointer<Pointer<Void>> p3 = calloc();
   Expect.throws(() => p3.value = x);
-  free(p3);
+  calloc.free(p3);
 }
 
 void testEquality() {
@@ -61,7 +62,7 @@
 
 /// With extension methods, the receiver position can be null.
 testNullReceivers() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
 
   Pointer<Int8> p4 = null;
   Expect.throws(() => Expect.equals(10, p4.value));
@@ -74,11 +75,11 @@
   Pointer<Foo> p6 = null;
   Expect.throws(() => Expect.equals(10, p6.ref));
 
-  free(p);
+  calloc.free(p);
 }
 
 testNullIndices() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
 
   Expect.throws(() => Expect.equals(10, p[null]));
   Expect.throws(() => p[null] = 10);
@@ -90,13 +91,13 @@
   Pointer<Foo> p6 = p.cast();
   Expect.throws(() => Expect.equals(10, p6[null]));
 
-  free(p);
+  calloc.free(p);
 }
 
 testNullArguments() {
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   Expect.throws(() => p.value = null);
-  free(p);
+  calloc.free(p);
 }
 
 class Foo extends Struct {
diff --git a/tests/ffi_2/regress_37254_test.dart b/tests/ffi_2/regress_37254_test.dart
index 6ba796f..e73562d 100644
--- a/tests/ffi_2/regress_37254_test.dart
+++ b/tests/ffi_2/regress_37254_test.dart
@@ -65,34 +65,36 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+
 // ===== a.value = b ======
 // The tests follow table cells left to right, top to bottom.
 void store1() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store2() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
   final Pointer<NativeType> b =
-      allocate<Int8>(); // Reified Pointer<Int8> at runtime.
+      calloc<Int8>(); // Reified Pointer<Int8> at runtime.
 
   // Successful implicit downcast of argument at runtime.
   // Should succeed now, should statically be rejected when NNBD lands.
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store3() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   // Failing implicit downcast of argument at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
@@ -100,124 +102,124 @@
     a.value = b;
   });
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store5() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   final Pointer<NativeType> b =
-      allocate<Int8>(); // Reified as Pointer<Int8> at runtime.
+      calloc<Int8>(); // Reified as Pointer<Int8> at runtime.
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store6() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   // Fails on type check of argument.
   Expect.throws(() {
     a.value = b;
   });
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store7() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
-  final Pointer<Int8> b = allocate<Int8>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
+  final Pointer<Int8> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store8() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   // Reified as Pointer<Int8> at runtime.
-  final Pointer<NativeType> b = allocate<Int8>();
+  final Pointer<NativeType> b = calloc<Int8>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 void store9() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
-  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
+  final Pointer<NativeType> b = calloc<Int8>().cast<Pointer<NativeType>>();
 
   a.value = b;
 
-  free(a);
-  free(b);
+  calloc.free(a);
+  calloc.free(b);
 }
 
 // ====== b = a.value ======
 // The tests follow table cells left to right, top to bottom.
 void load1() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
 
   Pointer<Int8> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load2() {
-  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<Int8>> a = calloc<Pointer<Int8>>();
 
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load3() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   Pointer<Int8> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<Int8>>();
 
   // Return value runtime type is Pointer<Int8>.
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void load5() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   // Failing implicit downcast of return value at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
@@ -225,16 +227,16 @@
     Pointer<Int8> b = a.value;
   });
 
-  free(a);
+  calloc.free(a);
 }
 
 void load6() {
-  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = calloc<Pointer<NativeType>>();
 
   Pointer<NativeType> b = a.value;
   Expect.type<Pointer<NativeType>>(b);
 
-  free(a);
+  calloc.free(a);
 }
 
 void main() {
diff --git a/tests/ffi_2/regress_39885_test.dart b/tests/ffi_2/regress_39885_test.dart
index 7d960f2..ef73ca7 100644
--- a/tests/ffi_2/regress_39885_test.dart
+++ b/tests/ffi_2/regress_39885_test.dart
@@ -3,12 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:ffi';
-import "package:ffi/ffi.dart" show allocate, free;
+
+import "package:ffi/ffi.dart";
+
+import 'calloc.dart';
 
 main() {
-  final data = allocate<Uint8>(count: 3);
+  final data = calloc<Uint8>(3);
   for (int i = 0; i < 3; ++i) {
     data.elementAt(i).value = 1;
   }
-  free(data);
+  calloc.free(data);
 }
diff --git a/tests/ffi_2/regress_43693_test.dart b/tests/ffi_2/regress_43693_test.dart
index a30a118..b589b0c 100644
--- a/tests/ffi_2/regress_43693_test.dart
+++ b/tests/ffi_2/regress_43693_test.dart
@@ -9,6 +9,7 @@
 import 'package:ffi/ffi.dart';
 import 'package:expect/expect.dart';
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 class Struct43693 extends Struct {
@@ -27,10 +28,10 @@
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
 void main() {
-  final myStructs = allocate<Struct43693>();
+  final myStructs = calloc<Struct43693>();
   myStructs[0].somePtr = nullptr;
   myStructs[0].someValue = 0xAAAAAAAABBBBBBBB;
   final result = readMyStructSomeValue(myStructs);
   Expect.equals(0xAAAAAAAABBBBBBBB, result);
-  free(myStructs);
+  calloc.free(myStructs);
 }
diff --git a/tests/ffi_2/structs_nested_test.dart b/tests/ffi_2/structs_nested_test.dart
index 7083044..3a69edb 100644
--- a/tests/ffi_2/structs_nested_test.dart
+++ b/tests/ffi_2/structs_nested_test.dart
@@ -11,6 +11,7 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
@@ -48,16 +49,16 @@
 }
 
 void testAllocate() {
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   Expect.type<Pointer<Struct8BytesNestedInt>>(p);
   print(p);
-  free(p);
+  calloc.free(p);
 }
 
 /// Test that reading does not segfault, even uninitialized.
 void testRead() {
   print("read");
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   print(p);
   print(p.ref.runtimeType);
   print(p.ref.addressOf);
@@ -65,13 +66,13 @@
   print(p.ref.a0.runtimeType);
   print(p.ref.a0.addressOf);
   print(p.ref.a0.a0);
-  free(p);
+  calloc.free(p);
   print("read");
 }
 
 void testWrite() {
   print("write");
-  final p = allocate<Struct8BytesNestedInt>(count: 2);
+  final p = calloc<Struct8BytesNestedInt>(2);
   p[0].a0.a0 = 12;
   p[0].a0.a1 = 13;
   p[0].a1.a0 = 14;
@@ -88,18 +89,18 @@
   Expect.equals(17, p[1].a0.a1);
   Expect.equals(18, p[1].a1.a0);
   Expect.equals(19, p[1].a1.a1);
-  free(p);
+  calloc.free(p);
   print("written");
 }
 
 void testCopy() {
   print("copy");
-  final p = allocate<Struct8BytesNestedInt>();
+  final p = calloc<Struct8BytesNestedInt>();
   p.ref.a0.a0 = 12;
   p.ref.a0.a1 = 13;
   p.ref.a1 = p.ref.a0;
   Expect.equals(12, p.ref.a1.a0);
   Expect.equals(13, p.ref.a1.a1);
-  free(p);
+  calloc.free(p);
   print("copied");
 }
diff --git a/tests/ffi_2/structs_test.dart b/tests/ffi_2/structs_test.dart
index 263d562..2759056 100644
--- a/tests/ffi_2/structs_test.dart
+++ b/tests/ffi_2/structs_test.dart
@@ -11,9 +11,10 @@
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
-import 'ffi_test_helpers.dart';
+import 'calloc.dart';
 import 'coordinate_bare.dart' as bare;
 import 'coordinate.dart';
+import 'ffi_test_helpers.dart';
 
 void main() {
   for (int i = 0; i < 100; i++) {
@@ -28,9 +29,12 @@
 
 /// allocates each coordinate separately in c memory
 void testStructAllocate() {
-  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
-  Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf;
-  Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf;
+  Pointer<Coordinate> c1 =
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
+  Pointer<Coordinate> c2 =
+      Coordinate.allocate(calloc, 20.0, 20.0, c1).addressOf;
+  Pointer<Coordinate> c3 =
+      Coordinate.allocate(calloc, 30.0, 30.0, c2).addressOf;
   c1.ref.next = c3;
 
   Coordinate currentCoordinate = c1.ref;
@@ -42,14 +46,14 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
-  free(c2);
-  free(c3);
+  calloc.free(c1);
+  calloc.free(c2);
+  calloc.free(c3);
 }
 
 /// allocates coordinates consecutively in c memory
 void testStructFromAddress() {
-  Pointer<Coordinate> c1 = allocate(count: 3);
+  Pointer<Coordinate> c1 = calloc(3);
   Pointer<Coordinate> c2 = c1.elementAt(1);
   Pointer<Coordinate> c3 = c1.elementAt(2);
   c1.ref
@@ -74,24 +78,24 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1);
+  calloc.free(c1);
 }
 
 void testStructWithNulls() {
   Pointer<Coordinate> coordinate =
-      Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
+      Coordinate.allocate(calloc, 10.0, 10.0, nullptr).addressOf;
   Expect.equals(coordinate.ref.next, nullptr);
   coordinate.ref.next = coordinate;
   Expect.notEquals(coordinate.ref.next, nullptr);
   coordinate.ref.next = nullptr;
   Expect.equals(coordinate.ref.next, nullptr);
-  free(coordinate);
+  calloc.free(coordinate);
 }
 
 void testBareStruct() {
   int structSize = sizeOf<Double>() * 2 + sizeOf<IntPtr>();
   bare.Coordinate c1 =
-      allocate<Uint8>(count: structSize * 3).cast<bare.Coordinate>().ref;
+      calloc<Uint8>(structSize * 3).cast<bare.Coordinate>().ref;
   bare.Coordinate c2 =
       c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().ref;
   bare.Coordinate c3 =
@@ -115,19 +119,19 @@
   currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  free(c1.addressOf);
+  calloc.free(c1.addressOf);
 }
 
 void testTypeTest() {
-  Coordinate c = Coordinate.allocate(10, 10, nullptr);
+  Coordinate c = Coordinate.allocate(calloc, 10, 10, nullptr);
   Expect.isTrue(c is Struct);
   Expect.isTrue(c.addressOf is Pointer<Coordinate>);
-  free(c.addressOf);
+  calloc.free(c.addressOf);
 }
 
 void testUtf8() {
   final String test = 'Hasta Mañana';
   final Pointer<Utf8> medium = Utf8.toUtf8(test);
   Expect.equals(test, Utf8.fromUtf8(medium));
-  free(medium);
+  calloc.free(medium);
 }
diff --git a/tests/ffi_2/variance_function_test.dart b/tests/ffi_2/variance_function_test.dart
index d6e6378..f53cdfc 100644
--- a/tests/ffi_2/variance_function_test.dart
+++ b/tests/ffi_2/variance_function_test.dart
@@ -12,11 +12,12 @@
 
 import 'dart:ffi';
 
-import 'dylib_utils.dart';
-
 import "package:expect/expect.dart";
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
+import 'dylib_utils.dart';
+
 typedef Int64PointerParamOpDart = void Function(Pointer<Int64>);
 typedef Int64PointerParamOp = Void Function(Pointer<Int64>);
 typedef NaTyPointerParamOpDart = void Function(Pointer<NativeType>);
@@ -38,19 +39,19 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<Int64PointerParamOp>>(paramOpName);
   final f = fp.asFunction<Int64PointerParamOpDart>();
-  final arg = allocate<Int64>();
+  final arg = calloc<Int64>();
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 void paramInvariant2() {
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final arg = allocate<Int64>().cast<NativeType>();
+  final arg = calloc<Int64>().cast<NativeType>();
   Expect.type<Pointer<NativeType>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 // Pass a statically and dynamically subtyped argument.
@@ -58,10 +59,10 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final arg = allocate<Int64>();
+  final arg = calloc<Int64>();
   Expect.type<Pointer<Int64>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 // Pass a statically subtyped but dynamically invariant argument.
@@ -69,10 +70,10 @@
   final fp =
       ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
   final f = fp.asFunction<NaTyPointerParamOpDart>();
-  final Pointer<NativeType> arg = allocate<Int64>();
+  final Pointer<NativeType> arg = calloc<Int64>();
   Expect.type<Pointer<Int64>>(arg);
   f(arg);
-  free(arg);
+  calloc.free(arg);
 }
 
 void returnInvariant1() {
@@ -220,7 +221,7 @@
 }
 
 void fromFunctionTests() {
-  data = allocate();
+  data = calloc();
   for (int i = 0; i < 100; ++i) {
     callbackParamInvariant1(); // Pointer<Int64> invariant
     callbackParamInvariant2(); // Pointer<NativeType> invariant
@@ -229,7 +230,7 @@
     callbackReturnInvariant1(); // Pointer<Int64> invariant
     callbackReturnInvariant2(); // Pointer<NativeType> invariant
   }
-  free(data);
+  calloc.free(data);
 }
 
 void main() {
diff --git a/tests/ffi_2/vmspecific_enable_ffi_test.dart b/tests/ffi_2/vmspecific_enable_ffi_test.dart
index f44753d..ce90607 100644
--- a/tests/ffi_2/vmspecific_enable_ffi_test.dart
+++ b/tests/ffi_2/vmspecific_enable_ffi_test.dart
@@ -7,11 +7,14 @@
 // VMOptions=--enable-ffi=false
 
 import 'dart:ffi'; //# 01: compile-time error
+
 import 'package:ffi/ffi.dart'; //# 01: compile-time error
 
+import 'calloc.dart'; //# 01: compile-time error
+
 void main() {
   Pointer<Int8> p = //# 01: compile-time error
-      allocate(); //# 01: compile-time error
+      calloc(); //# 01: compile-time error
   print(p.address); //# 01: compile-time error
-  free(p); //# 01: compile-time error
+  calloc.free(p); //# 01: compile-time error
 }
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index ebbe474..f1db86e 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -10,6 +10,7 @@
 
 import "package:ffi/ffi.dart";
 
+import 'calloc.dart';
 import 'dylib_utils.dart';
 
 void main() {
@@ -53,6 +54,8 @@
   testEmptyStructAsFunctionReturn();
   testEmptyStructFromFunctionArgument();
   testEmptyStructFromFunctionReturn();
+  testAllocateGeneric();
+  testAllocateNativeType();
 }
 
 typedef Int8UnOp = Int8 Function(Int8);
@@ -65,20 +68,20 @@
     return result;
   }
 
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 123;
   Pointer loseType = p;
   generic(loseType);
-  free(p);
+  calloc.free(p);
 }
 
 void testGetGeneric2() {
   T generic<T extends Object>() {
-    Pointer<Int8> p = allocate();
+    Pointer<Int8> p = calloc();
     p.value = 123;
     T result;
     result = p.value; //# 21: compile-time error
-    free(p);
+    calloc.free(p);
     return result;
   }
 
@@ -86,12 +89,12 @@
 }
 
 void testGetVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast();
 
   p2.value; //# 22: compile-time error
 
-  free(p1);
+  calloc.free(p1);
 }
 
 void testGetNativeFunction() {
@@ -104,14 +107,14 @@
 }
 
 void testGetTypeMismatch() {
-  Pointer<Pointer<Int16>> p = allocate();
+  Pointer<Pointer<Int16>> p = calloc();
   Pointer<Int16> typedNull = nullptr;
   p.value = typedNull;
 
   // this fails to compile due to type mismatch
   Pointer<Int8> p2 = p.value; //# 25: compile-time error
 
-  free(p);
+  calloc.free(p);
 }
 
 void testSetGeneric() {
@@ -119,30 +122,30 @@
     p.value = 123; //# 26: compile-time error
   }
 
-  Pointer<Int8> p = allocate();
+  Pointer<Int8> p = calloc();
   p.value = 123;
   Pointer loseType = p;
   generic(loseType);
-  free(p);
+  calloc.free(p);
 }
 
 void testSetGeneric2() {
   void generic<T extends Object>(T arg) {
-    Pointer<Int8> p = allocate();
+    Pointer<Int8> p = calloc();
     p.value = arg; //# 27: compile-time error
-    free(p);
+    calloc.free(p);
   }
 
   generic<int>(123);
 }
 
 void testSetVoid() {
-  Pointer<IntPtr> p1 = allocate();
+  Pointer<IntPtr> p1 = calloc();
   Pointer<Void> p2 = p1.cast();
 
   p2.value = 1234; //# 28: compile-time error
 
-  free(p1);
+  calloc.free(p1);
 }
 
 void testSetNativeFunction() {
@@ -157,16 +160,16 @@
 
 void testSetTypeMismatch() {
   // the pointer to pointer types must match up
-  Pointer<Int8> pHelper = allocate();
+  Pointer<Int8> pHelper = calloc();
   pHelper.value = 123;
 
-  Pointer<Pointer<Int16>> p = allocate();
+  Pointer<Pointer<Int16>> p = calloc();
 
   // this fails to compile due to type mismatch
   p.value = pHelper; //# 40: compile-time error
 
-  free(pHelper);
-  free(p);
+  calloc.free(pHelper);
+  calloc.free(p);
 }
 
 void testAsFunctionGeneric() {
@@ -475,6 +478,8 @@
 
 class IStruct implements Struct {} //# 815: compile-time error
 
+class IOpaque implements Opaque {} //# 816: compile-time error
+
 class MyClass {
   int x;
   MyClass(this.x);
@@ -550,3 +555,17 @@
 class HasNestedEmptyStruct extends Struct {
   EmptyStruct nestedEmptyStruct; //# 1106: compile-time error
 }
+
+void testAllocateGeneric() {
+  Pointer<T> generic<T extends NativeType>() {
+    Pointer<T> pointer = nullptr;
+    pointer = calloc(); //# 1320: compile-time error
+    return pointer;
+  }
+
+  Pointer p = generic<Int64>();
+}
+
+void testAllocateNativeType() {
+  calloc(); //# 1321: compile-time error
+}
diff --git a/tests/language/class/override_inference_error_test.dart b/tests/language/class/override_inference_error_test.dart
index 65bcae6..14e215f 100644
--- a/tests/language/class/override_inference_error_test.dart
+++ b/tests/language/class/override_inference_error_test.dart
@@ -200,8 +200,6 @@
   //   ^
   // [analyzer] COMPILE_TIME_ERROR.MISSING_DEFAULT_VALUE_FOR_PARAMETER
   // [cfe] unspecified
-  //   ^
-  // [analyzer] STATIC_WARNING.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED
 }
 
 // Inherits type variables, even with different names.
diff --git a/tests/language/extension_methods/static_extension_this_not_promoted_error_test.dart b/tests/language/extension_methods/static_extension_this_not_promoted_error_test.dart
new file mode 100644
index 0000000..342ccca
--- /dev/null
+++ b/tests/language/extension_methods/static_extension_this_not_promoted_error_test.dart
@@ -0,0 +1,55 @@
+// 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 test verifies that attempts to promote the type of `this` inside an
+// extension method have no effect.
+
+void f(dynamic d) {}
+
+class C {
+  int? cProp;
+}
+
+extension on C? {
+  void testCQuestion() {
+    if (this != null) {
+      f(this.cProp);
+      //^^^^
+      // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+      //     ^
+      // [cfe] Property 'cProp' cannot be accessed on 'C?' because it is potentially null.
+      f(cProp);
+      //^^^^^
+      // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+      // [cfe] Property 'cProp' cannot be accessed on 'C?' because it is potentially null.
+    }
+  }
+}
+
+class D extends C {
+  int? dProp;
+}
+
+extension on C {
+  void testC() {
+    if (this is D) {
+      f(this.dProp);
+      //     ^^^^^
+      // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
+      // [cfe] The getter 'dProp' isn't defined for the class 'C'.
+      f(dProp);
+      //^^^^^
+      // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER
+      // [cfe] The getter 'dProp' isn't defined for the class 'C'.
+    }
+  }
+}
+
+main() {
+  C().testCQuestion();
+  C().testC();
+  D().testCQuestion();
+  D().testC();
+  (null as C?).testCQuestion();
+}
diff --git a/tests/language/super/bound_closure_test.dart b/tests/language/super/bound_closure_test.dart
index 554b0e2..5061145 100644
--- a/tests/language/super/bound_closure_test.dart
+++ b/tests/language/super/bound_closure_test.dart
@@ -72,8 +72,7 @@
   fooIntercept27() => confuse(super.lastWhere)(0);
   fooIntercept28() => confuse(super.lastWhere)(3, orElse: 77);
 
-  // Warning: overrides should not change default parameter values.
-  bar([var optional]) => -1; //       //# 01: static type warning
+  bar([var optional]) => -1; //       //# 01: ok
   bar2({namedOptional}) => -1; //   //# 01: continued
   bar3(x, [var optional]) => -1; //   //# 01: continued
   bar4(x, {namedOptional}) => -1; //# 01: continued
diff --git a/tools/VERSION b/tools/VERSION
index 82ddcdf..5fccaeb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 223
+PRERELEASE 224
 PRERELEASE_PATCH 0
\ No newline at end of file