Version 3.6.0-105.0.dev

Merge 6995dc4447614ee9bb0f27f37cff664c5ff58867 into dev
diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml
index b688e04..487a5f7 100644
--- a/.github/workflows/scorecards-analysis.yml
+++ b/.github/workflows/scorecards-analysis.yml
@@ -29,7 +29,7 @@
           persist-credentials: false
 
       - name: "Run analysis"
-        uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534
+        uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46
         with:
           results_file: results.sarif
           results_format: sarif
@@ -52,6 +52,6 @@
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@4fa2a7953630fd2f3fb380f21be14ede0169dd4f
+        uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a
         with:
           sarif_file: results.sarif
diff --git a/pkg/dart2wasm/lib/async.dart b/pkg/dart2wasm/lib/async.dart
index ff526b1..deeca32 100644
--- a/pkg/dart2wasm/lib/async.dart
+++ b/pkg/dart2wasm/lib/async.dart
@@ -115,8 +115,8 @@
 
     // (1) Create async state.
 
-    final asyncStateLocal = function
-        .addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
+    final asyncStateLocal =
+        b.addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
 
     // AsyncResumeFun _resume
     b.global_get(translator.makeFunctionRef(resumeFun));
@@ -157,7 +157,7 @@
     b.struct_get(
         asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
     translator.convertType(
-        function,
+        b,
         asyncSuspendStateInfo.struct.fields[5].type.unpacked,
         completerFutureGetterType.inputs[0]);
     call(translator.completerFuture.getterReference);
@@ -171,17 +171,19 @@
     // Set the current Wasm function for the code generator to the inner
     // function of the `async`, which is to contain the body.
     function = resumeFun;
+    b = resumeFun.body;
+    functionType = resumeFun.type;
 
     // Set up locals for contexts and `this`.
     thisLocal = null;
     Context? localContext = context;
     while (localContext != null) {
       if (!localContext.isEmpty) {
-        localContext.currentLocal = function
-            .addLocal(w.RefType.def(localContext.struct, nullable: true));
+        localContext.currentLocal =
+            b.addLocal(w.RefType.def(localContext.struct, nullable: true));
         if (localContext.containsThis) {
           assert(thisLocal == null);
-          thisLocal = function.addLocal(localContext
+          thisLocal = b.addLocal(localContext
               .struct.fields[localContext.thisFieldIndex].type.unpacked
               .withNullability(false));
           translator.globals.instantiateDummyValue(b, thisLocal!.type);
@@ -375,7 +377,7 @@
     setVariable(awaitValueVar, () {
       b.local_get(_awaitValueLocal);
       translator.convertType(
-          function, _awaitValueLocal.type, translateType(awaitValueVar.type));
+          b, _awaitValueLocal.type, translateType(awaitValueVar.type));
     });
   }
 }
diff --git a/pkg/dart2wasm/lib/closures.dart b/pkg/dart2wasm/lib/closures.dart
index c565f2c..d91107b 100644
--- a/pkg/dart2wasm/lib/closures.dart
+++ b/pkg/dart2wasm/lib/closures.dart
@@ -529,7 +529,7 @@
 
     // Cast context reference to actual context type.
     w.RefType contextType = w.RefType.def(contextStruct, nullable: false);
-    w.Local contextLocal = trampoline.addLocal(contextType);
+    w.Local contextLocal = b.addLocal(contextType);
     b.local_get(trampoline.locals[0]);
     b.ref_cast(contextType);
     b.local_tee(contextLocal);
@@ -579,7 +579,7 @@
     final w.RefType instantiationContextType =
         w.RefType.def(instantiationContextStruct, nullable: false);
     final w.Local instantiationContextLocal =
-        function.addLocal(instantiationContextType);
+        b.addLocal(instantiationContextType);
     b.local_get(instantiatedClosureLocal);
     b.struct_get(closureBaseStruct, FieldIndex.closureContext);
     b.ref_cast(instantiationContextType);
@@ -590,7 +590,7 @@
         instantiationContextStruct, FieldIndex.instantiationContextInner);
 
     // Push types
-    translator.makeArray(function, translator.typeArrayType, typeCount,
+    translator.makeArray(b, translator.typeArrayType, typeCount,
         (elementType, elementIdx) {
       b.local_get(instantiationContextLocal);
       b.struct_get(instantiationContextStruct,
@@ -641,8 +641,8 @@
     ib.end();
 
     final instantiationFunction = m.functions.define(functionType, name);
-    w.Local preciseClosure = instantiationFunction.addLocal(genericClosureType);
     final b = instantiationFunction.body;
+    w.Local preciseClosure = b.addLocal(genericClosureType);
 
     // Parameters to the instantiation function
     final w.Local closureParam = instantiationFunction.locals[0];
@@ -703,8 +703,8 @@
     final thisContext = function.locals[0];
     final otherContext = function.locals[1];
 
-    final thisContextLocal = function.addLocal(contextRefType);
-    final otherContextLocal = function.addLocal(contextRefType);
+    final thisContextLocal = b.addLocal(contextRefType);
+    final otherContextLocal = b.addLocal(contextRefType);
 
     // Call site (`_Closure._equals`) checks that closures are instantiations
     // of the same function, so we can assume they have the right instantiation
@@ -751,7 +751,7 @@
     final contextRefType = w.RefType.def(contextStructType, nullable: false);
 
     final thisContext = function.locals[0];
-    final thisContextLocal = function.addLocal(contextRefType);
+    final thisContextLocal = b.addLocal(contextRefType);
 
     b.local_get(thisContext);
     b.ref_cast(contextRefType);
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 51e6f0b..6d96df2 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -40,7 +40,8 @@
     with ExpressionVisitor1DefaultMixin<w.ValueType, w.ValueType>
     implements InitializerVisitor<void>, StatementVisitor<void> {
   final Translator translator;
-  w.FunctionBuilder function;
+  w.FunctionType functionType;
+  w.InstructionsBuilder b;
   final Reference reference;
   late final List<w.Local> paramLocals;
   final w.Label? returnLabel;
@@ -86,9 +87,8 @@
   /// code for an inlined function by specifying the locals containing the
   /// parameters (instead of the function inputs) and the label to jump to on
   /// return (instead of emitting a `return` instruction).
-  CodeGenerator(this.translator, this.function, this.reference,
-      {List<w.Local>? paramLocals, this.returnLabel}) {
-    this.paramLocals = paramLocals ?? function.locals.toList();
+  CodeGenerator(this.translator, this.functionType, this.b, this.reference,
+      {required this.paramLocals, this.returnLabel}) {
     intrinsifier = Intrinsifier(this);
     typeContext = StaticTypeContext(member, translator.typeEnvironment);
   }
@@ -112,17 +112,16 @@
     } else if (!isTypeChecker && isAsync) {
       return AsyncCodeGenerator(translator, function, reference);
     } else {
-      return CodeGenerator(translator, function, reference);
+      return CodeGenerator(translator, function.type, function.body, reference,
+          paramLocals: function.locals.toList());
     }
   }
 
   w.ModuleBuilder get m => translator.m;
-  w.InstructionsBuilder get b => function.body;
 
   Member get member => reference.asMember;
 
-  List<w.ValueType> get outputs =>
-      returnLabel?.targetTypes ?? function.type.outputs;
+  List<w.ValueType> get outputs => functionType.outputs;
 
   w.ValueType get returnType => translator.outputOrVoid(outputs);
 
@@ -135,7 +134,7 @@
   w.ValueType translateType(DartType type) => translator.translateType(type);
 
   w.Local addLocal(w.ValueType type) {
-    return function.addLocal(type);
+    return b.addLocal(type);
   }
 
   DartType dartTypeOf(Expression exp) {
@@ -245,7 +244,7 @@
     }
 
     if (intrinsifier.generateMemberIntrinsic(
-        reference, function, paramLocals, returnLabel)) {
+        reference, functionType, paramLocals, returnLabel)) {
       b.end();
       return;
     }
@@ -258,7 +257,6 @@
         b.ref_null(w.HeapType.none);
       }
       translator.constants.instantiateConstant(
-          function,
           b,
           SymbolConstant(member.name.text, null),
           translator.classInfo[translator.symbolClass]!.nonNullableType);
@@ -335,7 +333,7 @@
       b.global_set(flag);
     }
     b.global_get(global);
-    translator.convertType(function, global.type.type, outputs.single);
+    translator.convertType(b, global.type.type, outputs.single);
     b.end();
   }
 
@@ -349,20 +347,20 @@
       w.Local thisLocal = paramLocals[0];
       w.RefType structType = w.RefType.def(struct, nullable: false);
       b.local_get(thisLocal);
-      translator.convertType(function, thisLocal.type, structType);
+      translator.convertType(b, thisLocal.type, structType);
     }
 
     if (reference.isImplicitGetter) {
       // Implicit getter
       getThis();
       b.struct_get(struct, fieldIndex);
-      translator.convertType(function, fieldType, returnType);
+      translator.convertType(b, fieldType, returnType);
     } else {
       // Implicit setter
       w.Local valueLocal = paramLocals[1];
       getThis();
       b.local_get(valueLocal);
-      translator.convertType(function, valueLocal.type, fieldType);
+      translator.convertType(b, valueLocal.type, fieldType);
       b.struct_set(struct, fieldIndex);
     }
     b.end();
@@ -407,7 +405,7 @@
         // have to handle sentinel before we can downcast the value.
         b.local_get(local);
         translator.constants.instantiateConstant(
-            function, b, ParameterInfo.defaultValueSentinel, local.type);
+            b, ParameterInfo.defaultValueSentinel, local.type);
         b.ref_eq();
         b.if_();
         wrap(variable.initializer!, local.type);
@@ -424,7 +422,7 @@
         if (!local.type.isSubtypeOf(incomingArgumentType)) {
           final newLocal = addLocal(incomingArgumentType);
           b.local_get(local);
-          translator.convertType(function, local.type, newLocal.type);
+          translator.convertType(b, local.type, newLocal.type);
           b.local_set(newLocal);
           local = newLocal;
         }
@@ -438,7 +436,7 @@
           if (!operand.type.isSubtypeOf(boxedType)) {
             final boxedOperand = addLocal(boxedType);
             b.local_get(operand);
-            translator.convertType(function, operand.type, boxedOperand.type);
+            translator.convertType(b, operand.type, boxedOperand.type);
             b.local_set(boxedOperand);
             operand = boxedOperand;
           }
@@ -459,7 +457,7 @@
         if (!variableType.isSubtypeOf(local.type)) {
           w.Local newLocal = addLocal(variableType);
           b.local_get(local);
-          translator.convertType(function, local.type, newLocal.type);
+          translator.convertType(b, local.type, newLocal.type);
           b.local_set(newLocal);
           local = newLocal;
         }
@@ -490,7 +488,7 @@
               parameterType.classNode == translator.wasmExternRefClass)) {
         w.Local newLocal = addLocal(translateType(parameterType));
         b.local_get(local);
-        translator.convertType(function, local.type, newLocal.type);
+        translator.convertType(b, local.type, newLocal.type);
         b.local_set(newLocal);
         locals[parameter] = newLocal;
       }
@@ -790,7 +788,7 @@
   }
 
   /// Generate code for the body of a lambda.
-  w.BaseFunction generateLambda(Lambda lambda, Closures closures) {
+  void generateLambda(Lambda lambda, Closures closures) {
     // Initialize closure information from enclosing member.
     this.closures = closures;
 
@@ -803,8 +801,6 @@
     visitStatement(lambda.functionNode.body!);
     _implicitReturn();
     b.end();
-
-    return function;
   }
 
   /// Initialize locals containing `this` in constructors and instance members.
@@ -821,7 +817,7 @@
       if (translator.needsConversion(thisLocal!.type, preciseThisType)) {
         preciseThisLocal = addLocal(preciseThisType);
         b.local_get(thisLocal!);
-        translator.convertType(function, thisLocal!.type, preciseThisType);
+        translator.convertType(b, thisLocal!.type, preciseThisType);
         b.local_set(preciseThisLocal!);
       } else {
         preciseThisLocal = thisLocal!;
@@ -929,7 +925,7 @@
       if (capture != null) {
         b.local_get(capture.context.currentLocal);
         b.local_get(local);
-        translator.convertType(function, local.type, capture.type);
+        translator.convertType(b, local.type, capture.type);
         b.struct_set(capture.context.struct, capture.fieldIndex);
       }
     });
@@ -938,7 +934,7 @@
       if (capture != null) {
         b.local_get(capture.context.currentLocal);
         b.local_get(local);
-        translator.convertType(function, local.type, capture.type);
+        translator.convertType(b, local.type, capture.type);
         b.struct_set(capture.context.struct, capture.fieldIndex);
       }
     });
@@ -967,7 +963,7 @@
     final oldFileOffset = setSourceMapFileOffset(node.fileOffset);
     try {
       w.ValueType resultType = node.accept1(this, expectedType);
-      translator.convertType(function, resultType, expectedType);
+      translator.convertType(b, resultType, expectedType);
       return expectedType;
     } catch (_) {
       _printLocation(node);
@@ -1019,7 +1015,7 @@
       }
       w.Label block = b.block(const [], targetFunctionType.outputs);
       b.comment("Inlined ${target.asMember}");
-      CodeGenerator(translator, function, target,
+      CodeGenerator(translator, targetFunctionType, b, target,
               paramLocals: inlinedLocals, returnLabel: block)
           .generate();
       return targetFunctionType.outputs;
@@ -1213,7 +1209,6 @@
           translator.classInfo[stringClass]!.nullableType;
       if (location != null) {
         translator.constants.instantiateConstant(
-          function,
           b,
           StringConstant(location.file.toString()),
           stringRefType,
@@ -1225,7 +1220,6 @@
         final String conditionString = sourceString.substring(
             node.conditionStartOffset, node.conditionEndOffset);
         translator.constants.instantiateConstant(
-          function,
           b,
           StringConstant(conditionString),
           stringRefType,
@@ -1300,7 +1294,7 @@
           b.local_get(thrownException);
           // Type test passed, downcast the exception to the expected type.
           translator.convertType(
-            function,
+            b,
             thrownException.type,
             translator.translateType(exceptionDeclaration.type),
           );
@@ -1452,7 +1446,7 @@
       } else {
         if (returnValueLocal != null) {
           b.local_get(returnValueLocal!);
-          translator.convertType(function, returnValueLocal!.type, returnType);
+          translator.convertType(b, returnValueLocal!.type, returnType);
         }
         _returnFromFunction();
       }
@@ -1641,7 +1635,7 @@
     if (expression != null) {
       wrap(expression, returnType);
     } else {
-      translator.convertType(function, voidMarker, returnType);
+      translator.convertType(b, voidMarker, returnType);
     }
 
     // If we are wrapped in a [TryFinally] node then we have to run finalizers
@@ -1720,9 +1714,7 @@
               : doneLabel;
       b.local_get(switchValueNullableLocal!);
       b.br_on_null(nullLabel);
-      translator.convertType(
-          function,
-          switchInfo.nullableType.withNullability(false),
+      translator.convertType(b, switchInfo.nullableType.withNullability(false),
           switchInfo.nonNullableType);
       b.local_set(switchValueNonNullableLocal);
     }
@@ -1852,7 +1844,7 @@
     // A user of `this` may have more precise type information, in which case
     // we downcast it here.
     b.local_get(thisLocal!);
-    translator.convertType(function, thisType, expectedType);
+    translator.convertType(b, thisType, expectedType);
     return expectedType;
   }
 
@@ -2020,12 +2012,11 @@
 
     // Evaluate receiver
     wrap(receiver, translator.topInfo.nullableType);
-    final nullableReceiverLocal =
-        function.addLocal(translator.topInfo.nullableType);
+    final nullableReceiverLocal = addLocal(translator.topInfo.nullableType);
     b.local_set(nullableReceiverLocal);
 
     // Evaluate type arguments.
-    final typeArgsLocal = function.addLocal(
+    final typeArgsLocal = addLocal(
         makeArray(translator.typeArrayType, typeArguments.length,
             (elementType, elementIdx) {
       translator.types.makeType(this, typeArguments[elementIdx]);
@@ -2033,7 +2024,7 @@
     b.local_set(typeArgsLocal);
 
     // Evaluate positional arguments
-    final positionalArgsLocal = function.addLocal(makeArray(
+    final positionalArgsLocal = addLocal(makeArray(
         translator.nullableObjectArrayType, positionalArguments.length,
         (elementType, elementIdx) {
       wrap(positionalArguments[elementIdx], elementType);
@@ -2047,14 +2038,14 @@
     final List<MapEntry<String, w.Local>> namedArgumentLocals = [];
     for (final namedArgument in namedArguments) {
       wrap(namedArgument.value, translator.topInfo.nullableType);
-      final argumentLocal = function.addLocal(translator.topInfo.nullableType);
+      final argumentLocal = addLocal(translator.topInfo.nullableType);
       b.local_set(argumentLocal);
       namedArgumentLocals.add(MapEntry(namedArgument.name, argumentLocal));
     }
     namedArgumentLocals.sort((e1, e2) => e1.key.compareTo(e2.key));
 
     // Create named argument array
-    final namedArgsLocal = function.addLocal(
+    final namedArgsLocal = addLocal(
         makeArray(translator.nullableObjectArrayType, namedArguments.length * 2,
             (elementType, elementIdx) {
       if (elementIdx % 2 == 0) {
@@ -2062,7 +2053,7 @@
         final w.ValueType symbolValueType =
             translator.classInfo[translator.symbolClass]!.nonNullableType;
         translator.constants.instantiateConstant(
-            function, b, SymbolConstant(name, null), symbolValueType);
+            b, SymbolConstant(name, null), symbolValueType);
       } else {
         final local = namedArgumentLocals[elementIdx ~/ 2].value;
         b.local_get(local);
@@ -2077,8 +2068,8 @@
     // invocation of `noSuchMethod` (done in [_callNoSuchMethod]), but we don't
     // have a `Null` class in dart2wasm so we throw directly.
     b.local_get(nullableReceiverLocal);
-    createInvocationObject(translator, function, forwarder.memberName,
-        typeArgsLocal, positionalArgsLocal, namedArgsLocal);
+    createInvocationObject(translator, b, forwarder.memberName, typeArgsLocal,
+        positionalArgsLocal, namedArgsLocal);
 
     call(translator.noSuchMethodErrorThrowWithInvocation.reference);
     b.unreachable();
@@ -2317,7 +2308,7 @@
   @override
   w.ValueType visitStaticTearOff(StaticTearOff node, w.ValueType expectedType) {
     translator.constants.instantiateConstant(
-        function, b, StaticTearOffConstant(node.target), expectedType);
+        b, StaticTearOffConstant(node.target), expectedType);
     return expectedType;
   }
 
@@ -2434,8 +2425,7 @@
 
     // Evaluate receiver
     wrap(receiver, translator.topInfo.nullableType);
-    final nullableReceiverLocal =
-        function.addLocal(translator.topInfo.nullableType);
+    final nullableReceiverLocal = addLocal(translator.topInfo.nullableType);
     b.local_set(nullableReceiverLocal);
 
     final nullBlock = b.block([], [translator.topInfo.nonNullableType]);
@@ -2445,7 +2435,7 @@
     // invocation of `noSuchMethod` (done in [_callNoSuchMethod]), but we don't
     // have a `Null` class in dart2wasm so we throw directly.
     b.local_get(nullableReceiverLocal);
-    createGetterInvocationObject(translator, function, forwarder.memberName);
+    createGetterInvocationObject(translator, b, forwarder.memberName);
 
     call(translator.noSuchMethodErrorThrowWithInvocation.reference);
     b.unreachable();
@@ -2466,14 +2456,12 @@
 
     // Evaluate receiver
     wrap(receiver, translator.topInfo.nullableType);
-    final nullableReceiverLocal =
-        function.addLocal(translator.topInfo.nullableType);
+    final nullableReceiverLocal = addLocal(translator.topInfo.nullableType);
     b.local_set(nullableReceiverLocal);
 
     // Evaluate positional arg
     wrap(value, translator.topInfo.nullableType);
-    final positionalArgLocal =
-        function.addLocal(translator.topInfo.nullableType);
+    final positionalArgLocal = addLocal(translator.topInfo.nullableType);
     b.local_set(positionalArgLocal);
 
     final nullBlock = b.block([], [translator.topInfo.nonNullableType]);
@@ -2484,7 +2472,7 @@
     // have a `Null` class in dart2wasm so we throw directly.
     b.local_get(nullableReceiverLocal);
     createSetterInvocationObject(
-        translator, function, forwarder.memberName, positionalArgLocal);
+        translator, b, forwarder.memberName, positionalArgLocal);
 
     call(translator.noSuchMethodErrorThrowWithInvocation.reference);
     b.unreachable();
@@ -2534,7 +2522,7 @@
         wrap(node.receiver, translator.topInfo.nullableType);
         b.br_on_null(nullLabel);
         translator.convertType(
-            function, translator.topInfo.nullableType, signature.inputs[0]);
+            b, translator.topInfo.nullableType, signature.inputs[0]);
       }, (_, __) {});
       b.br(doneLabel);
       b.end(); // nullLabel
@@ -2888,7 +2876,7 @@
     for (int i = positional.length; i < paramInfo.positional.length; i++) {
       final w.ValueType type = signature.inputs[signatureOffset + i];
       translator.constants
-          .instantiateConstant(function, b, paramInfo.positional[i]!, type);
+          .instantiateConstant(b, paramInfo.positional[i]!, type);
     }
     // Named arguments
     final Map<String, w.Local> namedLocals = {};
@@ -2908,7 +2896,7 @@
         b.local_get(namedLocal);
       } else {
         translator.constants
-            .instantiateConstant(function, b, paramInfo.named[name]!, type);
+            .instantiateConstant(b, paramInfo.named[name]!, type);
       }
     }
   }
@@ -2994,43 +2982,41 @@
   @override
   w.ValueType visitConstantExpression(
       ConstantExpression node, w.ValueType expectedType) {
-    translator.constants
-        .instantiateConstant(function, b, node.constant, expectedType);
+    translator.constants.instantiateConstant(b, node.constant, expectedType);
     return expectedType;
   }
 
   @override
   w.ValueType visitNullLiteral(NullLiteral node, w.ValueType expectedType) {
-    translator.constants
-        .instantiateConstant(function, b, NullConstant(), expectedType);
+    translator.constants.instantiateConstant(b, NullConstant(), expectedType);
     return expectedType;
   }
 
   @override
   w.ValueType visitStringLiteral(StringLiteral node, w.ValueType expectedType) {
-    translator.constants.instantiateConstant(
-        function, b, StringConstant(node.value), expectedType);
+    translator.constants
+        .instantiateConstant(b, StringConstant(node.value), expectedType);
     return expectedType;
   }
 
   @override
   w.ValueType visitBoolLiteral(BoolLiteral node, w.ValueType expectedType) {
-    translator.constants.instantiateConstant(
-        function, b, BoolConstant(node.value), expectedType);
+    translator.constants
+        .instantiateConstant(b, BoolConstant(node.value), expectedType);
     return expectedType;
   }
 
   @override
   w.ValueType visitIntLiteral(IntLiteral node, w.ValueType expectedType) {
-    translator.constants.instantiateConstant(
-        function, b, IntConstant(node.value), expectedType);
+    translator.constants
+        .instantiateConstant(b, IntConstant(node.value), expectedType);
     return expectedType;
   }
 
   @override
   w.ValueType visitDoubleLiteral(DoubleLiteral node, w.ValueType expectedType) {
-    translator.constants.instantiateConstant(
-        function, b, DoubleConstant(node.value), expectedType);
+    translator.constants
+        .instantiateConstant(b, DoubleConstant(node.value), expectedType);
     return expectedType;
   }
 
@@ -3075,7 +3061,7 @@
 
   w.ValueType makeArray(w.ArrayType arrayType, int length,
       void Function(w.ValueType, int) generateItem) {
-    return translator.makeArray(function, arrayType, length, generateItem);
+    return translator.makeArray(b, arrayType, length, generateItem);
   }
 
   @override
@@ -3224,7 +3210,7 @@
       b.struct_get(info.struct, fieldIndex);
       resultType = info.struct.fields[fieldIndex].type.unpacked;
     }
-    translator.convertType(function, resultType, types.nonNullableTypeType);
+    translator.convertType(b, resultType, types.nonNullableTypeType);
     return types.nonNullableTypeType;
   }
 
@@ -3425,8 +3411,8 @@
   /// This function will be called by a setter forwarder in a dynamic set to
   /// type check the setter argument before calling the actual setter.
   void _generateFieldSetterTypeCheckerMethod() {
-    final receiverLocal = function.locals[0];
-    final positionalArgLocal = function.locals[1];
+    final receiverLocal = paramLocals[0];
+    final positionalArgLocal = paramLocals[1];
 
     _initializeThis(member.reference);
 
@@ -3454,11 +3440,10 @@
     if (member_ is Field) {
       int fieldIndex = translator.fieldIndex[member_]!;
       b.local_get(receiverLocal);
-      translator.convertType(
-          function, receiverLocal.type, info.nonNullableType);
+      translator.convertType(b, receiverLocal.type, info.nonNullableType);
       b.local_get(argLocal);
-      translator.convertType(function, argLocal.type,
-          info.struct.fields[fieldIndex].type.unpacked);
+      translator.convertType(
+          b, argLocal.type, info.struct.fields[fieldIndex].type.unpacked);
       b.struct_set(info.struct, fieldIndex);
     } else {
       final setterProcedure = member_ as Procedure;
@@ -3467,9 +3452,9 @@
       final setterWasmInputs = setterProcedureWasmType.inputs;
       assert(setterWasmInputs.length == 2);
       b.local_get(receiverLocal);
-      translator.convertType(function, receiverLocal.type, setterWasmInputs[0]);
+      translator.convertType(b, receiverLocal.type, setterWasmInputs[0]);
       b.local_get(argLocal);
-      translator.convertType(function, argLocal.type, setterWasmInputs[1]);
+      translator.convertType(b, argLocal.type, setterWasmInputs[1]);
       call(setterProcedure.reference);
     }
 
@@ -3482,10 +3467,10 @@
   /// This function will be called by an invocation forwarder in a dynamic
   /// invocation to type check parameters before calling the actual method.
   void _generateProcedureTypeCheckerMethod() {
-    final receiverLocal = function.locals[0];
-    final typeArgsLocal = function.locals[1];
-    final positionalArgsLocal = function.locals[2];
-    final namedArgsLocal = function.locals[3];
+    final receiverLocal = paramLocals[0];
+    final typeArgsLocal = paramLocals[1];
+    final positionalArgsLocal = paramLocals[2];
+    final namedArgsLocal = paramLocals[3];
 
     _initializeThis(member.reference);
 
@@ -3605,7 +3590,7 @@
     final List<w.ValueType> memberWasmInputs = memberWasmFunctionType.inputs;
 
     b.local_get(receiverLocal);
-    translator.convertType(function, receiverLocal.type, memberWasmInputs[0]);
+    translator.convertType(b, receiverLocal.type, memberWasmInputs[0]);
 
     for (final typeParam in memberTypeParams) {
       b.local_get(typeLocals[typeParam]!);
@@ -3618,8 +3603,8 @@
       b.local_get(listLocal);
       b.i32_const(listIdx);
       b.array_get(translator.nullableObjectArrayType);
-      translator.convertType(function, translator.topInfo.nullableType,
-          memberWasmInputs[wasmInputIdx]);
+      translator.convertType(
+          b, translator.topInfo.nullableType, memberWasmInputs[wasmInputIdx]);
     }
 
     for (int positionalParamIdx = 0;
@@ -3639,7 +3624,7 @@
     call(member.reference);
 
     translator.convertType(
-        function,
+        b,
         translator.outputOrVoid(memberWasmFunctionType.outputs),
         translator.topInfo.nullableType);
 
@@ -3697,8 +3682,8 @@
     DartType bound,
   ) {
     b.local_get(typeLocal);
-    final boundLocal = function
-        .addLocal(translator.classInfo[translator.typeClass]!.nonNullableType);
+    final boundLocal =
+        b.addLocal(translator.classInfo[translator.typeClass]!.nonNullableType);
     types.makeType(this, bound);
     b.local_tee(boundLocal);
     call(translator.isTypeSubtype.reference);
@@ -3743,7 +3728,7 @@
     final printFunction =
         translator.functions.getFunction(translator.printToConsole.reference);
     translator.constants.instantiateConstant(
-        function, b, StringConstant(s), printFunction.type.inputs[0]);
+        b, StringConstant(s), printFunction.type.inputs[0]);
     b.call(printFunction);
   }
 
@@ -3877,11 +3862,11 @@
       compare = (switchExprLocal, pushCaseExpr) {
         final caseExprType = pushCaseExpr();
         translator.convertType(
-            codeGen.function, caseExprType, equalsMemberSignature.inputs[0]);
+            codeGen.b, caseExprType, equalsMemberSignature.inputs[0]);
 
         codeGen.b.local_get(switchExprLocal);
-        translator.convertType(codeGen.function, switchExprLocal.type,
-            equalsMemberSignature.inputs[1]);
+        translator.convertType(
+            codeGen.b, switchExprLocal.type, equalsMemberSignature.inputs[1]);
 
         codeGen.call(equalsMember.reference);
       };
@@ -4017,7 +4002,7 @@
       return;
     }
 
-    w.Local classId = addLocal(w.NumType.i32, isParameter: false);
+    w.Local classId = addLocal(w.NumType.i32);
     local_set(classId);
 
     final done = block([], outputs);
@@ -4092,7 +4077,7 @@
       return;
     }
 
-    w.Local classId = addLocal(w.NumType.i32, isParameter: false);
+    w.Local classId = addLocal(w.NumType.i32);
     local_set(classId);
     final done = block([], outputs);
     for (final (:range, :value) in ranges) {
@@ -4242,8 +4227,7 @@
   w.Local cloneFunctionLevelContext(
       Closures closures, Context context, FunctionNode functionNode) {
     final w.Local srcContext = context.currentLocal;
-    final w.Local destContext =
-        addLocal(context.currentLocal.type, isParameter: false);
+    final w.Local destContext = addLocal(context.currentLocal.type);
 
     struct_new_default(context.struct);
     local_set(destContext);
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index d1525f6..05e3a59 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -28,8 +28,7 @@
   bool get isLazy => function != null;
 }
 
-typedef ConstantCodeGenerator = void Function(
-    w.FunctionBuilder?, w.InstructionsBuilder);
+typedef ConstantCodeGenerator = void Function(w.InstructionsBuilder);
 
 /// Handles the creation of Dart constants.
 ///
@@ -130,10 +129,10 @@
   }
 
   /// Emit code to push a constant onto the stack.
-  void instantiateConstant(w.BaseFunction? function, w.InstructionsBuilder b,
-      Constant constant, w.ValueType expectedType) {
+  void instantiateConstant(
+      w.InstructionsBuilder b, Constant constant, w.ValueType expectedType) {
     if (expectedType == translator.voidMarker) return;
-    ConstantInstantiator(this, function, b, expectedType).instantiate(constant);
+    ConstantInstantiator(this, b, expectedType).instantiate(constant);
   }
 
   InstanceConstant _lowerTypeConstant(DartType type) {
@@ -293,12 +292,10 @@
 class ConstantInstantiator extends ConstantVisitor<w.ValueType>
     with ConstantVisitorDefaultMixin<w.ValueType> {
   final Constants constants;
-  final w.BaseFunction? function;
   final w.InstructionsBuilder b;
   final w.ValueType expectedType;
 
-  ConstantInstantiator(
-      this.constants, this.function, this.b, this.expectedType);
+  ConstantInstantiator(this.constants, this.b, this.expectedType);
 
   Translator get translator => constants.translator;
   w.ModuleBuilder get m => translator.m;
@@ -453,9 +450,9 @@
       global.initializer.end();
       w.FunctionType ftype = m.types.defineFunction(const [], [type]);
       final function = m.functions.define(ftype, "$constant");
-      generator(function, function.body);
-      w.Local temp = function.addLocal(type);
       final b2 = function.body;
+      generator(b2);
+      w.Local temp = b2.addLocal(type);
       b2.local_tee(temp);
       b2.global_set(global);
       b2.local_get(temp);
@@ -467,7 +464,7 @@
       assert(!constants.currentlyCreating);
       constants.currentlyCreating = true;
       final global = m.globals.define(w.GlobalType(type, mutable: false));
-      generator(null, global.initializer);
+      generator(global.initializer);
       global.initializer.end();
       constants.currentlyCreating = false;
 
@@ -481,7 +478,7 @@
   @override
   ConstantInfo? visitBoolConstant(BoolConstant constant) {
     ClassInfo info = translator.classInfo[translator.boxedBoolClass]!;
-    return createConstant(constant, info.nonNullableType, (function, b) {
+    return createConstant(constant, info.nonNullableType, (b) {
       b.i32_const(info.classId);
       b.i32_const(constant.value ? 1 : 0);
       b.struct_new(info.struct);
@@ -491,7 +488,7 @@
   @override
   ConstantInfo? visitIntConstant(IntConstant constant) {
     ClassInfo info = translator.classInfo[translator.boxedIntClass]!;
-    return createConstant(constant, info.nonNullableType, (function, b) {
+    return createConstant(constant, info.nonNullableType, (b) {
       b.i32_const(info.classId);
       b.i64_const(constant.value);
       b.struct_new(info.struct);
@@ -501,7 +498,7 @@
   @override
   ConstantInfo? visitDoubleConstant(DoubleConstant constant) {
     ClassInfo info = translator.classInfo[translator.boxedDoubleClass]!;
-    return createConstant(constant, info.nonNullableType, (function, b) {
+    return createConstant(constant, info.nonNullableType, (b) {
       b.i32_const(info.classId);
       b.f64_const(constant.value);
       b.struct_new(info.struct);
@@ -512,7 +509,7 @@
   ConstantInfo? visitStringConstant(StringConstant constant) {
     if (translator.options.jsCompatibility) {
       ClassInfo info = translator.classInfo[translator.jsStringClass]!;
-      return createConstant(constant, info.nonNullableType, (function, b) {
+      return createConstant(constant, info.nonNullableType, (b) {
         b.i32_const(info.classId);
         b.i32_const(initialIdentityHash);
         b.global_get(translator.getInternalizedStringGlobal(constant.value));
@@ -526,7 +523,7 @@
     translator.functions.recordClassAllocation(info.classId);
     w.RefType type = info.nonNullableType;
     bool lazy = constant.value.length > maxArrayNewFixedLength;
-    return createConstant(constant, type, lazy: lazy, (function, b) {
+    return createConstant(constant, type, lazy: lazy, (b) {
       w.ArrayType arrayType =
           (info.struct.fields[FieldIndex.stringArray].type as w.RefType)
               .heapType as w.ArrayType;
@@ -605,13 +602,13 @@
       args = supertype.typeArguments;
     }
 
-    return createConstant(constant, type, lazy: lazy, (function, b) {
+    return createConstant(constant, type, lazy: lazy, (b) {
       b.i32_const(info.classId);
       b.i32_const(initialIdentityHash);
       for (int i = baseFieldCount; i < fieldCount; i++) {
         Constant subConstant = subConstants[i]!;
         constants.instantiateConstant(
-            function, b, subConstant, info.struct.fields[i].type.unpacked);
+            b, subConstant, info.struct.fields[i].type.unpacked);
       }
       b.struct_new(info.struct);
     });
@@ -631,7 +628,7 @@
     }
 
     return createConstant(constant, w.RefType.def(arrayType, nullable: false),
-        lazy: lazy, (function, b) {
+        lazy: lazy, (b) {
       if (tooLargeForArrayNewFixed) {
         // We will initialize the array with one of the elements (using
         // `array.new`) and update the fields.
@@ -653,8 +650,8 @@
         }
 
         w.Local arrayLocal =
-            function!.addLocal(w.RefType.def(arrayType, nullable: false));
-        constants.instantiateConstant(function, b, initialElement, elementType);
+            b.addLocal(w.RefType.def(arrayType, nullable: false));
+        constants.instantiateConstant(b, initialElement, elementType);
         b.i32_const(elements.length);
         b.array_new(arrayType);
         b.local_set(arrayLocal);
@@ -674,7 +671,7 @@
 
           b.local_get(arrayLocal);
           b.i32_const(startInclusive);
-          constants.instantiateConstant(function, b, value, elementType);
+          constants.instantiateConstant(b, value, elementType);
           if (count > 1) {
             b.i32_const(count);
             b.array_fill(arrayType);
@@ -685,7 +682,7 @@
         b.local_get(arrayLocal);
       } else {
         for (Constant element in elements) {
-          constants.instantiateConstant(function, b, element, elementType);
+          constants.instantiateConstant(b, element, elementType);
         }
         b.array_new_fixed(arrayType, elements.length);
       }
@@ -705,35 +702,33 @@
     ClassInfo info = translator.classInfo[translator.immutableListClass]!;
     translator.functions.recordClassAllocation(info.classId);
     w.RefType type = info.nonNullableType;
-    return createConstant(constant, type, lazy: lazy, (function, b) {
+    return createConstant(constant, type, lazy: lazy, (b) {
       w.ArrayType arrayType = translator.listArrayType;
       w.ValueType elementType = arrayType.elementType.type.unpacked;
       int length = constant.entries.length;
       b.i32_const(info.classId);
       b.i32_const(initialIdentityHash);
       constants.instantiateConstant(
-          function, b, typeArgConstant, constants.typeInfo.nullableType);
+          b, typeArgConstant, constants.typeInfo.nullableType);
       b.i64_const(length);
       if (lazy) {
         // Allocate array and set each entry to the corresponding sub-constant.
         w.Local arrayLocal =
-            function!.addLocal(w.RefType.def(arrayType, nullable: false));
+            b.addLocal(w.RefType.def(arrayType, nullable: false));
         b.i32_const(length);
         b.array_new_default(arrayType);
         b.local_set(arrayLocal);
         for (int i = 0; i < length; i++) {
           b.local_get(arrayLocal);
           b.i32_const(i);
-          constants.instantiateConstant(
-              function, b, constant.entries[i], elementType);
+          constants.instantiateConstant(b, constant.entries[i], elementType);
           b.array_set(arrayType);
         }
         b.local_get(arrayLocal);
       } else {
         // Push all sub-constants on the stack and initialize array from them.
         for (int i = 0; i < length; i++) {
-          constants.instantiateConstant(
-              function, b, constant.entries[i], elementType);
+          constants.instantiateConstant(b, constant.entries[i], elementType);
         }
         b.array_new_fixed(arrayType, length);
       }
@@ -822,7 +817,7 @@
     ClosureImplementation closure = translator.getTearOffClosure(member);
     w.StructType struct = closure.representation.closureStruct;
     w.RefType type = w.RefType.def(struct, nullable: false);
-    return createConstant(constant, type, (function, b) {
+    return createConstant(constant, type, (b) {
       ClassInfo info = translator.closureInfo;
       translator.functions.recordClassAllocation(info.classId);
 
@@ -831,7 +826,7 @@
       b.global_get(translator.globals.dummyStructGlobal); // Dummy context
       b.global_get(closure.vtable);
       constants.instantiateConstant(
-          function, b, functionTypeConstant, types.nonNullableTypeType);
+          b, functionTypeConstant, types.nonNullableTypeType);
       b.struct_new(struct);
     });
   }
@@ -880,8 +875,7 @@
 
       b.local_get(closureLocal);
       final InstanceConstant typeArgs = constants.makeTypeArray(constant.types);
-      constants.instantiateConstant(
-          function, b, typeArgs, typeArgsListLocal.type);
+      constants.instantiateConstant(b, typeArgs, typeArgsListLocal.type);
       b.local_get(posArgsListLocal);
       b.local_get(namedArgsListLocal);
       b.call(tearOffClosure.dynamicCallEntry);
@@ -895,7 +889,7 @@
     // a constant while creating another one.
     final w.BaseFunction dynamicCallEntry = makeDynamicCallEntry();
 
-    return createConstant(constant, type, (function, b) {
+    return createConstant(constant, type, (b) {
       ClassInfo info = translator.closureInfo;
       translator.functions.recordClassAllocation(info.classId);
 
@@ -964,7 +958,7 @@
 
       makeVtable();
       constants.instantiateConstant(
-          function, b, functionTypeConstant, this.types.nonNullableTypeType);
+          b, functionTypeConstant, this.types.nonNullableTypeType);
       b.struct_new(struct);
     });
   }
@@ -982,11 +976,10 @@
         .classInfo[translator.coreTypes.stringClass]!.repr.nonNullableType;
     StringConstant nameConstant = StringConstant(constant.name);
     bool lazy = ensureConstant(nameConstant)?.isLazy ?? false;
-    return createConstant(constant, info.nonNullableType, lazy: lazy,
-        (function, b) {
+    return createConstant(constant, info.nonNullableType, lazy: lazy, (b) {
       b.i32_const(info.classId);
       b.i32_const(initialIdentityHash);
-      constants.instantiateConstant(function, b, nameConstant, stringType);
+      constants.instantiateConstant(b, nameConstant, stringType);
       b.struct_new(info.struct);
     });
   }
@@ -1005,12 +998,12 @@
     }
 
     return createConstant(constant, recordClassInfo.nonNullableType,
-        lazy: false, (function, b) {
+        lazy: false, (b) {
       b.i32_const(recordClassInfo.classId);
       b.i32_const(initialIdentityHash);
       for (Constant argument in arguments) {
         constants.instantiateConstant(
-            function, b, argument, translator.topInfo.nullableType);
+            b, argument, translator.topInfo.nullableType);
       }
       b.struct_new(recordClassInfo.struct);
     });
diff --git a/pkg/dart2wasm/lib/dynamic_forwarders.dart b/pkg/dart2wasm/lib/dynamic_forwarders.dart
index 9fec783..811c849 100644
--- a/pkg/dart2wasm/lib/dynamic_forwarders.dart
+++ b/pkg/dart2wasm/lib/dynamic_forwarders.dart
@@ -123,17 +123,14 @@
           translator.functions.getFunction(targetReference);
       b.local_get(receiverLocal);
       translator.convertType(
-          function, receiverLocal.type, targetFunction.type.inputs.first);
+          b, receiverLocal.type, targetFunction.type.inputs.first);
       b.call(targetFunction);
       // Box return value if needed
-      translator.convertType(function, targetFunction.type.outputs.single,
+      translator.convertType(b, targetFunction.type.outputs.single,
           _kind.functionType(translator).outputs.single);
     }, () {
-      generateNoSuchMethodCall(
-          translator,
-          function,
-          () => b.local_get(receiverLocal),
-          () => createGetterInvocationObject(translator, function, memberName));
+      generateNoSuchMethodCall(translator, b, () => b.local_get(receiverLocal),
+          () => createGetterInvocationObject(translator, b, memberName));
     });
 
     b.return_();
@@ -164,10 +161,10 @@
     }, () {
       generateNoSuchMethodCall(
           translator,
-          function,
+          b,
           () => b.local_get(receiverLocal),
           () => createSetterInvocationObject(
-              translator, function, memberName, positionalArgLocal));
+              translator, b, memberName, positionalArgLocal));
 
       b.drop(); // drop noSuchMethod return value
       b.local_get(positionalArgLocal);
@@ -185,12 +182,12 @@
     final positionalArgsLocal = function.locals[2]; // ref WasmArray
     final namedArgsLocal = function.locals[3]; // ref WasmArray
 
-    final classIdLocal = function.addLocal(w.NumType.i32);
+    final classIdLocal = b.addLocal(w.NumType.i32);
 
     // Continuation of this block calls `noSuchMethod` on the receiver.
     final noSuchMethodBlock = b.block();
 
-    final numArgsLocal = function.addLocal(w.NumType.i32);
+    final numArgsLocal = b.addLocal(w.NumType.i32);
 
     final methodSelectors =
         translator.dispatchTable.dynamicMethodSelectors(memberName);
@@ -277,13 +274,13 @@
         w.Local? adjustedPositionalArgsLocal;
         if (nRequired != nTotal) {
           adjustedPositionalArgsLocal =
-              function.addLocal(translator.nullableObjectArrayTypeRef);
+              b.addLocal(translator.nullableObjectArrayTypeRef);
           b.i32_const(nTotal);
           b.array_new_default(translator.nullableObjectArrayType);
           b.local_set(adjustedPositionalArgsLocal);
 
           // Copy passed arguments
-          final argIdxLocal = function.addLocal(w.NumType.i32);
+          final argIdxLocal = b.addLocal(w.NumType.i32);
           b.i32_const(0);
           b.local_set(argIdxLocal);
 
@@ -319,8 +316,8 @@
 
             b.local_get(adjustedPositionalArgsLocal);
             b.i32_const(optionalParamIdx);
-            translator.constants.instantiateConstant(
-                function, b, param, translator.topInfo.nullableType);
+            translator.constants
+                .instantiateConstant(b, param, translator.topInfo.nullableType);
             b.array_set(translator.nullableObjectArrayType);
             b.end();
           }
@@ -339,12 +336,12 @@
           b.br_if(noSuchMethodBlock);
         } else {
           adjustedNamedArgsLocal =
-              function.addLocal(translator.nullableObjectArrayTypeRef);
+              b.addLocal(translator.nullableObjectArrayTypeRef);
           b.i32_const(targetMemberParamInfo.named.length);
           b.array_new_default(translator.nullableObjectArrayType);
           b.local_set(adjustedNamedArgsLocal);
 
-          final namedParameterIdxLocal = function.addLocal(
+          final namedParameterIdxLocal = b.addLocal(
               translator.classInfo[translator.boxedIntClass]!.nullableType);
 
           final remainingNamedArgsLocal = numArgsLocal;
@@ -378,7 +375,6 @@
 
             b.local_get(namedArgsLocal);
             translator.constants.instantiateConstant(
-                function,
                 b,
                 SymbolConstant(name, null),
                 translator.classInfo[translator.symbolClass]!.nonNullableType);
@@ -411,7 +407,7 @@
               b.local_get(namedArgsLocal);
               b.local_get(namedParameterIdxLocal);
               translator.convertType(
-                  function, namedParameterIdxLocal.type, w.NumType.i64);
+                  b, namedParameterIdxLocal.type, w.NumType.i64);
               b.i32_wrap_i64();
               b.array_get(translator.nullableObjectArrayType);
 
@@ -427,14 +423,12 @@
               if (functionNodeDefaultValue != null) {
                 // Used by the member, has a default value
                 translator.constants.instantiateConstant(
-                    function,
                     b,
                     (functionNodeDefaultValue as ConstantExpression).constant,
                     translator.topInfo.nullableType);
               } else {
                 // Not used by the member
                 translator.constants.instantiateConstant(
-                  function,
                   b,
                   paramInfoDefaultValue!,
                   translator.topInfo.nullableType,
@@ -449,7 +443,7 @@
               b.local_get(namedArgsLocal);
               b.local_get(namedParameterIdxLocal);
               translator.convertType(
-                  function, namedParameterIdxLocal.type, w.NumType.i64);
+                  b, namedParameterIdxLocal.type, w.NumType.i64);
               b.i32_wrap_i64();
               b.array_get(translator.nullableObjectArrayType);
               b.array_set(translator.nullableObjectArrayType);
@@ -480,7 +474,7 @@
 
     final getterSelectors =
         translator.dispatchTable.dynamicGetterSelectors(memberName);
-    final getterValueLocal = function.addLocal(translator.topInfo.nullableType);
+    final getterValueLocal = b.addLocal(translator.topInfo.nullableType);
     for (final selector in getterSelectors) {
       for (final (:range, :target) in selector.targetRanges) {
         for (int classId = range.start; classId <= range.end; ++classId) {
@@ -513,9 +507,9 @@
           // Get field value
           b.local_get(receiverLocal);
           translator.convertType(
-              function, receiverLocal.type, targetFunction.type.inputs.first);
+              b, receiverLocal.type, targetFunction.type.inputs.first);
           b.call(targetFunction);
-          translator.convertType(function, targetFunction.type.outputs.single,
+          translator.convertType(b, targetFunction.type.outputs.single,
               translator.topInfo.nullableType);
           b.local_tee(getterValueLocal);
 
@@ -546,14 +540,14 @@
           final closureBaseType = w.RefType.def(
               translator.closureLayouter.closureBaseStruct,
               nullable: false);
-          final closureLocal = function.addLocal(closureBaseType);
+          final closureLocal = b.addLocal(closureBaseType);
           b.local_get(receiverLocal);
           b.ref_cast(closureBaseType);
           b.local_set(closureLocal);
 
           generateDynamicFunctionCall(
               translator,
-              function,
+              b,
               closureLocal,
               typeArgsLocal,
               positionalArgsLocal,
@@ -571,10 +565,10 @@
     // Unable to find a matching member, call `noSuchMethod`
     generateNoSuchMethodCall(
         translator,
-        function,
+        b,
         () => b.local_get(receiverLocal),
-        () => createInvocationObject(translator, function, memberName,
-            typeArgsLocal, positionalArgsLocal, namedArgsLocal));
+        () => createInvocationObject(translator, b, memberName, typeArgsLocal,
+            positionalArgsLocal, namedArgsLocal));
 
     b.end();
   }
@@ -616,7 +610,7 @@
 /// [noSuchMethodBlock] is used as the `br` target when the shape check fails.
 void generateDynamicFunctionCall(
   Translator translator,
-  w.FunctionBuilder function,
+  w.InstructionsBuilder b,
   w.Local closureLocal,
   w.Local typeArgsLocal,
   w.Local posArgsLocal,
@@ -627,11 +621,9 @@
   assert(posArgsLocal.type == translator.nullableObjectArrayTypeRef);
   assert(namedArgsLocal.type == translator.nullableObjectArrayTypeRef);
 
-  final b = function.body;
-
   // Read the `_FunctionType` field
   final functionTypeLocal =
-      function.addLocal(translator.closureLayouter.functionTypeType);
+      b.addLocal(translator.closureLayouter.functionTypeType);
   b.local_get(closureLocal);
   b.struct_get(translator.closureLayouter.closureBaseStruct,
       FieldIndex.closureRuntimeType);
@@ -691,17 +683,12 @@
 
 void createInvocationObject(
     Translator translator,
-    w.FunctionBuilder function,
+    w.InstructionsBuilder b,
     String memberName,
     w.Local typeArgsLocal,
     w.Local positionalArgsLocal,
     w.Local namedArgsLocal) {
-  final b = function.body;
-
-  translator.constants.instantiateConstant(
-      function,
-      b,
-      SymbolConstant(memberName, null),
+  translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
       translator.classInfo[translator.symbolClass]!.nonNullableType);
 
   b.local_get(typeArgsLocal);
@@ -719,15 +706,10 @@
 
 void createGetterInvocationObject(
   Translator translator,
-  w.FunctionBuilder function,
+  w.InstructionsBuilder b,
   String memberName,
 ) {
-  final b = function.body;
-
-  translator.constants.instantiateConstant(
-      function,
-      b,
-      SymbolConstant(memberName, null),
+  translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
       translator.classInfo[translator.symbolClass]!.nonNullableType);
 
   b.call(translator.functions
@@ -736,18 +718,13 @@
 
 void createSetterInvocationObject(
   Translator translator,
-  w.FunctionBuilder function,
+  w.InstructionsBuilder b,
   String memberName,
   w.Local positionalArgLocal,
 ) {
-  final b = function.body;
-
   memberName = '$memberName=';
 
-  translator.constants.instantiateConstant(
-      function,
-      b,
-      SymbolConstant(memberName, null),
+  translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
       translator.classInfo[translator.symbolClass]!.nonNullableType);
 
   b.local_get(positionalArgLocal);
@@ -757,12 +734,10 @@
 
 void generateNoSuchMethodCall(
   Translator translator,
-  w.FunctionBuilder function,
+  w.InstructionsBuilder b,
   void Function() pushReceiver,
   void Function() pushInvocationObject,
 ) {
-  final b = function.body;
-
   final SelectorInfo noSuchMethodSelector = translator.dispatchTable
       .selectorForTarget(translator.objectNoSuchMethod.reference);
   translator.functions.recordSelectorUse(noSuchMethodSelector);
@@ -775,7 +750,7 @@
 
   final invocationFactory = translator.functions
       .getFunction(translator.invocationGenericMethodFactory.reference);
-  translator.convertType(function, invocationFactory.type.outputs[0],
+  translator.convertType(b, invocationFactory.type.outputs[0],
       noSuchMethodSelector.signature.inputs[1]);
 
   // `noSuchMethod` can have extra parameters as long as they are optional.
@@ -786,10 +761,7 @@
       positionalArgIdx += 1) {
     final positionalParameterValue =
         noSuchMethodParamInfo.positional[positionalArgIdx]!;
-    translator.constants.instantiateConstant(
-        function,
-        b,
-        positionalParameterValue,
+    translator.constants.instantiateConstant(b, positionalParameterValue,
         noSuchMethodWasmFunctionType.inputs[wasmArgIdx]);
     wasmArgIdx += 1;
   }
@@ -798,7 +770,7 @@
   for (String namedParameterName in noSuchMethodParamInfo.names) {
     final namedParameterValue =
         noSuchMethodParamInfo.named[namedParameterName]!;
-    translator.constants.instantiateConstant(function, b, namedParameterValue,
+    translator.constants.instantiateConstant(b, namedParameterValue,
         noSuchMethodWasmFunctionType.inputs[wasmArgIdx]);
     wasmArgIdx += 1;
   }
diff --git a/pkg/dart2wasm/lib/globals.dart b/pkg/dart2wasm/lib/globals.dart
index 4ce65fb..e9a3897 100644
--- a/pkg/dart2wasm/lib/globals.dart
+++ b/pkg/dart2wasm/lib/globals.dart
@@ -149,7 +149,7 @@
         final global =
             m.globals.define(w.GlobalType(type, mutable: !field.isFinal));
         translator.constants
-            .instantiateConstant(null, global.initializer, init, type);
+            .instantiateConstant(global.initializer, init, type);
         global.initializer.end();
         return global;
       } else {
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index 497f846..df7261e 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -164,7 +164,7 @@
 
     // int.bitlength
     if (cls == translator.coreTypes.intClass && name == 'bitLength') {
-      w.Local temp = codeGen.function.addLocal(w.NumType.i64);
+      w.Local temp = b.addLocal(w.NumType.i64);
       b.i64_const(64);
       codeGen.wrap(receiver, w.NumType.i64);
       b.local_tee(temp);
@@ -537,21 +537,21 @@
               .translateStorageType(types.rtt.typeRowDisplacementOffsetsType)
               .unpacked;
           translator.constants.instantiateConstant(
-              null, b, types.rtt.typeRowDisplacementOffsets, type);
+              b, types.rtt.typeRowDisplacementOffsets, type);
           return type;
         case "_typeRowDisplacementTable":
           final type = translator
               .translateStorageType(types.rtt.typeRowDisplacementTableType)
               .unpacked;
-          translator.constants.instantiateConstant(
-              null, b, types.rtt.typeRowDisplacementTable, type);
+          translator.constants
+              .instantiateConstant(b, types.rtt.typeRowDisplacementTable, type);
           return type;
         case "_typeRowDisplacementSubstTable":
           final type = translator
               .translateStorageType(types.rtt.typeRowDisplacementSubstTableType)
               .unpacked;
           translator.constants.instantiateConstant(
-              null, b, types.rtt.typeRowDisplacementSubstTable, type);
+              b, types.rtt.typeRowDisplacementSubstTable, type);
           return type;
         case "_typeNames":
           final type =
@@ -560,7 +560,7 @@
             b.ref_null((type as w.RefType).heapType);
           } else {
             translator.constants
-                .instantiateConstant(null, b, types.rtt.typeNames, type);
+                .instantiateConstant(b, types.rtt.typeNames, type);
           }
           return type;
       }
@@ -652,8 +652,8 @@
 
             final sourceArrayRefType =
                 w.RefType.def(arrayType, nullable: false);
-            final sourceArrayLocal = codeGen.addLocal(sourceArrayRefType);
-            final newArrayLocal = codeGen.addLocal(sourceArrayRefType);
+            final sourceArrayLocal = b.addLocal(sourceArrayRefType);
+            final newArrayLocal = b.addLocal(sourceArrayRefType);
 
             codeGen.wrap(sourceArray, sourceArrayRefType);
             b.local_tee(sourceArrayLocal);
@@ -1033,7 +1033,7 @@
             b.array_new_default(arrayType);
           } else {
             // Initialize to the provided value
-            w.Local lengthTemp = codeGen.addLocal(w.NumType.i32);
+            w.Local lengthTemp = b.addLocal(w.NumType.i32);
             b.local_set(lengthTemp);
             codeGen.wrap(initialValue, arrayType.elementType.type.unpacked);
             b.local_get(lengthTemp);
@@ -1164,8 +1164,7 @@
     ClassInfo receiverInfo = translator.classInfo[translator.listBaseClass]!;
     codeGen.wrap(
         node.arguments.positional.single, receiverInfo.nonNullableType);
-    w.Local receiverLocal =
-        codeGen.function.addLocal(receiverInfo.nonNullableType);
+    w.Local receiverLocal = b.addLocal(receiverInfo.nonNullableType);
     b.local_set(receiverLocal);
 
     ClassInfo newInfo = translator.classInfo[newClass]!;
@@ -1227,7 +1226,7 @@
       assert(receiver.name.text == "call");
       w.RefType receiverType =
           translator.translateType(dartTypeOf(receiver.receiver)) as w.RefType;
-      w.Local temp = codeGen.addLocal(receiverType);
+      w.Local temp = b.addLocal(receiverType);
       codeGen.wrap(receiver.receiver, receiverType);
       b.local_set(temp);
       w.FunctionType functionType = receiverType.heapType as w.FunctionType;
@@ -1256,7 +1255,7 @@
           [receiver.arguments.types.single]);
       w.RefType receiverType =
           translator.translateType(wasmFunctionType) as w.RefType;
-      w.Local tableIndex = codeGen.addLocal(w.NumType.i32);
+      w.Local tableIndex = b.addLocal(w.NumType.i32);
       codeGen.wrap(receiver.arguments.positional.single, w.NumType.i32);
       b.local_set(tableIndex);
       w.FunctionType functionType = receiverType.heapType as w.FunctionType;
@@ -1273,7 +1272,7 @@
   }
 
   /// Generate Wasm function for an intrinsic member.
-  bool generateMemberIntrinsic(Reference target, w.FunctionBuilder function,
+  bool generateMemberIntrinsic(Reference target, w.FunctionType functionType,
       List<w.Local> paramLocals, w.Label? returnLabel) {
     Member member = target.asMember;
     if (member is! Procedure) return false;
@@ -1309,7 +1308,7 @@
       ClassInfo boolInfo = translator.classInfo[translator.boxedBoolClass]!;
       ClassInfo intInfo = translator.classInfo[translator.boxedIntClass]!;
       ClassInfo doubleInfo = translator.classInfo[translator.boxedDoubleClass]!;
-      w.Local cid = function.addLocal(w.NumType.i32);
+      w.Local cid = b.addLocal(w.NumType.i32);
 
       // If the references are identical, return true.
       b.local_get(first);
@@ -1400,8 +1399,7 @@
     if (member.enclosingLibrary == translator.coreTypes.coreLibrary &&
         name == "identityHashCode") {
       final w.Local arg = paramLocals[0];
-      final w.Local nonNullArg =
-          function.addLocal(translator.topInfo.nonNullableType);
+      final w.Local nonNullArg = b.addLocal(translator.topInfo.nonNullableType);
       final List<int> classIds = translator.valueClasses.keys
           .map((cls) => translator.classInfo[cls]!.classId)
           .toList()
@@ -1454,7 +1452,7 @@
       Class cls = member.enclosingClass!;
       ClassInfo classInfo = translator.classInfo[cls]!;
       w.ArrayType arrayType =
-          (function.type.outputs.single as w.RefType).heapType as w.ArrayType;
+          (functionType.outputs.single as w.RefType).heapType as w.ArrayType;
       w.Local object = paramLocals[0];
       w.Local preciseObject = codeGen.addLocal(classInfo.nonNullableType);
       b.local_get(object);
@@ -1478,63 +1476,63 @@
         CodeGenCallback? code = _unaryOperatorMap[intType]![op];
         if (code != null) {
           w.ValueType resultType = _unaryResultMap[op] ?? intType;
-          w.ValueType inputType = function.type.inputs.single;
-          w.ValueType outputType = function.type.outputs.single;
-          b.local_get(function.locals[0]);
-          translator.convertType(function, inputType, intType);
+          w.ValueType inputType = functionType.inputs.single;
+          w.ValueType outputType = functionType.outputs.single;
+          b.local_get(paramLocals[0]);
+          translator.convertType(b, inputType, intType);
           code(codeGen);
-          translator.convertType(function, resultType, outputType);
+          translator.convertType(b, resultType, outputType);
           return true;
         }
       } else if (functionNode.requiredParameterCount == 1) {
         CodeGenCallback? code = _binaryOperatorMap[intType]![intType]![op];
         if (code != null) {
-          w.ValueType leftType = function.type.inputs[0];
-          w.ValueType rightType = function.type.inputs[1];
-          w.ValueType outputType = function.type.outputs.single;
+          w.ValueType leftType = functionType.inputs[0];
+          w.ValueType rightType = functionType.inputs[1];
+          w.ValueType outputType = functionType.outputs.single;
           if (rightType == intType) {
             // int parameter
-            b.local_get(function.locals[0]);
-            translator.convertType(function, leftType, intType);
-            b.local_get(function.locals[1]);
+            b.local_get(paramLocals[0]);
+            translator.convertType(b, leftType, intType);
+            b.local_get(paramLocals[1]);
             code(codeGen);
             if (!isComparison(op)) {
-              translator.convertType(function, intType, outputType);
+              translator.convertType(b, intType, outputType);
             }
             return true;
           }
           // num parameter
           ClassInfo intInfo = translator.classInfo[translator.boxedIntClass]!;
           w.Label intArg = b.block(const [], [intInfo.nonNullableType]);
-          b.local_get(function.locals[1]);
-          b.br_on_cast(intArg, function.locals[1].type as w.RefType,
+          b.local_get(paramLocals[1]);
+          b.br_on_cast(intArg, paramLocals[1].type as w.RefType,
               intInfo.nonNullableType);
           // double argument
           b.drop();
-          b.local_get(function.locals[0]);
-          translator.convertType(function, leftType, intType);
+          b.local_get(paramLocals[0]);
+          translator.convertType(b, leftType, intType);
           b.f64_convert_i64_s();
-          b.local_get(function.locals[1]);
-          translator.convertType(function, rightType, doubleType);
+          b.local_get(paramLocals[1]);
+          translator.convertType(b, rightType, doubleType);
           // Inline double op
           CodeGenCallback doubleCode =
               _binaryOperatorMap[doubleType]![doubleType]![op]!;
           doubleCode(codeGen);
           if (!isComparison(op)) {
-            translator.convertType(function, doubleType, outputType);
+            translator.convertType(b, doubleType, outputType);
           }
           b.return_();
           b.end();
           // int argument
-          translator.convertType(function, intInfo.nonNullableType, intType);
-          w.Local rightTemp = function.addLocal(intType);
+          translator.convertType(b, intInfo.nonNullableType, intType);
+          w.Local rightTemp = b.addLocal(intType);
           b.local_set(rightTemp);
-          b.local_get(function.locals[0]);
-          translator.convertType(function, leftType, intType);
+          b.local_get(paramLocals[0]);
+          translator.convertType(b, leftType, intType);
           b.local_get(rightTemp);
           code(codeGen);
           if (!isComparison(op)) {
-            translator.convertType(function, intType, outputType);
+            translator.convertType(b, intType, outputType);
           }
           return true;
         }
@@ -1549,12 +1547,12 @@
         CodeGenCallback? code = _unaryOperatorMap[doubleType]![op];
         if (code != null) {
           w.ValueType resultType = _unaryResultMap[op] ?? doubleType;
-          w.ValueType inputType = function.type.inputs.single;
-          w.ValueType outputType = function.type.outputs.single;
-          b.local_get(function.locals[0]);
-          translator.convertType(function, inputType, doubleType);
+          w.ValueType inputType = functionType.inputs.single;
+          w.ValueType outputType = functionType.outputs.single;
+          b.local_get(paramLocals[0]);
+          translator.convertType(b, inputType, doubleType);
           code(codeGen);
-          translator.convertType(function, resultType, outputType);
+          translator.convertType(b, resultType, outputType);
           return true;
         }
       }
@@ -1562,26 +1560,26 @@
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_isInstantiationClosure") {
-      assert(function.locals.length == 1);
-      b.local_get(function.locals[0]); // ref _Closure
+      assert(paramLocals.length == 1);
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitInstantiationClosureCheck(translator);
       return true;
     }
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_instantiatedClosure") {
-      assert(function.locals.length == 1);
-      b.local_get(function.locals[0]); // ref _Closure
+      assert(paramLocals.length == 1);
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitGetInstantiatedClosure(translator);
       return true;
     }
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_instantiationClosureTypeHash") {
-      assert(function.locals.length == 1);
+      assert(paramLocals.length == 1);
 
       // Instantiation context, to be passed to the hash function.
-      b.local_get(function.locals[0]); // ref _Closure
+      b.local_get(paramLocals[0]); // ref _Closure
       b.ref_cast(w.RefType(translator.closureLayouter.closureBaseStruct,
           nullable: false));
       b.struct_get(translator.closureLayouter.closureBaseStruct,
@@ -1591,7 +1589,7 @@
           nullable: false));
 
       // Hash function.
-      b.local_get(function.locals[0]); // ref _Closure
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitGetInstantiatedClosure(translator);
       b.emitGetClosureVtable(translator);
       b.ref_cast(w.RefType.def(
@@ -1607,7 +1605,7 @@
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_instantiationClosureTypeEquals") {
-      assert(function.locals.length == 2);
+      assert(paramLocals.length == 2);
 
       final w.StructType closureBaseStruct =
           translator.closureLayouter.closureBaseStruct;
@@ -1616,17 +1614,17 @@
           translator.closureLayouter.instantiationContextBaseStruct,
           nullable: false);
 
-      b.local_get(function.locals[0]); // ref _Closure
+      b.local_get(paramLocals[0]); // ref _Closure
       b.ref_cast(w.RefType(closureBaseStruct, nullable: false));
       b.struct_get(closureBaseStruct, FieldIndex.closureContext);
       b.ref_cast(instantiationContextBase);
 
-      b.local_get(function.locals[1]); // ref _Closure
+      b.local_get(paramLocals[1]); // ref _Closure
       b.ref_cast(w.RefType(closureBaseStruct, nullable: false));
       b.struct_get(closureBaseStruct, FieldIndex.closureContext);
       b.ref_cast(instantiationContextBase);
 
-      b.local_get(function.locals[0]);
+      b.local_get(paramLocals[0]);
       b.emitGetInstantiatedClosure(translator);
       b.emitGetClosureVtable(translator);
       b.ref_cast(w.RefType.def(
@@ -1643,55 +1641,53 @@
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_isInstanceTearOff") {
-      assert(function.locals.length == 1);
-      b.local_get(function.locals[0]); // ref _Closure
+      assert(paramLocals.length == 1);
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitTearOffCheck(translator);
       return true;
     }
 
     if (member.enclosingClass == translator.closureClass &&
         name == "_instanceTearOffReceiver") {
-      assert(function.locals.length == 1);
-      b.local_get(function.locals[0]); // ref _Closure
+      assert(paramLocals.length == 1);
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitGetTearOffReceiver(translator);
       return true;
     }
 
     if (member.enclosingClass == translator.closureClass && name == "_vtable") {
-      assert(function.locals.length == 1);
-      b.local_get(function.locals[0]); // ref _Closure
+      assert(paramLocals.length == 1);
+      b.local_get(paramLocals[0]); // ref _Closure
       b.emitGetClosureVtable(translator);
       return true;
     }
 
     if (member.enclosingClass == translator.coreTypes.functionClass &&
         name == "apply") {
-      assert(function.type.inputs.length == 3);
+      assert(functionType.inputs.length == 3);
 
-      final closureLocal = function.locals[0]; // ref #ClosureBase
-      final posArgsNullableLocal = function.locals[1]; // ref null Object
-      final namedArgsLocal = function.locals[2]; // ref null Object
+      final closureLocal = paramLocals[0]; // ref #ClosureBase
+      final posArgsNullableLocal = paramLocals[1]; // ref null Object
+      final namedArgsLocal = paramLocals[2]; // ref null Object
 
       // Create empty type arguments array.
-      final typeArgsLocal = function.addLocal(translator.makeArray(function,
-          translator.typeArrayType, 0, (elementType, elementIndex) {}));
+      final typeArgsLocal = b.addLocal(translator.makeArray(
+          b, translator.typeArrayType, 0, (elementType, elementIndex) {}));
       b.local_set(typeArgsLocal);
 
       // Create empty list for positional args if the argument is null
-      final posArgsLocal =
-          function.addLocal(translator.nullableObjectArrayTypeRef);
+      final posArgsLocal = b.addLocal(translator.nullableObjectArrayTypeRef);
       b.local_get(posArgsNullableLocal);
       b.ref_is_null();
 
       b.if_([], [translator.nullableObjectArrayTypeRef]);
       translator.makeArray(
-          function, translator.nullableObjectArrayType, 0, (_, __) {});
+          b, translator.nullableObjectArrayType, 0, (_, __) {});
 
       b.else_();
       // List argument may be a custom list type, convert it to `WasmListBase`
       // with `WasmListBase.of`.
       translator.constants.instantiateConstant(
-        function,
         b,
         TypeLiteralConstant(DynamicType()),
         translator.types.nonNullableTypeType,
@@ -1706,33 +1702,33 @@
       // Convert named argument map to list, to be passed to shape and type
       // checkers and the dynamic call entry.
       final namedArgsListLocal =
-          function.addLocal(translator.nullableObjectArrayTypeRef);
+          b.addLocal(translator.nullableObjectArrayTypeRef);
       b.local_get(namedArgsLocal);
       codeGen.call(translator.namedParameterMapToArray.reference);
       b.local_set(namedArgsListLocal);
 
       final noSuchMethodBlock = b.block();
 
-      generateDynamicFunctionCall(translator, function, closureLocal,
-          typeArgsLocal, posArgsLocal, namedArgsListLocal, noSuchMethodBlock);
+      generateDynamicFunctionCall(translator, b, closureLocal, typeArgsLocal,
+          posArgsLocal, namedArgsListLocal, noSuchMethodBlock);
       b.return_();
 
       b.end(); // noSuchMethodBlock
 
       generateNoSuchMethodCall(
           translator,
-          function,
+          b,
           () => b.local_get(closureLocal),
-          () => createInvocationObject(translator, function, "call",
-              typeArgsLocal, posArgsLocal, namedArgsListLocal));
+          () => createInvocationObject(translator, b, "call", typeArgsLocal,
+              posArgsLocal, namedArgsListLocal));
 
       return true;
     }
 
     // Error._throw
     if (member.enclosingClass == translator.errorClass && name == "_throw") {
-      final objectLocal = function.locals[0]; // ref #Top
-      final stackTraceLocal = function.locals[1]; // ref Object
+      final objectLocal = paramLocals[0]; // ref #Top
+      final stackTraceLocal = paramLocals[1]; // ref Object
 
       final notErrorBlock = b.block([], [objectLocal.type]);
 
@@ -1744,7 +1740,7 @@
       b.br_on_cast_fail(
           notErrorBlock, objectLocal.type as w.RefType, errorRefType);
 
-      final errorLocal = function.addLocal(errorRefType);
+      final errorLocal = b.addLocal(errorRefType);
       b.local_tee(errorLocal);
 
       b.struct_get(errorClassInfo.struct, stackTraceFieldIndex);
diff --git a/pkg/dart2wasm/lib/state_machine.dart b/pkg/dart2wasm/lib/state_machine.dart
index 29bef15..cc0d292 100644
--- a/pkg/dart2wasm/lib/state_machine.dart
+++ b/pkg/dart2wasm/lib/state_machine.dart
@@ -7,6 +7,7 @@
 
 import 'closures.dart';
 import 'code_generator.dart';
+import 'translator.dart';
 
 /// Placement of a control flow graph target within a statement. This
 /// distinction is necessary since some statements need to have two targets
@@ -308,12 +309,13 @@
   /// Call this right before terminating a CFG block.
   void _terminateTryBlocks() {
     int nextHandlerIdx = _handlers.length - 1;
+    final b = codeGen.b;
     for (final int nCoveredHandlers in _tryBlockNumHandlers.reversed) {
-      final stackTraceLocal = codeGen
-          .addLocal(codeGen.translator.stackTraceInfo.repr.nonNullableType);
+      final stackTraceLocal =
+          b.addLocal(codeGen.translator.stackTraceInfo.repr.nonNullableType);
 
       final exceptionLocal =
-          codeGen.addLocal(codeGen.translator.topInfo.nonNullableType);
+          b.addLocal(codeGen.translator.topInfo.nonNullableType);
 
       void generateCatchBody() {
         // Set continuations of finalizers that can be reached by this `catch`
@@ -321,26 +323,25 @@
         for (int i = 0; i < nCoveredHandlers; i += 1) {
           final handler = _handlers[nextHandlerIdx - i];
           if (handler is Finalizer) {
-            handler.setContinuationRethrow(
-                () => codeGen.b.local_get(exceptionLocal),
-                () => codeGen.b.local_get(stackTraceLocal));
+            handler.setContinuationRethrow(() => b.local_get(exceptionLocal),
+                () => b.local_get(stackTraceLocal));
           }
         }
 
         // Set the untyped "current exception" variable. Catch blocks will do the
         // type tests as necessary using this variable and set their exception
         // and stack trace locals.
-        codeGen.setSuspendStateCurrentException(
-            () => codeGen.b.local_get(exceptionLocal));
+        codeGen
+            .setSuspendStateCurrentException(() => b.local_get(exceptionLocal));
         codeGen.setSuspendStateCurrentStackTrace(
-            () => codeGen.b.local_get(stackTraceLocal));
+            () => b.local_get(stackTraceLocal));
 
         codeGen._jumpToTarget(_handlers[nextHandlerIdx].target);
       }
 
-      codeGen.b.catch_(codeGen.translator.exceptionTag);
-      codeGen.b.local_set(stackTraceLocal);
-      codeGen.b.local_set(exceptionLocal);
+      b.catch_(codeGen.translator.exceptionTag);
+      b.local_set(stackTraceLocal);
+      b.local_set(exceptionLocal);
 
       generateCatchBody();
 
@@ -355,21 +356,21 @@
       }
 
       if (canHandleJSExceptions) {
-        codeGen.b.catch_all();
+        b.catch_all();
 
         // We can't inspect the thrown object in a `catch_all` and get a stack
         // trace, so we just attach the current stack trace.
         codeGen.call(codeGen.translator.stackTraceCurrent.reference);
-        codeGen.b.local_set(stackTraceLocal);
+        b.local_set(stackTraceLocal);
 
         // We create a generic JavaScript error.
         codeGen.call(codeGen.translator.javaScriptErrorFactory.reference);
-        codeGen.b.local_set(exceptionLocal);
+        b.local_set(exceptionLocal);
 
         generateCatchBody();
       }
 
-      codeGen.b.end(); // end catch
+      b.end(); // end catch
 
       nextHandlerIdx -= nCoveredHandlers;
     }
@@ -568,7 +569,12 @@
 ///
 /// This is used to compile `async` and `sync*` functions.
 abstract class StateMachineCodeGenerator extends CodeGenerator {
-  StateMachineCodeGenerator(super.translator, super.function, super.reference);
+  w.FunctionBuilder function;
+
+  StateMachineCodeGenerator(
+      Translator translator, this.function, Reference reference)
+      : super(translator, function.type, function.body, reference,
+            paramLocals: function.locals.toList());
 
   /// Targets of the CFG, indexed by target index.
   late final List<StateTarget> targets;
@@ -615,12 +621,11 @@
   }
 
   @override
-  w.BaseFunction generateLambda(Lambda lambda, Closures closures) {
+  void generateLambda(Lambda lambda, Closures closures) {
     this.closures = closures;
     setSourceMapSource(lambda.functionNodeSource);
     setupLambdaParametersAndContexts(lambda);
     _generateBodies(lambda.functionNode);
-    return function;
   }
 
   void _generateBodies(FunctionNode functionNode) {
@@ -832,8 +837,8 @@
       b.local_get(switchValueNullableLocal);
       b.ref_as_non_null();
       // Unbox if necessary
-      translator.convertType(function, switchValueNullableLocal.type,
-          switchValueNonNullableLocal.type);
+      translator.convertType(
+          b, switchValueNullableLocal.type, switchValueNonNullableLocal.type);
       b.local_set(switchValueNonNullableLocal);
     }
 
@@ -950,7 +955,7 @@
       setVariable(catch_.exception!, () {
         getSuspendStateCurrentException();
         // Type test already passed, convert the exception.
-        translator.convertType(function, translator.topInfo.nullableType,
+        translator.convertType(b, translator.topInfo.nullableType,
             translator.translateType(catch_.exception!.type));
       });
       setVariable(catch_.stackTrace!, () => getSuspendStateCurrentStackTrace());
@@ -1215,6 +1220,6 @@
   /// Same as [_getVariable], but boxes the value if it's not already boxed.
   void _getVariableBoxed(VariableDeclaration variable) {
     final varType = _getVariable(variable);
-    translator.convertType(function, varType, translator.topInfo.nullableType);
+    translator.convertType(b, varType, translator.topInfo.nullableType);
   }
 }
diff --git a/pkg/dart2wasm/lib/sync_star.dart b/pkg/dart2wasm/lib/sync_star.dart
index 3e8eece..38ff310 100644
--- a/pkg/dart2wasm/lib/sync_star.dart
+++ b/pkg/dart2wasm/lib/sync_star.dart
@@ -142,17 +142,19 @@
     // Set the current Wasm function for the code generator to the inner
     // function of the `sync*`, which is to contain the body.
     function = resumeFun;
+    b = resumeFun.body;
+    functionType = resumeFun.type;
 
     // Set up locals for contexts and `this`.
     thisLocal = null;
     Context? localContext = context;
     while (localContext != null) {
       if (!localContext.isEmpty) {
-        localContext.currentLocal = function
-            .addLocal(w.RefType.def(localContext.struct, nullable: true));
+        localContext.currentLocal =
+            b.addLocal(w.RefType.def(localContext.struct, nullable: true));
         if (localContext.containsThis) {
           assert(thisLocal == null);
-          thisLocal = function.addLocal(localContext
+          thisLocal = b.addLocal(localContext
               .struct.fields[localContext.thisFieldIndex].type.unpacked
               .withNullability(false));
           translator.globals.instantiateDummyValue(b, thisLocal!.type);
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 45b222b..ecb0bc9 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -374,8 +374,8 @@
       codeGen.generate();
 
       if (options.printWasm) {
-        print(codeGen.function.type);
-        print(codeGen.function.body.trace);
+        print(function.type);
+        print(function.body.trace);
       }
 
       // The constructor allocator, initializer, and body functions all
@@ -385,10 +385,11 @@
       // constructor initializer methods are generated.
       if (member is! Constructor || reference.isInitializerReference) {
         for (Lambda lambda in codeGen.closures.lambdas.values) {
-          w.BaseFunction lambdaFunction = CodeGenerator.forFunction(
-                  this, lambda.functionNode, lambda.function, reference)
+          final lambdaFunction = lambda.function;
+          CodeGenerator.forFunction(
+                  this, lambda.functionNode, lambdaFunction, reference)
               .generateLambda(lambda, codeGen.closures);
-          _printFunction(lambdaFunction, "$canonicalName (closure)");
+          _printFunction(function, "$canonicalName (closure)");
         }
       }
 
@@ -826,9 +827,7 @@
     return (from == voidMarker) ^ (to == voidMarker) || !from.isSubtypeOf(to);
   }
 
-  void convertType(
-      w.FunctionBuilder function, w.ValueType from, w.ValueType to) {
-    final b = function.body;
+  void convertType(w.InstructionsBuilder b, w.ValueType from, w.ValueType to) {
     if (from == voidMarker || to == voidMarker) {
       if (from != voidMarker) {
         b.drop();
@@ -856,7 +855,7 @@
         // Boxing
         ClassInfo info = classInfo[boxedClasses[from]!]!;
         assert(info.struct.isSubtypeOf(to.heapType));
-        w.Local temp = function.addLocal(from);
+        w.Local temp = b.addLocal(from);
         b.local_set(temp);
         b.i32_const(info.classId);
         b.local_get(temp);
@@ -1117,10 +1116,8 @@
     return null;
   }
 
-  w.ValueType makeArray(w.FunctionBuilder function, w.ArrayType arrayType,
+  w.ValueType makeArray(w.InstructionsBuilder b, w.ArrayType arrayType,
       int length, void Function(w.ValueType, int) generateItem) {
-    final b = function.body;
-
     final w.ValueType elementType = arrayType.elementType.type.unpacked;
     final arrayTypeRef = w.RefType.def(arrayType, nullable: false);
 
@@ -1129,7 +1126,7 @@
       b.i32_const(length);
       b.array_new_default(arrayType);
       if (length > 0) {
-        final w.Local arrayLocal = function.addLocal(arrayTypeRef);
+        final w.Local arrayLocal = b.addLocal(arrayTypeRef);
         b.local_set(arrayLocal);
         for (int i = 0; i < length; i++) {
           b.local_get(arrayLocal);
@@ -1216,7 +1213,7 @@
       w.Local receiver = trampoline.locals[0];
       b.local_get(receiver);
       translator.convertType(
-          trampoline, receiver.type, target.type.inputs[targetIndex++]);
+          b, receiver.type, target.type.inputs[targetIndex++]);
     }
     int argIndex = 1;
     for (int i = 0; i < typeCount; i++) {
@@ -1227,11 +1224,10 @@
       if (i < posArgCount) {
         w.Local arg = trampoline.locals[argIndex++];
         b.local_get(arg);
-        translator.convertType(
-            trampoline, arg.type, target.type.inputs[targetIndex++]);
+        translator.convertType(b, arg.type, target.type.inputs[targetIndex++]);
       } else {
-        translator.constants.instantiateConstant(trampoline, b,
-            paramInfo.positional[i]!, target.type.inputs[targetIndex++]);
+        translator.constants.instantiateConstant(
+            b, paramInfo.positional[i]!, target.type.inputs[targetIndex++]);
       }
     }
     int argNameIndex = 0;
@@ -1240,12 +1236,11 @@
       if (argNameIndex < argNames.length && argNames[argNameIndex] == argName) {
         w.Local arg = trampoline.locals[argIndex++];
         b.local_get(arg);
-        translator.convertType(
-            trampoline, arg.type, target.type.inputs[targetIndex++]);
+        translator.convertType(b, arg.type, target.type.inputs[targetIndex++]);
         argNameIndex++;
       } else {
-        translator.constants.instantiateConstant(trampoline, b,
-            paramInfo.named[argName]!, target.type.inputs[targetIndex++]);
+        translator.constants.instantiateConstant(
+            b, paramInfo.named[argName]!, target.type.inputs[targetIndex++]);
       }
     }
     assert(argIndex == trampoline.type.inputs.length);
@@ -1254,9 +1249,7 @@
 
     b.call(target);
 
-    translator.convertType(
-        trampoline,
-        translator.outputOrVoid(target.type.outputs),
+    translator.convertType(b, translator.outputOrVoid(target.type.outputs),
         translator.outputOrVoid(trampoline.type.outputs));
     b.end();
   }
@@ -1308,11 +1301,10 @@
 
       // Get context, downcast it to expected type
       b.local_get(closureLocal);
-      translator.convertType(function, closureLocal.type, closureBaseType);
+      translator.convertType(b, closureLocal.type, closureBaseType);
       b.struct_get(translator.closureLayouter.closureBaseStruct,
           FieldIndex.closureContext);
-      translator.convertType(
-          function, closureContextType, targetInputs[inputIdx]);
+      translator.convertType(b, closureContextType, targetInputs[inputIdx]);
       inputIdx += 1;
     }
 
@@ -1322,7 +1314,7 @@
       b.i32_const(typeIdx);
       b.array_get(translator.typeArrayType);
       translator.convertType(
-          function, translator.topInfo.nullableType, targetInputs[inputIdx]);
+          b, translator.topInfo.nullableType, targetInputs[inputIdx]);
       inputIdx += 1;
     }
 
@@ -1344,12 +1336,12 @@
         b.i32_const(posIdx);
         b.array_get(translator.nullableObjectArrayType);
         b.else_();
-        translator.constants.instantiateConstant(function, b,
-            paramInfo.positional[posIdx]!, translator.topInfo.nullableType);
+        translator.constants.instantiateConstant(
+            b, paramInfo.positional[posIdx]!, translator.topInfo.nullableType);
         b.end();
       }
       translator.convertType(
-          function, translator.topInfo.nullableType, targetInputs[inputIdx]);
+          b, translator.topInfo.nullableType, targetInputs[inputIdx]);
       inputIdx += 1;
     }
 
@@ -1364,7 +1356,7 @@
       return null;
     }
 
-    final namedArgValueIndexLocal = function
+    final namedArgValueIndexLocal = b
         .addLocal(translator.classInfo[translator.boxedIntClass]!.nullableType);
 
     for (String paramName in paramInfo.names) {
@@ -1375,7 +1367,6 @@
       // Get passed value
       b.local_get(namedArgsListLocal);
       translator.constants.instantiateConstant(
-          function,
           b,
           SymbolConstant(paramName, null),
           translator.classInfo[translator.symbolClass]!.nonNullableType);
@@ -1387,12 +1378,11 @@
         // Shape check passed, parameter must be passed
         b.local_get(namedArgsListLocal);
         b.local_get(namedArgValueIndexLocal);
-        translator.convertType(
-            function, namedArgValueIndexLocal.type, w.NumType.i64);
+        translator.convertType(b, namedArgValueIndexLocal.type, w.NumType.i64);
         b.i32_wrap_i64();
         b.array_get(translator.nullableObjectArrayType);
         translator.convertType(
-            function,
+            b,
             translator.nullableObjectArrayType.elementType.type.unpacked,
             target.type.inputs[inputIdx]);
       } else {
@@ -1403,14 +1393,12 @@
         if (functionNodeDefaultValue != null) {
           // Used by the member, has a default value
           translator.constants.instantiateConstant(
-              function,
               b,
               (functionNodeDefaultValue as ConstantExpression).constant,
               translator.topInfo.nullableType);
         } else {
           // Not used by the member
           translator.constants.instantiateConstant(
-            function,
             b,
             paramInfoDefaultValue!,
             translator.topInfo.nullableType,
@@ -1419,22 +1407,19 @@
         b.else_(); // value index not null
         b.local_get(namedArgsListLocal);
         b.local_get(namedArgValueIndexLocal);
-        translator.convertType(
-            function, namedArgValueIndexLocal.type, w.NumType.i64);
+        translator.convertType(b, namedArgValueIndexLocal.type, w.NumType.i64);
         b.i32_wrap_i64();
         b.array_get(translator.nullableObjectArrayType);
         b.end();
         translator.convertType(
-            function, translator.topInfo.nullableType, targetInputs[inputIdx]);
+            b, translator.topInfo.nullableType, targetInputs[inputIdx]);
       }
       inputIdx += 1;
     }
 
     b.call(target);
 
-    translator.convertType(
-        function,
-        translator.outputOrVoid(target.type.outputs),
+    translator.convertType(b, translator.outputOrVoid(target.type.outputs),
         translator.outputOrVoid(function.type.outputs));
 
     b.end(); // end function
@@ -1503,8 +1488,8 @@
           ),
           name);
       final b = function.body;
-      translator.constants.instantiateConstant(function, b,
-          TypeLiteralConstant(type), translator.types.nonNullableTypeType);
+      translator.constants.instantiateConstant(
+          b, TypeLiteralConstant(type), translator.types.nonNullableTypeType);
       for (int i = 1; i < wasmTarget.type.inputs.length; ++i) {
         b.local_get(b.locals[i - 1]);
       }
@@ -1531,10 +1516,10 @@
           ),
           name);
       final b = function.body;
-      translator.constants.instantiateConstant(function, b,
-          TypeLiteralConstant(type1), translator.types.nonNullableTypeType);
-      translator.constants.instantiateConstant(function, b,
-          TypeLiteralConstant(type2), translator.types.nonNullableTypeType);
+      translator.constants.instantiateConstant(
+          b, TypeLiteralConstant(type1), translator.types.nonNullableTypeType);
+      translator.constants.instantiateConstant(
+          b, TypeLiteralConstant(type2), translator.types.nonNullableTypeType);
       for (int i = 2; i < wasmTarget.type.inputs.length; ++i) {
         b.local_get(b.locals[i - 2]);
       }
diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart
index 6032c0a..e70b8b2 100644
--- a/pkg/dart2wasm/lib/types.dart
+++ b/pkg/dart2wasm/lib/types.dart
@@ -168,7 +168,7 @@
   /// stack.
   void _makeTypeArray(CodeGenerator codeGen, Iterable<DartType> types) {
     if (types.every(isTypeConstant)) {
-      translator.constants.instantiateConstant(codeGen.function, codeGen.b,
+      translator.constants.instantiateConstant(codeGen.b,
           translator.constants.makeTypeArray(types), typeArrayExpectedType);
     } else {
       for (DartType type in types) {
@@ -194,7 +194,7 @@
         type.named.map((t) => StringConstant(t.name)).toList());
 
     translator.constants.instantiateConstant(
-        codeGen.function, codeGen.b, names, recordTypeNamesFieldExpectedType);
+        codeGen.b, names, recordTypeNamesFieldExpectedType);
     _makeTypeArray(
         codeGen, type.positional.followedBy(type.named.map((t) => t.type)));
   }
@@ -267,7 +267,6 @@
     // WasmArray<_NamedParameter> namedParameters
     if (type.namedParameters.every((n) => isTypeConstant(n.type))) {
       translator.constants.instantiateConstant(
-          codeGen.function,
           b,
           translator.constants.makeNamedParametersArray(type),
           namedParametersExpectedType);
@@ -291,8 +290,8 @@
       }
       w.ValueType namedParametersListType =
           codeGen.makeArrayFromExpressions(expressions, namedParameterType);
-      translator.convertType(codeGen.function, namedParametersListType,
-          namedParametersExpectedType);
+      translator.convertType(
+          b, namedParametersListType, namedParametersExpectedType);
     }
   }
 
@@ -305,7 +304,7 @@
     final b = codeGen.b;
     if (isTypeConstant(type)) {
       translator.constants.instantiateConstant(
-          codeGen.function, b, TypeLiteralConstant(type), nonNullableTypeType);
+          b, TypeLiteralConstant(type), nonNullableTypeType);
       return nonNullableTypeType;
     }
     // All of the singleton types represented by canonical objects should be
@@ -385,8 +384,7 @@
     b.comment("type check against $testedAgainstType");
     w.Local? operandTemp;
     if (translator.options.verifyTypeChecks) {
-      operandTemp =
-          b.addLocal(translator.topInfo.nullableType, isParameter: false);
+      operandTemp = b.addLocal(translator.topInfo.nullableType);
       b.local_tee(operandTemp);
     }
     final (typeToCheck, :checkArguments) =
@@ -431,8 +429,8 @@
       if (location != null) {
         w.FunctionType verifyFunctionType = translator.signatureForDirectCall(
             translator.verifyOptimizedTypeCheck.reference);
-        translator.constants.instantiateConstant(codeGen.function, b,
-            StringConstant('$location'), verifyFunctionType.inputs.last);
+        translator.constants.instantiateConstant(
+            b, StringConstant('$location'), verifyFunctionType.inputs.last);
       } else {
         b.ref_null(w.HeapType.none);
       }
@@ -458,7 +456,7 @@
       return translator.translateType(testedAgainstType);
     }
 
-    w.Local operand = b.addLocal(boxedOperandType, isParameter: false);
+    w.Local operand = b.addLocal(boxedOperandType);
     b.local_tee(operand);
 
     late List<w.ValueType> outputsToDrop;
@@ -609,7 +607,7 @@
       final b = function.body;
 
       w.Local operand = b.locals[0];
-      w.Local boolTemp = function.addLocal(w.NumType.i32);
+      w.Local boolTemp = b.addLocal(w.NumType.i32);
 
       final w.Label resultLabel = b.block(const [], const [w.NumType.i32]);
       if (operandIsNullable) {
@@ -617,7 +615,7 @@
         b.local_get(operand);
         b.br_on_null(nullLabel);
         final nonNullableOperand =
-            function.addLocal(translator.topInfo.nonNullableType);
+            b.addLocal(translator.topInfo.nonNullableType);
         b.local_get(operand);
         b.ref_cast(nonNullableOperand.type as w.RefType);
         b.local_set(nonNullableOperand);
@@ -644,7 +642,7 @@
         // Otherwise we have to check each argument.
 
         // Call Object._getArguments()
-        w.Local typeArguments = function.addLocal(typeArrayExpectedType);
+        w.Local typeArguments = b.addLocal(typeArrayExpectedType);
         b.local_get(operand);
         b.call(translator.functions
             .getFunction(translator.objectGetTypeArguments.reference));
@@ -778,8 +776,8 @@
         }
       } else {
         b.local_get(b.locals[0]);
-        translator.constants.instantiateConstant(function, b,
-            TypeLiteralConstant(testedAgainstType), nonNullableTypeType);
+        translator.constants.instantiateConstant(
+            b, TypeLiteralConstant(testedAgainstType), nonNullableTypeType);
         b.call(translator.functions
             .getFunction(translator.throwAsCheckError.reference));
       }
@@ -788,7 +786,7 @@
       b.end();
 
       b.local_get(b.locals[0]);
-      translator.convertType(function, argumentType, returnType);
+      translator.convertType(b, argumentType, returnType);
       b.return_();
       b.end();
 
diff --git a/pkg/front_end/presubmit_helper.dart b/pkg/front_end/presubmit_helper.dart
index cd97221..5df71cc 100644
--- a/pkg/front_end/presubmit_helper.dart
+++ b/pkg/front_end/presubmit_helper.dart
@@ -16,7 +16,7 @@
   // Expect something like /full/path/to/sdk/pkg/some_dir/whatever/else
   if (args.length != 1) throw "Need exactly one argument.";
 
-  final List<String> changedFiles = getChangedFiles();
+  final List<String> changedFiles = getChangedFiles(collectUncommitted: false);
   String callerPath = args[0].replaceAll("\\", "/");
   if (!_shouldRun(changedFiles, callerPath)) {
     return;
@@ -291,7 +291,18 @@
 /// Queries git about changes against upstream, or origin/main if no upstream is
 /// set. This is similar (but different), I believe, to what
 /// `git cl presubmit` does.
-List<String> getChangedFiles() {
+List<String> getChangedFiles({required bool collectUncommitted}) {
+  Set<String> paths = {};
+  void collectChanges(ProcessResult processResult) {
+    for (String line in processResult.stdout.toString().split("\n")) {
+      List<String> split = line.split("\t");
+      if (split.length != 2) continue;
+      if (split[0] == 'D') continue; // Don't check deleted files.
+      String path = split[1].trim().replaceAll("\\", "/");
+      paths.add(path);
+    }
+  }
+
   ProcessResult result = Process.runSync(
       "git",
       [
@@ -300,7 +311,7 @@
         "diff",
         "--name-status",
         "--no-renames",
-        "@{u}...HEAD"
+        "@{u}...HEAD",
       ],
       runInShell: true);
   if (result.exitCode != 0) {
@@ -312,23 +323,31 @@
           "diff",
           "--name-status",
           "--no-renames",
-          "origin/main...HEAD"
+          "origin/main...HEAD",
         ],
         runInShell: true);
   }
   if (result.exitCode != 0) {
     throw "Failure";
   }
+  collectChanges(result);
 
-  List<String> paths = [];
-  for (String line in result.stdout.toString().split("\n")) {
-    List<String> split = line.split("\t");
-    if (split.length != 2) continue;
-    if (split[0] == 'D') continue; // Don't check deleted files.
-    String path = split[1].trim().replaceAll("\\", "/");
-    paths.add(path);
+  if (collectUncommitted) {
+    result = Process.runSync(
+        "git",
+        [
+          "-c",
+          "core.quotePath=false",
+          "diff",
+          "--name-status",
+          "--no-renames",
+          "HEAD",
+        ],
+        runInShell: true);
+    collectChanges(result);
   }
-  return paths;
+
+  return paths.toList();
 }
 
 /// If [inner] is a dir or file inside [outer] this returns the index into
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 9041a7e6..23cfea6 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -838,6 +838,7 @@
 unawaited
 unbreak
 uncaught
+uncommitted
 uncompiled
 unconverted
 uncover
diff --git a/pkg/front_end/tool/format_cl.dart b/pkg/front_end/tool/format_cl.dart
index f6622fa..c6fbb6b 100644
--- a/pkg/front_end/tool/format_cl.dart
+++ b/pkg/front_end/tool/format_cl.dart
@@ -11,7 +11,8 @@
 
 Future<void> main() async {
   Uri executable = getDartExecutable();
-  final List<String> allChangedFiles = getChangedFiles();
+  final List<String> allChangedFiles =
+      getChangedFiles(collectUncommitted: true);
   if (allChangedFiles.isEmpty) {
     print("No changes in CL.");
     return;
diff --git a/pkg/wasm_builder/lib/src/builder/function.dart b/pkg/wasm_builder/lib/src/builder/function.dart
index 4fe8eca..77b5554 100644
--- a/pkg/wasm_builder/lib/src/builder/function.dart
+++ b/pkg/wasm_builder/lib/src/builder/function.dart
@@ -15,16 +15,9 @@
 
   FunctionBuilder(ModuleBuilder module, super.index, super.type,
       [super.functionName]) {
-    body = InstructionsBuilder(module, type.outputs);
-    for (ir.ValueType paramType in type.inputs) {
-      body.addLocal(paramType, isParameter: true);
-    }
+    body = InstructionsBuilder(module, type.inputs, type.outputs);
   }
 
-  /// Add a local variable to the function.
-  ir.Local addLocal(ir.ValueType type) =>
-      body.addLocal(type, isParameter: false);
-
   @override
   ir.DefinedFunction forceBuild() =>
       ir.DefinedFunction(body.build(), finalizableIndex, type, functionName);
diff --git a/pkg/wasm_builder/lib/src/builder/global.dart b/pkg/wasm_builder/lib/src/builder/global.dart
index b7b8749..d5d7f90 100644
--- a/pkg/wasm_builder/lib/src/builder/global.dart
+++ b/pkg/wasm_builder/lib/src/builder/global.dart
@@ -10,7 +10,7 @@
 
   GlobalBuilder(ModuleBuilder module, super.index, super.type,
       [super.globalName])
-      : initializer = InstructionsBuilder(module, [type.type]);
+      : initializer = InstructionsBuilder(module, [], [type.type]);
 
   @override
   ir.DefinedGlobal forceBuild() =>
diff --git a/pkg/wasm_builder/lib/src/builder/instructions.dart b/pkg/wasm_builder/lib/src/builder/instructions.dart
index ba4cd00..9b34531 100644
--- a/pkg/wasm_builder/lib/src/builder/instructions.dart
+++ b/pkg/wasm_builder/lib/src/builder/instructions.dart
@@ -147,10 +147,14 @@
   final Map<ir.Instruction, StackTrace>? _stackTraces;
 
   /// Create a new instruction sequence.
-  InstructionsBuilder(this.module, List<ir.ValueType> outputs)
+  InstructionsBuilder(
+      this.module, List<ir.ValueType> inputs, List<ir.ValueType> outputs)
       : _stackTraces = module.watchPoints.isNotEmpty ? {} : null,
         _sourceMappings = module.sourceMapUrl == null ? null : [] {
     _labelStack.add(Expression(const [], outputs));
+    for (ir.ValueType paramType in inputs) {
+      _addParameter(paramType);
+    }
   }
 
   /// Whether the instruction sequence has been completed by the final `end`.
@@ -173,10 +177,17 @@
     }
   }
 
-  ir.Local addLocal(ir.ValueType type, {required bool isParameter}) {
+  ir.Local _addParameter(ir.ValueType type) {
     final local = ir.Local(locals.length, type);
     locals.add(local);
-    _localInitialized.add(isParameter || type.defaultable);
+    _localInitialized.add(true);
+    return local;
+  }
+
+  ir.Local addLocal(ir.ValueType type) {
+    final local = ir.Local(locals.length, type);
+    locals.add(local);
+    _localInitialized.add(type.defaultable);
     return local;
   }
 
diff --git a/tools/VERSION b/tools/VERSION
index a2fc125..4f2a1a3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 6
 PATCH 0
-PRERELEASE 104
+PRERELEASE 105
 PRERELEASE_PATCH 0