Version 2.14.0-135.0.dev

Merge commit '2b507fb850ff2d66a16417913e09f1a72a261a72' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 7773b42..dd474e4 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-05-20T07:53:18.817456",
+  "generated": "2021-05-20T11:33:30.068787",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
@@ -779,7 +779,7 @@
       "name": "wasm",
       "rootUri": "../pkg/wasm",
       "packageUri": "lib/",
-      "languageVersion": "2.10"
+      "languageVersion": "2.12"
     },
     {
       "name": "watcher",
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index b286788..c995737 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 139;
+  static const int DATA_VERSION = 140;
 
   /// The length of the list returned by [_computeDeclaredVariablesSignature].
   static const int _declaredVariablesSignatureLength = 4;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 351b628..e31e14d 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -18,7 +18,6 @@
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
-import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/constant/compute.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
@@ -957,7 +956,7 @@
 
   /// A list containing all of the extensions contained in this compilation
   /// unit.
-  List<ExtensionElement> _extensions = _Sentinel.extensionElement;
+  List<ExtensionElement> _extensions = const [];
 
   /// A list containing all of the top-level functions contained in this
   /// compilation unit.
@@ -974,7 +973,7 @@
 
   /// A list containing all of the type aliases contained in this compilation
   /// unit.
-  List<TypeAliasElement> _typeAliases = _Sentinel.typeAliasElement;
+  List<TypeAliasElement> _typeAliases = const [];
 
   /// A list containing all of the classes contained in this compilation unit.
   List<ClassElement> _types = const [];
@@ -1035,29 +1034,6 @@
 
   @override
   List<ExtensionElement> get extensions {
-    if (!identical(_extensions, _Sentinel.extensionElement)) {
-      return _extensions;
-    }
-
-    if (linkedNode != null) {
-      var containerRef = reference!.getChild('@extension');
-      _extensions = <ExtensionElement>[];
-      var nextUnnamedExtensionId = 0;
-      for (var node in _linkedUnitDeclarations) {
-        if (node is ExtensionDeclarationImpl) {
-          var nameIdentifier = node.name;
-          var refName = nameIdentifier != null
-              ? nameIdentifier.name
-              : 'extension-${nextUnnamedExtensionId++}';
-          var reference = containerRef.getChild(refName);
-          var element = node.declaredElement;
-          element ??= ExtensionElementImpl.forLinkedNode(this, reference, node);
-          _extensions.add(element);
-        }
-      }
-      return _extensions;
-    }
-
     return _extensions;
   }
 
@@ -1161,31 +1137,6 @@
 
   @override
   List<TypeAliasElement> get typeAliases {
-    if (!identical(_typeAliases, _Sentinel.typeAliasElement)) {
-      return _typeAliases;
-    }
-
-    if (linkedNode != null) {
-      var containerRef = reference!.getChild('@typeAlias');
-      _typeAliases = <TypeAliasElement>[];
-      for (var node in _linkedUnitDeclarations) {
-        String name;
-        if (node is FunctionTypeAlias) {
-          name = node.name.name;
-        } else if (node is GenericTypeAlias) {
-          name = node.name.name;
-        } else {
-          continue;
-        }
-
-        var reference = containerRef.getChild(name);
-        var element = node.declaredElement as TypeAliasElement?;
-        element ??= TypeAliasElementImpl.forLinkedNodeFactory(
-            this, reference, node as TypeAlias);
-        _typeAliases.add(element);
-      }
-    }
-
     return _typeAliases;
   }
 
@@ -1219,10 +1170,6 @@
     _types = types;
   }
 
-  List<CompilationUnitMember> get _linkedUnitDeclarations {
-    return linkedContext!.unit.declarations;
-  }
-
   @override
   bool operator ==(Object object) =>
       object is CompilationUnitElementImpl && source == object.source;
@@ -3112,13 +3059,6 @@
   /// element.
   ExtensionElementImpl(String? name, int nameOffset) : super(name, nameOffset);
 
-  /// Initialize using the given linked information.
-  ExtensionElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
-      Reference reference, ExtensionDeclarationImpl linkedNode)
-      : super.forLinkedNode(enclosing, reference, linkedNode) {
-    linkedNode.declaredElement = this;
-  }
-
   @override
   List<PropertyAccessorElement> get accessors {
     return _accessors;
@@ -3149,13 +3089,6 @@
 
   DartType get extendedTypeInternal {
     linkedData?.read(this);
-    if (_extendedType != null) return _extendedType!;
-
-    if (linkedNode != null) {
-      final linkedNode = this.linkedNode as ExtensionDeclaration;
-      return _extendedType = linkedNode.extendedType.typeOrThrow;
-    }
-
     return _extendedType!;
   }
 
@@ -3173,10 +3106,7 @@
 
   @override
   String get identifier {
-    if (linkedData != null) {
-      return linkedData!.reference.name;
-    }
-    if (linkedNode != null) {
+    if (reference != null) {
       return reference!.name;
     }
     return super.identifier;
@@ -3208,23 +3138,6 @@
   }
 
   @override
-  String? get name {
-    if (linkedNode != null) {
-      return (linkedNode as ExtensionDeclaration).name?.name;
-    }
-    return super.name;
-  }
-
-  @override
-  int get nameOffset {
-    if (linkedNode != null) {
-      return enclosingUnit.linkedContext!.getNameOffset(linkedNode!);
-    }
-
-    return super.nameOffset;
-  }
-
-  @override
   List<TypeParameterElement> get typeParameters {
     linkedData?.read(this);
     return super.typeParameters;
@@ -3433,12 +3346,6 @@
   FunctionTypeAliasElementImpl(String name, int nameOffset)
       : super(name, nameOffset);
 
-  FunctionTypeAliasElementImpl.forLinkedNode(
-    CompilationUnitElementImpl enclosingUnit,
-    Reference reference,
-    TypeAlias linkedNode,
-  ) : super.forLinkedNode(enclosingUnit, reference, linkedNode);
-
   @Deprecated('Use aliasedElement instead')
   @override
   GenericFunctionTypeElementImpl get function {
@@ -3562,12 +3469,6 @@
     );
   }
 
-  @override
-  List<TypeParameterElement> get typeParameters {
-    // TODO(scheglov) remove the method
-    return _typeParameterElements;
-  }
-
   /// Set the type parameters defined by this function type element to the given
   /// [typeParameters].
   set typeParameters(List<TypeParameterElement> typeParameters) {
@@ -5561,40 +5462,6 @@
 
   TypeAliasElementImpl(String name, int nameOffset) : super(name, nameOffset);
 
-  TypeAliasElementImpl.forLinkedNode(
-    CompilationUnitElementImpl enclosingUnit,
-    Reference reference,
-    TypeAlias linkedNode,
-  ) : super.forLinkedNode(enclosingUnit, reference, linkedNode) {
-    var nameNode = linkedNode is FunctionTypeAliasImpl
-        ? linkedNode.name
-        : (linkedNode as GenericTypeAliasImpl).name;
-    nameNode.staticElement = this;
-  }
-
-  factory TypeAliasElementImpl.forLinkedNodeFactory(
-    CompilationUnitElementImpl enclosingUnit,
-    Reference reference,
-    TypeAlias linkedNode,
-  ) {
-    if (linkedNode is FunctionTypeAlias) {
-      // ignore: deprecated_member_use_from_same_package
-      return FunctionTypeAliasElementImpl.forLinkedNode(
-          enclosingUnit, reference, linkedNode);
-    } else {
-      var aliasedType = (linkedNode as GenericTypeAlias).type;
-      if (aliasedType is GenericFunctionType ||
-          !enclosingUnit.isNonFunctionTypeAliasesEnabled) {
-        // ignore: deprecated_member_use_from_same_package
-        return FunctionTypeAliasElementImpl.forLinkedNode(
-            enclosingUnit, reference, linkedNode);
-      } else {
-        return TypeAliasElementImpl.forLinkedNode(
-            enclosingUnit, reference, linkedNode);
-      }
-    }
-  }
-
   @override
   ElementImpl? get aliasedElement {
     linkedData?.read(this);
@@ -5609,24 +5476,6 @@
   @override
   DartType get aliasedType {
     linkedData?.read(this);
-    if (_aliasedType != null) return _aliasedType!;
-
-    final linkedNode = this.linkedNode;
-    if (linkedNode is GenericTypeAlias) {
-      var typeNode = linkedNode.type;
-      if (isNonFunctionTypeAliasesEnabled) {
-        _aliasedType = typeNode.type;
-        assert(_aliasedType != null);
-      } else if (typeNode is GenericFunctionType) {
-        _aliasedType = typeNode.type;
-        assert(_aliasedType != null);
-      } else {
-        _aliasedType = _errorFunctionType(NullabilitySuffix.none);
-      }
-    } else if (linkedNode is FunctionTypeAlias) {
-      _aliasedType = (_aliasedElement as GenericFunctionTypeElementImpl).type;
-    }
-
     return _aliasedType!;
   }
 
@@ -5658,22 +5507,10 @@
 
   @override
   String get name {
-    if (linkedNode != null) {
-      return reference!.name;
-    }
     return super.name!;
   }
 
   @override
-  int get nameOffset {
-    if (linkedNode != null) {
-      return enclosingUnit.linkedContext!.getNameOffset(linkedNode!);
-    }
-
-    return super.nameOffset;
-  }
-
-  @override
   List<TypeParameterElement> get typeParameters {
     linkedData?.read(this);
     return super.typeParameters;
@@ -5784,12 +5621,6 @@
   /// [offset].
   TypeParameterElementImpl(String name, int offset) : super(name, offset);
 
-  TypeParameterElementImpl.forLinkedNode(
-      ElementImpl enclosing, TypeParameterImpl linkedNode)
-      : super.forLinkedNode(enclosing, null, linkedNode) {
-    linkedNode.name.staticElement = this;
-  }
-
   /// Initialize a newly created synthetic type parameter element to have the
   /// given [name], and with [synthetic] set to true.
   TypeParameterElementImpl.synthetic(String name) : super(name, -1) {
@@ -5805,13 +5636,6 @@
   }
 
   DartType? get boundInternal {
-    if (_bound != null) return _bound;
-
-    final linkedNode = this.linkedNode;
-    if (linkedNode is TypeParameter) {
-      return _bound = linkedNode.bound?.type;
-    }
-
     return _bound;
   }
 
@@ -5830,22 +5654,9 @@
 
   @override
   String get name {
-    if (linkedNode != null) {
-      var node = linkedNode as TypeParameter;
-      return node.name.name;
-    }
     return super.name!;
   }
 
-  @override
-  int get nameOffset {
-    if (linkedNode != null) {
-      return enclosingUnit.linkedContext!.getNameOffset(linkedNode!);
-    }
-
-    return super.nameOffset;
-  }
-
   Variance get variance {
     return _variance ?? Variance.covariant;
   }
@@ -5889,35 +5700,15 @@
 /// Mixin representing an element which can have type parameters.
 mixin TypeParameterizedElementMixin
     implements _ExistingElementImpl, TypeParameterizedElement {
-  /// A cached list containing the type parameters declared by this element
-  /// directly, or `null` if the elements have not been created yet. This does
-  /// not include type parameters that are declared by any enclosing elements.
-  List<TypeParameterElement> _typeParameterElements =
-      _Sentinel.typeParameterElement;
+  /// The type parameters declared by this element directly. This does not
+  /// include type parameters that are declared by any enclosing elements.
+  List<TypeParameterElement> _typeParameterElements = const [];
 
   @override
   bool get isSimplyBounded => true;
 
   @override
   List<TypeParameterElement> get typeParameters {
-    if (!identical(_typeParameterElements, _Sentinel.typeParameterElement)) {
-      return _typeParameterElements;
-    }
-
-    if (linkedNode != null) {
-      var typeParameters = linkedContext!.getTypeParameters2(linkedNode!);
-      if (typeParameters == null) {
-        return _typeParameterElements = const [];
-      }
-      return _typeParameterElements = typeParameters.typeParameters
-          .cast<TypeParameterImpl>()
-          .map<TypeParameterElement>((node) {
-        var element = node.declaredElement;
-        element ??= TypeParameterElementImpl.forLinkedNode(this, node);
-        return element;
-      }).toList();
-    }
-
     return _typeParameterElements;
   }
 
@@ -6133,7 +5924,6 @@
   static final List<ElementAnnotation> elementAnnotation =
       List.unmodifiable([]);
   static final List<ExportElement> exportElement = List.unmodifiable([]);
-  static final List<ExtensionElement> extensionElement = List.unmodifiable([]);
   static final List<FieldElement> fieldElement = List.unmodifiable([]);
   @Deprecated('Use TypeAliasElement instead')
   static final List<FunctionTypeAliasElement> functionTypeAliasElement =
@@ -6142,7 +5932,4 @@
   static final List<MethodElement> methodElement = List.unmodifiable([]);
   static final List<PropertyAccessorElement> propertyAccessorElement =
       List.unmodifiable([]);
-  static final List<TypeAliasElement> typeAliasElement = List.unmodifiable([]);
-  static final List<TypeParameterElement> typeParameterElement =
-      List.unmodifiable([]);
 }
diff --git a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
index e4f5c28..c1c1a79 100644
--- a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
@@ -103,6 +103,7 @@
     }
 
     return NamedTypeBuilder(
+      type.linker,
       type.typeSystem,
       type.element,
       newTypeArguments ?? type.arguments,
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index 4d72f96..326f73a 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -536,6 +536,7 @@
     }
 
     return NamedTypeBuilder(
+      type.linker,
       type.typeSystem,
       type.element,
       arguments,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index ca2d949..c210b45 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -402,7 +402,6 @@
   int _classMembersLengthsIndex = 0;
 
   late List<Reference> exports;
-  var nextUnnamedExtensionId = 0;
 
   LibraryReader._({
     required LinkedElementFactory elementFactory,
@@ -655,7 +654,7 @@
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     var name = _reader.readOptionalStringReference();
-    var refName = name ?? 'extension-${nextUnnamedExtensionId++}';
+    var refName = _reader.readStringReference();
     var reference = unitReference.getChild('@extension').getChild(refName);
 
     var element = ExtensionElementImpl(name, -1);
@@ -1189,7 +1188,6 @@
     unitElement.uri = _reader.readOptionalStringReference();
     unitElement.isSynthetic = _reader.readBool();
 
-    nextUnnamedExtensionId = 0;
     _readClasses(unitElement, unitReference);
     _readEnums(unitElement, unitReference);
     _readExtensions(unitElement, unitReference);
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index e6ca6ed..769e3f2 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -195,9 +195,12 @@
   }
 
   void _writeExtensionElement(ExtensionElement element) {
+    element as ExtensionElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
 
     _sink._writeOptionalStringReference(element.name);
+    _sink._writeStringReference(element.reference!.name);
+
     _resolutionSink._writeAnnotationList(element.metadata);
 
     _writeTypeParameters(element.typeParameters, () {
@@ -790,16 +793,10 @@
 
   static FunctionType _toSyntheticFunctionType(FunctionType type) {
     var typeParameters = type.typeFormals;
-
     if (typeParameters.isEmpty) return type;
 
-    var onlySyntheticTypeParameters = typeParameters.every((e) {
-      return e is TypeParameterElementImpl && e.linkedNode == null;
-    });
-    if (onlySyntheticTypeParameters) return type;
-
-    var parameters = getFreshTypeParameters(typeParameters);
-    return parameters.applyToFunctionType(type);
+    var fresh = getFreshTypeParameters(typeParameters);
+    return fresh.applyToFunctionType(type);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 453957c..cdfde28 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -22,6 +23,7 @@
   var _hasCoreImport = false;
 
   _EnclosingContext _enclosingContext;
+  var _nextUnnamedExtensionId = 0;
 
   ElementBuilder({
     required LibraryBuilder libraryBuilder,
@@ -31,6 +33,12 @@
         _unitElement = unitElement,
         _enclosingContext = _EnclosingContext(unitReference, unitElement);
 
+  bool get _isNonFunctionTypeAliasesEnabled {
+    return _libraryElement.featureSet.isEnabled(
+      Feature.nonfunction_type_aliases,
+    );
+  }
+
   LibraryElementImpl get _libraryElement => _libraryBuilder.element;
 
   Linker get _linker => _libraryBuilder.linker;
@@ -39,11 +47,13 @@
     unit.declarations.accept(this);
     _unitElement.accessors = _enclosingContext.propertyAccessors;
     _unitElement.enums = _enclosingContext.enums;
+    _unitElement.extensions = _enclosingContext.extensions;
     _unitElement.functions = _enclosingContext.functions;
     _unitElement.mixins = _enclosingContext.mixins;
     _unitElement.topLevelVariables = _enclosingContext.properties
         .whereType<TopLevelVariableElementImpl>()
         .toList();
+    _unitElement.typeAliases = _enclosingContext.typeAliases;
     _unitElement.types = _enclosingContext.classes;
   }
 
@@ -193,12 +203,40 @@
   }
 
   @override
-  void visitExtensionDeclaration(ExtensionDeclaration node) {
-    var element = node.declaredElement as ExtensionElementImpl;
-    var holder = _buildClassMembers(element, node.members);
-    element.accessors = holder.propertyAccessors;
-    element.fields = holder.properties.whereType<FieldElement>().toList();
-    element.methods = holder.methods;
+  void visitExtensionDeclaration(covariant ExtensionDeclarationImpl node) {
+    var nodeName = node.name;
+    var name = nodeName?.name;
+    var nameOffset = nodeName?.offset ?? -1;
+
+    var element = ExtensionElementImpl(name, nameOffset);
+    element.metadata = _buildAnnotations(node.metadata);
+    _setCodeRange(element, node);
+
+    node.declaredElement = element;
+    _linker.elementNodes[element] = node;
+
+    var refName = name ?? 'extension-${_nextUnnamedExtensionId++}';
+    var reference = _enclosingContext.addExtension(refName, element);
+
+    if (name != null) {
+      _libraryBuilder.localScope.declare(name, reference);
+    }
+
+    var holder = _EnclosingContext(reference, element);
+    _withEnclosing(holder, () {
+      var typeParameters = node.typeParameters;
+      if (typeParameters != null) {
+        typeParameters.accept(this);
+        element.typeParameters = holder.typeParameters;
+      }
+    });
+
+    {
+      var holder = _buildClassMembers(element, node.members);
+      element.accessors = holder.propertyAccessors;
+      element.fields = holder.properties.whereType<FieldElement>().toList();
+      element.methods = holder.methods;
+    }
 
     node.extendedType.accept(this);
   }
@@ -374,21 +412,35 @@
   }
 
   @override
-  void visitFunctionTypeAlias(FunctionTypeAlias node) {
-    node.returnType?.accept(this);
-    node.typeParameters?.accept(this);
-    node.parameters.accept(this);
+  void visitFunctionTypeAlias(covariant FunctionTypeAliasImpl node) {
+    var nameNode = node.name;
+    var name = nameNode.name;
 
-    var element = node.declaredElement as TypeAliasElementImpl;
+    // ignore: deprecated_member_use_from_same_package
+    var element = FunctionTypeAliasElementImpl(name, nameNode.offset);
+    element.isFunctionTypeAliasBased = true;
+    element.metadata = _buildAnnotations(node.metadata);
+    _setCodeRange(element, node);
+
+    nameNode.staticElement = element;
+    _linker.elementNodes[element] = node;
+
+    var reference = _enclosingContext.addTypeAlias(name, element);
+    _libraryBuilder.localScope.declare(name, reference);
+
+    var holder = _EnclosingContext(reference, element);
+    _withEnclosing(holder, () {
+      node.typeParameters?.accept(this);
+      node.returnType?.accept(this);
+      node.parameters.accept(this);
+    });
 
     var aliasedElement = GenericFunctionTypeElementImpl.forOffset(
       node.name.offset,
     );
-    // TODO(scheglov) Use enclosing context?
-    aliasedElement.parameters = node.parameters.parameters
-        .map((parameterNode) => parameterNode.declaredElement!)
-        .toList();
+    aliasedElement.parameters = holder.parameters;
 
+    element.typeParameters = holder.typeParameters;
     element.aliasedElement = aliasedElement;
   }
 
@@ -463,13 +515,38 @@
   }
 
   @override
-  void visitGenericTypeAlias(GenericTypeAlias node) {
-    node.typeParameters?.accept(this);
-    node.type.accept(this);
+  void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) {
+    var nameNode = node.name;
+    var name = nameNode.name;
+
+    TypeAliasElementImpl element;
+    var aliasedType = node.type;
+    if (aliasedType is GenericFunctionType ||
+        !_isNonFunctionTypeAliasesEnabled) {
+      // ignore: deprecated_member_use_from_same_package
+      element = FunctionTypeAliasElementImpl(name, nameNode.offset);
+    } else {
+      element = TypeAliasElementImpl(name, nameNode.offset);
+    }
+    element.metadata = _buildAnnotations(node.metadata);
+    _setCodeRange(element, node);
+
+    nameNode.staticElement = element;
+    _linker.elementNodes[element] = node;
+
+    var reference = _enclosingContext.addTypeAlias(name, element);
+    _libraryBuilder.localScope.declare(name, reference);
+
+    var holder = _EnclosingContext(reference, element);
+    _withEnclosing(holder, () {
+      node.typeParameters?.accept(this);
+    });
+    element.typeParameters = holder.typeParameters;
 
     var typeNode = node.type;
+    typeNode.accept(this);
+
     if (typeNode is GenericFunctionTypeImpl) {
-      var element = node.declaredElement as TypeAliasElementImpl;
       element.aliasedElement =
           typeNode.declaredElement as GenericFunctionTypeElementImpl;
     }
@@ -1014,12 +1091,14 @@
   final List<ClassElementImpl> classes = [];
   final List<ConstructorElementImpl> constructors = [];
   final List<EnumElementImpl> enums = [];
+  final List<ExtensionElementImpl> extensions = [];
   final List<FunctionElementImpl> functions = [];
   final List<MethodElementImpl> methods = [];
   final List<MixinElementImpl> mixins = [];
   final List<ParameterElementImpl> parameters = [];
   final List<PropertyInducingElementImpl> properties = [];
   final List<PropertyAccessorElementImpl> propertyAccessors = [];
+  final List<TypeAliasElementImpl> typeAliases = [];
   final List<TypeParameterElementImpl> typeParameters = [];
   final bool hasConstConstructor;
 
@@ -1044,6 +1123,11 @@
     return _bindReference('@enum', name, element);
   }
 
+  Reference addExtension(String name, ExtensionElementImpl element) {
+    extensions.add(element);
+    return _bindReference('@extension', name, element);
+  }
+
   Reference addField(String name, FieldElementImpl element) {
     properties.add(element);
     return _bindReference('@field', name, element);
@@ -1087,6 +1171,11 @@
     return _bindReference('@variable', name, element);
   }
 
+  Reference addTypeAlias(String name, TypeAliasElementImpl element) {
+    typeAliases.add(element);
+    return _bindReference('@typeAlias', name, element);
+  }
+
   void addTypeParameter(String name, TypeParameterElementImpl element) {
     typeParameters.add(element);
     this.element.encloseElement(element);
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index be39cb7..318f25f 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -84,10 +84,6 @@
   /// Add top-level declaration of the library units to the local scope.
   void addLocalDeclarations() {
     for (var linkingUnit in context.units) {
-      var unitRef = reference.getChild('@unit').getChild(linkingUnit.uriStr);
-      var extensionRef = unitRef.getChild('@extension');
-      var typeAliasRef = unitRef.getChild('@typeAlias');
-      var nextUnnamedExtensionId = 0;
       for (var node in linkingUnit.unit.declarations) {
         if (node is ast.ClassDeclaration) {
           // Handled in ElementBuilder.
@@ -96,44 +92,13 @@
         } else if (node is ast.EnumDeclarationImpl) {
           // Handled in ElementBuilder.
         } else if (node is ast.ExtensionDeclarationImpl) {
-          var name = node.name?.name;
-          var refName = name ?? 'extension-${nextUnnamedExtensionId++}';
-
-          var reference = extensionRef.getChild(refName);
-          reference.node ??= node;
-
-          if (name != null) {
-            localScope.declare(name, reference);
-          }
-
-          ExtensionElementImpl.forLinkedNode(
-              linkingUnit.reference.element as CompilationUnitElementImpl,
-              reference,
-              node);
+          // Handled in ElementBuilder.
         } else if (node is ast.FunctionDeclarationImpl) {
           // Handled in ElementBuilder.
         } else if (node is ast.FunctionTypeAlias) {
-          var name = node.name.name;
-          var reference = typeAliasRef.getChild(name);
-          reference.node ??= node;
-          localScope.declare(name, reference);
-
-          var element = TypeAliasElementImpl.forLinkedNodeFactory(
-              linkingUnit.reference.element as CompilationUnitElementImpl,
-              reference,
-              node);
-          element.isFunctionTypeAliasBased = true;
+          // Handled in ElementBuilder.
         } else if (node is ast.GenericTypeAlias) {
-          var name = node.name.name;
-          var reference = typeAliasRef.getChild(name);
-          reference.node ??= node;
-
-          localScope.declare(name, reference);
-
-          TypeAliasElementImpl.forLinkedNodeFactory(
-              linkingUnit.reference.element as CompilationUnitElementImpl,
-              reference,
-              node);
+          // Handled in ElementBuilder.
         } else if (node is ast.MixinDeclarationImpl) {
           // Handled in ElementBuilder.
         } else if (node is ast.TopLevelVariableDeclaration) {
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 8987d12..65975220 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -216,7 +216,7 @@
     for (var library in builders.values) {
       library.resolveTypes(nodesToBuildType);
     }
-    VarianceBuilder().perform(this);
+    VarianceBuilder(this).perform();
     computeSimplyBounded(this);
     TypeAliasSelfReferenceFinder().perform(this);
     TypesBuilder(this).build(nodesToBuildType);
diff --git a/pkg/analyzer/lib/src/summary2/named_type_builder.dart b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
index 2e5eb2f..a7364a7 100644
--- a/pkg/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/type_visitor.dart';
+import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/type_builder.dart';
 
 /// The type builder for a [TypeName].
@@ -22,6 +23,9 @@
   static const _aliasedTypeKey = '_aliasedType';
   static DynamicTypeImpl get _dynamicType => DynamicTypeImpl.instance;
 
+  /// The linker that contains this type.
+  final Linker linker;
+
   /// The type system of the library with the type name.
   final TypeSystemImpl typeSystem;
 
@@ -44,11 +48,12 @@
   /// and set for the [node].
   DartType? _type;
 
-  NamedTypeBuilder(
-      this.typeSystem, this.element, this.arguments, this.nullabilitySuffix,
+  NamedTypeBuilder(this.linker, this.typeSystem, this.element, this.arguments,
+      this.nullabilitySuffix,
       {this.node});
 
   factory NamedTypeBuilder.of(
+    Linker linker,
     TypeSystemImpl typeSystem,
     TypeNameImpl node,
     Element element,
@@ -62,7 +67,8 @@
       arguments = <DartType>[];
     }
 
-    return NamedTypeBuilder(typeSystem, element, arguments, nullabilitySuffix,
+    return NamedTypeBuilder(
+        linker, typeSystem, element, arguments, nullabilitySuffix,
         node: node);
   }
 
@@ -147,7 +153,8 @@
       return this;
     }
 
-    return NamedTypeBuilder(typeSystem, element, arguments, nullabilitySuffix,
+    return NamedTypeBuilder(
+        linker, typeSystem, element, arguments, nullabilitySuffix,
         node: node);
   }
 
@@ -248,15 +255,13 @@
   }
 
   DartType _getAliasedType(TypeAliasElementImpl element) {
-    // If the element is not being linked, there is no reason (or a way,
-    // because the linked node might be read only partially) to go through
-    // its node - all its types have already been built.
-    if (element.linkedContext == null) {
+    var typedefNode = linker.getLinkingNode(element);
+
+    // If the element is not being linked, the types have already been built.
+    if (typedefNode == null) {
       return element.aliasedType;
     }
 
-    var typedefNode = element.linkedNode!;
-
     // Break a possible recursion.
     var existing = typedefNode.getProperty(_aliasedTypeKey) as DartType?;
     if (existing != null) {
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 150ac8d..9169ffb 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -140,7 +140,6 @@
 
     var element = node.declaredElement as ExtensionElementImpl;
 
-    _createTypeParameterElements(element, node.typeParameters);
     scope = TypeParameterScope(scope, element.typeParameters);
 
     node.typeParameters?.accept(this);
@@ -167,7 +166,6 @@
     var element = node.declaredElement as FieldFormalParameterElementImpl;
     element.parameters; // create elements
 
-    _createTypeParameterElements(element, node.typeParameters);
     scope = TypeParameterScope(scope, element.typeParameters);
 
     node.type?.accept(this);
@@ -190,10 +188,6 @@
     var element = node.declaredElement as ExecutableElementImpl;
     element.parameters; // create elements
 
-    _createTypeParameterElements(
-      element,
-      node.functionExpression.typeParameters,
-    );
     scope = TypeParameterScope(outerScope, element.typeParameters);
     LinkingNodeContext(node, scope);
 
@@ -216,7 +210,6 @@
 
     var element = node.declaredElement as TypeAliasElementImpl;
 
-    _createTypeParameterElements(element, node.typeParameters);
     scope = TypeParameterScope(outerScope, element.typeParameters);
 
     node.returnType?.accept(this);
@@ -238,7 +231,6 @@
     var element = node.declaredElement as ParameterElementImpl;
     element.parameters; // create elements
 
-    _createTypeParameterElements(element, node.typeParameters);
     scope = TypeParameterScope(scope, element.typeParameters);
 
     node.returnType?.accept(this);
@@ -275,7 +267,6 @@
 
     var element = node.declaredElement as TypeAliasElementImpl;
 
-    _createTypeParameterElements(element, node.typeParameters);
     scope = TypeParameterScope(outerScope, element.typeParameters);
 
     node.typeParameters?.accept(this);
@@ -304,8 +295,6 @@
     var element = node.declaredElement as ExecutableElementImpl;
     element.parameters; // create elements
 
-    _createTypeParameterElements(element, node.typeParameters);
-
     scope = TypeParameterScope(scope, element.typeParameters);
     LinkingNodeContext(node, scope);
 
@@ -405,6 +394,7 @@
       );
     } else {
       var builder = NamedTypeBuilder.of(
+        linker,
         _typeSystem,
         node,
         element,
@@ -422,9 +412,6 @@
       bound.accept(this);
       var element = node.declaredElement as TypeParameterElementImpl;
       element.bound = bound.type;
-      // TODO(scheglov) We should not need to do it here.
-      // Only in the element builder, eventually.z
-      linker.elementNodes[element] = node;
     }
   }
 
@@ -444,29 +431,6 @@
     node.mixinTypes.accept(this);
   }
 
-  void _createTypeParameterElement(
-    ElementImpl enclosingElement,
-    TypeParameterImpl node,
-  ) {
-    var element = TypeParameterElementImpl.forLinkedNode(
-      enclosingElement,
-      node,
-    );
-    node.name.staticElement = element;
-  }
-
-  void _createTypeParameterElements(
-    ElementImpl enclosingElement,
-    TypeParameterList? typeParameterList,
-  ) {
-    if (typeParameterList == null) return;
-
-    for (var typeParameter in typeParameterList.typeParameters) {
-      typeParameter as TypeParameterImpl;
-      _createTypeParameterElement(enclosingElement, typeParameter);
-    }
-  }
-
   NullabilitySuffix _getNullabilitySuffix(bool hasQuestion) {
     if (isNNBD) {
       if (hasQuestion) {
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 6023f77..4f9d087 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -81,10 +81,6 @@
       builder.build();
     }
 
-    for (var declaration in nodes.declarations) {
-      _declaration(declaration);
-    }
-
     // TODO(scheglov) generalize
     _linker.elementNodes.forEach((element, node) {
       if (element is GenericFunctionTypeElementImpl &&
@@ -96,6 +92,10 @@
       }
     });
 
+    for (var declaration in nodes.declarations) {
+      _declaration(declaration);
+    }
+
     _MixinsInference(_linker).perform(nodes.declarations);
   }
 
@@ -187,7 +187,7 @@
     } else if (node is FunctionTypedFormalParameter) {
       _functionTypedFormalParameter(node);
     } else if (node is GenericTypeAlias) {
-      // TODO(scheglov) ???
+      _genericTypeAlias(node);
     } else if (node is MethodDeclaration) {
       var returnType = node.returnType?.type;
       if (returnType == null) {
@@ -218,7 +218,10 @@
     }
   }
 
-  void _extensionDeclaration(ExtensionDeclaration node) {}
+  void _extensionDeclaration(ExtensionDeclaration node) {
+    var element = node.declaredElement as ExtensionElementImpl;
+    element.extendedType = node.extendedType.typeOrThrow;
+  }
 
   void _fieldFormalParameter(FieldFormalParameter node) {
     var element = node.declaredElement as FieldFormalParameterElementImpl;
@@ -243,10 +246,10 @@
   }
 
   void _functionTypeAlias(FunctionTypeAlias node) {
-    var returnTypeNode = node.returnType;
-    var element = node.declaredElement as TypeAliasElement;
+    var element = node.declaredElement as TypeAliasElementImpl;
     var function = element.aliasedElement as GenericFunctionTypeElementImpl;
-    function.returnType = returnTypeNode?.type ?? _dynamicType;
+    function.returnType = node.returnType?.type ?? _dynamicType;
+    element.aliasedType = function.type;
   }
 
   void _functionTypedFormalParameter(FunctionTypedFormalParameter node) {
@@ -260,6 +263,20 @@
     element.type = type;
   }
 
+  void _genericTypeAlias(GenericTypeAlias node) {
+    var element = node.declaredElement as TypeAliasElementImpl;
+    var featureSet = element.library.featureSet;
+
+    var typeNode = node.type;
+    if (featureSet.isEnabled(Feature.nonfunction_type_aliases)) {
+      element.aliasedType = typeNode.typeOrThrow;
+    } else if (typeNode is GenericFunctionType) {
+      element.aliasedType = typeNode.typeOrThrow;
+    } else {
+      element.aliasedType = _errorFunctionType();
+    }
+  }
+
   bool _isNonNullableByDefault(AstNode node) {
     var unit = node.thisOrAncestorOfType<CompilationUnit>();
     return unit!.featureSet.isEnabled(Feature.non_nullable);
@@ -303,6 +320,17 @@
         .toList();
   }
 
+  /// The [FunctionType] to use when a function type is expected for a type
+  /// alias, but the actual provided type annotation is not a function type.
+  static FunctionTypeImpl _errorFunctionType() {
+    return FunctionTypeImpl(
+      typeFormals: const [],
+      parameters: const [],
+      returnType: DynamicTypeImpl.instance,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
   static InterfaceType _objectType(ClassElementImpl element) {
     return element.library.typeProvider.objectType;
   }
diff --git a/pkg/analyzer/lib/src/summary2/variance_builder.dart b/pkg/analyzer/lib/src/summary2/variance_builder.dart
index 517aa4a..8d7438d 100644
--- a/pkg/analyzer/lib/src/summary2/variance_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/variance_builder.dart
@@ -13,11 +13,14 @@
 import 'package:analyzer/src/summary2/named_type_builder.dart';
 
 class VarianceBuilder {
+  final Linker _linker;
   final Set<TypeAlias> _pending = Set.identity();
   final Set<TypeAlias> _visit = Set.identity();
 
-  void perform(Linker linker) {
-    for (var builder in linker.builders.values) {
+  VarianceBuilder(this._linker);
+
+  void perform() {
+    for (var builder in _linker.builders.values) {
       for (var unitContext in builder.context.units) {
         for (var node in unitContext.unit.declarations) {
           if (node is FunctionTypeAlias) {
@@ -29,7 +32,7 @@
       }
     }
 
-    for (var builder in linker.builders.values) {
+    for (var builder in _linker.builders.values) {
       for (var unitContext in builder.context.units) {
         for (var node in unitContext.unit.declarations) {
           if (node is ClassTypeAlias) {
@@ -217,7 +220,7 @@
   }
 
   void _typeAliasElement(TypeAliasElementImpl element) {
-    var node = element.linkedNode;
+    var node = _linker.getLinkingNode(element);
     if (node == null) {
       // Not linking.
     } else if (node is GenericTypeAlias) {
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 28eb94e..8707e64 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -65,6 +65,7 @@
 kernel/testcases/*: Skip # These are not tests but input for tests.
 vm/test/transformations/type_flow/transformer_test: Slow, Pass
 vm/testcases/*: SkipByDesign # These are not tests but input for tests.
+wasm/*: SkipByDesign # These can't be run without running wasm:setup first.
 
 [ $compiler == dart2analyzer ]
 dev_compiler/test/options/*: SkipByDesign
@@ -95,6 +96,7 @@
 telemetry/test/*: SkipByDesign # Only meant to run on vm
 test_runner/test/*: SkipByDesign # Only meant to run on vm
 testing/*: SkipByDesign # Only meant to run on vm
+wasm/*: SkipByDesign # Only meant to run on vm
 
 [ $mode == debug ]
 compiler/test/deferred/load_graph_segmentation_test: Slow, Pass
diff --git a/pkg/wasm/README.md b/pkg/wasm/README.md
index ce842cd..1fcab7e 100644
--- a/pkg/wasm/README.md
+++ b/pkg/wasm/README.md
@@ -6,3 +6,44 @@
 ## Setup
 
 Run `dart bin/setup.dart` to build the Wasmer runtime.
+
+## Basic Usage
+
+As a simple example, we'll try to call the following C function from Dart using
+`package:wasm`. For a more detailed example that uses WASI, check out the
+example directory.
+
+```c++
+extern "C" int square(int n) { return n * n; }
+```
+
+We can compile this C++ code to WASM using a recent version of clang:
+
+```bash
+clang --target=wasm32 -nostdlib -Wl,--export-all -Wl,--no-entry -o square.wasm square.cc
+```
+
+Then we can load and run it like this:
+
+```dart
+import "dart:io";
+import "package:wasm/wasm.dart";
+
+void main() {
+  final data = File("square.wasm").readAsBytesSync();
+  final mod = WasmModule(data);
+  print(mod.describe());
+  final inst = mod.instantiate().build();
+  final square = inst.lookupFunction("square");
+  print(square(12));
+}
+```
+
+This should print:
+
+```
+export memory: memory
+export function: int32 square(int32)
+
+144
+```
diff --git a/pkg/wasm/bin/setup.dart b/pkg/wasm/bin/setup.dart
index 2e8fcad..ad36423 100644
--- a/pkg/wasm/bin/setup.dart
+++ b/pkg/wasm/bin/setup.dart
@@ -14,7 +14,7 @@
   // The common case, and how cli_util.dart computes the Dart SDK directory,
   // path.dirname called twice on Platform.resolvedExecutable.
   final exe = Uri.file(Platform.resolvedExecutable);
-  final commonSdkDir = exe.resolve('../..');
+  final commonSdkDir = exe.resolve('../../dart-sdk/');
   if (Directory(commonSdkDir.path).existsSync()) {
     return commonSdkDir;
   }
@@ -22,7 +22,7 @@
   // This is the less common case where the user is in the checked out Dart
   // SDK, and is executing dart via:
   // ./out/ReleaseX64/dart ...
-  final checkedOutSdkDir = exe.resolve('../dart-sdk');
+  final checkedOutSdkDir = exe.resolve('../dart-sdk/');
   if (Directory(checkedOutSdkDir.path).existsSync()) {
     return checkedOutSdkDir;
   }
@@ -31,6 +31,17 @@
   return commonSdkDir;
 }
 
+Uri getOutDir(Uri root) {
+  // Traverse up until we see a `.dart_tool/package_config.json` file.
+  do {
+    if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
+        .existsSync()) {
+      return root.resolve('.dart_tool/wasm/');
+    }
+  } while (root != (root = root.resolve('..')));
+  throw Exception(".dart_tool/package_config.json not found");
+}
+
 String getOutLib(String target) {
   final os = RegExp(r'^.*-.*-(.*)').firstMatch(target)?.group(1) ?? '';
   if (os == 'darwin' || os == 'ios') {
@@ -89,10 +100,12 @@
   final target = args.length >= 1 ? args[0] : await getTargetTriple();
   final sdkDir = getSdkDir();
   final binDir = Platform.script;
-  final outLib = binDir.resolve('out/' + getOutLib(target)).path;
+  final outDir = getOutDir(binDir);
+  final outLib = outDir.resolve(getOutLib(target)).path;
 
   print('Dart SDK directory: ${sdkDir.path}');
   print('Script directory: ${binDir.path}');
+  print('Output directory: ${outDir.path}');
   print('Target: $target');
   print('Output library: $outLib');
 
@@ -102,12 +115,21 @@
     '--target',
     target,
     '--target-dir',
-    binDir.resolve('out').path,
+    outDir.path,
     '--manifest-path',
     binDir.resolve('Cargo.toml').path,
     '--release'
   ]);
 
+  // Hack around a bug with dart_api_dl_impl.h include path in dart_api_dl.c.
+  if (!File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'))
+      .existsSync()) {
+    Directory(outDir.resolve('include/internal/').path)
+        .createSync(recursive: true);
+    File.fromUri(sdkDir.resolve('include/runtime/dart_api_dl_impl.h'))
+        .copy(outDir.resolve('include/internal/dart_api_dl_impl.h').path);
+  }
+
   // Build dart_api_dl.o.
   await run('clang', [
     '-DDART_SHARED_LIB',
@@ -117,10 +139,14 @@
     '-O3',
     '-target',
     target,
+    '-I',
+    sdkDir.resolve('include/').path,
+    '-I',
+    outDir.resolve('include/').path,
     '-c',
-    sdkDir.resolve('runtime/include/dart_api_dl.c').path,
+    sdkDir.resolve('include/dart_api_dl.c').path,
     '-o',
-    binDir.resolve('out/dart_api_dl.o').path
+    outDir.resolve('dart_api_dl.o').path
   ]);
 
   // Build finalizers.o.
@@ -135,11 +161,13 @@
     '-target',
     target,
     '-I',
-    sdkDir.resolve('runtime').path,
+    sdkDir.path,
+    '-I',
+    outDir.resolve('include/').path,
     '-c',
     binDir.resolve('finalizers.cc').path,
     '-o',
-    binDir.resolve('out/finalizers.o').path
+    outDir.resolve('finalizers.o').path
   ]);
 
   // Link wasmer, dart_api_dl, and finalizers to create the output library.
@@ -156,9 +184,9 @@
     '-Wl,--gc-sections',
     '-target',
     target,
-    binDir.resolve('out/dart_api_dl.o').path,
-    binDir.resolve('out/finalizers.o').path,
-    binDir.resolve('out/' + target + '/release/libwasmer.a').path,
+    outDir.resolve('dart_api_dl.o').path,
+    outDir.resolve('finalizers.o').path,
+    outDir.resolve('' + target + '/release/libwasmer.a').path,
     '-o',
     outLib
   ]);
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
index 6eb4e12..305d239 100644
--- a/pkg/wasm/lib/src/module.dart
+++ b/pkg/wasm/lib/src/module.dart
@@ -109,6 +109,8 @@
   }
 }
 
+class _WasmImportOwner {}
+
 /// WasmInstanceBuilder is used collect all the imports that a WasmModule
 /// requires before it is instantiated.
 class WasmInstanceBuilder {
@@ -117,7 +119,7 @@
   Map<String, int> _importIndex;
   Pointer<WasmerExternVec> _imports = calloc<WasmerExternVec>();
   Pointer<WasmerWasiEnv> _wasiEnv = nullptr;
-  Object _importOwner = Object();
+  _WasmImportOwner _importOwner = _WasmImportOwner();
 
   WasmInstanceBuilder(this._module) : _importIndex = {} {
     _importDescs = WasmRuntime().importDescriptors(_module._module);
@@ -215,7 +217,7 @@
   Stream<List<int>>? _stdout;
   Stream<List<int>>? _stderr;
   Map<String, WasmFunction> _functions = {};
-  Object _importOwner;
+  _WasmImportOwner _importOwner;
 
   WasmInstance(this._module, Pointer<WasmerExternVec> imports, this._wasiEnv,
       this._importOwner) {
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
index c543752..b8defab 100644
--- a/pkg/wasm/lib/src/runtime.dart
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -12,7 +12,6 @@
 import 'dart:io';
 import 'dart:typed_data';
 import 'package:ffi/ffi.dart';
-import 'package:path/path.dart' as path;
 import 'wasmer_api.dart';
 
 class WasmImportDescriptor {
@@ -161,37 +160,28 @@
     throw Exception("Wasm not currently supported on this platform");
   }
 
-  static String _getLibDir() {
-    // The common case, and how cli_util.dart computes the Dart SDK directory,
-    // path.dirname called twice on Platform.resolvedExecutable.
-    var commonLibDir = path.join(
-        path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))),
-        'bin',
-        'third_party',
-        'wasmer');
-    if (Directory(commonLibDir).existsSync()) {
-      return commonLibDir;
-    }
-
-    // This is the less common case where the user is in the checked out Dart
-    // SDK, and is executing dart via:
-    // ./out/ReleaseX64/dart ...
-    var checkedOutLibDir = path.join(
-        path.absolute(path.dirname(Platform.resolvedExecutable)),
-        'dart-sdk',
-        'bin',
-        'third_party',
-        'wasmer');
-    if (Directory(checkedOutLibDir).existsSync()) {
-      return checkedOutLibDir;
-    }
-
-    // If neither returned above, we return the common case:
-    return commonLibDir;
+  static String? _getLibPathFrom(Uri root) {
+    // The dynamic library created by pub run wasm:setup is located relative to
+    // the package_config.json file, so walk up from the script directory until
+    // we find it.
+    do {
+      if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
+          .existsSync()) {
+        return root.resolve('.dart_tool/wasm/' + _getLibName()).path;
+      }
+    } while (root != (root = root.resolve('..')));
+    return null;
   }
 
-  WasmRuntime._init()
-      : _lib = DynamicLibrary.open(path.join(_getLibDir(), _getLibName())) {
+  static String _getLibPath() {
+    var path = _getLibPathFrom(Platform.script.resolve('./'));
+    if (path != null) return path;
+    path = _getLibPathFrom(Directory.current.uri);
+    if (path != null) return path;
+    throw Exception("Wasm library not found. Did you `pub run wasm:setup`?");
+  }
+
+  WasmRuntime._init() : _lib = DynamicLibrary.open(_getLibPath()) {
     _Dart_InitializeApiDL = _lib.lookupFunction<
         NativeWasmerDartInitializeApiDLFn,
         WasmerDartInitializeApiDLFn>('Dart_InitializeApiDL');
diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart
index 2757504..0394c10 100644
--- a/pkg/wasm/lib/src/tools/runtime_template.dart
+++ b/pkg/wasm/lib/src/tools/runtime_template.dart
@@ -10,7 +10,6 @@
 import 'dart:io';
 import 'dart:typed_data';
 import 'package:ffi/ffi.dart';
-import 'package:path/path.dart' as path;
 import 'wasmer_api.dart';
 
 class WasmImportDescriptor {
@@ -76,37 +75,28 @@
     throw Exception("Wasm not currently supported on this platform");
   }
 
-  static String _getLibDir() {
-    // The common case, and how cli_util.dart computes the Dart SDK directory,
-    // path.dirname called twice on Platform.resolvedExecutable.
-    var commonLibDir = path.join(
-        path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))),
-        'bin',
-        'third_party',
-        'wasmer');
-    if (Directory(commonLibDir).existsSync()) {
-      return commonLibDir;
-    }
-
-    // This is the less common case where the user is in the checked out Dart
-    // SDK, and is executing dart via:
-    // ./out/ReleaseX64/dart ...
-    var checkedOutLibDir = path.join(
-        path.absolute(path.dirname(Platform.resolvedExecutable)),
-        'dart-sdk',
-        'bin',
-        'third_party',
-        'wasmer');
-    if (Directory(checkedOutLibDir).existsSync()) {
-      return checkedOutLibDir;
-    }
-
-    // If neither returned above, we return the common case:
-    return commonLibDir;
+  static String? _getLibPathFrom(Uri root) {
+    // The dynamic library created by pub run wasm:setup is located relative to
+    // the package_config.json file, so walk up from the script directory until
+    // we find it.
+    do {
+      if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
+          .existsSync()) {
+        return root.resolve('.dart_tool/wasm/' + _getLibName()).path;
+      }
+    } while (root != (root = root.resolve('..')));
+    return null;
   }
 
-  WasmRuntime._init()
-      : _lib = DynamicLibrary.open(path.join(_getLibDir(), _getLibName())) {
+  static String _getLibPath() {
+    var path = _getLibPathFrom(Platform.script.resolve('./'));
+    if (path != null) return path;
+    path = _getLibPathFrom(Directory.current.uri);
+    if (path != null) return path;
+    throw Exception("Wasm library not found. Did you `pub run wasm:setup`?");
+  }
+
+  WasmRuntime._init() : _lib = DynamicLibrary.open(_getLibPath()) {
 /* <RUNTIME_LOAD> */
 
     if (_Dart_InitializeApiDL(NativeApi.initializeApiDLData) != 0) {
diff --git a/pkg/wasm/pubspec.yaml b/pkg/wasm/pubspec.yaml
index 570631c..ef31927 100644
--- a/pkg/wasm/pubspec.yaml
+++ b/pkg/wasm/pubspec.yaml
@@ -3,10 +3,13 @@
 description: Load and run wasm bytecode.
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/wasm
-# This package is not intended for consumption on pub.dev. DO NOT publish.
-publish_to: none
+
 environment:
-  sdk: '>=2.10.0-0 <2.10.0'
+  sdk: '>=2.12.0 <3.0.0'
+
 dependencies:
-  ffi: ^0.1.3
-  path: ^1.0.0
+  ffi: ^1.0.0
+
+dev_dependencies:
+  pedantic: ^1.10.0
+  test: ^1.16.0
diff --git a/pkg/wasm/test/basic_test.dart b/pkg/wasm/test/basic_test.dart
new file mode 100644
index 0000000..5986a34
--- /dev/null
+++ b/pkg/wasm/test/basic_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+// Test that we can load a wasm module, find a function, and call it.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("basics", () {
+    // int64_t square(int64_t n) { return n * n; }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+      0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70,
+      0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f,
+      0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65,
+      0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72,
+      0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00,
+      0x7e, 0x0b,
+    ]);
+
+    var inst = WasmModule(data).instantiate().build();
+    var fn = inst.lookupFunction("square");
+    int n = fn(1234);
+
+    expect(n, 1234 * 1234);
+
+    expect(inst.lookupFunction("not_a_function"), isNull);
+  });
+}
diff --git a/pkg/wasm/test/corrupted_error_test.dart b/pkg/wasm/test/corrupted_error_test.dart
new file mode 100644
index 0000000..ac94ae8
--- /dev/null
+++ b/pkg/wasm/test/corrupted_error_test.dart
@@ -0,0 +1,22 @@
+// 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.
+
+// Test error thrown when the wasm module is corrupted.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("corrupted module", () {
+    var data = Uint8List.fromList([
+      0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7e, 0x01, 0x7e,
+      0x07, 0x13, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+      0x06, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x00, 0x00, 0x20, 0x00,
+      0x7e, 0x0b,
+    ]);
+
+    expect(() => WasmModule(data), throwsA(isException));
+  });
+}
diff --git a/pkg/wasm/test/fn_call_error_test.dart b/pkg/wasm/test/fn_call_error_test.dart
new file mode 100644
index 0000000..bcaf64c
--- /dev/null
+++ b/pkg/wasm/test/fn_call_error_test.dart
@@ -0,0 +1,31 @@
+// 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.
+
+// Test error thrown when a function is called with the wrong args.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("function with wrong arguments", () {
+    // int64_t square(int64_t n) { return n * n; }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+      0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70,
+      0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f,
+      0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65,
+      0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72,
+      0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00,
+      0x7e, 0x0b,
+    ]);
+
+    var inst = WasmModule(data).instantiate().build();
+    var fn = inst.lookupFunction("square");
+
+    expect(() => fn(), throwsA(isArgumentError));
+    expect(() => fn(1, 2, 3), throwsA(isArgumentError));
+    expect(() => fn(1.23), throwsA(isArgumentError));
+  });
+}
diff --git a/pkg/wasm/test/fn_import_error_test.dart b/pkg/wasm/test/fn_import_error_test.dart
new file mode 100644
index 0000000..71482bd
--- /dev/null
+++ b/pkg/wasm/test/fn_import_error_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test errors thrown by function imports.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("bad function imports", () {
+    // This module expects a function import like:
+    // int64_t someFn(int32_t a, int64_t b, float c, double d);
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x02, 0x60,
+      0x04, 0x7f, 0x7e, 0x7d, 0x7c, 0x01, 0x7e, 0x60, 0x00, 0x00, 0x02, 0x0e,
+      0x01, 0x03, 0x65, 0x6e, 0x76, 0x06, 0x73, 0x6f, 0x6d, 0x65, 0x46, 0x6e,
+      0x00, 0x00, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
+      0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41,
+      0x80, 0x88, 0x04, 0x0b, 0x07, 0x11, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
+      0x72, 0x79, 0x02, 0x00, 0x04, 0x62, 0x6c, 0x61, 0x68, 0x00, 0x01, 0x0a,
+      0x1d, 0x01, 0x1b, 0x00, 0x41, 0x01, 0x42, 0x02, 0x43, 0x00, 0x00, 0x40,
+      0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x10, 0x80,
+      0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b,
+    ]);
+
+    var mod = WasmModule(data);
+
+    // Valid instantiation.
+    var inst = mod
+        .instantiate()
+        .addFunction("env", "someFn", (int a, int b, num c, double d) => 123)
+        .build();
+
+    // Missing imports.
+    expect(() => mod.instantiate().build(),
+        throwsA(predicate((Exception e) => "$e".contains("Missing import"))));
+
+    // Wrong kind of import.
+    expect(
+        () =>
+            mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)),
+        throwsA(predicate(
+            (Exception e) => "$e".contains("Import is not a memory"))));
+
+    // Wrong namespace.
+    expect(
+        () => mod
+            .instantiate()
+            .addFunction(
+                "foo", "someFn", (int a, int b, num c, double d) => 123)
+            .build(),
+        throwsA(predicate((Exception e) => "$e".contains("Import not found"))));
+
+    // Wrong name.
+    expect(
+        () => mod
+            .instantiate()
+            .addFunction(
+                "env", "otherFn", (int a, int b, num c, double d) => 123)
+            .build(),
+        throwsA(predicate((Exception e) => "$e".contains("Import not found"))));
+
+    // Already filled.
+    expect(
+        () => mod
+            .instantiate()
+            .addFunction(
+                "env", "someFn", (int a, int b, num c, double d) => 123)
+            .addFunction(
+                "env", "someFn", (int a, int b, num c, double d) => 456)
+            .build(),
+        throwsA(predicate(
+            (Exception e) => "$e".contains("Import already filled"))));
+  });
+}
diff --git a/pkg/wasm/test/fn_import_exception_test.dart b/pkg/wasm/test/fn_import_exception_test.dart
new file mode 100644
index 0000000..e9de6ca
--- /dev/null
+++ b/pkg/wasm/test/fn_import_exception_test.dart
@@ -0,0 +1,50 @@
+// 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.
+
+// Test throwing exceptions from an imported function.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("exception thrown from imported function", () {
+    // void fn() {
+    //   a();
+    //   b();
+    // }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60,
+      0x00, 0x00, 0x02, 0x11, 0x02, 0x03, 0x65, 0x6e, 0x76, 0x01, 0x61, 0x00,
+      0x00, 0x03, 0x65, 0x6e, 0x76, 0x01, 0x62, 0x00, 0x00, 0x03, 0x02, 0x01,
+      0x00, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00,
+      0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07,
+      0x0f, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x02,
+      0x66, 0x6e, 0x00, 0x02, 0x0a, 0x10, 0x01, 0x0e, 0x00, 0x10, 0x80, 0x80,
+      0x80, 0x80, 0x00, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x0b,
+    ]);
+
+    bool called_b = false;
+    var thrownException = Exception("Hello exception!");
+    var inst = WasmModule(data).instantiate().addFunction("env", "a", () {
+      throw thrownException;
+    }).addFunction("env", "b", () {
+      called_b = true;
+    }).build();
+    var fn = inst.lookupFunction("fn");
+    expect(() => fn(), throwsA(thrownException));
+    expect(called_b, isFalse);
+
+    bool called_a = false;
+    inst = WasmModule(data).instantiate().addFunction("env", "a", () {
+      called_a = true;
+    }).addFunction("env", "b", () {
+      called_b = true;
+    }).build();
+    fn = inst.lookupFunction("fn");
+    fn();
+    expect(called_a, isTrue);
+    expect(called_b, isTrue);
+  });
+}
diff --git a/pkg/wasm/test/fn_import_test.dart b/pkg/wasm/test/fn_import_test.dart
new file mode 100644
index 0000000..3543f0b
--- /dev/null
+++ b/pkg/wasm/test/fn_import_test.dart
@@ -0,0 +1,39 @@
+// 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.
+
+// Test that we can load a wasm module, find a function, and call it.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("function import", () {
+    // void reportStuff() { report(123, 456); }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60,
+      0x02, 0x7e, 0x7e, 0x00, 0x60, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x03, 0x65,
+      0x6e, 0x76, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x00, 0x03,
+      0x02, 0x01, 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, 0x05, 0x03,
+      0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x80, 0x88, 0x04,
+      0x0b, 0x07, 0x18, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02,
+      0x00, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x75, 0x66,
+      0x66, 0x00, 0x01, 0x0a, 0x10, 0x01, 0x0e, 0x00, 0x42, 0xfb, 0x00, 0x42,
+      0xc8, 0x03, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x0b,
+    ]);
+
+    int report_x = -1;
+    int report_y = -1;
+
+    var inst = WasmModule(data).instantiate()
+      .addFunction("env", "report", (int x, int y) {
+        report_x = x;
+        report_y = y;
+      }).build();
+    var fn = inst.lookupFunction("reportStuff");
+    fn();
+    expect(123, report_x);
+    expect(456, report_y);
+  });
+}
diff --git a/pkg/wasm/test/hello_wasi_test.dart b/pkg/wasm/test/hello_wasi_test.dart
new file mode 100644
index 0000000..f41bd50
--- /dev/null
+++ b/pkg/wasm/test/hello_wasi_test.dart
@@ -0,0 +1,182 @@
+// 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.
+
+// Variant of hello_world_test that uses the default WASI imports.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:convert";
+import "dart:typed_data";
+
+void main() {
+  test("hello wasi", () async {
+    // Hello world module generated by emscripten+WASI. Exports a function like
+    // `void _start()`, and prints using `int fd_write(int, int, int, int)`.
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x60,
+      0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f,
+      0x01, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, 0x7e, 0x60,
+      0x00, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x03, 0x7f, 0x7f, 0x7f,
+      0x00, 0x02, 0x1a, 0x01, 0x0d, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x75, 0x6e,
+      0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x08, 0x66, 0x64, 0x5f, 0x77, 0x72,
+      0x69, 0x74, 0x65, 0x00, 0x01, 0x03, 0x0f, 0x0e, 0x03, 0x04, 0x00, 0x03,
+      0x02, 0x07, 0x05, 0x04, 0x03, 0x06, 0x02, 0x02, 0x08, 0x00, 0x04, 0x05,
+      0x01, 0x70, 0x01, 0x04, 0x04, 0x05, 0x06, 0x01, 0x01, 0x80, 0x02, 0x80,
+      0x02, 0x06, 0x09, 0x01, 0x7f, 0x01, 0x41, 0xc0, 0x95, 0xc0, 0x02, 0x0b,
+      0x07, 0x2e, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+      0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
+      0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x05, 0x04, 0x6d, 0x61, 0x69,
+      0x6e, 0x00, 0x04, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x0b,
+      0x09, 0x09, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x03, 0x08, 0x0e, 0x07, 0x0a,
+      0xae, 0x0c, 0x0e, 0xbf, 0x01, 0x01, 0x05, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x04, 0x02, 0x40, 0x20, 0x01, 0x28, 0x02, 0x10, 0x22, 0x02, 0x04, 0x7f,
+      0x20, 0x02, 0x05, 0x20, 0x01, 0x10, 0x02, 0x0d, 0x01, 0x20, 0x01, 0x28,
+      0x02, 0x10, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x14, 0x22, 0x05, 0x6b, 0x20,
+      0x00, 0x49, 0x04, 0x40, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20, 0x00, 0x20,
+      0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x20,
+      0x01, 0x2c, 0x00, 0x4b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x20, 0x00, 0x21,
+      0x03, 0x03, 0x40, 0x20, 0x03, 0x22, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x02,
+      0x41, 0x7f, 0x6a, 0x22, 0x03, 0x41, 0x80, 0x08, 0x6a, 0x2d, 0x00, 0x00,
+      0x41, 0x0a, 0x47, 0x0d, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20,
+      0x02, 0x20, 0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x22, 0x03, 0x20,
+      0x02, 0x49, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6b, 0x21, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0x08, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x02, 0x21, 0x06, 0x0b, 0x20, 0x05, 0x20, 0x04, 0x20,
+      0x00, 0x10, 0x03, 0x1a, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x14, 0x20,
+      0x00, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x06, 0x6a, 0x21, 0x03,
+      0x0b, 0x20, 0x03, 0x0b, 0x59, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x20, 0x00,
+      0x2d, 0x00, 0x4a, 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x3a,
+      0x00, 0x4a, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71,
+      0x04, 0x40, 0x20, 0x00, 0x20, 0x01, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02, 0x1c, 0x20,
+      0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01, 0x20, 0x00,
+      0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0x82, 0x04,
+      0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x4f, 0x04, 0x40,
+      0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x0d, 0x20, 0x00, 0x0f, 0x0b,
+      0x20, 0x00, 0x20, 0x02, 0x6a, 0x21, 0x03, 0x02, 0x40, 0x20, 0x00, 0x20,
+      0x01, 0x73, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x02, 0x40, 0x20, 0x02,
+      0x41, 0x01, 0x48, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b,
+      0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02, 0x03, 0x40, 0x20, 0x02, 0x20,
+      0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a,
+      0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02, 0x20, 0x03, 0x4f,
+      0x0d, 0x01, 0x20, 0x02, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x0b, 0x0b, 0x02,
+      0x40, 0x20, 0x03, 0x41, 0x7c, 0x71, 0x22, 0x04, 0x41, 0xc0, 0x00, 0x49,
+      0x0d, 0x00, 0x20, 0x02, 0x20, 0x04, 0x41, 0x40, 0x6a, 0x22, 0x05, 0x4b,
+      0x0d, 0x00, 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36,
+      0x02, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x04, 0x36, 0x02, 0x04,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x08, 0x36, 0x02, 0x08, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x0c, 0x36, 0x02, 0x0c, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x10, 0x36, 0x02, 0x10, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x14, 0x36, 0x02, 0x14, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x18, 0x36,
+      0x02, 0x18, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x1c, 0x36, 0x02, 0x1c,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x20, 0x36, 0x02, 0x20, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x24, 0x36, 0x02, 0x24, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x28, 0x36, 0x02, 0x28, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x2c, 0x36, 0x02, 0x2c, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x30, 0x36,
+      0x02, 0x30, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x34, 0x36, 0x02, 0x34,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x38, 0x36, 0x02, 0x38, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x3c, 0x36, 0x02, 0x3c, 0x20, 0x01, 0x41, 0x40,
+      0x6b, 0x21, 0x01, 0x20, 0x02, 0x41, 0x40, 0x6b, 0x22, 0x02, 0x20, 0x05,
+      0x4d, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x04, 0x4f, 0x0d, 0x01,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00,
+      0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x04, 0x6a,
+      0x22, 0x02, 0x20, 0x04, 0x49, 0x0d, 0x00, 0x0b, 0x0c, 0x01, 0x0b, 0x20,
+      0x03, 0x41, 0x04, 0x49, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01,
+      0x0b, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x22, 0x04, 0x20, 0x00, 0x49, 0x04,
+      0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, 0x20, 0x02,
+      0x20, 0x01, 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x20, 0x01,
+      0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21,
+      0x01, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x20, 0x04, 0x4d, 0x0d,
+      0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x03, 0x49, 0x04, 0x40, 0x03, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01,
+      0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02,
+      0x20, 0x03, 0x47, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0x06, 0x00,
+      0x10, 0x0c, 0x41, 0x00, 0x0b, 0x03, 0x00, 0x01, 0x0b, 0x7e, 0x01, 0x03,
+      0x7f, 0x23, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x01, 0x24, 0x00, 0x20, 0x01,
+      0x41, 0x0a, 0x3a, 0x00, 0x0f, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10,
+      0x22, 0x02, 0x45, 0x04, 0x40, 0x20, 0x00, 0x10, 0x02, 0x0d, 0x01, 0x20,
+      0x00, 0x28, 0x02, 0x10, 0x21, 0x02, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28,
+      0x02, 0x14, 0x22, 0x03, 0x20, 0x02, 0x4f, 0x0d, 0x00, 0x20, 0x00, 0x2c,
+      0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x03, 0x41,
+      0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x03, 0x41, 0x0a, 0x3a, 0x00, 0x00,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x01, 0x41, 0x0f, 0x6a, 0x41, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x41, 0x01, 0x47, 0x0d,
+      0x00, 0x20, 0x01, 0x2d, 0x00, 0x0f, 0x1a, 0x0b, 0x20, 0x01, 0x41, 0x10,
+      0x6a, 0x24, 0x00, 0x0b, 0x04, 0x00, 0x42, 0x00, 0x0b, 0x04, 0x00, 0x41,
+      0x00, 0x0b, 0x31, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x21, 0x02, 0x20, 0x02,
+      0x02, 0x7f, 0x20, 0x01, 0x28, 0x02, 0x4c, 0x41, 0x7f, 0x4c, 0x04, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x10, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x20,
+      0x01, 0x10, 0x01, 0x0b, 0x22, 0x01, 0x46, 0x04, 0x40, 0x20, 0x00, 0x0f,
+      0x0b, 0x20, 0x01, 0x0b, 0x62, 0x01, 0x03, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x00, 0x03, 0x40, 0x20, 0x00, 0x22, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x00,
+      0x20, 0x01, 0x28, 0x02, 0x00, 0x22, 0x02, 0x41, 0x7f, 0x73, 0x20, 0x02,
+      0x41, 0xff, 0xfd, 0xfb, 0x77, 0x6a, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84,
+      0x78, 0x71, 0x45, 0x0d, 0x00, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0xff,
+      0x01, 0x71, 0x45, 0x04, 0x40, 0x20, 0x01, 0x21, 0x00, 0x0c, 0x01, 0x0b,
+      0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x21, 0x02, 0x20, 0x01, 0x41,
+      0x01, 0x6a, 0x22, 0x00, 0x21, 0x01, 0x20, 0x02, 0x0d, 0x00, 0x0b, 0x0b,
+      0x20, 0x00, 0x41, 0x80, 0x08, 0x6b, 0x0b, 0x0c, 0x00, 0x02, 0x7f, 0x41,
+      0x00, 0x41, 0x00, 0x10, 0x04, 0x0b, 0x1a, 0x0b, 0x66, 0x01, 0x02, 0x7f,
+      0x41, 0x90, 0x08, 0x28, 0x02, 0x00, 0x22, 0x00, 0x28, 0x02, 0x4c, 0x41,
+      0x00, 0x4e, 0x04, 0x7f, 0x41, 0x01, 0x05, 0x20, 0x01, 0x0b, 0x1a, 0x02,
+      0x40, 0x41, 0x7f, 0x41, 0x00, 0x10, 0x0a, 0x22, 0x01, 0x20, 0x01, 0x20,
+      0x00, 0x10, 0x09, 0x47, 0x1b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x02, 0x40,
+      0x20, 0x00, 0x2d, 0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00,
+      0x28, 0x02, 0x14, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x10, 0x4f, 0x0d,
+      0x00, 0x20, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20,
+      0x01, 0x41, 0x0a, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x10,
+      0x06, 0x0b, 0x0b, 0x3d, 0x01, 0x01, 0x7f, 0x20, 0x02, 0x04, 0x40, 0x03,
+      0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0xc0, 0x00, 0x49, 0x1b, 0x22, 0x03, 0x10, 0x03, 0x21,
+      0x00, 0x20, 0x01, 0x41, 0x80, 0x40, 0x6b, 0x21, 0x01, 0x20, 0x00, 0x41,
+      0x80, 0x40, 0x6b, 0x21, 0x00, 0x20, 0x02, 0x20, 0x03, 0x6b, 0x22, 0x02,
+      0x0d, 0x00, 0x0b, 0x0b, 0x0b, 0xb1, 0x02, 0x01, 0x06, 0x7f, 0x23, 0x00,
+      0x41, 0x20, 0x6b, 0x22, 0x03, 0x24, 0x00, 0x20, 0x03, 0x20, 0x00, 0x28,
+      0x02, 0x1c, 0x22, 0x04, 0x36, 0x02, 0x10, 0x20, 0x00, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x1c, 0x20, 0x03, 0x20,
+      0x01, 0x36, 0x02, 0x18, 0x20, 0x03, 0x20, 0x05, 0x20, 0x04, 0x6b, 0x22,
+      0x01, 0x36, 0x02, 0x14, 0x20, 0x01, 0x20, 0x02, 0x6a, 0x21, 0x06, 0x41,
+      0x02, 0x21, 0x05, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x21, 0x01, 0x03, 0x40,
+      0x02, 0x40, 0x02, 0x7f, 0x20, 0x06, 0x02, 0x7f, 0x20, 0x00, 0x28, 0x02,
+      0x3c, 0x20, 0x01, 0x20, 0x05, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, 0x00,
+      0x04, 0x40, 0x20, 0x03, 0x41, 0x7f, 0x36, 0x02, 0x0c, 0x41, 0x7f, 0x0c,
+      0x01, 0x0b, 0x20, 0x03, 0x28, 0x02, 0x0c, 0x0b, 0x22, 0x04, 0x46, 0x04,
+      0x40, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02,
+      0x1c, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x20, 0x02, 0x0c,
+      0x01, 0x0b, 0x20, 0x04, 0x41, 0x7f, 0x4a, 0x0d, 0x01, 0x20, 0x00, 0x41,
+      0x00, 0x36, 0x02, 0x1c, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, 0x10, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x00, 0x1a, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x04, 0x6b, 0x0b, 0x21, 0x04, 0x20, 0x03, 0x41,
+      0x20, 0x6a, 0x24, 0x00, 0x20, 0x04, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0x08,
+      0x6a, 0x20, 0x01, 0x20, 0x04, 0x20, 0x01, 0x28, 0x02, 0x04, 0x22, 0x07,
+      0x4b, 0x22, 0x08, 0x1b, 0x22, 0x01, 0x20, 0x04, 0x20, 0x07, 0x41, 0x00,
+      0x20, 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x20, 0x01, 0x28, 0x02, 0x00, 0x6a,
+      0x36, 0x02, 0x00, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x04, 0x20, 0x07,
+      0x6b, 0x36, 0x02, 0x04, 0x20, 0x06, 0x20, 0x04, 0x6b, 0x21, 0x06, 0x20,
+      0x05, 0x20, 0x08, 0x6b, 0x21, 0x05, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x0b,
+      0x0b, 0x4d, 0x06, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x12, 0x68, 0x65, 0x6c,
+      0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00, 0x00,
+      0x00, 0x18, 0x04, 0x00, 0x41, 0x98, 0x08, 0x0b, 0x01, 0x05, 0x00, 0x41,
+      0xa4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xbc, 0x08, 0x0b, 0x0e, 0x02,
+      0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00,
+      0x04, 0x00, 0x41, 0xd4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xe3, 0x08,
+      0x0b, 0x05, 0x0a, 0xff, 0xff, 0xff, 0xff,
+    ]);
+
+    var inst =
+        WasmModule(data).instantiate().enableWasi(captureStdout: true).build();
+
+    var fn = inst.lookupFunction("_start");
+    fn();
+    var out = utf8.decode(await inst.stdout.first);
+    expect(out, "hello, world!\n");
+  });
+}
diff --git a/pkg/wasm/test/hello_world_test.dart b/pkg/wasm/test/hello_world_test.dart
new file mode 100644
index 0000000..8a49ae2
--- /dev/null
+++ b/pkg/wasm/test/hello_world_test.dart
@@ -0,0 +1,209 @@
+// 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.
+
+// @dart = 2.12
+
+// Test for hello world built using emscripten with WASI.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("hello world", () {
+    // Hello world module generated by emscripten+WASI. Exports a function like
+    // `void _start()`, and prints using `int fd_write(int, int, int, int)`.
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x60,
+      0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f,
+      0x01, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, 0x7e, 0x60,
+      0x00, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x03, 0x7f, 0x7f, 0x7f,
+      0x00, 0x02, 0x1a, 0x01, 0x0d, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x75, 0x6e,
+      0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x08, 0x66, 0x64, 0x5f, 0x77, 0x72,
+      0x69, 0x74, 0x65, 0x00, 0x01, 0x03, 0x0f, 0x0e, 0x03, 0x04, 0x00, 0x03,
+      0x02, 0x07, 0x05, 0x04, 0x03, 0x06, 0x02, 0x02, 0x08, 0x00, 0x04, 0x05,
+      0x01, 0x70, 0x01, 0x04, 0x04, 0x05, 0x06, 0x01, 0x01, 0x80, 0x02, 0x80,
+      0x02, 0x06, 0x09, 0x01, 0x7f, 0x01, 0x41, 0xc0, 0x95, 0xc0, 0x02, 0x0b,
+      0x07, 0x2e, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+      0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
+      0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x05, 0x04, 0x6d, 0x61, 0x69,
+      0x6e, 0x00, 0x04, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x0b,
+      0x09, 0x09, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x03, 0x08, 0x0e, 0x07, 0x0a,
+      0xae, 0x0c, 0x0e, 0xbf, 0x01, 0x01, 0x05, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x04, 0x02, 0x40, 0x20, 0x01, 0x28, 0x02, 0x10, 0x22, 0x02, 0x04, 0x7f,
+      0x20, 0x02, 0x05, 0x20, 0x01, 0x10, 0x02, 0x0d, 0x01, 0x20, 0x01, 0x28,
+      0x02, 0x10, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x14, 0x22, 0x05, 0x6b, 0x20,
+      0x00, 0x49, 0x04, 0x40, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20, 0x00, 0x20,
+      0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x20,
+      0x01, 0x2c, 0x00, 0x4b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x20, 0x00, 0x21,
+      0x03, 0x03, 0x40, 0x20, 0x03, 0x22, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x02,
+      0x41, 0x7f, 0x6a, 0x22, 0x03, 0x41, 0x80, 0x08, 0x6a, 0x2d, 0x00, 0x00,
+      0x41, 0x0a, 0x47, 0x0d, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20,
+      0x02, 0x20, 0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x22, 0x03, 0x20,
+      0x02, 0x49, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6b, 0x21, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0x08, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x02, 0x21, 0x06, 0x0b, 0x20, 0x05, 0x20, 0x04, 0x20,
+      0x00, 0x10, 0x03, 0x1a, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x14, 0x20,
+      0x00, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x06, 0x6a, 0x21, 0x03,
+      0x0b, 0x20, 0x03, 0x0b, 0x59, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x20, 0x00,
+      0x2d, 0x00, 0x4a, 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x3a,
+      0x00, 0x4a, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71,
+      0x04, 0x40, 0x20, 0x00, 0x20, 0x01, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02, 0x1c, 0x20,
+      0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01, 0x20, 0x00,
+      0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0x82, 0x04,
+      0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x4f, 0x04, 0x40,
+      0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x0d, 0x20, 0x00, 0x0f, 0x0b,
+      0x20, 0x00, 0x20, 0x02, 0x6a, 0x21, 0x03, 0x02, 0x40, 0x20, 0x00, 0x20,
+      0x01, 0x73, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x02, 0x40, 0x20, 0x02,
+      0x41, 0x01, 0x48, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b,
+      0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02, 0x03, 0x40, 0x20, 0x02, 0x20,
+      0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a,
+      0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02, 0x20, 0x03, 0x4f,
+      0x0d, 0x01, 0x20, 0x02, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x0b, 0x0b, 0x02,
+      0x40, 0x20, 0x03, 0x41, 0x7c, 0x71, 0x22, 0x04, 0x41, 0xc0, 0x00, 0x49,
+      0x0d, 0x00, 0x20, 0x02, 0x20, 0x04, 0x41, 0x40, 0x6a, 0x22, 0x05, 0x4b,
+      0x0d, 0x00, 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36,
+      0x02, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x04, 0x36, 0x02, 0x04,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x08, 0x36, 0x02, 0x08, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x0c, 0x36, 0x02, 0x0c, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x10, 0x36, 0x02, 0x10, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x14, 0x36, 0x02, 0x14, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x18, 0x36,
+      0x02, 0x18, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x1c, 0x36, 0x02, 0x1c,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x20, 0x36, 0x02, 0x20, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x24, 0x36, 0x02, 0x24, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x28, 0x36, 0x02, 0x28, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x2c, 0x36, 0x02, 0x2c, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x30, 0x36,
+      0x02, 0x30, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x34, 0x36, 0x02, 0x34,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x38, 0x36, 0x02, 0x38, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x3c, 0x36, 0x02, 0x3c, 0x20, 0x01, 0x41, 0x40,
+      0x6b, 0x21, 0x01, 0x20, 0x02, 0x41, 0x40, 0x6b, 0x22, 0x02, 0x20, 0x05,
+      0x4d, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x04, 0x4f, 0x0d, 0x01,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00,
+      0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x04, 0x6a,
+      0x22, 0x02, 0x20, 0x04, 0x49, 0x0d, 0x00, 0x0b, 0x0c, 0x01, 0x0b, 0x20,
+      0x03, 0x41, 0x04, 0x49, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01,
+      0x0b, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x22, 0x04, 0x20, 0x00, 0x49, 0x04,
+      0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, 0x20, 0x02,
+      0x20, 0x01, 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x20, 0x01,
+      0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21,
+      0x01, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x20, 0x04, 0x4d, 0x0d,
+      0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x03, 0x49, 0x04, 0x40, 0x03, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01,
+      0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02,
+      0x20, 0x03, 0x47, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0x06, 0x00,
+      0x10, 0x0c, 0x41, 0x00, 0x0b, 0x03, 0x00, 0x01, 0x0b, 0x7e, 0x01, 0x03,
+      0x7f, 0x23, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x01, 0x24, 0x00, 0x20, 0x01,
+      0x41, 0x0a, 0x3a, 0x00, 0x0f, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10,
+      0x22, 0x02, 0x45, 0x04, 0x40, 0x20, 0x00, 0x10, 0x02, 0x0d, 0x01, 0x20,
+      0x00, 0x28, 0x02, 0x10, 0x21, 0x02, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28,
+      0x02, 0x14, 0x22, 0x03, 0x20, 0x02, 0x4f, 0x0d, 0x00, 0x20, 0x00, 0x2c,
+      0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x03, 0x41,
+      0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x03, 0x41, 0x0a, 0x3a, 0x00, 0x00,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x01, 0x41, 0x0f, 0x6a, 0x41, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x41, 0x01, 0x47, 0x0d,
+      0x00, 0x20, 0x01, 0x2d, 0x00, 0x0f, 0x1a, 0x0b, 0x20, 0x01, 0x41, 0x10,
+      0x6a, 0x24, 0x00, 0x0b, 0x04, 0x00, 0x42, 0x00, 0x0b, 0x04, 0x00, 0x41,
+      0x00, 0x0b, 0x31, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x21, 0x02, 0x20, 0x02,
+      0x02, 0x7f, 0x20, 0x01, 0x28, 0x02, 0x4c, 0x41, 0x7f, 0x4c, 0x04, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x10, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x20,
+      0x01, 0x10, 0x01, 0x0b, 0x22, 0x01, 0x46, 0x04, 0x40, 0x20, 0x00, 0x0f,
+      0x0b, 0x20, 0x01, 0x0b, 0x62, 0x01, 0x03, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x00, 0x03, 0x40, 0x20, 0x00, 0x22, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x00,
+      0x20, 0x01, 0x28, 0x02, 0x00, 0x22, 0x02, 0x41, 0x7f, 0x73, 0x20, 0x02,
+      0x41, 0xff, 0xfd, 0xfb, 0x77, 0x6a, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84,
+      0x78, 0x71, 0x45, 0x0d, 0x00, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0xff,
+      0x01, 0x71, 0x45, 0x04, 0x40, 0x20, 0x01, 0x21, 0x00, 0x0c, 0x01, 0x0b,
+      0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x21, 0x02, 0x20, 0x01, 0x41,
+      0x01, 0x6a, 0x22, 0x00, 0x21, 0x01, 0x20, 0x02, 0x0d, 0x00, 0x0b, 0x0b,
+      0x20, 0x00, 0x41, 0x80, 0x08, 0x6b, 0x0b, 0x0c, 0x00, 0x02, 0x7f, 0x41,
+      0x00, 0x41, 0x00, 0x10, 0x04, 0x0b, 0x1a, 0x0b, 0x66, 0x01, 0x02, 0x7f,
+      0x41, 0x90, 0x08, 0x28, 0x02, 0x00, 0x22, 0x00, 0x28, 0x02, 0x4c, 0x41,
+      0x00, 0x4e, 0x04, 0x7f, 0x41, 0x01, 0x05, 0x20, 0x01, 0x0b, 0x1a, 0x02,
+      0x40, 0x41, 0x7f, 0x41, 0x00, 0x10, 0x0a, 0x22, 0x01, 0x20, 0x01, 0x20,
+      0x00, 0x10, 0x09, 0x47, 0x1b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x02, 0x40,
+      0x20, 0x00, 0x2d, 0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00,
+      0x28, 0x02, 0x14, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x10, 0x4f, 0x0d,
+      0x00, 0x20, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20,
+      0x01, 0x41, 0x0a, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x10,
+      0x06, 0x0b, 0x0b, 0x3d, 0x01, 0x01, 0x7f, 0x20, 0x02, 0x04, 0x40, 0x03,
+      0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0xc0, 0x00, 0x49, 0x1b, 0x22, 0x03, 0x10, 0x03, 0x21,
+      0x00, 0x20, 0x01, 0x41, 0x80, 0x40, 0x6b, 0x21, 0x01, 0x20, 0x00, 0x41,
+      0x80, 0x40, 0x6b, 0x21, 0x00, 0x20, 0x02, 0x20, 0x03, 0x6b, 0x22, 0x02,
+      0x0d, 0x00, 0x0b, 0x0b, 0x0b, 0xb1, 0x02, 0x01, 0x06, 0x7f, 0x23, 0x00,
+      0x41, 0x20, 0x6b, 0x22, 0x03, 0x24, 0x00, 0x20, 0x03, 0x20, 0x00, 0x28,
+      0x02, 0x1c, 0x22, 0x04, 0x36, 0x02, 0x10, 0x20, 0x00, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x1c, 0x20, 0x03, 0x20,
+      0x01, 0x36, 0x02, 0x18, 0x20, 0x03, 0x20, 0x05, 0x20, 0x04, 0x6b, 0x22,
+      0x01, 0x36, 0x02, 0x14, 0x20, 0x01, 0x20, 0x02, 0x6a, 0x21, 0x06, 0x41,
+      0x02, 0x21, 0x05, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x21, 0x01, 0x03, 0x40,
+      0x02, 0x40, 0x02, 0x7f, 0x20, 0x06, 0x02, 0x7f, 0x20, 0x00, 0x28, 0x02,
+      0x3c, 0x20, 0x01, 0x20, 0x05, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, 0x00,
+      0x04, 0x40, 0x20, 0x03, 0x41, 0x7f, 0x36, 0x02, 0x0c, 0x41, 0x7f, 0x0c,
+      0x01, 0x0b, 0x20, 0x03, 0x28, 0x02, 0x0c, 0x0b, 0x22, 0x04, 0x46, 0x04,
+      0x40, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02,
+      0x1c, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x20, 0x02, 0x0c,
+      0x01, 0x0b, 0x20, 0x04, 0x41, 0x7f, 0x4a, 0x0d, 0x01, 0x20, 0x00, 0x41,
+      0x00, 0x36, 0x02, 0x1c, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, 0x10, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x00, 0x1a, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x04, 0x6b, 0x0b, 0x21, 0x04, 0x20, 0x03, 0x41,
+      0x20, 0x6a, 0x24, 0x00, 0x20, 0x04, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0x08,
+      0x6a, 0x20, 0x01, 0x20, 0x04, 0x20, 0x01, 0x28, 0x02, 0x04, 0x22, 0x07,
+      0x4b, 0x22, 0x08, 0x1b, 0x22, 0x01, 0x20, 0x04, 0x20, 0x07, 0x41, 0x00,
+      0x20, 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x20, 0x01, 0x28, 0x02, 0x00, 0x6a,
+      0x36, 0x02, 0x00, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x04, 0x20, 0x07,
+      0x6b, 0x36, 0x02, 0x04, 0x20, 0x06, 0x20, 0x04, 0x6b, 0x21, 0x06, 0x20,
+      0x05, 0x20, 0x08, 0x6b, 0x21, 0x05, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x0b,
+      0x0b, 0x4d, 0x06, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x12, 0x68, 0x65, 0x6c,
+      0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00, 0x00,
+      0x00, 0x18, 0x04, 0x00, 0x41, 0x98, 0x08, 0x0b, 0x01, 0x05, 0x00, 0x41,
+      0xa4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xbc, 0x08, 0x0b, 0x0e, 0x02,
+      0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00,
+      0x04, 0x00, 0x41, 0xd4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xe3, 0x08,
+      0x0b, 0x05, 0x0a, 0xff, 0xff, 0xff, 0xff,
+    ]);
+
+    late WasmMemory mem;
+    String out = "";
+    var getI32 = (int p) {
+      // Read a little-endian I32.
+      int n = 0;
+      for (var i = p + 3; i >= p; --i) {
+        n *= 256;
+        n += mem[i];
+      }
+      return n;
+    };
+    var inst = WasmModule(data)
+        .instantiate()
+        .addFunction("wasi_unstable", "fd_write",
+            (int fd, int iovs, int iovs_len, int unused) {
+      // iovs points to an array of length iovs_len. Each element is two I32s,
+      // a char* and a length.
+      String o = "";
+      for (var i = 0; i < iovs_len; ++i) {
+        var str = getI32(iovs + 8 * i);
+        var len = getI32(iovs + 4 + 8 * i);
+        for (var j = 0; j < len; ++j) {
+          o += String.fromCharCode(mem[str + j]);
+        }
+      }
+      out += o;
+      return o.length;
+    }).build();
+    mem = inst.memory;
+
+    var fn = inst.lookupFunction("_start");
+    fn();
+    expect(out, "hello, world!\n");
+  });
+}
diff --git a/pkg/wasm/test/memory_error_test.dart b/pkg/wasm/test/memory_error_test.dart
new file mode 100644
index 0000000..6409022
--- /dev/null
+++ b/pkg/wasm/test/memory_error_test.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// Test errors thrown by WasmMemory.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("memory errors", () {
+    // Empty wasm module.
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x06, 0x81, 0x00, 0x00,
+    ]);
+    var module = WasmModule(data);
+
+    expect(() => module.createMemory(1000000000), throwsA(isException));
+    var mem = module.createMemory(100);
+    expect(() => mem.grow(1000000000), throwsA(isException));
+    mem = module.createMemory(100, 200);
+    expect(() => mem.grow(300), throwsA(isException));
+  });
+}
diff --git a/pkg/wasm/test/memory_test.dart b/pkg/wasm/test/memory_test.dart
new file mode 100644
index 0000000..95ea288
--- /dev/null
+++ b/pkg/wasm/test/memory_test.dart
@@ -0,0 +1,31 @@
+// 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.
+
+// Test that we can create a WasmMemory, edit it, and grow it.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("memory", () {
+    // Empty wasm module.
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x06, 0x81, 0x00, 0x00,
+    ]);
+    var module = WasmModule(data);
+
+    var mem = module.createMemory(100);
+    expect(mem.lengthInPages, 100);
+    expect(mem.lengthInBytes, 100 * WasmMemory.kPageSizeInBytes);
+
+    mem[123] = 45;
+    expect(mem[123], 45);
+
+    mem.grow(10);
+    expect(mem.lengthInPages, 110);
+    expect(mem.lengthInBytes, 110 * WasmMemory.kPageSizeInBytes);
+    expect(mem[123], 45);
+  });
+}
diff --git a/pkg/wasm/test/numerics_test.dart b/pkg/wasm/test/numerics_test.dart
new file mode 100644
index 0000000..5fa19d0
--- /dev/null
+++ b/pkg/wasm/test/numerics_test.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.
+
+// Test numeric types.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("numerics", () {
+    // int64_t addI64(int64_t x, int64_t y) { return x + y; }
+    // int32_t addI32(int32_t x, int32_t y) { return x + y; }
+    // double addF64(double x, double y) { return x + y; }
+    // float addF32(float x, float y) { return x + y; }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x19, 0x04, 0x60,
+      0x02, 0x7e, 0x7e, 0x01, 0x7e, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+      0x02, 0x7c, 0x7c, 0x01, 0x7c, 0x60, 0x02, 0x7d, 0x7d, 0x01, 0x7d, 0x03,
+      0x05, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
+      0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41,
+      0x80, 0x88, 0x04, 0x0b, 0x07, 0x2e, 0x05, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
+      0x72, 0x79, 0x02, 0x00, 0x06, 0x61, 0x64, 0x64, 0x49, 0x36, 0x34, 0x00,
+      0x00, 0x06, 0x61, 0x64, 0x64, 0x49, 0x33, 0x32, 0x00, 0x01, 0x06, 0x61,
+      0x64, 0x64, 0x46, 0x36, 0x34, 0x00, 0x02, 0x06, 0x61, 0x64, 0x64, 0x46,
+      0x33, 0x32, 0x00, 0x03, 0x0a, 0x21, 0x04, 0x07, 0x00, 0x20, 0x01, 0x20,
+      0x00, 0x7c, 0x0b, 0x07, 0x00, 0x20, 0x01, 0x20, 0x00, 0x6a, 0x0b, 0x07,
+      0x00, 0x20, 0x00, 0x20, 0x01, 0xa0, 0x0b, 0x07, 0x00, 0x20, 0x00, 0x20,
+      0x01, 0x92, 0x0b,
+    ]);
+
+    var inst = WasmModule(data).instantiate().build();
+    var addI64 = inst.lookupFunction("addI64");
+    var addI32 = inst.lookupFunction("addI32");
+    var addF64 = inst.lookupFunction("addF64");
+    var addF32 = inst.lookupFunction("addF32");
+
+    int i64 = addI64(0x123456789ABCDEF, 0xFEDCBA987654321);
+    expect(i64, 0x1111111111111110);
+
+    int i32 = addI32(0xABCDEF, 0xFEDCBA);
+    expect(i32, 0x1aaaaa9);
+
+    double f64 = addF64(1234.5678, 8765.4321);
+    expect(f64, closeTo(9999.9999, 1e-6));
+
+    double f32 = addF32(1234.5678, 8765.4321);
+    expect(f32, closeTo(9999.9999, 1e-3));
+  });
+}
diff --git a/pkg/wasm/test/test_all.dart b/pkg/wasm/test/test_all.dart
new file mode 100644
index 0000000..edf3850
--- /dev/null
+++ b/pkg/wasm/test/test_all.dart
@@ -0,0 +1,35 @@
+// 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:test/test.dart';
+
+import 'basic_test.dart' as basic;
+import 'corrupted_error_test.dart' as corrupted_error;
+import 'fn_call_error_test.dart' as fn_call_error;
+import 'fn_import_error_test.dart' as fn_import_error;
+import 'fn_import_exception_test.dart' as fn_import_exception;
+import 'fn_import_test.dart' as fn_import;
+import 'hello_wasi_test.dart' as hello_wasi;
+import 'hello_world_test.dart' as hello_world;
+import 'memory_error_test.dart' as memory_error;
+import 'memory_test.dart' as memory;
+import 'numerics_test.dart' as numerics;
+import 'void_test.dart' as void_;
+import 'wasi_error_test.dart' as wasi_error;
+
+void main() {
+  group('basic', basic.main);
+  group('corrupted_error', corrupted_error.main);
+  group('fn_call_error', fn_call_error.main);
+  group('fn_import_error', fn_import_error.main);
+  group('fn_import_exception', fn_import_exception.main);
+  group('fn_import', fn_import.main);
+  group('hello_wasi', hello_wasi.main);
+  group('hello_world', hello_world.main);
+  group('memory_error', memory_error.main);
+  group('memory', memory.main);
+  group('numerics', numerics.main);
+  group('void', void_.main);
+  group('wasi_error', wasi_error.main);
+}
diff --git a/pkg/wasm/test/void_test.dart b/pkg/wasm/test/void_test.dart
new file mode 100644
index 0000000..d1804eb
--- /dev/null
+++ b/pkg/wasm/test/void_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.
+
+// Test functions with void return type, and functions that take no args.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("void return type", () {
+    // int64_t x = 0;
+    // void set(int64_t a, int64_t b) { x = a + b; }
+    // int64_t get() { return x; }
+    var data = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x02, 0x60,
+      0x02, 0x7e, 0x7e, 0x00, 0x60, 0x00, 0x01, 0x7e, 0x03, 0x03, 0x02, 0x00,
+      0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00,
+      0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0b, 0x07,
+      0x16, 0x03, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x03,
+      0x73, 0x65, 0x74, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, 0x01, 0x0a,
+      0x1e, 0x02, 0x10, 0x00, 0x41, 0x00, 0x20, 0x01, 0x20, 0x00, 0x7c, 0x37,
+      0x03, 0x80, 0x88, 0x80, 0x80, 0x00, 0x0b, 0x0b, 0x00, 0x41, 0x00, 0x29,
+      0x03, 0x80, 0x88, 0x80, 0x80, 0x00, 0x0b, 0x0b, 0x0f, 0x01, 0x00, 0x41,
+      0x80, 0x08, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ]);
+
+    var inst = WasmModule(data).instantiate().build();
+    var setFn = inst.lookupFunction("set");
+    var getFn = inst.lookupFunction("get");
+    expect(setFn(123, 456), isNull);
+    int n = getFn();
+    expect(n, 123 + 456);
+  });
+}
diff --git a/pkg/wasm/test/wasi_error_test.dart b/pkg/wasm/test/wasi_error_test.dart
new file mode 100644
index 0000000..3c6f46d
--- /dev/null
+++ b/pkg/wasm/test/wasi_error_test.dart
@@ -0,0 +1,209 @@
+// 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.
+
+// Test the errors that can be thrown by WASI.
+
+import "package:test/test.dart";
+import "package:wasm/wasm.dart";
+import "dart:typed_data";
+
+void main() {
+  test("wasi error", () {
+    // Empty wasm module.
+    var emptyModuleData = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x06, 0x81, 0x00, 0x00,
+    ]);
+
+    // Failed to fill WASI imports (the empty module was not built with WASI).
+    expect(() => WasmModule(emptyModuleData).instantiate().enableWasi(),
+        throwsA(predicate(
+            (Exception e) => "$e".contains("Failed to fill WASI imports"))));
+
+    // Hello world module generated by emscripten+WASI. Exports a function like
+    // `void _start()`, and prints using `int fd_write(int, int, int, int)`.
+    var helloWorldData = Uint8List.fromList([
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x60,
+      0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f,
+      0x01, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, 0x7e, 0x60,
+      0x00, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x03, 0x7f, 0x7f, 0x7f,
+      0x00, 0x02, 0x1a, 0x01, 0x0d, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x75, 0x6e,
+      0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x08, 0x66, 0x64, 0x5f, 0x77, 0x72,
+      0x69, 0x74, 0x65, 0x00, 0x01, 0x03, 0x0f, 0x0e, 0x03, 0x04, 0x00, 0x03,
+      0x02, 0x07, 0x05, 0x04, 0x03, 0x06, 0x02, 0x02, 0x08, 0x00, 0x04, 0x05,
+      0x01, 0x70, 0x01, 0x04, 0x04, 0x05, 0x06, 0x01, 0x01, 0x80, 0x02, 0x80,
+      0x02, 0x06, 0x09, 0x01, 0x7f, 0x01, 0x41, 0xc0, 0x95, 0xc0, 0x02, 0x0b,
+      0x07, 0x2e, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+      0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
+      0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x05, 0x04, 0x6d, 0x61, 0x69,
+      0x6e, 0x00, 0x04, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x0b,
+      0x09, 0x09, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x03, 0x08, 0x0e, 0x07, 0x0a,
+      0xae, 0x0c, 0x0e, 0xbf, 0x01, 0x01, 0x05, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x04, 0x02, 0x40, 0x20, 0x01, 0x28, 0x02, 0x10, 0x22, 0x02, 0x04, 0x7f,
+      0x20, 0x02, 0x05, 0x20, 0x01, 0x10, 0x02, 0x0d, 0x01, 0x20, 0x01, 0x28,
+      0x02, 0x10, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x14, 0x22, 0x05, 0x6b, 0x20,
+      0x00, 0x49, 0x04, 0x40, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20, 0x00, 0x20,
+      0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x20,
+      0x01, 0x2c, 0x00, 0x4b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x20, 0x00, 0x21,
+      0x03, 0x03, 0x40, 0x20, 0x03, 0x22, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x02,
+      0x41, 0x7f, 0x6a, 0x22, 0x03, 0x41, 0x80, 0x08, 0x6a, 0x2d, 0x00, 0x00,
+      0x41, 0x0a, 0x47, 0x0d, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20,
+      0x02, 0x20, 0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x22, 0x03, 0x20,
+      0x02, 0x49, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6b, 0x21, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0x08, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x02, 0x21, 0x06, 0x0b, 0x20, 0x05, 0x20, 0x04, 0x20,
+      0x00, 0x10, 0x03, 0x1a, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x14, 0x20,
+      0x00, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x06, 0x6a, 0x21, 0x03,
+      0x0b, 0x20, 0x03, 0x0b, 0x59, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x20, 0x00,
+      0x2d, 0x00, 0x4a, 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x3a,
+      0x00, 0x4a, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71,
+      0x04, 0x40, 0x20, 0x00, 0x20, 0x01, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02, 0x1c, 0x20,
+      0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01, 0x20, 0x00,
+      0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0x82, 0x04,
+      0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x4f, 0x04, 0x40,
+      0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x0d, 0x20, 0x00, 0x0f, 0x0b,
+      0x20, 0x00, 0x20, 0x02, 0x6a, 0x21, 0x03, 0x02, 0x40, 0x20, 0x00, 0x20,
+      0x01, 0x73, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x02, 0x40, 0x20, 0x02,
+      0x41, 0x01, 0x48, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b,
+      0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02, 0x03, 0x40, 0x20, 0x02, 0x20,
+      0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a,
+      0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02, 0x20, 0x03, 0x4f,
+      0x0d, 0x01, 0x20, 0x02, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x0b, 0x0b, 0x02,
+      0x40, 0x20, 0x03, 0x41, 0x7c, 0x71, 0x22, 0x04, 0x41, 0xc0, 0x00, 0x49,
+      0x0d, 0x00, 0x20, 0x02, 0x20, 0x04, 0x41, 0x40, 0x6a, 0x22, 0x05, 0x4b,
+      0x0d, 0x00, 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36,
+      0x02, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x04, 0x36, 0x02, 0x04,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x08, 0x36, 0x02, 0x08, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x0c, 0x36, 0x02, 0x0c, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x10, 0x36, 0x02, 0x10, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x14, 0x36, 0x02, 0x14, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x18, 0x36,
+      0x02, 0x18, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x1c, 0x36, 0x02, 0x1c,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x20, 0x36, 0x02, 0x20, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x24, 0x36, 0x02, 0x24, 0x20, 0x02, 0x20, 0x01,
+      0x28, 0x02, 0x28, 0x36, 0x02, 0x28, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+      0x2c, 0x36, 0x02, 0x2c, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x30, 0x36,
+      0x02, 0x30, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x34, 0x36, 0x02, 0x34,
+      0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x38, 0x36, 0x02, 0x38, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x3c, 0x36, 0x02, 0x3c, 0x20, 0x01, 0x41, 0x40,
+      0x6b, 0x21, 0x01, 0x20, 0x02, 0x41, 0x40, 0x6b, 0x22, 0x02, 0x20, 0x05,
+      0x4d, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x04, 0x4f, 0x0d, 0x01,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00,
+      0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x04, 0x6a,
+      0x22, 0x02, 0x20, 0x04, 0x49, 0x0d, 0x00, 0x0b, 0x0c, 0x01, 0x0b, 0x20,
+      0x03, 0x41, 0x04, 0x49, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01,
+      0x0b, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x22, 0x04, 0x20, 0x00, 0x49, 0x04,
+      0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02,
+      0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, 0x20, 0x02,
+      0x20, 0x01, 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x20, 0x01,
+      0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21,
+      0x01, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x20, 0x04, 0x4d, 0x0d,
+      0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x03, 0x49, 0x04, 0x40, 0x03, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01,
+      0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02,
+      0x20, 0x03, 0x47, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0x06, 0x00,
+      0x10, 0x0c, 0x41, 0x00, 0x0b, 0x03, 0x00, 0x01, 0x0b, 0x7e, 0x01, 0x03,
+      0x7f, 0x23, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x01, 0x24, 0x00, 0x20, 0x01,
+      0x41, 0x0a, 0x3a, 0x00, 0x0f, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10,
+      0x22, 0x02, 0x45, 0x04, 0x40, 0x20, 0x00, 0x10, 0x02, 0x0d, 0x01, 0x20,
+      0x00, 0x28, 0x02, 0x10, 0x21, 0x02, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28,
+      0x02, 0x14, 0x22, 0x03, 0x20, 0x02, 0x4f, 0x0d, 0x00, 0x20, 0x00, 0x2c,
+      0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x03, 0x41,
+      0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x03, 0x41, 0x0a, 0x3a, 0x00, 0x00,
+      0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x01, 0x41, 0x0f, 0x6a, 0x41, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x41, 0x01, 0x47, 0x0d,
+      0x00, 0x20, 0x01, 0x2d, 0x00, 0x0f, 0x1a, 0x0b, 0x20, 0x01, 0x41, 0x10,
+      0x6a, 0x24, 0x00, 0x0b, 0x04, 0x00, 0x42, 0x00, 0x0b, 0x04, 0x00, 0x41,
+      0x00, 0x0b, 0x31, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x21, 0x02, 0x20, 0x02,
+      0x02, 0x7f, 0x20, 0x01, 0x28, 0x02, 0x4c, 0x41, 0x7f, 0x4c, 0x04, 0x40,
+      0x20, 0x02, 0x20, 0x01, 0x10, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x20,
+      0x01, 0x10, 0x01, 0x0b, 0x22, 0x01, 0x46, 0x04, 0x40, 0x20, 0x00, 0x0f,
+      0x0b, 0x20, 0x01, 0x0b, 0x62, 0x01, 0x03, 0x7f, 0x41, 0x80, 0x08, 0x21,
+      0x00, 0x03, 0x40, 0x20, 0x00, 0x22, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x00,
+      0x20, 0x01, 0x28, 0x02, 0x00, 0x22, 0x02, 0x41, 0x7f, 0x73, 0x20, 0x02,
+      0x41, 0xff, 0xfd, 0xfb, 0x77, 0x6a, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84,
+      0x78, 0x71, 0x45, 0x0d, 0x00, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0xff,
+      0x01, 0x71, 0x45, 0x04, 0x40, 0x20, 0x01, 0x21, 0x00, 0x0c, 0x01, 0x0b,
+      0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x21, 0x02, 0x20, 0x01, 0x41,
+      0x01, 0x6a, 0x22, 0x00, 0x21, 0x01, 0x20, 0x02, 0x0d, 0x00, 0x0b, 0x0b,
+      0x20, 0x00, 0x41, 0x80, 0x08, 0x6b, 0x0b, 0x0c, 0x00, 0x02, 0x7f, 0x41,
+      0x00, 0x41, 0x00, 0x10, 0x04, 0x0b, 0x1a, 0x0b, 0x66, 0x01, 0x02, 0x7f,
+      0x41, 0x90, 0x08, 0x28, 0x02, 0x00, 0x22, 0x00, 0x28, 0x02, 0x4c, 0x41,
+      0x00, 0x4e, 0x04, 0x7f, 0x41, 0x01, 0x05, 0x20, 0x01, 0x0b, 0x1a, 0x02,
+      0x40, 0x41, 0x7f, 0x41, 0x00, 0x10, 0x0a, 0x22, 0x01, 0x20, 0x01, 0x20,
+      0x00, 0x10, 0x09, 0x47, 0x1b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x02, 0x40,
+      0x20, 0x00, 0x2d, 0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00,
+      0x28, 0x02, 0x14, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x10, 0x4f, 0x0d,
+      0x00, 0x20, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20,
+      0x01, 0x41, 0x0a, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x10,
+      0x06, 0x0b, 0x0b, 0x3d, 0x01, 0x01, 0x7f, 0x20, 0x02, 0x04, 0x40, 0x03,
+      0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x20,
+      0x02, 0x41, 0x80, 0xc0, 0x00, 0x49, 0x1b, 0x22, 0x03, 0x10, 0x03, 0x21,
+      0x00, 0x20, 0x01, 0x41, 0x80, 0x40, 0x6b, 0x21, 0x01, 0x20, 0x00, 0x41,
+      0x80, 0x40, 0x6b, 0x21, 0x00, 0x20, 0x02, 0x20, 0x03, 0x6b, 0x22, 0x02,
+      0x0d, 0x00, 0x0b, 0x0b, 0x0b, 0xb1, 0x02, 0x01, 0x06, 0x7f, 0x23, 0x00,
+      0x41, 0x20, 0x6b, 0x22, 0x03, 0x24, 0x00, 0x20, 0x03, 0x20, 0x00, 0x28,
+      0x02, 0x1c, 0x22, 0x04, 0x36, 0x02, 0x10, 0x20, 0x00, 0x28, 0x02, 0x14,
+      0x21, 0x05, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x1c, 0x20, 0x03, 0x20,
+      0x01, 0x36, 0x02, 0x18, 0x20, 0x03, 0x20, 0x05, 0x20, 0x04, 0x6b, 0x22,
+      0x01, 0x36, 0x02, 0x14, 0x20, 0x01, 0x20, 0x02, 0x6a, 0x21, 0x06, 0x41,
+      0x02, 0x21, 0x05, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x21, 0x01, 0x03, 0x40,
+      0x02, 0x40, 0x02, 0x7f, 0x20, 0x06, 0x02, 0x7f, 0x20, 0x00, 0x28, 0x02,
+      0x3c, 0x20, 0x01, 0x20, 0x05, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, 0x00,
+      0x04, 0x40, 0x20, 0x03, 0x41, 0x7f, 0x36, 0x02, 0x0c, 0x41, 0x7f, 0x0c,
+      0x01, 0x0b, 0x20, 0x03, 0x28, 0x02, 0x0c, 0x0b, 0x22, 0x04, 0x46, 0x04,
+      0x40, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02,
+      0x1c, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01,
+      0x20, 0x00, 0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x20, 0x02, 0x0c,
+      0x01, 0x0b, 0x20, 0x04, 0x41, 0x7f, 0x4a, 0x0d, 0x01, 0x20, 0x00, 0x41,
+      0x00, 0x36, 0x02, 0x1c, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, 0x10, 0x20,
+      0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+      0x41, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x00, 0x1a, 0x20, 0x02,
+      0x20, 0x01, 0x28, 0x02, 0x04, 0x6b, 0x0b, 0x21, 0x04, 0x20, 0x03, 0x41,
+      0x20, 0x6a, 0x24, 0x00, 0x20, 0x04, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0x08,
+      0x6a, 0x20, 0x01, 0x20, 0x04, 0x20, 0x01, 0x28, 0x02, 0x04, 0x22, 0x07,
+      0x4b, 0x22, 0x08, 0x1b, 0x22, 0x01, 0x20, 0x04, 0x20, 0x07, 0x41, 0x00,
+      0x20, 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x20, 0x01, 0x28, 0x02, 0x00, 0x6a,
+      0x36, 0x02, 0x00, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x04, 0x20, 0x07,
+      0x6b, 0x36, 0x02, 0x04, 0x20, 0x06, 0x20, 0x04, 0x6b, 0x21, 0x06, 0x20,
+      0x05, 0x20, 0x08, 0x6b, 0x21, 0x05, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x0b,
+      0x0b, 0x4d, 0x06, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x12, 0x68, 0x65, 0x6c,
+      0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00, 0x00,
+      0x00, 0x18, 0x04, 0x00, 0x41, 0x98, 0x08, 0x0b, 0x01, 0x05, 0x00, 0x41,
+      0xa4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xbc, 0x08, 0x0b, 0x0e, 0x02,
+      0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00,
+      0x04, 0x00, 0x41, 0xd4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xe3, 0x08,
+      0x0b, 0x05, 0x0a, 0xff, 0xff, 0xff, 0xff,
+    ]);
+
+    // Trying to import WASI twice.
+    expect(
+        () => WasmModule(helloWorldData).instantiate().enableWasi().enableWasi(),
+        throwsA(predicate(
+            (Exception e) => "$e".contains("WASI is already enabled"))));
+
+    // Missing imports due to not enabling WASI.
+    expect(() => WasmModule(helloWorldData).instantiate().build(),
+        throwsA(predicate((Exception e) => "$e".contains("Missing import"))));
+
+    // Trying to get stdout/stderr without WASI enabled (WASI function import has
+    // been manually filled).
+    var inst = WasmModule(helloWorldData)
+        .instantiate()
+        .addFunction("wasi_unstable", "fd_write",
+            (int fd, int iovs, int iovs_len, int unused) => 0)
+        .build();
+    expect(
+        () => inst.stdout,
+        throwsA(predicate((Exception e) =>
+            "$e".contains("Can't capture stdout without WASI enabled"))));
+    expect(
+        () => inst.stderr,
+        throwsA(predicate((Exception e) =>
+            "$e".contains("Can't capture stderr without WASI enabled"))));
+  });
+}
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index a97d6bd..be649ed 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -182,7 +182,7 @@
   // Returns true if these roots are the first snapshot loaded into a heap, and
   // so can assume any canonical objects don't already exist. Returns false if
   // some other snapshot may be loaded before these roots, and so written
-  // canonical objects need to run canoncalization during load.
+  // canonical objects need to run canonicalization during load.
   virtual bool AddBaseObjects(Deserializer* deserializer) = 0;
   virtual void ReadRoots(Deserializer* deserializer) = 0;
   virtual void PostLoad(Deserializer* deserializer, const Array& refs) = 0;
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 512db83..1011d8c 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1201,11 +1201,6 @@
   // them here.
   if (!value.IsNull() && !value.IsSmi() && value.IsInstance() &&
       !value.IsCanonical() && (value.ptr() != Object::sentinel().ptr())) {
-    // The only allowed type for which IsCanonical() never answers true is
-    // TypeParameter. (They are treated as canonical due to how they are
-    // created, but there is no way to canonicalize a new TypeParameter
-    // instance containing the same information as an existing instance.)
-    //
     // Arrays in ConstantInstrs are usually immutable and canonicalized, but
     // there are at least a couple of cases where one or both is not true:
     //
@@ -1224,8 +1219,7 @@
     //
     // LibraryPrefixes are also never canonicalized since their equality is
     // their identity.
-    ASSERT(value.IsTypeParameter() || value.IsArray() || value.IsTypedData() ||
-           value.IsLibraryPrefix());
+    ASSERT(value.IsArray() || value.IsTypedData() || value.IsLibraryPrefix());
   }
 #endif
 }
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 491e59f..32cbeee 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1268,7 +1268,7 @@
   static word cache_offset();
 
   static const word kTestEntryLength;
-  static const word kInstanceClassIdOrFunction;
+  static const word kInstanceCidOrSignature;
   static const word kDestinationType;
   static const word kInstanceTypeArguments;
   static const word kInstantiatorTypeArguments;
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 91374ad..95c2e89 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -77,7 +77,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -616,7 +616,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -1160,7 +1160,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -1696,7 +1696,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -2241,7 +2241,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -2785,7 +2785,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -3329,7 +3329,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -3862,7 +3862,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -4400,7 +4400,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -4930,7 +4930,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -5469,7 +5469,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -6007,7 +6007,7 @@
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -6559,7 +6559,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -7163,7 +7163,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -7773,7 +7773,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -8381,7 +8381,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -8988,7 +8988,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -9594,7 +9594,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -10191,7 +10191,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -10794,7 +10794,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -11395,7 +11395,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
@@ -11995,7 +11995,7 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kFunctionTypeArguments = 5;
 static constexpr dart::compiler::target::word
-    AOT_SubtypeTestCache_kInstanceClassIdOrFunction = 1;
+    AOT_SubtypeTestCache_kInstanceCidOrSignature = 1;
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_kDestinationType = 2;
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index fe34979..08f4fe7 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -78,7 +78,7 @@
   CONSTANT(NativeEntry, kNumCallWrapperArguments)                              \
   CONSTANT(String, kMaxElements)                                               \
   CONSTANT(SubtypeTestCache, kFunctionTypeArguments)                           \
-  CONSTANT(SubtypeTestCache, kInstanceClassIdOrFunction)                       \
+  CONSTANT(SubtypeTestCache, kInstanceCidOrSignature)                          \
   CONSTANT(SubtypeTestCache, kDestinationType)                                 \
   CONSTANT(SubtypeTestCache, kInstanceDelayedFunctionTypeArguments)            \
   CONSTANT(SubtypeTestCache, kInstanceParentFunctionTypeArguments)             \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index ea32cf7..0045e4e 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -2676,20 +2676,23 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrSignatureReg,
                            TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrSignatureReg,
                    TypeTestABI::kInstanceReg);
   }
-  __ CompareImmediate(STCInternalRegs::kInstanceCidOrFunctionReg, kClosureCid);
+  __ CompareImmediate(STCInternalRegs::kInstanceCidOrSignatureReg, kClosureCid);
   __ b(&not_closure, NE);
 
   // Closure handling.
   {
-    __ ldr(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ ldr(STCInternalRegs::kInstanceCidOrSignatureReg,
            FieldAddress(TypeTestABI::kInstanceReg,
                         target::Closure::function_offset()));
+    __ ldr(STCInternalRegs::kInstanceCidOrSignatureReg,
+           FieldAddress(STCInternalRegs::kInstanceCidOrSignatureReg,
+                        target::Function::signature_offset()));
     if (n >= 3) {
       __ ldr(
           kInstanceInstantiatorTypeArgumentsReg,
@@ -2713,7 +2716,8 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+      __ LoadClassById(kScratchReg,
+                       STCInternalRegs::kInstanceCidOrSignatureReg);
       __ mov(kInstanceInstantiatorTypeArgumentsReg, Operand(kNullReg));
       __ ldr(
           kScratchReg,
@@ -2733,7 +2737,7 @@
         __ PushRegister(kNullReg);
       }
     }
-    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrSignatureReg);
   }
 
   const intptr_t kNoDepth = -1;
@@ -2747,10 +2751,10 @@
   __ ldr(kScratchReg,
          Address(kCacheArrayReg,
                  target::kWordSize *
-                     target::SubtypeTestCache::kInstanceClassIdOrFunction));
+                     target::SubtypeTestCache::kInstanceCidOrSignature));
   __ cmp(kScratchReg, Operand(kNullReg));
   __ b(&not_found, EQ);
-  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrFunctionReg));
+  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrSignatureReg));
   if (n == 1) {
     __ b(&found, EQ);
   } else {
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index ef37b4e..428b5df 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2829,20 +2829,23 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrSignatureReg,
                            TypeTestABI::TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrSignatureReg,
                    TypeTestABI::kInstanceReg);
   }
-  __ CompareImmediate(STCInternalRegs::kInstanceCidOrFunctionReg, kClosureCid);
+  __ CompareImmediate(STCInternalRegs::kInstanceCidOrSignatureReg, kClosureCid);
   __ b(&not_closure, NE);
 
   // Closure handling.
   {
-    __ ldr(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ ldr(STCInternalRegs::kInstanceCidOrSignatureReg,
            FieldAddress(TypeTestABI::kInstanceReg,
                         target::Closure::function_offset()));
+    __ LoadCompressed(STCInternalRegs::kInstanceCidOrSignatureReg,
+                      FieldAddress(STCInternalRegs::kInstanceCidOrSignatureReg,
+                                   target::Function::signature_offset()));
     if (n >= 3) {
       __ ldr(
           STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
@@ -2865,7 +2868,8 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+      __ LoadClassById(kScratchReg,
+                       STCInternalRegs::kInstanceCidOrSignatureReg);
       __ mov(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ LoadFieldFromOffset(
           kScratchReg, kScratchReg,
@@ -2886,7 +2890,7 @@
                kNullReg);
       }
     }
-    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrSignatureReg);
   }
 
   Label found, done, next_iteration;
@@ -2896,10 +2900,10 @@
   __ ldr(kScratchReg,
          Address(kCacheArrayReg,
                  target::kWordSize *
-                     target::SubtypeTestCache::kInstanceClassIdOrFunction));
+                     target::SubtypeTestCache::kInstanceCidOrSignature));
   __ cmp(kScratchReg, Operand(kNullReg));
   __ b(&done, EQ);
-  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrFunctionReg));
+  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrSignatureReg));
   if (n == 1) {
     __ b(&found, EQ);
   } else {
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 7e7e6da..940b20f 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -2252,7 +2252,7 @@
   // Other values are stored in non-kInstanceReg registers from TypeTestABI.
   const Register kCacheArrayReg = TypeTestABI::kInstantiatorTypeArgumentsReg;
   const Register kScratchReg = TypeTestABI::kSubtypeTestCacheReg;
-  const Register kInstanceCidOrFunction =
+  const Register kInstanceCidOrSignature =
       TypeTestABI::kFunctionTypeArgumentsReg;
   const Register kInstanceInstantiatorTypeArgumentsReg =
       TypeTestABI::kDstTypeReg;
@@ -2286,18 +2286,21 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassIdMayBeSmi(kInstanceCidOrSignature, TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassId(kInstanceCidOrSignature, TypeTestABI::kInstanceReg);
   }
-  __ cmpl(kInstanceCidOrFunction, Immediate(kClosureCid));
+  __ cmpl(kInstanceCidOrSignature, Immediate(kClosureCid));
   __ j(NOT_EQUAL, &not_closure, Assembler::kNearJump);
 
   // Closure handling.
   {
-    __ movl(kInstanceCidOrFunction,
+    __ movl(kInstanceCidOrSignature,
             FieldAddress(TypeTestABI::kInstanceReg,
                          target::Closure::function_offset()));
+    __ movl(kInstanceCidOrSignature,
+            FieldAddress(kInstanceCidOrSignature,
+                         target::Function::signature_offset()));
     if (n >= 3) {
       __ movl(
           kInstanceInstantiatorTypeArgumentsReg,
@@ -2320,7 +2323,7 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
+      __ LoadClassById(kScratchReg, kInstanceCidOrSignature);
       __ movl(kInstanceInstantiatorTypeArgumentsReg, raw_null);
       __ movl(
           kScratchReg,
@@ -2338,7 +2341,7 @@
         __ pushl(raw_null);  // function.
       }
     }
-    __ SmiTag(kInstanceCidOrFunction);
+    __ SmiTag(kInstanceCidOrSignature);
   }
 
   if (n >= 7) {
@@ -2358,10 +2361,10 @@
   __ movl(kScratchReg,
           Address(kCacheArrayReg,
                   target::kWordSize *
-                      target::SubtypeTestCache::kInstanceClassIdOrFunction));
+                      target::SubtypeTestCache::kInstanceCidOrSignature));
   __ cmpl(kScratchReg, raw_null);
   __ j(EQUAL, &done, Assembler::kNearJump);
-  __ cmpl(kScratchReg, kInstanceCidOrFunction);
+  __ cmpl(kScratchReg, kInstanceCidOrSignature);
   if (n == 1) {
     __ j(EQUAL, &done, Assembler::kNearJump);
   } else {
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 9aa8e8c..6b0782f 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2791,20 +2791,23 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrSignatureReg,
                            TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrSignatureReg,
                    TypeTestABI::kInstanceReg);
   }
-  __ cmpq(STCInternalRegs::kInstanceCidOrFunctionReg, Immediate(kClosureCid));
+  __ cmpq(STCInternalRegs::kInstanceCidOrSignatureReg, Immediate(kClosureCid));
   __ j(NOT_EQUAL, &not_closure, Assembler::kNearJump);
 
   // Closure handling.
   {
-    __ movq(STCInternalRegs::kInstanceCidOrFunctionReg,
+    __ movq(STCInternalRegs::kInstanceCidOrSignatureReg,
             FieldAddress(TypeTestABI::kInstanceReg,
                          target::Closure::function_offset()));
+    __ LoadCompressed(STCInternalRegs::kInstanceCidOrSignatureReg,
+                      FieldAddress(STCInternalRegs::kInstanceCidOrSignatureReg,
+                                   target::Function::signature_offset()));
     if (n >= 3) {
       __ movq(
           STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
@@ -2828,7 +2831,8 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+      __ LoadClassById(kScratchReg,
+                       STCInternalRegs::kInstanceCidOrSignatureReg);
       __ movq(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ movl(
           kScratchReg,
@@ -2846,7 +2850,7 @@
         __ movq(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
       }
     }
-    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrSignatureReg);
   }
 
   Label found, not_found, next_iteration;
@@ -2856,10 +2860,10 @@
   __ movq(kScratchReg,
           Address(STCInternalRegs::kCacheEntryReg,
                   target::kWordSize *
-                      target::SubtypeTestCache::kInstanceClassIdOrFunction));
+                      target::SubtypeTestCache::kInstanceCidOrSignature));
   __ cmpq(kScratchReg, kNullReg);
   __ j(EQUAL, &not_found, Assembler::kNearJump);
-  __ cmpq(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+  __ cmpq(kScratchReg, STCInternalRegs::kInstanceCidOrSignatureReg);
   if (n == 1) {
     __ j(EQUAL, &found, Assembler::kNearJump);
   } else {
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index f638186..5ef978d 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -350,9 +350,9 @@
 // Registers in addition to those listed in TypeTestABI used inside the
 // implementation of subtype test cache stubs that are _not_ preserved.
 struct STCInternalRegs {
-  static const Register kInstanceCidOrFunctionReg = R9;
+  static const Register kInstanceCidOrSignatureReg = R9;
 
-  static const intptr_t kInternalRegisters = (1 << kInstanceCidOrFunctionReg);
+  static const intptr_t kInternalRegisters = (1 << kInstanceCidOrSignatureReg);
 };
 
 // Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 8abe440..69f5cf0 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -183,13 +183,13 @@
 // Registers in addition to those listed in TypeTestABI used inside the
 // implementation of subtype test cache stubs that are _not_ preserved.
 struct STCInternalRegs {
-  static const Register kInstanceCidOrFunctionReg = R6;
+  static const Register kInstanceCidOrSignatureReg = R6;
   static const Register kInstanceInstantiatorTypeArgumentsReg = R5;
   static const Register kInstanceParentFunctionTypeArgumentsReg = R9;
   static const Register kInstanceDelayedFunctionTypeArgumentsReg = R10;
 
   static const intptr_t kInternalRegisters =
-      (1 << kInstanceCidOrFunctionReg) |
+      (1 << kInstanceCidOrSignatureReg) |
       (1 << kInstanceInstantiatorTypeArgumentsReg) |
       (1 << kInstanceParentFunctionTypeArgumentsReg) |
       (1 << kInstanceDelayedFunctionTypeArgumentsReg);
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 469b90b..953c2ce 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -160,11 +160,11 @@
 // implementation of subtype test cache stubs that are _not_ preserved.
 struct STCInternalRegs {
   static const Register kCacheEntryReg = RDI;
-  static const Register kInstanceCidOrFunctionReg = R10;
+  static const Register kInstanceCidOrSignatureReg = R10;
   static const Register kInstanceInstantiatorTypeArgumentsReg = R13;
 
   static const intptr_t kInternalRegisters =
-      (1 << kCacheEntryReg) | (1 << kInstanceCidOrFunctionReg) |
+      (1 << kCacheEntryReg) | (1 << kInstanceCidOrSignatureReg) |
       (1 << kInstanceInstantiatorTypeArgumentsReg);
 };
 
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index f5cc809..46124a8 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -2116,7 +2116,7 @@
         entries_(Array::Handle(zone)),
         instantiator_type_arguments_(TypeArguments::Handle(zone)),
         function_type_arguments_(TypeArguments::Handle(zone)),
-        instance_cid_or_function_(Object::Handle(zone)),
+        instance_cid_or_signature_(Object::Handle(zone)),
         instance_type_arguments_(TypeArguments::Handle(zone)),
         parent_function_type_arguments_(TypeArguments::Handle(zone)),
         delayed_function_type_arguments_(TypeArguments::Handle(zone)) {}
@@ -2215,7 +2215,7 @@
     cls_ = value.clazz();
     const intptr_t cid = cls_.id();
     if (cid == kClosureCid) {
-      instance_cid_or_function_ = Closure::Cast(value).function();
+      instance_cid_or_signature_ = Closure::Cast(value).signature();
       instance_type_arguments_ =
           Closure::Cast(value).instantiator_type_arguments();
       parent_function_type_arguments_ =
@@ -2223,7 +2223,7 @@
       delayed_function_type_arguments_ =
           Closure::Cast(value).delayed_type_arguments();
     } else {
-      instance_cid_or_function_ = Smi::New(cid);
+      instance_cid_or_signature_ = Smi::New(cid);
       if (cls_.NumTypeArguments() > 0) {
         instance_type_arguments_ = value_.GetTypeArguments();
       } else {
@@ -2243,8 +2243,8 @@
     bool cache_hit = false;
     for (intptr_t i = 0; entries_.At(i) != Object::null();
          i += SubtypeTestCache::kTestEntryLength) {
-      if ((entries_.At(i + SubtypeTestCache::kInstanceClassIdOrFunction) ==
-           instance_cid_or_function_.ptr()) &&
+      if ((entries_.At(i + SubtypeTestCache::kInstanceCidOrSignature) ==
+           instance_cid_or_signature_.ptr()) &&
           (entries_.At(i + SubtypeTestCache::kDestinationType) ==
            type_.ptr()) &&
           (entries_.At(i + SubtypeTestCache::kInstanceTypeArguments) ==
@@ -2275,7 +2275,7 @@
         ASSERT(!FLAG_identity_reload);
         field.set_needs_load_guard(true);
       } else {
-        cache_.AddCheck(instance_cid_or_function_, type_,
+        cache_.AddCheck(instance_cid_or_signature_, type_,
                         instance_type_arguments_, instantiator_type_arguments_,
                         function_type_arguments_,
                         parent_function_type_arguments_,
@@ -2293,7 +2293,7 @@
   Array& entries_;
   TypeArguments& instantiator_type_arguments_;
   TypeArguments& function_type_arguments_;
-  Object& instance_cid_or_function_;
+  Object& instance_cid_or_signature_;
   TypeArguments& instance_type_arguments_;
   TypeArguments& parent_function_type_arguments_;
   TypeArguments& delayed_function_type_arguments_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0834a41..7a61184 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -9367,7 +9367,11 @@
   PrintParameters(thread, zone, name_visibility, printer);
   printer->AddString(") => ");
   const AbstractType& res_type = AbstractType::Handle(zone, result_type());
-  res_type.PrintName(name_visibility, printer);
+  if (!res_type.IsNull()) {
+    res_type.PrintName(name_visibility, printer);
+  } else {
+    printer->AddString("null");
+  }
 }
 
 bool Function::HasInstantiatedSignature(Genericity genericity,
@@ -17953,7 +17957,7 @@
 }
 
 void SubtypeTestCache::AddCheck(
-    const Object& instance_class_id_or_function,
+    const Object& instance_class_id_or_signature,
     const AbstractType& destination_type,
     const TypeArguments& instance_type_arguments,
     const TypeArguments& instantiator_type_arguments,
@@ -17973,8 +17977,8 @@
 
   SubtypeTestCacheTable entries(data);
   auto entry = entries[old_num];
-  ASSERT(entry.Get<kInstanceClassIdOrFunction>() == Object::null());
-  entry.Set<kInstanceClassIdOrFunction>(instance_class_id_or_function);
+  ASSERT(entry.Get<kInstanceCidOrSignature>() == Object::null());
+  entry.Set<kInstanceCidOrSignature>(instance_class_id_or_signature);
   entry.Set<kDestinationType>(destination_type);
   entry.Set<kInstanceTypeArguments>(instance_type_arguments);
   entry.Set<kInstantiatorTypeArguments>(instantiator_type_arguments);
@@ -17992,7 +17996,7 @@
 
 void SubtypeTestCache::GetCheck(
     intptr_t ix,
-    Object* instance_class_id_or_function,
+    Object* instance_class_id_or_signature,
     AbstractType* destination_type,
     TypeArguments* instance_type_arguments,
     TypeArguments* instantiator_type_arguments,
@@ -18004,7 +18008,7 @@
              ->isolate_group()
              ->subtype_test_cache_mutex()
              ->IsOwnedByCurrentThread());
-  GetCurrentCheck(ix, instance_class_id_or_function, destination_type,
+  GetCurrentCheck(ix, instance_class_id_or_signature, destination_type,
                   instance_type_arguments, instantiator_type_arguments,
                   function_type_arguments,
                   instance_parent_function_type_arguments,
@@ -18013,7 +18017,7 @@
 
 void SubtypeTestCache::GetCurrentCheck(
     intptr_t ix,
-    Object* instance_class_id_or_function,
+    Object* instance_class_id_or_signature,
     AbstractType* destination_type,
     TypeArguments* instance_type_arguments,
     TypeArguments* instantiator_type_arguments,
@@ -18024,7 +18028,7 @@
   Array& data = Array::Handle(cache());
   SubtypeTestCacheTable entries(data);
   auto entry = entries[ix];
-  *instance_class_id_or_function = entry.Get<kInstanceClassIdOrFunction>();
+  *instance_class_id_or_signature = entry.Get<kInstanceCidOrSignature>();
   *destination_type = entry.Get<kDestinationType>();
   *instance_type_arguments = entry.Get<kInstanceTypeArguments>();
   *instantiator_type_arguments = entry.Get<kInstantiatorTypeArguments>();
@@ -18037,7 +18041,7 @@
 }
 
 bool SubtypeTestCache::HasCheck(
-    const Object& instance_class_id_or_function,
+    const Object& instance_class_id_or_signature,
     const AbstractType& destination_type,
     const TypeArguments& instance_type_arguments,
     const TypeArguments& instantiator_type_arguments,
@@ -18056,8 +18060,8 @@
   SubtypeTestCacheTable entries(data);
   for (intptr_t i = 0; i < last_index; i++) {
     const auto entry = entries[i];
-    if (entry.Get<kInstanceClassIdOrFunction>() ==
-            instance_class_id_or_function.ptr() &&
+    if (entry.Get<kInstanceCidOrSignature>() ==
+            instance_class_id_or_signature.ptr() &&
         entry.Get<kDestinationType>() == destination_type.ptr() &&
         entry.Get<kInstanceTypeArguments>() == instance_type_arguments.ptr() &&
         entry.Get<kInstantiatorTypeArguments>() ==
@@ -18097,7 +18101,7 @@
     const char* line_prefix) const {
   const char* separator =
       line_prefix == nullptr ? ", " : OS::SCreate(zone, "\n%s", line_prefix);
-  auto& instance_class_id_or_function = Object::Handle(zone);
+  auto& instance_class_id_or_signature = Object::Handle(zone);
   auto& destination_type = AbstractType::Handle(zone);
   auto& instance_type_arguments = TypeArguments::Handle(zone);
   auto& instantiator_type_arguments = TypeArguments::Handle(zone);
@@ -18105,7 +18109,7 @@
   auto& instance_parent_function_type_arguments = TypeArguments::Handle(zone);
   auto& instance_delayed_type_arguments = TypeArguments::Handle(zone);
   auto& result = Bool::Handle(zone);
-  GetCurrentCheck(index, &instance_class_id_or_function, &destination_type,
+  GetCurrentCheck(index, &instance_class_id_or_signature, &destination_type,
                   &instance_type_arguments, &instantiator_type_arguments,
                   &function_type_arguments,
                   &instance_parent_function_type_arguments,
@@ -18114,7 +18118,7 @@
   buffer->Printf(
       "[ %#" Px ", %#" Px ", %#" Px ", %#" Px ", %#" Px ", %#" Px ", %#" Px
       ", %#" Px " ]",
-      static_cast<uword>(instance_class_id_or_function.ptr()),
+      static_cast<uword>(instance_class_id_or_signature.ptr()),
       static_cast<uword>(destination_type.ptr()),
       static_cast<uword>(instance_type_arguments.ptr()),
       static_cast<uword>(instantiator_type_arguments.ptr()),
@@ -18122,14 +18126,14 @@
       static_cast<uword>(instance_parent_function_type_arguments.ptr()),
       static_cast<uword>(instance_delayed_type_arguments.ptr()),
       static_cast<uword>(result.ptr()));
-  if (instance_class_id_or_function.IsSmi()) {
+  if (instance_class_id_or_signature.IsSmi()) {
     buffer->Printf("%sclass id: %" Pd "", separator,
-                   Smi::Cast(instance_class_id_or_function).Value());
+                   Smi::Cast(instance_class_id_or_signature).Value());
   } else {
-    ASSERT(instance_class_id_or_function.IsFunction());
-    buffer->Printf("%sfunction: %s", separator,
-                   Function::Cast(instance_class_id_or_function)
-                       .ToFullyQualifiedCString());
+    ASSERT(instance_class_id_or_signature.IsFunctionType());
+    buffer->Printf(
+        "%sfunction: %s", separator,
+        FunctionType::Cast(instance_class_id_or_signature).ToCString());
   }
   if (!destination_type.IsNull()) {
     buffer->Printf("%sdestination type: %s", separator,
@@ -18147,11 +18151,11 @@
     }
   }
   if (!instance_type_arguments.IsNull()) {
-    if (instance_class_id_or_function.IsSmi()) {
+    if (instance_class_id_or_signature.IsSmi()) {
       buffer->Printf("%sinstance type arguments: %s", separator,
                      instance_type_arguments.ToCString());
     } else {
-      ASSERT(instance_class_id_or_function.IsFunction());
+      ASSERT(instance_class_id_or_signature.IsFunctionType());
       buffer->Printf("%sclosure instantiator function type arguments: %s",
                      separator, instance_type_arguments.ToCString());
     }
@@ -18165,12 +18169,12 @@
                    function_type_arguments.ToCString());
   }
   if (!instance_parent_function_type_arguments.IsNull()) {
-    ASSERT(instance_class_id_or_function.IsFunction());
+    ASSERT(instance_class_id_or_signature.IsFunctionType());
     buffer->Printf("%sclosure parent function type arguments: %s", separator,
                    instance_parent_function_type_arguments.ToCString());
   }
   if (!instance_delayed_type_arguments.IsNull()) {
-    ASSERT(instance_class_id_or_function.IsFunction());
+    ASSERT(instance_class_id_or_signature.IsFunctionType());
     buffer->Printf("%sclosure delayed function type arguments: %s", separator,
                    instance_delayed_type_arguments.ToCString());
   }
@@ -24972,6 +24976,10 @@
                         const Function& function,
                         const Context& context,
                         Heap::Space space) {
+  ASSERT(instantiator_type_arguments.IsCanonical());
+  ASSERT(function_type_arguments.IsCanonical());
+  ASSERT(delayed_type_arguments.IsCanonical());
+  ASSERT(FunctionType::Handle(function.signature()).IsCanonical());
   Closure& result = Closure::Handle();
   {
     ObjectPtr raw =
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 4766260..a04f9b1 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -6940,7 +6940,7 @@
  public:
   enum Entries {
     kTestResult = 0,
-    kInstanceClassIdOrFunction = 1,
+    kInstanceCidOrSignature = 1,
     kDestinationType = 2,
     kInstanceTypeArguments = 3,
     kInstantiatorTypeArguments = 4,
@@ -6951,7 +6951,7 @@
   };
 
   virtual intptr_t NumberOfChecks() const;
-  void AddCheck(const Object& instance_class_id_or_function,
+  void AddCheck(const Object& instance_class_id_or_signature,
                 const AbstractType& destination_type,
                 const TypeArguments& instance_type_arguments,
                 const TypeArguments& instantiator_type_arguments,
@@ -6960,7 +6960,7 @@
                 const TypeArguments& instance_delayed_type_arguments,
                 const Bool& test_result) const;
   void GetCheck(intptr_t ix,
-                Object* instance_class_id_or_function,
+                Object* instance_class_id_or_signature,
                 AbstractType* destination_type,
                 TypeArguments* instance_type_arguments,
                 TypeArguments* instantiator_type_arguments,
@@ -6972,7 +6972,7 @@
   // Like GetCheck(), but does not require the subtype test cache mutex and so
   // may see an outdated view of the cache.
   void GetCurrentCheck(intptr_t ix,
-                       Object* instance_class_id_or_function,
+                       Object* instance_class_id_or_signature,
                        AbstractType* destination_type,
                        TypeArguments* instance_type_arguments,
                        TypeArguments* instantiator_type_arguments,
@@ -6987,7 +6987,7 @@
   //
   // If [index] is not nullptr, then it is set to the matching entry's index.
   // If [result] is not nullptr, then it is set to the matching entry's result.
-  bool HasCheck(const Object& instance_class_id_or_function,
+  bool HasCheck(const Object& instance_class_id_or_signature,
                 const AbstractType& destination_type,
                 const TypeArguments& instance_type_arguments,
                 const TypeArguments& instantiator_type_arguments,
@@ -10982,6 +10982,10 @@
     return OFFSET_OF(UntaggedClosure, function_);
   }
 
+  FunctionTypePtr signature() const {
+    return untag()->function()->untag()->signature();
+  }
+
   ContextPtr context() const { return untag()->context(); }
   static intptr_t context_offset() {
     return OFFSET_OF(UntaggedClosure, context_);
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 324a031..d119a05 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2644,7 +2644,7 @@
   const Context& context = Context::Handle(Context::New(0));
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
-  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   parent = Function::New(signature, parent_name,
                          UntaggedFunction::kRegularFunction, false, false,
                          false, false, false, cls, TokenPosition::kMinSource);
@@ -2652,12 +2652,17 @@
   {
     SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
     cls.SetFunctions(functions);
+    cls.Finalize();
   }
 
   Function& function = Function::Handle();
   const String& function_name = String::Handle(Symbols::New(thread, "foo"));
   function = Function::NewClosureFunction(function_name, parent,
                                           TokenPosition::kMinSource);
+  signature = function.signature();
+  signature.set_result_type(Object::dynamic_type());
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  function.set_signature(signature);
   const Closure& closure = Closure::Handle(
       Closure::New(Object::null_type_arguments(), Object::null_type_arguments(),
                    function, context));
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index e420a88..7584d90 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -736,6 +736,9 @@
     const Bool& result,
     const SubtypeTestCache& new_cache) {
   ASSERT(!new_cache.IsNull());
+  ASSERT(destination_type.IsCanonical());
+  ASSERT(instantiator_type_arguments.IsCanonical());
+  ASSERT(function_type_arguments.IsCanonical());
   Class& instance_class = Class::Handle(zone);
   if (instance.IsSmi()) {
     instance_class = Smi::Class();
@@ -745,23 +748,26 @@
   // If the type is uninstantiated and refers to parent function type
   // parameters, the function_type_arguments have been canonicalized
   // when concatenated.
-  ASSERT(function_type_arguments.IsNull() ||
-         function_type_arguments.IsCanonical());
-  auto& instance_class_id_or_function = Object::Handle(zone);
+  auto& instance_class_id_or_signature = Object::Handle(zone);
   auto& instance_type_arguments = TypeArguments::Handle(zone);
   auto& instance_parent_function_type_arguments = TypeArguments::Handle(zone);
   auto& instance_delayed_type_arguments = TypeArguments::Handle(zone);
   if (instance_class.IsClosureClass()) {
     const auto& closure = Closure::Cast(instance);
     const auto& closure_function = Function::Handle(zone, closure.function());
-    instance_class_id_or_function = closure_function.ptr();
+    instance_class_id_or_signature = closure_function.signature();
     instance_type_arguments = closure.instantiator_type_arguments();
     instance_parent_function_type_arguments = closure.function_type_arguments();
     instance_delayed_type_arguments = closure.delayed_type_arguments();
+    ASSERT(instance_class_id_or_signature.IsCanonical());
+    ASSERT(instance_type_arguments.IsCanonical());
+    ASSERT(instance_parent_function_type_arguments.IsCanonical());
+    ASSERT(instance_delayed_type_arguments.IsCanonical());
   } else {
-    instance_class_id_or_function = Smi::New(instance_class.id());
+    instance_class_id_or_signature = Smi::New(instance_class.id());
     if (instance_class.NumTypeArguments() > 0) {
       instance_type_arguments = instance.GetTypeArguments();
+      ASSERT(instance_type_arguments.IsCanonical());
     }
   }
   if (FLAG_trace_type_checks) {
@@ -780,7 +786,7 @@
     buffer.Printf(
         "    raw entry: [ %#" Px ", %#" Px ", %#" Px ", %#" Px ", %#" Px
         ", %#" Px ", %#" Px ", %#" Px " ]\n",
-        static_cast<uword>(instance_class_id_or_function.ptr()),
+        static_cast<uword>(instance_class_id_or_signature.ptr()),
         static_cast<uword>(destination_type.ptr()),
         static_cast<uword>(instance_type_arguments.ptr()),
         static_cast<uword>(instantiator_type_arguments.ptr()),
@@ -803,20 +809,10 @@
       }
       return;
     }
-    ASSERT(instance_type_arguments.IsNull() ||
-           instance_type_arguments.IsCanonical());
-    ASSERT(instantiator_type_arguments.IsNull() ||
-           instantiator_type_arguments.IsCanonical());
-    ASSERT(function_type_arguments.IsNull() ||
-           function_type_arguments.IsCanonical());
-    ASSERT(instance_parent_function_type_arguments.IsNull() ||
-           instance_parent_function_type_arguments.IsCanonical());
-    ASSERT(instance_delayed_type_arguments.IsNull() ||
-           instance_delayed_type_arguments.IsCanonical());
     intptr_t colliding_index = -1;
     auto& old_result = Bool::Handle(zone);
     if (new_cache.HasCheck(
-            instance_class_id_or_function, destination_type,
+            instance_class_id_or_signature, destination_type,
             instance_type_arguments, instantiator_type_arguments,
             function_type_arguments, instance_parent_function_type_arguments,
             instance_delayed_type_arguments, &colliding_index, &old_result)) {
@@ -839,7 +835,7 @@
       // found missing and now.
       return;
     }
-    new_cache.AddCheck(instance_class_id_or_function, destination_type,
+    new_cache.AddCheck(instance_class_id_or_signature, destination_type,
                        instance_type_arguments, instantiator_type_arguments,
                        function_type_arguments,
                        instance_parent_function_type_arguments,
diff --git a/tools/VERSION b/tools/VERSION
index b260b95..9e20aca 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 134
+PRERELEASE 135
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/flutter/analyze_flutter_flutter.sh b/tools/bots/flutter/analyze_flutter_flutter.sh
index 4ec83ad..d040021 100755
--- a/tools/bots/flutter/analyze_flutter_flutter.sh
+++ b/tools/bots/flutter/analyze_flutter_flutter.sh
@@ -39,3 +39,6 @@
 pushd packages/flutter/test_fixes
 ../../../bin/dart fix --compare-to-golden
 popd
+
+# Analyze the sample code in dartdoc snippets.
+./bin/dart dev/bots/analyze_sample_code.dart