Version 2.15.0-284.0.dev

Merge commit 'efa5a003f07862a4959fa1af736f3128ad0cd817' into 'dev'
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index e8b8488..3f766ba 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -23,6 +23,7 @@
 import '../js_backend/string_reference.dart' show StringReference;
 import '../js_backend/type_reference.dart' show TypeReference;
 import '../js_emitter/code_emitter_task.dart' show Emitter;
+import '../js_model/elements.dart' show JGeneratorBody;
 import '../js_model/type_recipe.dart' show TypeRecipe;
 import '../native/behavior.dart';
 import '../serialization/serialization.dart';
@@ -720,32 +721,35 @@
     sink.end(tag);
   }
 
+  @override
+  bool get isFinalized => _value != null;
+
   js.Name get value {
-    assert(_value != null, 'value not set for $this');
+    assert(isFinalized, 'value not set for $this');
     return _value;
   }
 
   void set value(js.Name node) {
-    assert(_value == null);
+    assert(!isFinalized);
     assert(node != null);
     _value = node.withSourceInformation(sourceInformation);
   }
 
   @override
   String get key {
-    assert(_value != null);
+    assert(isFinalized);
     return _value.key;
   }
 
   @override
   String get name {
-    assert(_value != null, 'value not set for $this');
+    assert(isFinalized, 'value not set for $this');
     return _value.name;
   }
 
   @override
   bool get allowRename {
-    assert(_value != null, 'value not set for $this');
+    assert(isFinalized, 'value not set for $this');
     return _value.allowRename;
   }
 
@@ -771,6 +775,98 @@
   @override
   String toString() =>
       'ModularName(kind=$kind, data=$data, value=${_value?.key})';
+
+  @override
+  String nonfinalizedDebugText() {
+    switch (kind) {
+      case ModularNameKind.rtiField:
+        return r'ModularName"$ti"';
+      case ModularNameKind.instanceField:
+        return 'ModularName"field:${(data as Entity).name}"';
+      case ModularNameKind.instanceMethod:
+        return 'ModularName"${_instanceMethodName(data)}"';
+      case ModularNameKind.methodProperty:
+        return 'ModularName"methodProperty:${(data as Entity).name}"';
+      case ModularNameKind.operatorIs:
+        return 'ModularName"is:${_className(data)}"';
+      case ModularNameKind.className:
+        return 'ModularName"class:${_className(data)}"';
+      case ModularNameKind.globalPropertyNameForClass:
+        return 'ModularName"classref:${_className(data)}"';
+      case ModularNameKind.aliasedSuperMember:
+        MemberEntity member = (data as MemberEntity);
+        String className = _className(member.enclosingClass);
+        String invocationName = Namer.operatorNameToIdentifier(member.name);
+        final description = "$className.$invocationName";
+        return 'ModularName"alias:$description"';
+      case ModularNameKind.staticClosure:
+        return 'ModularName"closure:${_qualifiedStaticName(data)}"';
+      case ModularNameKind.lazyInitializer:
+        return 'ModularName"lazy:${(data as MemberEntity).name}"';
+      case ModularNameKind.globalPropertyNameForMember:
+        MemberEntity member = data as MemberEntity;
+        return 'ModularName"ref:${_qualifiedStaticName(member)}"';
+      case ModularNameKind.invocation:
+        return 'ModularName"selector:${_selectorText(data as Selector)}"';
+      case ModularNameKind.nameForOneShotInterceptor:
+        return 'ModularName"oneshot:${_selectorText(data as Selector)}"';
+      case ModularNameKind.globalNameForInterfaceTypeVariable:
+        break;
+      case ModularNameKind.nameForGetInterceptor:
+        return 'ModularName"getInterceptor"';
+      case ModularNameKind.asName:
+        return 'ModularName"asName:$data"';
+    }
+    return super.nonfinalizedDebugText();
+  }
+
+  String _className(ClassEntity cls) {
+    return cls.name.replaceAll('&', '_');
+  }
+
+  String _qualifiedStaticName(MemberEntity member) {
+    if (member.isConstructor || member.isStatic) {
+      return '${_className(member.enclosingClass)}.${member.name}';
+    }
+    return member.name;
+  }
+
+  String _instanceMethodInvocationName(MemberEntity member) {
+    String invocationName = Namer.operatorNameToIdentifier(member.name);
+    if (member.isGetter) invocationName = r'get$' + invocationName;
+    if (member.isSetter) invocationName = r'set$' + invocationName;
+    return invocationName;
+  }
+
+  String _instanceMethodName(MemberEntity member) {
+    if (member is ConstructorBodyEntity) {
+      return 'constructorBody:${_qualifiedStaticName(member.constructor)}';
+    }
+    if (member is JGeneratorBody) {
+      MemberEntity function = member.function;
+      return 'generatorBody:'
+          '${_className(function.enclosingClass)}.'
+          '${_instanceMethodInvocationName(function)}';
+    }
+    return 'instanceMethod:${_instanceMethodInvocationName(member)}';
+  }
+
+  String _selectorText(Selector selector) {
+    // Approximation to unminified selector.
+    if (selector.isGetter) return r'get$' + selector.name;
+    if (selector.isSetter) return r'set$' + selector.name;
+    if (selector.isOperator || selector.isIndex || selector.isIndexSet) {
+      return Namer.operatorNameToIdentifier(selector.name);
+    }
+    List<String> parts = [
+      selector.name,
+      if (selector.callStructure.typeArgumentCount > 0)
+        '${selector.callStructure.typeArgumentCount}',
+      '${selector.callStructure.argumentCount}',
+      ...selector.callStructure.getOrderedNamedArguments()
+    ];
+    return parts.join(r'$');
+  }
 }
 
 enum ModularExpressionKind {
@@ -819,13 +915,16 @@
   }
 
   @override
+  bool get isFinalized => _value != null;
+
+  @override
   js.Expression get value {
-    assert(_value != null);
+    assert(isFinalized);
     return _value;
   }
 
   void set value(js.Expression node) {
-    assert(_value == null);
+    assert(!isFinalized);
     assert(node != null);
     _value = node.withSourceInformation(sourceInformation);
   }
@@ -863,6 +962,17 @@
     sb.write(',value=$_value)');
     return sb.toString();
   }
+
+  @override
+  String nonfinalizedDebugText() {
+    switch (kind) {
+      case ModularExpressionKind.constant:
+        return 'ModularExpression"<constant>"';
+      case ModularExpressionKind.embeddedGlobalAccess:
+        return 'ModularExpression"init.$data"';
+    }
+    return super.nonfinalizedDebugText();
+  }
 }
 
 enum JsNodeKind {
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 144d936..86abfd0 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -857,10 +857,16 @@
   ConstantValueKind get kind => ConstantValueKind.JS_NAME;
 
   @override
-  String toDartText(DartTypes dartTypes) => 'js_name(${name})';
+  String toDartText(DartTypes dartTypes) {
+    if (name.isFinalized) 'js_name(${name})';
+    return 'js_name(name.nonfinalizedDebugText())';
+  }
 
   @override
-  String toStructuredText(DartTypes dartTypes) => 'JsNameConstant(${name})';
+  String toStructuredText(DartTypes dartTypes) {
+    if (name.isFinalized) return 'JsNameConstant(${name})';
+    return 'JsNameConstant(name.nonfinalizedDebugText())';
+  }
 }
 
 /// A constant used as the dummy receiver value for intercepted calls with
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 1b1ac8e..c8f5a30 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -83,6 +83,9 @@
     codePositionListener.onPositions(
         node, startPosition, endPosition, closingPosition);
   }
+
+  @override
+  bool get isDebugContext => false;
 }
 
 /// Interface for ast nodes that encapsulate an ast that needs to be
diff --git a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
index 3df93c3..8b46bb4 100644
--- a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
+++ b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
@@ -147,6 +147,32 @@
   }
 
   @override
+  String nonfinalizedDebugText() {
+    switch (kind) {
+      case DeferredHolderExpressionKind.globalObjectForClass:
+        return 'Holder"${_className(data)}"';
+      case DeferredHolderExpressionKind.globalObjectForMember:
+        return 'Holder"${_qualifiedStaticName(data)}"';
+      case DeferredHolderExpressionKind.globalObjectForInterceptors:
+        return 'J';
+      case DeferredHolderExpressionKind.globalObjectForConstant:
+        return 'Holder"constants"';
+      case DeferredHolderExpressionKind.globalObjectForStaticState:
+        return r'$';
+    }
+    return super.nonfinalizedDebugText();
+  }
+
+  String _className(ClassEntity cls) => cls.name.replaceAll('&', '_');
+
+  String _qualifiedStaticName(MemberEntity member) {
+    if (member.isConstructor || member.isStatic) {
+      return '${_className(member.enclosingClass)}.${member.name}';
+    }
+    return member.name;
+  }
+
+  @override
   Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
 }
 
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index 94f28fc..82c7200 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -380,7 +380,7 @@
   jsAst.Name nameForOneShotInterceptor(
       Selector selector, Iterable<ClassEntity> classes) {
     String root = selector.isOperator
-        ? operatorNameToIdentifier(selector.name)
+        ? Namer.operatorNameToIdentifier(selector.name)
         : privateName(selector.memberName);
     String prefix = selector.isGetter
         ? r"$get"
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 11d3b51..83c7797 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1425,7 +1425,7 @@
     return StringBackedName(name);
   }
 
-  String operatorNameToIdentifier(String name) {
+  static String operatorNameToIdentifier(String name) {
     if (name == null) return null;
     if (name == '==') {
       return r'$eq';
diff --git a/pkg/compiler/lib/src/js_backend/string_reference.dart b/pkg/compiler/lib/src/js_backend/string_reference.dart
index 62c378b..69d1a2d 100644
--- a/pkg/compiler/lib/src/js_backend/string_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/string_reference.dart
@@ -143,6 +143,26 @@
 
   @override
   Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+
+  @override
+  String nonfinalizedDebugText() {
+    const doubleQuote = 0x22;
+    final buffer = StringBuffer('StringReference');
+    if (constant.stringValue.length <= 1000) {
+      buffer.writeCharCode(doubleQuote);
+      for (int rune in constant.stringValue.runes) {
+        if (rune >= 0x20 && rune < 0x7F && rune != doubleQuote) {
+          buffer.writeCharCode(rune);
+        } else {
+          buffer.write(r'\u{');
+          buffer.write(rune.toRadixString(16));
+          buffer.write(r'}');
+        }
+      }
+      buffer.writeCharCode(doubleQuote);
+    }
+    return '$buffer';
+  }
 }
 
 /// A [StringReferenceResource] is a deferred JavaScript statement determined
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index d488b24..7bfc470 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -161,6 +161,15 @@
 
   @override
   Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+
+  @override
+  String nonfinalizedDebugText() {
+    TypeRecipe typeRecipe = this.typeRecipe;
+    if (typeRecipe is TypeExpressionRecipe) {
+      return 'TypeReference"${typeRecipe.type.toString()}"';
+    }
+    return super.nonfinalizedDebugText();
+  }
 }
 
 /// A [TypeReferenceResource] is a deferred JavaScript statement determined by
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index e7ec92f..5e44fa5 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -95,13 +95,18 @@
       CodegenRegistry registry,
       ModularNamer namer,
       ModularEmitter emitter) {
+    js.Expression code;
     if (member.isField) {
-      return generateLazyInitializer(
+      code = generateLazyInitializer(
           member, graph, codegen, closedWorld, registry, namer, emitter);
     } else {
-      return generateMethod(
+      code = generateMethod(
           member, graph, codegen, closedWorld, registry, namer, emitter);
     }
+    if (code != null) {
+      codegen.tracer.traceJavaScriptText('JavaScript', code.debugPrint);
+    }
+    return code;
   }
 
   js.Expression generateLazyInitializer(
@@ -113,7 +118,6 @@
       ModularNamer namer,
       ModularEmitter emitter) {
     return measure(() {
-      codegen.tracer.traceGraph("codegen", graph);
       SourceInformation sourceInformation = sourceInformationStrategy
           .createBuilderForContext(field)
           .buildDeclaration(field);
@@ -129,6 +133,7 @@
           closedWorld,
           registry);
       codeGenerator.visitGraph(graph);
+      codegen.tracer.traceGraph("codegen", graph);
       return js.Fun(codeGenerator.parameters, codeGenerator.body)
           .withSourceInformation(sourceInformation);
     });
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 5b825ce..39c3355 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -101,6 +101,8 @@
           graph.asyncElementType,
           sourceInformationBuilder.buildAsyncBody(),
           sourceInformationBuilder.buildAsyncExit());
+      _codegen.tracer
+          .traceJavaScriptText('JavaScript.rewrite', result.debugPrint);
     }
     if (result.sourceInformation == null) {
       result = result.withSourceInformation(
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 8887610..c8a843f 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -30,6 +30,35 @@
     });
   }
 
+  void traceJavaScriptText(String name, String data) {
+    DEBUG_MODE = true;
+    tag("cfg", () {
+      printProperty("name", name);
+      // Emit a fake basic block, with one 'instruction' per line of text.
+      tag("block", () {
+        printProperty("name", "B1");
+        printProperty("from_bci", -1);
+        printProperty("to_bci", -1);
+        printEmptyProperty("predecessors");
+        printEmptyProperty("successors");
+        printEmptyProperty("xhandlers");
+        printEmptyProperty("flags");
+        tag("states", () {
+          tag("locals", () {
+            printProperty("size", 0);
+            printProperty("method", "None");
+          });
+        });
+        tag("HIR", () {
+          for (final line in data.split('\n')) {
+            addIndent();
+            add("0 0 i0 js | $line<|@\n");
+          }
+        });
+      });
+    });
+  }
+
   void addPredecessors(HBasicBlock block) {
     if (block.predecessors.isEmpty) {
       printEmptyProperty("predecessors");
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index 3386c81..26f4bb3d 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -55,6 +55,11 @@
     }
   }
 
+  void traceJavaScriptText(String name, String Function() getText) {
+    if (!traceActive) return;
+    HTracer(output, closedWorld).traceJavaScriptText(name, getText());
+  }
+
   void close() {
     if (output != null) {
       output.close();
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
index 8f1e1c3..57cc30b 100644
--- a/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
@@ -59,16 +59,16 @@
   #C7 = core::pragma {name:#C1, options:#C6}
   #C8 = ffi::Double {}
   #C9 = 0
-  #C10 = <core::int*>[#C9, #C9, #C9]
+  #C10 = <core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <core::int*>[#C11, #C11, #C11]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <core::int*>[#C13, #C13, #C13]
+  #C14 = <core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <core::int*>[#C17, #C18, #C17]
+  #C19 = <core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
 
 
diff --git a/pkg/front_end/testcases/incremental/crash_05.yaml.world.1.expect b/pkg/front_end/testcases/incremental/crash_05.yaml.world.1.expect
index 9ecd41a..cd22c39 100644
--- a/pkg/front_end/testcases/incremental/crash_05.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/crash_05.yaml.world.1.expect
@@ -56,11 +56,11 @@
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = dart.ffi::Uint32 {}
   #C8 = 0
-  #C9 = <dart.core::int*>[#C8, #C8, #C8]
+  #C9 = <dart.core::int*>[#C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8]
   #C10 = "vm:prefer-inline"
   #C11 = dart.core::pragma {name:#C10, options:#C4}
   #C12 = 4
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
+  #C13 = <dart.core::int*>[#C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12]
   #C14 = TypeLiteralConstant(lib::Y)
   #C15 = <dart.core::Type>[#C14]
   #C16 = dart.ffi::_FfiStructLayout {fieldTypes:#C15, packing:#C4}
diff --git a/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect b/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect
index 9ecd41a..cd22c39 100644
--- a/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect
@@ -56,11 +56,11 @@
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = dart.ffi::Uint32 {}
   #C8 = 0
-  #C9 = <dart.core::int*>[#C8, #C8, #C8]
+  #C9 = <dart.core::int*>[#C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8]
   #C10 = "vm:prefer-inline"
   #C11 = dart.core::pragma {name:#C10, options:#C4}
   #C12 = 4
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
+  #C13 = <dart.core::int*>[#C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12]
   #C14 = TypeLiteralConstant(lib::Y)
   #C15 = <dart.core::Type>[#C14]
   #C16 = dart.ffi::_FfiStructLayout {fieldTypes:#C15, packing:#C4}
diff --git a/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect b/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect
index e06b9d6..2b217e2 100644
--- a/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect
@@ -62,7 +62,7 @@
   #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = 0
-  #C8 = <dart.core::int*>[#C7, #C7, #C7]
+  #C8 = <dart.core::int*>[#C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7]
   #C9 = "vm:prefer-inline"
   #C10 = dart.core::pragma {name:#C9, options:#C4}
 }
diff --git a/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect b/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect
index e06b9d6..2b217e2 100644
--- a/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect
@@ -62,7 +62,7 @@
   #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = 0
-  #C8 = <dart.core::int*>[#C7, #C7, #C7]
+  #C8 = <dart.core::int*>[#C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7]
   #C9 = "vm:prefer-inline"
   #C10 = dart.core::pragma {name:#C9, options:#C4}
 }
diff --git a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
index 7f32b12..2e5c180 100644
--- a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
@@ -62,14 +62,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
index 17f1531..a82af2e 100644
--- a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
@@ -66,14 +66,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect b/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
index 583ebfd..68633a6 100644
--- a/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
@@ -63,14 +63,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/issue_46666.yaml.world.1.expect b/pkg/front_end/testcases/incremental/issue_46666.yaml.world.1.expect
index 3456d148..e925f93 100644
--- a/pkg/front_end/testcases/incremental/issue_46666.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/issue_46666.yaml.world.1.expect
@@ -101,19 +101,19 @@
   #C6 = dart.ffi::_FfiStructLayout {fieldTypes:#C4, packing:#C5}
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = 0
-  #C9 = <dart.core::int*>[#C8, #C8, #C8]
-  #C10 = 8
-  #C11 = 4
-  #C12 = <dart.core::int*>[#C10, #C11, #C11]
+  #C9 = <dart.core::int*>[#C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8]
+  #C10 = 4
+  #C11 = 8
+  #C12 = <dart.core::int*>[#C10, #C11, #C10, #C11, #C11, #C11, #C10, #C11, #C11, #C10, #C11, #C10, #C11, #C11, #C11, #C11, #C10, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C10, #C10]
-  #C15 = 24
-  #C16 = 12
-  #C17 = <dart.core::int*>[#C15, #C16, #C16]
+  #C14 = <dart.core::int*>[#C11, #C13, #C11, #C13, #C13, #C13, #C11, #C13, #C13, #C11, #C13, #C11, #C13, #C13, #C13, #C13, #C11, #C13]
+  #C15 = 12
+  #C16 = 24
+  #C17 = <dart.core::int*>[#C15, #C16, #C15, #C16, #C16, #C16, #C15, #C16, #C16, #C15, #C16, #C15, #C16, #C16, #C16, #C16, #C15, #C16]
   #C18 = "vm:prefer-inline"
   #C19 = dart.core::pragma {name:#C18, options:#C5}
   #C20 = 48
-  #C21 = <dart.core::int*>[#C20, #C15, #C15]
+  #C21 = <dart.core::int*>[#C16, #C20, #C16, #C20, #C20, #C20, #C16, #C20, #C20, #C16, #C20, #C16, #C20, #C20, #C20, #C20, #C16, #C20]
   #C22 = <dart.core::Type>[#C2, #C2, #C2]
   #C23 = dart.ffi::_FfiStructLayout {fieldTypes:#C22, packing:#C5}
   #C24 = dart.core::pragma {name:#C1, options:#C23}
diff --git a/pkg/front_end/testcases/incremental/issue_46666.yaml.world.2.expect b/pkg/front_end/testcases/incremental/issue_46666.yaml.world.2.expect
index 3456d148..e925f93 100644
--- a/pkg/front_end/testcases/incremental/issue_46666.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/issue_46666.yaml.world.2.expect
@@ -101,19 +101,19 @@
   #C6 = dart.ffi::_FfiStructLayout {fieldTypes:#C4, packing:#C5}
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = 0
-  #C9 = <dart.core::int*>[#C8, #C8, #C8]
-  #C10 = 8
-  #C11 = 4
-  #C12 = <dart.core::int*>[#C10, #C11, #C11]
+  #C9 = <dart.core::int*>[#C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8, #C8]
+  #C10 = 4
+  #C11 = 8
+  #C12 = <dart.core::int*>[#C10, #C11, #C10, #C11, #C11, #C11, #C10, #C11, #C11, #C10, #C11, #C10, #C11, #C11, #C11, #C11, #C10, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C10, #C10]
-  #C15 = 24
-  #C16 = 12
-  #C17 = <dart.core::int*>[#C15, #C16, #C16]
+  #C14 = <dart.core::int*>[#C11, #C13, #C11, #C13, #C13, #C13, #C11, #C13, #C13, #C11, #C13, #C11, #C13, #C13, #C13, #C13, #C11, #C13]
+  #C15 = 12
+  #C16 = 24
+  #C17 = <dart.core::int*>[#C15, #C16, #C15, #C16, #C16, #C16, #C15, #C16, #C16, #C15, #C16, #C15, #C16, #C16, #C16, #C16, #C15, #C16]
   #C18 = "vm:prefer-inline"
   #C19 = dart.core::pragma {name:#C18, options:#C5}
   #C20 = 48
-  #C21 = <dart.core::int*>[#C20, #C15, #C15]
+  #C21 = <dart.core::int*>[#C16, #C20, #C16, #C20, #C20, #C20, #C16, #C20, #C20, #C16, #C20, #C16, #C20, #C20, #C20, #C20, #C16, #C20]
   #C22 = <dart.core::Type>[#C2, #C2, #C2]
   #C23 = dart.ffi::_FfiStructLayout {fieldTypes:#C22, packing:#C5}
   #C24 = dart.core::pragma {name:#C1, options:#C23}
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
index 7f32b12..2e5c180 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
@@ -62,14 +62,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
index ea6646e..9d91273 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
@@ -63,14 +63,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
index 127f040..afef6e0 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
@@ -64,14 +64,14 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Double {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C14 = <dart.core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = dart.core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <dart.core::int*>[#C17, #C18, #C17]
+  #C19 = <dart.core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.1.expect
index e53139b..3f3d73e 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.1.expect
@@ -82,26 +82,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 1
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = dart.ffi::Uint64 {}
   #C14 = 8
   #C15 = 4
-  #C16 = <dart.core::int*>[#C14, #C15, #C14]
+  #C16 = <dart.core::int*>[#C14, #C14, #C15, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C14, #C14]
   #C17 = "vm:prefer-inline"
   #C18 = dart.core::pragma {name:#C17, options:#C5}
   #C19 = 16
   #C20 = 12
-  #C21 = <dart.core::int*>[#C19, #C20, #C19]
+  #C21 = <dart.core::int*>[#C19, #C19, #C20, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C19, #C19]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 32
   #C27 = 24
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 40
   #C30 = 28
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.2.expect
index c5fa703..e241ee1 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_48_ffi.yaml.world.2.expect
@@ -82,26 +82,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = dart.ffi::Uint64 {}
   #C12 = 8
   #C13 = 4
-  #C14 = <dart.core::int*>[#C12, #C13, #C12]
+  #C14 = <dart.core::int*>[#C12, #C12, #C13, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C12, #C12]
   #C15 = 16
   #C16 = 12
-  #C17 = <dart.core::int*>[#C15, #C16, #C15]
+  #C17 = <dart.core::int*>[#C15, #C15, #C16, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C15, #C15]
   #C18 = "vm:prefer-inline"
   #C19 = dart.core::pragma {name:#C18, options:#C5}
   #C20 = 24
-  #C21 = <dart.core::int*>[#C20, #C15, #C20]
+  #C21 = <dart.core::int*>[#C20, #C20, #C15, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C20, #C20]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 48
   #C27 = 32
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 56
   #C30 = 36
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.1.expect
index e53139b..3f3d73e 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.1.expect
@@ -82,26 +82,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 1
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = dart.ffi::Uint64 {}
   #C14 = 8
   #C15 = 4
-  #C16 = <dart.core::int*>[#C14, #C15, #C14]
+  #C16 = <dart.core::int*>[#C14, #C14, #C15, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C14, #C14]
   #C17 = "vm:prefer-inline"
   #C18 = dart.core::pragma {name:#C17, options:#C5}
   #C19 = 16
   #C20 = 12
-  #C21 = <dart.core::int*>[#C19, #C20, #C19]
+  #C21 = <dart.core::int*>[#C19, #C19, #C20, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C19, #C19]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 32
   #C27 = 24
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 40
   #C30 = 28
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.2.expect
index c5fa703..e241ee1 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_49_ffi.yaml.world.2.expect
@@ -82,26 +82,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = dart.ffi::Uint64 {}
   #C12 = 8
   #C13 = 4
-  #C14 = <dart.core::int*>[#C12, #C13, #C12]
+  #C14 = <dart.core::int*>[#C12, #C12, #C13, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C12, #C12]
   #C15 = 16
   #C16 = 12
-  #C17 = <dart.core::int*>[#C15, #C16, #C15]
+  #C17 = <dart.core::int*>[#C15, #C15, #C16, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C15, #C15]
   #C18 = "vm:prefer-inline"
   #C19 = dart.core::pragma {name:#C18, options:#C5}
   #C20 = 24
-  #C21 = <dart.core::int*>[#C20, #C15, #C20]
+  #C21 = <dart.core::int*>[#C20, #C20, #C15, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C20, #C20]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 48
   #C27 = 32
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 56
   #C30 = 36
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
index 1d8965d..1c2210e 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
@@ -228,26 +228,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 1
-  #C12 = <dart.core::int*>[#C11, #C11, #C11]
+  #C12 = <dart.core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = dart.ffi::Uint64 {}
   #C14 = 8
   #C15 = 4
-  #C16 = <dart.core::int*>[#C14, #C15, #C14]
+  #C16 = <dart.core::int*>[#C14, #C14, #C15, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C15, #C14, #C14, #C14, #C14, #C14, #C14]
   #C17 = "vm:prefer-inline"
   #C18 = dart.core::pragma {name:#C17, options:#C5}
   #C19 = 16
   #C20 = 12
-  #C21 = <dart.core::int*>[#C19, #C20, #C19]
+  #C21 = <dart.core::int*>[#C19, #C19, #C20, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C20, #C19, #C19, #C19, #C19, #C19, #C19]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 32
   #C27 = 24
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 40
   #C30 = 28
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
index 6bf1e19..ae09732 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
@@ -228,26 +228,26 @@
   #C7 = dart.core::pragma {name:#C1, options:#C6}
   #C8 = dart.ffi::Uint8 {}
   #C9 = 0
-  #C10 = <dart.core::int*>[#C9, #C9, #C9]
+  #C10 = <dart.core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = dart.ffi::Uint64 {}
   #C12 = 8
   #C13 = 4
-  #C14 = <dart.core::int*>[#C12, #C13, #C12]
+  #C14 = <dart.core::int*>[#C12, #C12, #C13, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C13, #C12, #C12, #C12, #C12, #C12, #C12]
   #C15 = 16
   #C16 = 12
-  #C17 = <dart.core::int*>[#C15, #C16, #C15]
+  #C17 = <dart.core::int*>[#C15, #C15, #C16, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C16, #C15, #C15, #C15, #C15, #C15, #C15]
   #C18 = "vm:prefer-inline"
   #C19 = dart.core::pragma {name:#C18, options:#C5}
   #C20 = 24
-  #C21 = <dart.core::int*>[#C20, #C15, #C20]
+  #C21 = <dart.core::int*>[#C20, #C20, #C15, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C15, #C20, #C20, #C20, #C20, #C20, #C20]
   #C22 = TypeLiteralConstant(lib::Y)
   #C23 = <dart.core::Type>[#C22, #C22, #C2]
   #C24 = dart.ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C5}
   #C25 = dart.core::pragma {name:#C1, options:#C24}
   #C26 = 48
   #C27 = 32
-  #C28 = <dart.core::int*>[#C26, #C27, #C26]
+  #C28 = <dart.core::int*>[#C26, #C26, #C27, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C27, #C26, #C26, #C26, #C26, #C26, #C26]
   #C29 = 56
   #C30 = 36
-  #C31 = <dart.core::int*>[#C29, #C30, #C29]
+  #C31 = <dart.core::int*>[#C29, #C29, #C30, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C30, #C29, #C29, #C29, #C29, #C29, #C29]
 }
diff --git a/pkg/front_end/testcases/incremental/regress_46004.yaml.world.1.expect b/pkg/front_end/testcases/incremental/regress_46004.yaml.world.1.expect
index ef8614b..9cb7f28 100644
--- a/pkg/front_end/testcases/incremental/regress_46004.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/regress_46004.yaml.world.1.expect
@@ -55,12 +55,12 @@
   #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = 0
-  #C8 = <dart.core::int*>[#C7, #C7, #C7]
+  #C8 = <dart.core::int*>[#C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7]
   #C9 = "vm:prefer-inline"
   #C10 = dart.core::pragma {name:#C9, options:#C4}
-  #C11 = 8
-  #C12 = 4
-  #C13 = <dart.core::int*>[#C11, #C12, #C12]
+  #C11 = 4
+  #C12 = 8
+  #C13 = <dart.core::int*>[#C11, #C12, #C11, #C12, #C12, #C12, #C11, #C12, #C12, #C11, #C12, #C11, #C12, #C12, #C12, #C12, #C11, #C12]
   #C14 = TypeLiteralConstant(lib::COMObject)
   #C15 = <dart.core::Type>[#C14]
   #C16 = dart.ffi::_FfiStructLayout {fieldTypes:#C15, packing:#C4}
diff --git a/pkg/front_end/testcases/incremental/regress_46004.yaml.world.2.expect b/pkg/front_end/testcases/incremental/regress_46004.yaml.world.2.expect
index ef8614b..9cb7f28 100644
--- a/pkg/front_end/testcases/incremental/regress_46004.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/regress_46004.yaml.world.2.expect
@@ -55,12 +55,12 @@
   #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
   #C6 = dart.core::pragma {name:#C1, options:#C5}
   #C7 = 0
-  #C8 = <dart.core::int*>[#C7, #C7, #C7]
+  #C8 = <dart.core::int*>[#C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7]
   #C9 = "vm:prefer-inline"
   #C10 = dart.core::pragma {name:#C9, options:#C4}
-  #C11 = 8
-  #C12 = 4
-  #C13 = <dart.core::int*>[#C11, #C12, #C12]
+  #C11 = 4
+  #C12 = 8
+  #C13 = <dart.core::int*>[#C11, #C12, #C11, #C12, #C12, #C12, #C11, #C12, #C12, #C11, #C12, #C11, #C12, #C12, #C12, #C12, #C11, #C12]
   #C14 = TypeLiteralConstant(lib::COMObject)
   #C15 = <dart.core::Type>[#C14]
   #C16 = dart.ffi::_FfiStructLayout {fieldTypes:#C15, packing:#C4}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
index 1f2d2a4..6b19c1d 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
@@ -50,16 +50,16 @@
   #C7 = core::pragma {name:#C1, options:#C6}
   #C8 = ffi::Double {}
   #C9 = 0
-  #C10 = <core::int*>[#C9, #C9, #C9]
+  #C10 = <core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <core::int*>[#C11, #C11, #C11]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <core::int*>[#C13, #C13, #C13]
+  #C14 = <core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <core::int*>[#C17, #C18, #C17]
+  #C19 = <core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
index 1f2d2a4..6b19c1d 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
@@ -50,16 +50,16 @@
   #C7 = core::pragma {name:#C1, options:#C6}
   #C8 = ffi::Double {}
   #C9 = 0
-  #C10 = <core::int*>[#C9, #C9, #C9]
+  #C10 = <core::int*>[#C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9, #C9]
   #C11 = 8
-  #C12 = <core::int*>[#C11, #C11, #C11]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
   #C13 = 16
-  #C14 = <core::int*>[#C13, #C13, #C13]
+  #C14 = <core::int*>[#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13]
   #C15 = "vm:prefer-inline"
   #C16 = core::pragma {name:#C15, options:#C5}
   #C17 = 24
   #C18 = 20
-  #C19 = <core::int*>[#C17, #C18, #C17]
+  #C19 = <core::int*>[#C17, #C17, #C18, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C18, #C17, #C17, #C17, #C17, #C17, #C17]
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index 1513405..0dc519f 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -42,8 +42,8 @@
   #C8 = core::pragma {name:#C1, options:#C7}
   #C9 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6}
   #C10 = 0
-  #C11 = <core::int*>[#C10, #C10, #C10]
-  #C12 = <core::int*>[#C3, #C3, #C3]
+  #C11 = <core::int*>[#C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10]
+  #C12 = <core::int*>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
   #C13 = <core::int*>[]
   #C14 = "vm:prefer-inline"
   #C15 = core::pragma {name:#C14, options:#C6}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index ce41031..6a48895 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -42,8 +42,8 @@
   #C8 = core::pragma {name:#C1, options:#C7}
   #C9 = ffi::_ArraySize<ffi::NativeType*> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6}
   #C10 = 0
-  #C11 = <core::int*>[#C10, #C10, #C10]
-  #C12 = <core::int*>[#C3, #C3, #C3]
+  #C11 = <core::int*>[#C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10, #C10]
+  #C12 = <core::int*>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
   #C13 = <core::int*>[]
   #C14 = "vm:prefer-inline"
   #C15 = core::pragma {name:#C14, options:#C6}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
index 1648007..036c491 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
@@ -67,8 +67,8 @@
   #C9 = 2
   #C10 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C9, dimension2:#C9, dimension3:#C9, dimension4:#C6, dimension5:#C6, dimensions:#C6}
   #C11 = 0
-  #C12 = <core::int*>[#C11, #C11, #C11]
-  #C13 = <core::int*>[#C3, #C3, #C3]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
+  #C13 = <core::int*>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
   #C14 = <core::int*>[#C9, #C9]
   #C15 = "vm:prefer-inline"
   #C16 = core::pragma {name:#C15, options:#C6}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
index ca6f28b..8d6be3c 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
@@ -67,8 +67,8 @@
   #C9 = 2
   #C10 = ffi::_ArraySize<ffi::NativeType*> {dimension1:#C9, dimension2:#C9, dimension3:#C9, dimension4:#C6, dimension5:#C6, dimensions:#C6}
   #C11 = 0
-  #C12 = <core::int*>[#C11, #C11, #C11]
-  #C13 = <core::int*>[#C3, #C3, #C3]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
+  #C13 = <core::int*>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
   #C14 = <core::int*>[#C9, #C9]
   #C15 = "vm:prefer-inline"
   #C16 = core::pragma {name:#C15, options:#C6}
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index b84ef51..0d4e490 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -436,12 +436,12 @@
   R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg);
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg);
 
-  // Shallow clone of node.  Does not clone positions since the only use of this
-  // private method is create a copy with a new position.
+  /// Shallow clone of node.  Does not clone positions since the only use of
+  /// this private method is create a copy with a new position.
   Node _clone();
 
-  // Returns a node equivalent to [this], but with new source position and end
-  // source position.
+  /// Returns a node equivalent to [this], but with new source position and end
+  /// source position.
   Node withSourceInformation(
       JavaScriptNodeSourceInformation sourceInformation) {
     if (sourceInformation == _sourceInformation) {
@@ -456,13 +456,23 @@
 
   bool get isCommaOperator => false;
 
-  bool get isFinalized => true;
-
   Statement toStatement() {
     throw UnsupportedError('toStatement');
   }
 
   String debugPrint() => DebugPrint(this);
+
+  /// Some nodes, e.g. DeferredExpression, become finalized in a 'linking'
+  /// phase.
+  bool get isFinalized => true;
+
+  /// If a node is not finalized, debug printing can print something indicative
+  /// of the node instead of the finalized AST. This method returns the
+  /// replacement text.
+  String nonfinalizedDebugText() {
+    assert(!isFinalized);
+    return '$runtimeType';
+  }
 }
 
 class Program extends Node {
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 5c5620e..0f3c329 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -45,6 +45,10 @@
   /// [enterNode] is called in post-traversal order.
   void exitNode(
       Node node, int startPosition, int endPosition, int closingPosition) {}
+
+  /// Should return `true` if the printing tolerates unfinalized deferred AST
+  /// nodes.
+  bool get isDebugContext => false;
 }
 
 /// A simple implementation of [JavaScriptPrintingContext] suitable for tests.
@@ -58,9 +62,13 @@
   String getText() => buffer.toString();
 }
 
+class _DebugJavaScriptPrintingContext extends SimpleJavaScriptPrintingContext {
+  bool get isDebugContext => true;
+}
+
 String DebugPrint(Node node, {bool utf8 = false}) {
   JavaScriptPrintingOptions options = JavaScriptPrintingOptions(utf8: utf8);
-  SimpleJavaScriptPrintingContext context = SimpleJavaScriptPrintingContext();
+  SimpleJavaScriptPrintingContext context = _DebugJavaScriptPrintingContext();
   Printer printer = Printer(options, context);
   printer.visit(node);
   return context.getText();
@@ -72,6 +80,7 @@
   final bool shouldCompressOutput;
   final DanglingElseVisitor danglingElseVisitor;
   final LocalNamer localNamer;
+  final bool isDebugContext;
 
   int _charCount = 0;
   bool inForInit = false;
@@ -90,6 +99,7 @@
   Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context)
       : options = options,
         context = context,
+        isDebugContext = context.isDebugContext,
         shouldCompressOutput = options.shouldCompressOutput,
         danglingElseVisitor = DanglingElseVisitor(context),
         localNamer = determineRenamer(
@@ -220,7 +230,9 @@
   void startNode(Node node) {
     currentNode = EnterExitNode(currentNode, node);
     if (node is DeferredExpression) {
-      startNode(node.value);
+      if (!isDebugContext || node.isFinalized) {
+        startNode(node.value);
+      }
     }
   }
 
@@ -230,7 +242,9 @@
 
   void endNode(Node node) {
     if (node is DeferredExpression) {
-      endNode(node.value);
+      if (!isDebugContext || node.isFinalized) {
+        endNode(node.value);
+      }
     }
     assert(currentNode.node == node);
     currentNode = currentNode.exitNode(context, _charCount);
@@ -259,6 +273,12 @@
     nodes.forEach(visit);
   }
 
+  Node _undefer(Node node) {
+    if (isDebugContext && !node.isFinalized) return node;
+    if (node is DeferredExpression) return _undefer(node.value);
+    return node;
+  }
+
   @override
   void visitProgram(Program program) {
     if (program.body.isNotEmpty) {
@@ -657,10 +677,12 @@
 
   visitNestedExpression(Expression node, int requiredPrecedence,
       {bool newInForInit, bool newAtStatementBegin}) {
+    int precedenceLevel =
+        (isDebugContext && !node.isFinalized) ? CALL : node.precedenceLevel;
     bool needsParentheses =
         // a - (b + c).
         (requiredPrecedence != EXPRESSION &&
-                node.precedenceLevel < requiredPrecedence) ||
+                precedenceLevel < requiredPrecedence) ||
             // for (a = (x in o); ... ; ... ) { ... }
             (newInForInit && node is Binary && node.op == "in") ||
             // (function() { ... })().
@@ -720,9 +742,10 @@
     }
   }
 
-  static bool _isSmallInitialization(Node node) {
+  bool _isSmallInitialization(Node node) {
     if (node is VariableInitialization) {
-      Node value = undefer(node.value);
+      if (node.value == null) return true;
+      Node value = _undefer(node.value);
       if (value == null) return true;
       if (value is This) return true;
       if (value is LiteralNull) return true;
@@ -755,8 +778,9 @@
     /// `++a` and `a += b` in the face of [DeferredExpression]s we detect the
     /// pattern of the undeferred assignment.
     String op = assignment.op;
-    Node leftHandSide = undefer(assignment.leftHandSide);
-    Node rightHandSide = undefer(assignment.value);
+    Node leftHandSide = _undefer(assignment.leftHandSide);
+    Node value = assignment.value;
+    Node rightHandSide = value == null ? value : _undefer(value);
     if ((op == '+' || op == '-') &&
         leftHandSide is VariableUse &&
         rightHandSide is LiteralNumber &&
@@ -768,8 +792,8 @@
     if (!assignment.isCompound &&
         leftHandSide is VariableUse &&
         rightHandSide is Binary) {
-      Node rLeft = undefer(rightHandSide.left);
-      Node rRight = undefer(rightHandSide.right);
+      Node rLeft = _undefer(rightHandSide.left);
+      Node rRight = _undefer(rightHandSide.right);
       String op = rightHandSide.op;
       if (op == '+' ||
           op == '-' ||
@@ -804,12 +828,12 @@
     }
     visitNestedExpression(assignment.leftHandSide, CALL,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
-    if (assignment.value != null) {
+    if (value != null) {
       spaceOut();
       if (op != null) out(op);
       out("=");
       spaceOut();
-      visitNestedExpression(assignment.value, ASSIGNMENT,
+      visitNestedExpression(value, ASSIGNMENT,
           newInForInit: inForInit, newAtStatementBegin: false);
     }
   }
@@ -1045,15 +1069,23 @@
     visitNestedExpression(access.receiver, CALL,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
 
-    Node selector = undefer(access.selector);
+    Node selector = _undefer(access.selector);
+    if (isDebugContext && !selector.isFinalized) {
+      _dotString(
+          access.selector, access.receiver, selector.nonfinalizedDebugText(),
+          assumeValid: true);
+      return;
+    }
     if (selector is LiteralString) {
       _dotString(access.selector, access.receiver, selector.value);
       return;
-    } else if (selector is StringConcatenation) {
+    }
+    if (selector is StringConcatenation) {
       _dotString(access.selector, access.receiver,
-          _StringContentsCollector().collect(selector));
+          _StringContentsCollector(isDebugContext).collect(selector));
       return;
-    } else if (selector is Name) {
+    }
+    if (selector is Name) {
       _dotString(access.selector, access.receiver, selector.name);
       return;
     }
@@ -1064,9 +1096,10 @@
     out(']');
   }
 
-  void _dotString(Node selector, Node receiver, String selectorValue) {
-    if (isValidJavaScriptId(selectorValue)) {
-      if (undefer(receiver) is LiteralNumber &&
+  void _dotString(Node selector, Node receiver, String selectorValue,
+      {bool assumeValid = false}) {
+    if (assumeValid || isValidJavaScriptId(selectorValue)) {
+      if (_undefer(receiver) is LiteralNumber &&
           lastCharCode != charCodes.$CLOSE_PAREN) {
         out(' ', isWhitespace: true);
       }
@@ -1157,6 +1190,10 @@
 
   @override
   visitDeferredExpression(DeferredExpression node) {
+    if (isDebugContext && !node.isFinalized) {
+      out(node.nonfinalizedDebugText());
+      return;
+    }
     // Continue printing with the expression value.
     assert(node.precedenceLevel == node.value.precedenceLevel);
     node.value.accept(this);
@@ -1194,12 +1231,16 @@
 
   @override
   void visitLiteralString(LiteralString node) {
+    if (isDebugContext && !node.isFinalized) {
+      _handleString(node.nonfinalizedDebugText());
+      return;
+    }
     _handleString(node.value);
   }
 
   @override
   visitStringConcatenation(StringConcatenation node) {
-    _handleString(_StringContentsCollector().collect(node));
+    _handleString(_StringContentsCollector(isDebugContext).collect(node));
   }
 
   void _handleString(String value) {
@@ -1217,6 +1258,10 @@
 
   @override
   visitName(Name node) {
+    if (isDebugContext && !node.isFinalized) {
+      out(node.nonfinalizedDebugText());
+      return;
+    }
     out(node.name);
   }
 
@@ -1342,7 +1387,7 @@
 
   void propertyNameOut(Property node) {
     startNode(node.name);
-    Node name = undefer(node.name);
+    Node name = _undefer(node.name);
     if (name is LiteralString) {
       _outPropertyName(name.value);
     } else if (name is Name) {
@@ -1433,6 +1478,9 @@
 
 class _StringContentsCollector extends BaseVisitor<void> {
   final StringBuffer _buffer = StringBuffer();
+  final bool isDebugContext;
+
+  _StringContentsCollector(this.isDebugContext);
 
   String collect(Node node) {
     node.accept(this);
@@ -1450,17 +1498,29 @@
 
   @override
   void visitLiteralString(LiteralString node) {
-    _add(node.value);
+    if (isDebugContext && !node.isFinalized) {
+      _add(node.nonfinalizedDebugText());
+    } else {
+      _add(node.value);
+    }
   }
 
   @override
   void visitLiteralNumber(LiteralNumber node) {
-    _add(node.value);
+    if (isDebugContext && !node.isFinalized) {
+      _add(node.nonfinalizedDebugText());
+    } else {
+      _add(node.value);
+    }
   }
 
   @override
   void visitName(Name node) {
-    _add(node.name);
+    if (isDebugContext && !node.isFinalized) {
+      _add(node.nonfinalizedDebugText());
+    } else {
+      _add(node.name);
+    }
   }
 
   @override
@@ -1609,6 +1669,8 @@
   bool visitLabeledStatement(LabeledStatement node) => node.body.accept(this);
   bool visitLiteralStatement(LiteralStatement node) => true;
 
+  bool visitDartYield(DartYield node) => false;
+
   bool visitExpression(Expression node) => false;
 }
 
diff --git a/pkg/js_ast/test/deferred_expression_test.dart b/pkg/js_ast/test/deferred_expression_test.dart
index afd9805..29fc4d1 100644
--- a/pkg/js_ast/test/deferred_expression_test.dart
+++ b/pkg/js_ast/test/deferred_expression_test.dart
@@ -127,6 +127,9 @@
   Map<Node, _Position> exitPositions = {};
 
   @override
+  bool get isDebugContext => false;
+
+  @override
   void emit(String string) {
     sb.write(string);
   }
diff --git a/pkg/vm/lib/transformations/ffi/abi.dart b/pkg/vm/lib/transformations/ffi/abi.dart
new file mode 100644
index 0000000..795574a
--- /dev/null
+++ b/pkg/vm/lib/transformations/ffi/abi.dart
@@ -0,0 +1,175 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common.dart';
+
+/// The hardware architectures the Dart VM runs on.
+enum _Architecture {
+  arm,
+  arm64,
+  ia32,
+  x64,
+}
+
+extension on _Architecture {
+  /// The size of integer registers and memory addresses in bytes.
+  int get wordSize {
+    switch (this) {
+      case _Architecture.arm:
+      case _Architecture.ia32:
+        return 4;
+      case _Architecture.arm64:
+      case _Architecture.x64:
+        return 8;
+    }
+  }
+}
+
+/// The operating systems the Dart VM runs on.
+enum _OS {
+  android,
+  fuchsia,
+  ios,
+  linux,
+  macos,
+  windows,
+}
+
+/// Application binary interface.
+///
+/// The Dart VM can run on a variety of [Abi]s, see [supportedAbis].
+class Abi {
+  /// The operating system of this [Abi].
+  // ignore: unused_field
+  final _OS _os;
+
+  /// The architecture of this [Abi].
+  final _Architecture _architecture;
+
+  /// The size of integer registers and memory addresses in bytes.
+  int get wordSize => _architecture.wordSize;
+
+  const Abi._(this._architecture, this._os);
+}
+
+const androidArm = Abi._(_Architecture.arm, _OS.android);
+const androidArm64 = Abi._(_Architecture.arm64, _OS.android);
+const androidIA32 = Abi._(_Architecture.ia32, _OS.android);
+const androidX64 = Abi._(_Architecture.x64, _OS.android);
+const fuchsiaArm64 = Abi._(_Architecture.arm64, _OS.fuchsia);
+const fuchsiaX64 = Abi._(_Architecture.x64, _OS.fuchsia);
+const iosArm = Abi._(_Architecture.arm, _OS.ios);
+const iosArm64 = Abi._(_Architecture.arm64, _OS.ios);
+const iosX64 = Abi._(_Architecture.x64, _OS.ios);
+const linuxArm = Abi._(_Architecture.arm, _OS.linux);
+const linuxArm64 = Abi._(_Architecture.arm64, _OS.linux);
+const linuxIA32 = Abi._(_Architecture.ia32, _OS.linux);
+const linuxX64 = Abi._(_Architecture.x64, _OS.linux);
+const macosArm64 = Abi._(_Architecture.arm64, _OS.macos);
+
+// No macosIA32, not intending to support.
+// https://github.com/dart-lang/sdk/issues/39810
+
+const macosX64 = Abi._(_Architecture.x64, _OS.macos);
+
+/// Currently not supported, but feature requested for Flutter.
+/// https://github.com/flutter/flutter/issues/53120
+const windowsArm64 = Abi._(_Architecture.arm64, _OS.windows);
+const windowsIA32 = Abi._(_Architecture.ia32, _OS.windows);
+const windowsX64 = Abi._(_Architecture.x64, _OS.windows);
+
+/// All ABIs that the DartVM can run on sorted alphabetically.
+///
+/// Keep consistent with runtime/vm/compiler/ffi/abi.cc.
+const supportedAbisOrdered = [
+  androidArm,
+  androidArm64,
+  androidIA32,
+  androidX64,
+  fuchsiaArm64,
+  fuchsiaX64,
+  iosArm,
+  iosArm64,
+  iosX64,
+  linuxArm,
+  linuxArm64,
+  linuxIA32,
+  linuxX64,
+  macosArm64,
+  macosX64,
+  windowsArm64,
+  windowsIA32,
+  windowsX64,
+];
+
+/// The size of integer registers and memory addresses in bytes per [Abi].
+// Keep consistent with sdk/lib/_internal/vm/lib/ffi_patch.dart
+final Map<Abi, int> wordSize = {
+  for (final abi in supportedAbisOrdered) abi: abi.wordSize
+};
+
+/// Struct and union fields that are not aligned to their size.
+///
+/// Has an entry for all Abis. Empty entries document that every native
+/// type is aligned to it's own size in this ABI.
+///
+/// See runtime/vm/compiler/ffi/abi.cc for asserts in the VM that verify these
+/// alignments.
+const nonSizeAlignment = <Abi, Map<NativeType, int>>{
+  // _wordSize64
+  androidArm64: _wordSize64,
+  androidX64: _wordSize64,
+  fuchsiaArm64: _wordSize64,
+  fuchsiaX64: _wordSize64,
+  iosArm64: _wordSize64,
+  iosX64: _wordSize64,
+  linuxArm64: _wordSize64,
+  linuxX64: _wordSize64,
+  macosArm64: _wordSize64,
+  macosX64: _wordSize64,
+  windowsArm64: _wordSize64,
+  windowsX64: _wordSize64,
+  // _wordSize32Align32
+  androidIA32: _wordSize32Align32,
+  iosArm: _wordSize32Align32,
+  linuxIA32: _wordSize32Align32,
+  // _wordSize32Align64
+  androidArm: _wordSize32Align64,
+  linuxArm: _wordSize32Align64,
+  windowsIA32: _wordSize32Align64,
+};
+
+// All 64 bit ABIs align struct fields to their size.
+const Map<NativeType, int> _wordSize64 = {};
+
+// x86 System V ABI:
+// > uint64_t | size 8 | alignment 4
+// > double   | size 8 | alignment 4
+// https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-1.1.pdf page 8.
+//
+// ios 32 bit alignment:
+// https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/updating_data_structures
+const Map<NativeType, int> _wordSize32Align32 = {
+  NativeType.kDouble: 4,
+  NativeType.kInt64: 4,
+  NativeType.kUint64: 4
+};
+
+// The default for MSVC x86:
+// > The alignment-requirement for all data except structures, unions, and
+// > arrays is either the size of the object or the current packing size
+// > (specified with either /Zp or the pack pragma, whichever is less).
+// https://docs.microsoft.com/en-us/cpp/c-language/padding-and-alignment-of-structure-members?view=vs-2019
+//
+// GCC _can_ compile on Linux to this alignment with -malign-double, but does
+// not do so by default:
+// > Warning: if you use the -malign-double switch, structures containing the
+// > above types are aligned differently than the published application
+// > binary interface specifications for the x86-32 and are not binary
+// > compatible with structures in code compiled without that switch.
+// https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
+//
+// ARM always requires 8 byte alignment for 8 byte values:
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf 4.1 Fundamental Data Types
+const Map<NativeType, int> _wordSize32Align64 = {};
diff --git a/pkg/vm/lib/transformations/ffi/common.dart b/pkg/vm/lib/transformations/ffi/common.dart
index dc51195..4d242a7 100644
--- a/pkg/vm/lib/transformations/ffi/common.dart
+++ b/pkg/vm/lib/transformations/ffi/common.dart
@@ -17,6 +17,8 @@
 import 'package:kernel/type_environment.dart'
     show TypeEnvironment, SubtypeCheckMode;
 
+import 'abi.dart';
+
 /// Represents the (instantiated) ffi.NativeType.
 enum NativeType {
   kNativeType,
@@ -107,78 +109,6 @@
   NativeType.kBool: 1,
 };
 
-/// The struct layout in various ABIs.
-///
-/// ABIs differ per architectures and with different compilers.
-/// We pick the default struct layout based on the architecture and OS.
-///
-/// Compilers _can_ deviate from the default layout, but this prevents
-/// executables from making system calls. So this seems rather uncommon.
-///
-/// In the future, we might support custom struct layouts. For more info see
-/// https://github.com/dart-lang/sdk/issues/35768.
-enum Abi {
-  /// Layout in all 64bit ABIs (x64 and arm64).
-  wordSize64,
-
-  /// Layout in System V ABI for x386 (ia32 on Linux) and in iOS Arm 32 bit.
-  wordSize32Align32,
-
-  /// Layout in both the Arm 32 bit ABI and the Windows ia32 ABI.
-  wordSize32Align64,
-}
-
-/// WORD_SIZE in bytes.
-const wordSize = <Abi, int>{
-  Abi.wordSize64: 8,
-  Abi.wordSize32Align32: 4,
-  Abi.wordSize32Align64: 4,
-};
-
-/// Elements that are not aligned to their size.
-///
-/// Has an entry for all Abis. Empty entries document that every native
-/// type is aligned to it's own size in this ABI.
-///
-/// See runtime/vm/ffi/abi.cc for asserts in the VM that verify these
-/// alignments.
-///
-/// TODO(37470): Add uncommon primitive data types when we want to support them.
-const nonSizeAlignment = <Abi, Map<NativeType, int>>{
-  Abi.wordSize64: {},
-
-  // x86 System V ABI:
-  // > uint64_t | size 8 | alignment 4
-  // > double   | size 8 | alignment 4
-  // https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-1.1.pdf page 8.
-  //
-  // iOS 32 bit alignment:
-  // https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/updating_data_structures
-  Abi.wordSize32Align32: {
-    NativeType.kDouble: 4,
-    NativeType.kInt64: 4,
-    NativeType.kUint64: 4
-  },
-
-  // The default for MSVC x86:
-  // > The alignment-requirement for all data except structures, unions, and
-  // > arrays is either the size of the object or the current packing size
-  // > (specified with either /Zp or the pack pragma, whichever is less).
-  // https://docs.microsoft.com/en-us/cpp/c-language/padding-and-alignment-of-structure-members?view=vs-2019
-  //
-  // GCC _can_ compile on Linux to this alignment with -malign-double, but does
-  // not do so by default:
-  // > Warning: if you use the -malign-double switch, structures containing the
-  // > above types are aligned differently than the published application
-  // > binary interface specifications for the x86-32 and are not binary
-  // > compatible with structures in code compiled without that switch.
-  // https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
-  //
-  // Arm always requires 8 byte alignment for 8 byte values:
-  // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf 4.1 Fundamental Data Types
-  Abi.wordSize32Align64: {},
-};
-
 /// Load, store, and elementAt are rewired to their static type for these types.
 const List<NativeType> optimizedTypes = [
   NativeType.kBool,
@@ -617,9 +547,7 @@
     return InstanceInvocation(
         InstanceAccessKind.Instance,
         intListConstantExpression([
-          values[Abi.wordSize64]!,
-          values[Abi.wordSize32Align32]!,
-          values[Abi.wordSize32Align64]!
+          for (final abi in supportedAbisOrdered) values[abi]!,
         ]),
         listElementAt.name,
         Arguments([StaticInvocation(abiMethod, Arguments([]))]),
diff --git a/pkg/vm/lib/transformations/ffi/definitions.dart b/pkg/vm/lib/transformations/ffi/definitions.dart
index 49a4b8d..f87519e 100644
--- a/pkg/vm/lib/transformations/ffi/definitions.dart
+++ b/pkg/vm/lib/transformations/ffi/definitions.dart
@@ -31,6 +31,7 @@
 import 'package:kernel/type_environment.dart' show SubtypeCheckMode;
 import 'package:kernel/util/graph.dart';
 
+import 'abi.dart';
 import 'common.dart';
 
 /// Checks and elaborates the dart:ffi compounds and their fields.
@@ -833,7 +834,8 @@
   void _addSizeOfField(Class compound, IndexedClass? indexedClass,
       [Map<Abi, int>? sizes = null]) {
     if (sizes == null) {
-      sizes = Map.fromEntries(Abi.values.map((abi) => MapEntry(abi, 0)));
+      sizes =
+          Map.fromEntries(supportedAbisOrdered.map((abi) => MapEntry(abi, 0)));
     }
     final name = Name("#sizeOf");
     final getterReference = indexedClass?.lookupGetterReference(name);
@@ -1079,12 +1081,14 @@
     if (size == WORD_SIZE) {
       return wordSize;
     }
-    return Map.fromEntries(Abi.values.map((abi) => MapEntry(abi, size)));
+    return Map.fromEntries(
+        supportedAbisOrdered.map((abi) => MapEntry(abi, size)));
   }
 
   @override
-  Map<Abi, int> get alignment => Map.fromEntries(Abi.values.map((abi) =>
-      MapEntry(abi, nonSizeAlignment[abi]![nativeType] ?? size[abi]!)));
+  Map<Abi, int> get alignment =>
+      Map.fromEntries(supportedAbisOrdered.map((abi) =>
+          MapEntry(abi, nonSizeAlignment[abi]![nativeType] ?? size[abi]!)));
 
   @override
   Constant generateConstant(FfiTransformer transformer) =>
@@ -1305,7 +1309,7 @@
 
   factory StructNativeTypeCfe(Class clazz, List<NativeTypeCfe> members,
       {int? packing}) {
-    final layout = Map.fromEntries(Abi.values
+    final layout = Map.fromEntries(supportedAbisOrdered
         .map((abi) => MapEntry(abi, _calculateLayout(members, packing, abi))));
     return StructNativeTypeCfe._(clazz, members, packing, layout);
   }
@@ -1341,8 +1345,8 @@
 
 class UnionNativeTypeCfe extends CompoundNativeTypeCfe {
   factory UnionNativeTypeCfe(Class clazz, List<NativeTypeCfe> members) {
-    final layout = Map.fromEntries(
-        Abi.values.map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
+    final layout = Map.fromEntries(supportedAbisOrdered
+        .map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
     return UnionNativeTypeCfe._(clazz, members, layout);
   }
 
diff --git a/pkg/vm/lib/transformations/ffi/use_sites.dart b/pkg/vm/lib/transformations/ffi/use_sites.dart
index 744bc00..69a52e5 100644
--- a/pkg/vm/lib/transformations/ffi/use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi/use_sites.dart
@@ -26,14 +26,9 @@
 import 'package:kernel/type_algebra.dart' show Substitution;
 import 'package:kernel/type_environment.dart';
 
+import 'abi.dart' show wordSize;
 import 'common.dart'
-    show
-        NativeType,
-        FfiTransformer,
-        nativeTypeSizes,
-        WORD_SIZE,
-        UNKNOWN,
-        wordSize;
+    show NativeType, FfiTransformer, nativeTypeSizes, WORD_SIZE, UNKNOWN;
 
 /// Checks and replaces calls to dart:ffi compound fields and methods.
 void transformLibraries(
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
index f449731..c2c6faa 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
@@ -128,10 +128,10 @@
   #C9 = ffi::_FfiStructLayout {fieldTypes:#C8, packing:#C4}
   #C10 = core::pragma {name:#C1, options:#C9}
   #C11 = 0
-  #C12 = <core::int*>[#C11, #C11, #C11]
-  #C13 = 8
-  #C14 = 4
-  #C15 = <core::int*>[#C13, #C14, #C14]
+  #C12 = <core::int*>[#C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11, #C11]
+  #C13 = 4
+  #C14 = 8
+  #C15 = <core::int*>[#C13, #C14, #C13, #C14, #C14, #C14, #C13, #C14, #C14, #C13, #C14, #C13, #C14, #C14, #C14, #C14, #C13, #C14]
   #C16 = static-tearoff self::useStruct3
   #C17 = static-tearoff self::returnStruct7
   #C18 = 1
diff --git a/runtime/vm/compiler/ffi/abi.cc b/runtime/vm/compiler/ffi/abi.cc
index d71ad34..25900e4 100644
--- a/runtime/vm/compiler/ffi/abi.cc
+++ b/runtime/vm/compiler/ffi/abi.cc
@@ -12,7 +12,7 @@
 
 namespace ffi {
 
-// See pkg/vm/lib/transformations/ffi.dart, which makes these assumptions.
+// See pkg/vm/lib/transformations/ffi/abi.dart, which makes these assumptions.
 struct AbiAlignmentDouble {
   int8_t use_one_byte;
   double d;
@@ -45,20 +45,42 @@
 #error "Unknown platform. Please add alignment requirements for ABI."
 #endif
 
-Abi TargetAbi() {
-#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
-  return Abi::kWordSize64;
-#elif (defined(TARGET_ARCH_IA32) && /* NOLINT(whitespace/parens) */            \
-       (defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_MACOS) ||      \
-        defined(DART_TARGET_OS_ANDROID))) ||                                   \
-    (defined(TARGET_ARCH_ARM) && defined(DART_TARGET_OS_MACOS_IOS))
-  return Abi::kWordSize32Align32;
-#elif defined(TARGET_ARCH_IA32) && defined(DART_TARGET_OS_WINDOWS) ||          \
-    defined(TARGET_ARCH_ARM)
-  return Abi::kWordSize32Align64;
+#if defined(DART_TARGET_OS_ANDROID)
+#define DART_TARGET_OS_NAME Android
+#elif defined(DART_TARGET_OS_FUCHSIA)
+#define DART_TARGET_OS_NAME Fuchsia
+#elif defined(DART_TARGET_OS_LINUX)
+#define DART_TARGET_OS_NAME Linux
+#elif defined(DART_TARGET_OS_MACOS)
+#if DART_TARGET_OS_MACOS_IOS
+#define DART_TARGET_OS_NAME IOS
 #else
-#error "Unknown platform. Please add alignment requirements for ABI."
+#define DART_TARGET_OS_NAME MacOS
 #endif
+#elif defined(DART_TARGET_OS_WINDOWS)
+#define DART_TARGET_OS_NAME Windows
+#else
+#error Unknown OS
+#endif
+
+#if defined(TARGET_ARCH_IA32)
+#define TARGET_ARCH_NAME IA32
+#elif defined(TARGET_ARCH_X64)
+#define TARGET_ARCH_NAME X64
+#elif defined(TARGET_ARCH_ARM)
+#define TARGET_ARCH_NAME Arm
+#elif defined(TARGET_ARCH_ARM64)
+#define TARGET_ARCH_NAME Arm64
+#else
+#error Unknown arch
+#endif
+
+#define ABI_NAME1(os, arch) k##os##arch
+#define ABI_NAME2(os, arch) ABI_NAME1(os, arch)
+#define ABI_NAME3 ABI_NAME2(DART_TARGET_OS_NAME, TARGET_ARCH_NAME)
+
+Abi TargetAbi() {
+  return Abi::ABI_NAME3;
 }
 
 }  // namespace ffi
diff --git a/runtime/vm/compiler/ffi/abi.h b/runtime/vm/compiler/ffi/abi.h
index fb6f937..118054f 100644
--- a/runtime/vm/compiler/ffi/abi.h
+++ b/runtime/vm/compiler/ffi/abi.h
@@ -17,12 +17,34 @@
 
 namespace ffi {
 
-// These ABIs should be kept in sync with pkg/vm/lib/transformations/ffi.dart.
+// These ABIs should be kept in sync with
+// pkg/vm/lib/transformations/ffi/abi.dart.
 enum class Abi {
-  kWordSize64 = 0,
-  kWordSize32Align32 = 1,
-  kWordSize32Align64 = 2
+  kAndroidArm,
+  kAndroidArm64,
+  kAndroidIA32,
+  kAndroidX64,
+  kFuchsiaArm64,
+  kFuchsiaX64,
+  kIOSArm,
+  kIOSArm64,
+  kIOSX64,
+  kLinuxArm,
+  kLinuxArm64,
+  kLinuxIA32,
+  kLinuxX64,
+  kMacOSArm64,
+  kMacOSX64,
+  kWindowsArm64,
+  kWindowsIA32,
+  kWindowsX64,
 };
+// We use the integer values of this enum in
+// runtime/vm/compiler/frontend/kernel_to_il.cc
+static_assert(static_cast<int64_t>(Abi::kAndroidArm) == 0,
+              "Enum value unexpected.");
+static_assert(static_cast<int64_t>(Abi::kWindowsX64) == 17,
+              "Enum value unexpected.");
 
 // The target ABI. Defines sizes and alignment of native types.
 Abi TargetAbi();
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 3f7276b..2dcd5f8 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -21,8 +21,28 @@
   Double: 8,
 };
 
+// Keep consistent with pkg/vm/lib/transformations/ffi/abi.dart.
 @pragma("vm:prefer-inline")
-int get _intPtrSize => (const [8, 4, 4])[_abi()];
+int get _intPtrSize => (const [
+      4, // androidArm,
+      8, // androidArm64,
+      4, // androidIA32,
+      8, // androidX64,
+      8, // fuchsiaArm64,
+      8, // fuchsiaX64,
+      4, // iosArm,
+      8, // iosArm64,
+      8, // iosX64,
+      4, // linuxArm,
+      8, // linuxArm64,
+      4, // linuxIA32,
+      8, // linuxX64,
+      8, // macosArm64,
+      8, // macosX64,
+      8, // windowsArm64,
+      4, // windowsIA32,
+      8, // windowsX64,
+    ])[_abi()];
 
 @patch
 int sizeOf<T extends NativeType>() {
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index d439fd4..438e967 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -563,9 +563,9 @@
   /// This operation is potentially dangerous and should be used judiciously.
   /// The isolate stops operating *immediately*. It throws if the optional
   /// [message] does not adhere to the limitations on what can be sent from one
-  /// isolate to another. It also throws if a [finalMessagePort] is associated
-  /// with an isolate spawned outside of current isolate group, spawned via
-  /// [spawnUri].
+  /// isolate to another (see [SendPort.send] for more details). It also throws
+  /// if a [finalMessagePort] is associated with an isolate spawned outside of
+  /// current isolate group, spawned via [spawnUri].
   ///
   /// If successful, a call to this method does not return. Pending `finally`
   /// blocks are not executed, control flow will not go back to the event loop,
@@ -575,9 +575,9 @@
   /// code will run in the isolate.)
   ///
   /// If [finalMessagePort] is provided, and the [message] can be sent through
-  /// it, then the message is sent through that port as the final operation of
-  /// the current isolate. The isolate terminates immediately after
-  /// that [SendPort.send] call returns.
+  /// it (see [SendPort.send] for more details), then the message is sent
+  /// through that port as the final operation of the current isolate. The
+  /// isolate terminates immediately after that [SendPort.send] call returns.
   ///
   /// If the port is a native port -- one provided by [ReceivePort.sendPort] or
   /// [RawReceivePort.sendPort] -- the system may be able to send this final
@@ -599,9 +599,10 @@
 /// when sent.
 abstract class SendPort implements Capability {
   /// Sends an asynchronous [message] through this send port, to its
-  /// corresponding `ReceivePort`.
+  /// corresponding [ReceivePort].
   ///
-  /// The content of [message] can be:
+  /// The transitive object graph of [message] can contain the following
+  /// objects:
   ///   - [Null]
   ///   - [bool]
   ///   - [int]
@@ -612,14 +613,34 @@
   ///   - [SendPort]
   ///   - [Capability]
   ///
-  /// In the special circumstances when two isolates share the same code and are
-  /// running in the same process (e.g. isolates created via [Isolate.spawn]),
-  /// it is also possible to send object instances (which would be copied in the
-  /// process).
+  /// If the sender and receiver isolate share the same code (e.g. isolates
+  /// created via [Isolate.spawn]), the transitive object graph of [message] can
+  /// contain any object, with the following exceptions:
   ///
-  /// The send happens immediately and doesn't block.  The corresponding receive
+  ///   - Objects with native resources (subclasses of e.g.
+  ///     `NativeFieldWrapperClass1`). A [Socket] object for example referrs
+  ///     internally to objects that have native resources attached and can
+  ///     therefore not be sent.
+  ///   - [ReceivePort]
+  ///   - [DynamicLibrary]
+  ///   - [Pointer]
+  ///   - [UserTag]
+  ///   - `MirrorReference`
+  ///
+  /// Apart from those exceptions any object can be sent. Objects that are
+  /// identified as immutable (e.g. strings) will be shared whereas all other
+  /// objects will be copied.
+  ///
+  /// The send happens immediately and may have a linear time cost to copy the
+  /// transtive object graph. The send itself doesn't block (i.e. doesn't wait
+  /// until the receiver has received the message). The corresponding receive
   /// port can receive the message as soon as its isolate's event loop is ready
   /// to deliver it, independently of what the sending isolate is doing.
+  ///
+  /// Note: Due to an implementation choice the Dart VM made for how closures
+  /// represent captured state, closures can currently capture more state than
+  /// they need, which can cause the transitive closure to be larger than
+  /// needed. Open bug to address this: http://dartbug.com/36983
   void send(Object? message);
 
   /// Tests whether [other] is a [SendPort] pointing to the same
diff --git a/tests/web/dummy_compiler_test.dart b/tests/web/dummy_compiler_test.dart
deleted file mode 100644
index 53d4c20..0000000
--- a/tests/web/dummy_compiler_test.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Tests that the dart2js compiler can be run in a js engine.  This ensures that
-// the internal compiler APIs have no dependency on dart:io.
-library dummy_compiler;
-
-import 'dart:async';
-
-import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler.dart';
-
-import 'mock_libraries.dart';
-
-String libProvider(Uri uri) {
-  if (uri.path.endsWith(".platform")) {
-    return DEFAULT_PLATFORM_CONFIG;
-  }
-  if (uri.path.endsWith("/core.dart")) {
-    return buildLibrarySource(DEFAULT_CORE_LIBRARY);
-  } else if (uri.path.endsWith('core_patch.dart')) {
-    return DEFAULT_PATCH_CORE_SOURCE;
-  } else if (uri.path.endsWith('internal.dart')) {
-    return buildLibrarySource(DEFAULT_INTERNAL_LIBRARY);
-  } else if (uri.path.endsWith('interceptors.dart')) {
-    return buildLibrarySource(DEFAULT_INTERCEPTORS_LIBRARY);
-  } else if (uri.path.endsWith('js_helper.dart')) {
-    return buildLibrarySource(DEFAULT_JS_HELPER_LIBRARY);
-  } else if (uri.path.endsWith('/async.dart')) {
-    return buildLibrarySource(DEFAULT_ASYNC_LIBRARY);
-  } else {
-    return "library lib${uri.path.replaceAll('/', '.')};";
-  }
-}
-
-Future<String> provider(Uri uri) {
-  String source;
-  if (uri.scheme == "main") {
-    source = "main() {}";
-  } else if (uri.scheme == "lib") {
-    source = libProvider(uri);
-  } else {
-    throw "unexpected URI $uri";
-  }
-  return new Future.value(source);
-}
-
-void handler(Uri uri, int begin, int end, String message, Diagnostic kind) {
-  if (uri == null) {
-    print('$kind: $message');
-  } else {
-    print('$uri:$begin:$end: $kind: $message');
-  }
-}
-
-main() {
-  asyncStart();
-  Future<CompilationResult> result = compile(new Uri(scheme: 'main'),
-      new Uri(scheme: 'lib', path: '/'), provider, handler);
-  result.then((CompilationResult result) {
-    if (!result.isSuccess) {
-      throw 'Compilation failed';
-    }
-  }, onError: (e, s) {
-    throw 'Compilation failed: $e\n$s';
-  }).then(asyncSuccess);
-}
diff --git a/tests/web/internal/mock_libraries.dart b/tests/web/internal/mock_libraries.dart
deleted file mode 100644
index d279e0c..0000000
--- a/tests/web/internal/mock_libraries.dart
+++ /dev/null
@@ -1,463 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Library for creating mock versions of platform and internal libraries.
-
-library mock_libraries;
-
-const DEFAULT_PLATFORM_CONFIG = """
-[libraries]
-core:core/core.dart
-async:async/async.dart
-_js_helper:_internal/js_runtime/lib/js_helper.dart
-_interceptors:_internal/js_runtime/lib/interceptors.dart
-_internal:internal/internal.dart
-""";
-
-String buildLibrarySource(Map<String, String> elementMap,
-    [Map<String, String> additionalElementMap = const <String, String>{}]) {
-  Map<String, String> map = new Map<String, String>.from(elementMap);
-  if (additionalElementMap != null) {
-    map.addAll(additionalElementMap);
-  }
-  StringBuffer sb = new StringBuffer();
-  map.values.forEach((String element) {
-    sb.write('$element\n');
-  });
-  return sb.toString();
-}
-
-const Map<String, String> DEFAULT_CORE_LIBRARY = const <String, String>{
-  '<imports>': '''
-import 'dart:_internal' as internal;
-''',
-  'bool': 'class bool {}',
-  'Comparator': 'abstract class Comparator<T> {}',
-  'DateTime': r'''
-      class DateTime {
-        DateTime(year);
-        DateTime.utc(year);
-      }''',
-  'Deprecated': r'''
-      class Deprecated extends Object {
-        final String expires;
-        const Deprecated(this.expires);
-      }''',
-  'deprecated': 'const Object deprecated = const Deprecated("next release");',
-  'double': r'''
-      abstract class double extends num {
-        static var nan = 0;
-        static parse(s) {}
-      }''',
-  'Enum': r'''
-      abstract class Enum {
-        int get index;
-      }''',
-  'Function': r'''
-      class Function {
-        static apply(Function fn, List positional, [Map named]) => null;
-      }''',
-  'identical': 'bool identical(Object a, Object b) { return true; }',
-  'int': 'abstract class int extends num { }',
-  'Iterable': '''
-      abstract class Iterable<E> {
-          Iterator<E> get iterator => null;
-      }''',
-  'Iterator': '''
-      abstract class Iterator<E> {
-          E get current => null;
-      }''',
-  'LinkedHashMap': r'''
-      class LinkedHashMap<K, V> implements Map<K, V> {
-      }''',
-  'List': r'''
-      class List<E> extends Iterable<E> {
-        var length;
-        List([length]);
-        List.filled(length, element);
-        E get first => null;
-        E get last => null;
-        E get single => null;
-        E removeLast() => null;
-        E removeAt(i) => null;
-        E elementAt(i) => null;
-        E singleWhere(f) => null;
-      }''',
-  'Map': 'abstract class Map<K,V> {}',
-  'Null': 'class Null {}',
-  'num': r'''
-      abstract class num {
-        operator +(_);
-        operator *(_);
-        operator -();
-      }''',
-  'print': 'print(var obj) {}',
-  'proxy': 'const proxy = 0;',
-  'Object': r'''
-      class Object {
-        const Object();
-        operator ==(other) { return true; }
-        get hashCode => throw "Object.hashCode not implemented.";
-        String toString() { return null; }
-        noSuchMethod(im) { throw im; }
-      }''',
-  'StackTrace': 'abstract class StackTrace {}',
-  'String': 'class String implements Pattern {}',
-  'Symbol': '''
-      abstract class Symbol {
-        const factory Symbol(String name) = internal.Symbol;
-      }
-      ''',
-  'Type': 'class Type {}',
-  'Pattern': 'abstract class Pattern {}',
-  '_genericNoSuchMethod': '_genericNoSuchMethod(a,b,c,d,e) {}',
-  '_unresolvedConstructorError': '_unresolvedConstructorError(a,b,c,d,e) {}',
-  '_malformedTypeError': '_malformedTypeError(message) {}',
-};
-
-const Map<String, String> DEFAULT_INTERNAL_LIBRARY = const <String, String>{
-  '<imports>': '''
-import 'dart:core' as core;
-''',
-  'Symbol': '''
-class Symbol implements core.Symbol {
-  final core.String _name;
-
-  const Symbol(this._name);
-  Symbol.validated(this._name);
-}
-''',
-};
-
-const String DEFAULT_PATCH_CORE_SOURCE = r'''
-import 'dart:_js_helper';
-import 'dart:_interceptors';
-import 'dart:async';
-
-@patch
-class LinkedHashMap<K, V> {
-  factory LinkedHashMap._empty() => null;
-  factory LinkedHashMap._literal(elements) => null;
-  static _makeEmpty() => null;
-  static _makeLiteral(elements) => null;
-}
-''';
-
-const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{
-  'assertTest': 'assertTest(a) {}',
-  'assertThrow': 'assertThrow(a) {}',
-  'assertHelper': 'assertHelper(a) {}',
-  'assertUnreachable': 'assertUnreachable() {}',
-  'assertIsSubtype': 'assertIsSubtype(subtype, supertype, message) {}',
-  'assertSubtype': 'assertSubtype(object, isField, checks, asField) {}',
-  'assertSubtypeOfRuntimeType': 'assertSubtypeOfRuntimeType(object, type) {}',
-  'asyncHelper': 'asyncHelper(object, asyncBody, completer) {}',
-  'boolConversionCheck': 'boolConversionCheck(x) {}',
-  'boolTypeCast': 'boolTypeCast(value) {}',
-  'boolTypeCheck': 'boolTypeCheck(value) {}',
-  'checkSubtype': 'checkSubtype(object, isField, checks, asField) {}',
-  'checkSubtypeOfRuntimeType': 'checkSubtypeOfRuntimeType(o, t) {}',
-  'BoundClosure': r'''abstract class BoundClosure extends Closure {
-    var self;
-    var target;
-    var receiver;
-  }''',
-  'buildFunctionType': r'''buildFunctionType(returnType, parameterTypes,
-                            optionalParameterTypes) {
-            return new RuntimeFunctionType();
-          }''',
-  'buildInterfaceType': '''buildInterfaceType(rti, typeArguments) {
-                             if (rti == null) return new RuntimeTypePlain();
-                             return new RuntimeTypeGeneric();
-                           }''',
-  'buildNamedFunctionType':
-      r'''buildNamedFunctionType(returnType, parameterTypes,
-                                 namedParameters) {
-            return new RuntimeFunctionType();
-          }''',
-  'checkFunctionSubtype':
-      r'''checkFunctionSubtype(var target, String signatureName,
-                               String contextName, var context,
-                               var typeArguments) {}''',
-  'checkMalformedType': 'checkMalformedType(value, message) {}',
-  'checkInt': 'checkInt(value) {}',
-  'checkNum': 'checkNum(value) {}',
-  'checkString': 'checkString(value) {}',
-  'Closure': 'abstract class Closure implements Function { }',
-  'closureFromTearOff':
-      r'''closureFromTearOff(receiver, functions, reflectionInfo,
-                             isStatic, jsArguments, name) {}''',
-  'computeSignature':
-      'computeSignature(var signature, var context, var contextName) {}',
-  'ConstantMap': 'class ConstantMap<K, V> {}',
-  'ConstantProtoMap': 'class ConstantProtoMap<K, V> {}',
-  'ConstantStringMap': 'class ConstantStringMap<K, V> {}',
-  'createInvocationMirror': 'createInvocationMirror(a0, a1, a2, a3, a4, a5) {}',
-  'createRuntimeType': 'createRuntimeType(a) {}',
-  'doubleTypeCast': 'doubleTypeCast(value) {}',
-  'doubleTypeCheck': 'doubleTypeCheck(value) {}',
-  'functionSubtypeCast':
-      r'''functionSubtypeCast(Object object, String signatureName,
-                              String contextName, var context) {}''',
-  'functionTypeTestMetaHelper': r'''
-      functionTypeTestMetaHelper() {
-        buildFunctionType(null, null, null);
-        buildNamedFunctionType(null, null, null);
-        buildInterfaceType(null, null);
-      }''',
-  'functionTypeTest': r'functionTypeTest(f, t) {}',
-  'functionTypeCast': r'functionTypeCast(f, t) { return f; }',
-  'functionTypeCheck': r'functionTypeCheck(f, t) { return f; }',
-  'futureOrTest': r'futureOrTest(f, t) {}',
-  'futureOrCast': r'futureOrCast(f, t) { return f; }',
-  'futureOrCheck': r'futureOrCheck(f, t) { return f; }',
-  'getFallThroughError': 'getFallThroughError() {}',
-  'getIsolateAffinityTag': 'getIsolateAffinityTag(_) {}',
-  'getRuntimeTypeArgumentIntercepted':
-      'getRuntimeTypeArgumentIntercepted(interceptor, target, substitutionName, index) {}',
-  'getRuntimeTypeArgument':
-      'getRuntimeTypeArgument(target, substitutionName, index) {}',
-  'getRuntimeTypeArguments':
-      'getRuntimeTypeArguments(target, substitutionName) {}',
-  'getRuntimeTypeInfo': 'getRuntimeTypeInfo(a) {}',
-  'getTraceFromException': 'getTraceFromException(exception) {}',
-  'getTypeArgumentByIndex': 'getTypeArgumentByIndex(target, index) {}',
-  'GeneralConstantMap': 'class GeneralConstantMap {}',
-  'iae': 'iae(x) { throw x; } ioore(x) { throw x; }',
-  'Instantiation1': 'class Instantiation1<T1> extends Closure {}',
-  'Instantiation2': 'class Instantiation2<T1,T2> extends Closure {}',
-  'Instantiation3': 'class Instantiation3<T1,T2,T3> extends Closure {}',
-  'interceptedTypeCast': 'interceptedTypeCast(value, property) {}',
-  'interceptedTypeCheck': 'interceptedTypeCheck(value, property) {}',
-  'intTypeCast': 'intTypeCast(value) {}',
-  'intTypeCheck': 'intTypeCheck(value) {}',
-  'isJsIndexable': 'isJsIndexable(a, b) {}',
-  'JavaScriptIndexingBehavior': 'abstract class JavaScriptIndexingBehavior {}',
-  'JSInvocationMirror': r'''
-  class JSInvocationMirror {
-    get typeArguments => null;
-  }''',
-  'listSuperNativeTypeCast': 'listSuperNativeTypeCast(value) {}',
-  'listSuperNativeTypeCheck': 'listSuperNativeTypeCheck(value) {}',
-  'listSuperTypeCast': 'listSuperTypeCast(value) {}',
-  'listSuperTypeCheck': 'listSuperTypeCheck(value) {}',
-  'listTypeCast': 'listTypeCast(value) {}',
-  'listTypeCheck': 'listTypeCheck(value) {}',
-  'makeLiteralMap': 'makeLiteralMap(List keyValuePairs) {}',
-  'Native': 'class Native {}',
-  'numberOrStringSuperNativeTypeCast':
-      'numberOrStringSuperNativeTypeCast(value) {}',
-  'numberOrStringSuperNativeTypeCheck':
-      'numberOrStringSuperNativeTypeCheck(value) {}',
-  'numberOrStringSuperTypeCast': 'numberOrStringSuperTypeCast(value) {}',
-  'numberOrStringSuperTypeCheck': 'numberOrStringSuperTypeCheck(value) {}',
-  'numTypeCast': 'numTypeCast(value) {}',
-  'numTypeCheck': 'numTypeCheck(value) {}',
-  '_Patch': 'class _Patch { final tag; const _Patch(this.tag); }',
-  'patch': 'const patch = const _Patch(null);',
-  'patch_full': 'const patch_full = const _Patch("full");',
-  'patch_lazy': 'const patch_lazy = const _Patch("lazy");',
-  'patch_startup': 'const patch_startup = const _Patch("startup");',
-  'propertyTypeCast': 'propertyTypeCast(x) {}',
-  'propertyTypeCheck': 'propertyTypeCheck(value, property) {}',
-  'requiresPreamble': 'requiresPreamble() {}',
-  'RuntimeFunctionType': 'class RuntimeFunctionType {}',
-  'RuntimeTypeGeneric': 'class RuntimeTypeGeneric {}',
-  'RuntimeTypePlain': 'class RuntimeTypePlain {}',
-  'S': 'S() {}',
-  'setRuntimeTypeInfo': 'setRuntimeTypeInfo(a, b) {}',
-  'stringSuperNativeTypeCast': 'stringSuperNativeTypeCast(value) {}',
-  'stringSuperNativeTypeCheck': 'stringSuperNativeTypeCheck(value) {}',
-  'stringSuperTypeCast': 'stringSuperTypeCast(value) {}',
-  'stringSuperTypeCheck': 'stringSuperTypeCheck(value) {}',
-  'stringTypeCast': 'stringTypeCast(x) {}',
-  'stringTypeCheck': 'stringTypeCheck(x) {}',
-  'subtypeCast': 'subtypeCast(object, isField, checks, asField) {}',
-  'subtypeOfRuntimeTypeCast': 'subtypeOfRuntimeTypeCast(object, type) {}',
-  'checkConcurrentModificationError':
-      'checkConcurrentModificationError(collection) {}',
-  'throwConcurrentModificationError':
-      'throwConcurrentModificationError(collection) {}',
-  'throwCyclicInit': 'throwCyclicInit(staticName) {}',
-  'throwExpression': 'throwExpression(e) {}',
-  'throwNoSuchMethod':
-      'throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}',
-  'throwUnsupportedError': 'throwUnsupportedError(message) {}',
-  'throwTypeError': 'throwTypeError(message) {}',
-  'unwrapException': 'unwrapException(e) {}',
-  'voidTypeCheck': 'voidTypeCheck(value) {}',
-  'wrapException': 'wrapException(x) { return x; }',
-  'badMain': 'badMain() { throw "bad main"; }',
-  'missingMain': 'missingMain() { throw "missing main"; }',
-  'mainHasTooManyParameters': 'mainHasTooManyParameters() '
-      '{ throw "main has too many parameters"; }',
-};
-
-const Map<String, String> DEFAULT_FOREIGN_HELPER_LIBRARY =
-    const <String, String>{
-  'JS': r'''
-      dynamic JS(String typeDescription, String codeTemplate,
-        [var arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6,
-         var arg7, var arg8, var arg9, var arg10, var arg11]) {}''',
-};
-
-const Map<String, String> DEFAULT_INTERCEPTORS_LIBRARY = const <String, String>{
-  'findIndexForNativeSubclassType': 'findIndexForNativeSubclassType(type) {}',
-  'getDispatchProperty': 'getDispatchProperty(o) {}',
-  'getInterceptor': 'getInterceptor(x) {}',
-  'getNativeInterceptor': 'getNativeInterceptor(x) {}',
-  'initializeDispatchProperty': 'initializeDispatchProperty(f,p,i) {}',
-  'initializeDispatchPropertyCSP': 'initializeDispatchPropertyCSP(f,p,i) {}',
-  'Interceptor': r'''
-      class Interceptor {
-        toString() {}
-        bool operator==(other) => identical(this, other);
-        get hashCode => throw "Interceptor.hashCode not implemented.";
-        noSuchMethod(im) { throw im; }
-      }''',
-  'JSArray': r'''
-          class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
-            JSArray();
-            factory JSArray.typed(a) => a;
-            var length;
-            operator[](index) => this[index];
-            operator[]=(index, value) { this[index] = value; }
-            add(value) { this[length] = value; }
-            insert(index, value) {}
-            E get first => this[0];
-            E get last => this[0];
-            E get single => this[0];
-            E removeLast() => this[0];
-            E removeAt(index) => this[0];
-            E elementAt(index) => this[0];
-            E singleWhere(f) => this[0];
-            Iterator<E> get iterator => null;
-          }''',
-  'JSBool': 'class JSBool extends Interceptor implements bool {}',
-  'JSDouble': 'class JSDouble extends JSNumber implements double {}',
-  'JSExtendableArray': 'class JSExtendableArray extends JSMutableArray {}',
-  'JSFixedArray': 'class JSFixedArray extends JSMutableArray {}',
-  'JSFunction':
-      'abstract class JSFunction extends Interceptor implements Function {}',
-  'JSIndexable': r'''
-      abstract class JSIndexable {
-        get length;
-        operator[](index);
-      }''',
-  'JSInt': r'''
-       class JSInt extends JSNumber implements int {
-         operator~() => this;
-       }''',
-  'JSMutableArray':
-      'class JSMutableArray extends JSArray implements JSMutableIndexable {}',
-  'JSUnmodifiableArray': 'class JSUnmodifiableArray extends JSArray {}',
-  'JSMutableIndexable':
-      'abstract class JSMutableIndexable extends JSIndexable {}',
-  'JSPositiveInt': 'class JSPositiveInt extends JSInt {}',
-  'JSNull': r'''
-      class JSNull extends Interceptor {
-        bool operator==(other) => identical(null, other);
-        get hashCode => throw "JSNull.hashCode not implemented.";
-        String toString() => 'Null';
-        Type get runtimeType => null;
-        noSuchMethod(x) => super.noSuchMethod(x);
-      }''',
-  'JSNumber': r'''
-      class JSNumber extends Interceptor implements num {
-        // All these methods return a number to please type inferencing.
-        operator-() => (this is JSInt) ? 42 : 42.2;
-        operator +(other) => (this is JSInt) ? 42 : 42.2;
-        operator -(other) => (this is JSInt) ? 42 : 42.2;
-        operator ~/(other) => _tdivFast(other);
-        operator /(other) => (this is JSInt) ? 42 : 42.2;
-        operator *(other) => (this is JSInt) ? 42 : 42.2;
-        operator %(other) => (this is JSInt) ? 42 : 42.2;
-        operator <<(other) => _shlPositive(other);
-        operator >>(other) {
-          return _shrBothPositive(other) + _shrReceiverPositive(other) +
-            _shrOtherPositive(other);
-        }
-        operator |(other) => 42;
-        operator &(other) => 42;
-        operator ^(other) => 42;
-
-        operator >(other) => !identical(this, other);
-        operator >=(other) => !identical(this, other);
-        operator <(other) => !identical(this, other);
-        operator <=(other) => !identical(this, other);
-        operator ==(other) => identical(this, other);
-        get hashCode => throw "JSNumber.hashCode not implemented.";
-
-        // We force side effects on _tdivFast to mimic the shortcomings of
-        // the effect analysis: because the `_tdivFast` implementation of
-        // the core library has calls that may not already be analyzed,
-        // the analysis will conclude that `_tdivFast` may have side
-        // effects.
-        _tdivFast(other) => new List()..length = 42;
-        _shlPositive(other) => 42;
-        _shrBothPositive(other) => 42;
-        _shrReceiverPositive(other) => 42;
-        _shrOtherPositive(other) => 42;
-
-        abs() => (this is JSInt) ? 42 : 42.2;
-        remainder(other) => (this is JSInt) ? 42 : 42.2;
-        truncate() => 42;
-      }''',
-  'JSString': r'''
-      class JSString extends Interceptor implements String, JSIndexable {
-        split(pattern) => [];
-        int get length => 42;
-        operator[](index) {}
-        toString() {}
-        operator+(other) => this;
-        codeUnitAt(index) => 42;
-      }''',
-  'JSUInt31': 'class JSUInt31 extends JSUInt32 {}',
-  'JSUInt32': 'class JSUInt32 extends JSPositiveInt {}',
-  'ObjectInterceptor': 'class ObjectInterceptor {}',
-  'JavaScriptObject': 'class JavaScriptObject {}',
-  'PlainJavaScriptObject': 'class PlainJavaScriptObject {}',
-  'UnknownJavaScriptObject': 'class UnknownJavaScriptObject {}',
-  'JavaScriptFunction': 'class JavaScriptFunction {}',
-};
-
-const Map<String, String> DEFAULT_ASYNC_LIBRARY = const <String, String>{
-  'DeferredLibrary': 'class DeferredLibrary {}',
-  'Future': '''
-      class Future<T> {
-        Future.value([value]);
-      }
-      ''',
-  'Stream': 'class Stream<T> {}',
-  'Completer': 'class Completer<T> {}',
-  'StreamIterator': 'class StreamIterator<T> {}',
-};
-
-/// These members are only needed when async/await is used.
-const Map<String, String> ASYNC_AWAIT_LIBRARY = const <String, String>{
-  '_wrapJsFunctionForAsync': '_wrapJsFunctionForAsync(f) {}',
-  '_asyncHelper': '_asyncHelper(o, f, c) {}',
-  '_SyncStarIterable': 'class _SyncStarIterable {}',
-  '_IterationMarker': 'class _IterationMarker {}',
-  '_AsyncStarStreamController': 'class _AsyncStarStreamController {}',
-  '_asyncStarHelper': '_asyncStarHelper(x, y, z) {}',
-  '_streamOfController': '_streamOfController(x) {}',
-};
-
-const String DEFAULT_MIRRORS_SOURCE = r'''
-import 'dart:_js_mirrors' as js;
-class Comment {}
-class MirrorSystem {}
-class MirrorsUsed {
-  final targets;
-  const MirrorsUsed({this.targets});
-}
-void reflectType(Type t) => js.disableTreeShaking();
-''';
-
-const String DEFAULT_JS_MIRRORS_SOURCE = r'''
-disableTreeShaking(){}
-preserveMetadata(){}
-preserveLibraryNames(){}
-''';
diff --git a/tests/web_2/dummy_compiler_test.dart b/tests/web_2/dummy_compiler_test.dart
deleted file mode 100644
index 1f66dca..0000000
--- a/tests/web_2/dummy_compiler_test.dart
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.7
-
-// Tests that the dart2js compiler can be run in a js engine.  This ensures that
-// the internal compiler APIs have no dependency on dart:io.
-library dummy_compiler;
-
-import 'dart:async';
-
-import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler.dart';
-
-import 'mock_libraries.dart';
-
-String libProvider(Uri uri) {
-  if (uri.path.endsWith(".platform")) {
-    return DEFAULT_PLATFORM_CONFIG;
-  }
-  if (uri.path.endsWith("/core.dart")) {
-    return buildLibrarySource(DEFAULT_CORE_LIBRARY);
-  } else if (uri.path.endsWith('core_patch.dart')) {
-    return DEFAULT_PATCH_CORE_SOURCE;
-  } else if (uri.path.endsWith('internal.dart')) {
-    return buildLibrarySource(DEFAULT_INTERNAL_LIBRARY);
-  } else if (uri.path.endsWith('interceptors.dart')) {
-    return buildLibrarySource(DEFAULT_INTERCEPTORS_LIBRARY);
-  } else if (uri.path.endsWith('js_helper.dart')) {
-    return buildLibrarySource(DEFAULT_JS_HELPER_LIBRARY);
-  } else if (uri.path.endsWith('/async.dart')) {
-    return buildLibrarySource(DEFAULT_ASYNC_LIBRARY);
-  } else {
-    return "library lib${uri.path.replaceAll('/', '.')};";
-  }
-}
-
-Future<String> provider(Uri uri) {
-  String source;
-  if (uri.scheme == "main") {
-    source = "main() {}";
-  } else if (uri.scheme == "lib") {
-    source = libProvider(uri);
-  } else {
-    throw "unexpected URI $uri";
-  }
-  return new Future.value(source);
-}
-
-void handler(Uri uri, int begin, int end, String message, Diagnostic kind) {
-  if (uri == null) {
-    print('$kind: $message');
-  } else {
-    print('$uri:$begin:$end: $kind: $message');
-  }
-}
-
-main() {
-  asyncStart();
-  Future<CompilationResult> result = compile(new Uri(scheme: 'main'),
-      new Uri(scheme: 'lib', path: '/'), provider, handler);
-  result.then((CompilationResult result) {
-    if (!result.isSuccess) {
-      throw 'Compilation failed';
-    }
-  }, onError: (e, s) {
-    throw 'Compilation failed: $e\n$s';
-  }).then(asyncSuccess);
-}
diff --git a/tests/web_2/internal/mock_libraries.dart b/tests/web_2/internal/mock_libraries.dart
deleted file mode 100644
index 9aa36ad..0000000
--- a/tests/web_2/internal/mock_libraries.dart
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.7
-
-// Library for creating mock versions of platform and internal libraries.
-
-library mock_libraries;
-
-const DEFAULT_PLATFORM_CONFIG = """
-[libraries]
-core:core/core.dart
-async:async/async.dart
-_js_helper:_internal/js_runtime/lib/js_helper.dart
-_interceptors:_internal/js_runtime/lib/interceptors.dart
-_internal:internal/internal.dart
-""";
-
-String buildLibrarySource(Map<String, String> elementMap,
-    [Map<String, String> additionalElementMap = const <String, String>{}]) {
-  Map<String, String> map = new Map<String, String>.from(elementMap);
-  if (additionalElementMap != null) {
-    map.addAll(additionalElementMap);
-  }
-  StringBuffer sb = new StringBuffer();
-  map.values.forEach((String element) {
-    sb.write('$element\n');
-  });
-  return sb.toString();
-}
-
-const Map<String, String> DEFAULT_CORE_LIBRARY = const <String, String>{
-  '<imports>': '''
-import 'dart:_internal' as internal;
-''',
-  'bool': 'class bool {}',
-  'Comparator': 'abstract class Comparator<T> {}',
-  'DateTime': r'''
-      class DateTime {
-        DateTime(year);
-        DateTime.utc(year);
-      }''',
-  'Deprecated': r'''
-      class Deprecated extends Object {
-        final String expires;
-        const Deprecated(this.expires);
-      }''',
-  'deprecated': 'const Object deprecated = const Deprecated("next release");',
-  'double': r'''
-      abstract class double extends num {
-        static var nan = 0;
-        static parse(s) {}
-      }''',
-  'Function': r'''
-      class Function {
-        static apply(Function fn, List positional, [Map named]) => null;
-      }''',
-  'identical': 'bool identical(Object a, Object b) { return true; }',
-  'int': 'abstract class int extends num { }',
-  'Iterable': '''
-      abstract class Iterable<E> {
-          Iterator<E> get iterator => null;
-      }''',
-  'Iterator': '''
-      abstract class Iterator<E> {
-          E get current => null;
-      }''',
-  'LinkedHashMap': r'''
-      class LinkedHashMap<K, V> implements Map<K, V> {
-      }''',
-  'List': r'''
-      class List<E> extends Iterable<E> {
-        var length;
-        List([length]);
-        List.filled(length, element);
-        E get first => null;
-        E get last => null;
-        E get single => null;
-        E removeLast() => null;
-        E removeAt(i) => null;
-        E elementAt(i) => null;
-        E singleWhere(f) => null;
-      }''',
-  'Map': 'abstract class Map<K,V> {}',
-  'Null': 'class Null {}',
-  'num': r'''
-      abstract class num {
-        operator +(_);
-        operator *(_);
-        operator -();
-      }''',
-  'print': 'print(var obj) {}',
-  'proxy': 'const proxy = 0;',
-  'Object': r'''
-      class Object {
-        const Object();
-        operator ==(other) { return true; }
-        get hashCode => throw "Object.hashCode not implemented.";
-        String toString() { return null; }
-        noSuchMethod(im) { throw im; }
-      }''',
-  'StackTrace': 'abstract class StackTrace {}',
-  'String': 'class String implements Pattern {}',
-  'Symbol': '''
-      abstract class Symbol {
-        const factory Symbol(String name) = internal.Symbol;
-      }
-      ''',
-  'Type': 'class Type {}',
-  'Pattern': 'abstract class Pattern {}',
-  '_genericNoSuchMethod': '_genericNoSuchMethod(a,b,c,d,e) {}',
-  '_unresolvedConstructorError': '_unresolvedConstructorError(a,b,c,d,e) {}',
-  '_malformedTypeError': '_malformedTypeError(message) {}',
-};
-
-const Map<String, String> DEFAULT_INTERNAL_LIBRARY = const <String, String>{
-  '<imports>': '''
-import 'dart:core' as core;
-''',
-  'Symbol': '''
-class Symbol implements core.Symbol {
-  final core.String _name;
-
-  const Symbol(this._name);
-  Symbol.validated(this._name);
-}
-''',
-};
-
-const String DEFAULT_PATCH_CORE_SOURCE = r'''
-import 'dart:_js_helper';
-import 'dart:_interceptors';
-import 'dart:async';
-
-@patch
-class LinkedHashMap<K, V> {
-  factory LinkedHashMap._empty() => null;
-  factory LinkedHashMap._literal(elements) => null;
-  static _makeEmpty() => null;
-  static _makeLiteral(elements) => null;
-}
-''';
-
-const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{
-  'assertTest': 'assertTest(a) {}',
-  'assertThrow': 'assertThrow(a) {}',
-  'assertHelper': 'assertHelper(a) {}',
-  'assertUnreachable': 'assertUnreachable() {}',
-  'assertSubtype': 'assertSubtype(object, isField, checks, asField) {}',
-  'asyncHelper': 'asyncHelper(object, asyncBody, completer) {}',
-  'boolConversionCheck': 'boolConversionCheck(x) {}',
-  'checkSubtype': 'checkSubtype(object, isField, checks, asField) {}',
-  'BoundClosure': r'''abstract class BoundClosure extends Closure {
-    var self;
-    var target;
-    var receiver;
-  }''',
-  'buildFunctionType': r'''buildFunctionType(returnType, parameterTypes,
-                            optionalParameterTypes) {
-            return new RuntimeFunctionType();
-          }''',
-  'buildInterfaceType': '''buildInterfaceType(rti, typeArguments) {
-                             if (rti == null) return new RuntimeTypePlain();
-                             return new RuntimeTypeGeneric();
-                           }''',
-  'buildNamedFunctionType':
-      r'''buildNamedFunctionType(returnType, parameterTypes,
-                                 namedParameters) {
-            return new RuntimeFunctionType();
-          }''',
-  'checkFunctionSubtype':
-      r'''checkFunctionSubtype(var target, String signatureName,
-                               String contextName, var context,
-                               var typeArguments) {}''',
-  'checkMalformedType': 'checkMalformedType(value, message) {}',
-  'checkInt': 'checkInt(value) {}',
-  'checkNum': 'checkNum(value) {}',
-  'checkString': 'checkString(value) {}',
-  'Closure': 'abstract class Closure implements Function { }',
-  'closureFromTearOff':
-      r'''closureFromTearOff(receiver, functions, reflectionInfo,
-                             isStatic, jsArguments, name) {}''',
-  'computeSignature':
-      'computeSignature(var signature, var context, var contextName) {}',
-  'ConstantMap': 'class ConstantMap<K, V> {}',
-  'ConstantProtoMap': 'class ConstantProtoMap<K, V> {}',
-  'ConstantStringMap': 'class ConstantStringMap<K, V> {}',
-  'createInvocationMirror': 'createInvocationMirror(a0, a1, a2, a3, a4, a5) {}',
-  'createRuntimeType': 'createRuntimeType(a) {}',
-  'functionSubtypeCast':
-      r'''functionSubtypeCast(Object object, String signatureName,
-                              String contextName, var context) {}''',
-  'functionTypeTestMetaHelper': r'''
-      functionTypeTestMetaHelper() {
-        buildFunctionType(null, null, null);
-        buildNamedFunctionType(null, null, null);
-        buildInterfaceType(null, null);
-      }''',
-  'getFallThroughError': 'getFallThroughError() {}',
-  'getIsolateAffinityTag': 'getIsolateAffinityTag(_) {}',
-  'getRuntimeTypeArguments':
-      'getRuntimeTypeArguments(target, substitutionName) {}',
-  'getRuntimeTypeInfo': 'getRuntimeTypeInfo(a) {}',
-  'getTraceFromException': 'getTraceFromException(exception) {}',
-  'GeneralConstantMap': 'class GeneralConstantMap {}',
-  'iae': 'iae(x) { throw x; } ioore(x) { throw x; }',
-  'Instantiation1': 'class Instantiation1<T1> extends Closure {}',
-  'Instantiation2': 'class Instantiation2<T1,T2> extends Closure {}',
-  'Instantiation3': 'class Instantiation3<T1,T2,T3> extends Closure {}',
-  'interceptedTypeCast': 'interceptedTypeCast(value, property) {}',
-  'interceptedTypeCheck': 'interceptedTypeCheck(value, property) {}',
-  'isJsIndexable': 'isJsIndexable(a, b) {}',
-  'JavaScriptIndexingBehavior': 'abstract class JavaScriptIndexingBehavior {}',
-  'JSInvocationMirror': r'''
-  class JSInvocationMirror {
-    get typeArguments => null;
-  }''',
-  'makeLiteralMap': 'makeLiteralMap(List keyValuePairs) {}',
-  'Native': 'class Native {}',
-  '_Patch': 'class _Patch { final tag; const _Patch(this.tag); }',
-  'patch': 'const patch = const _Patch(null);',
-  'patch_full': 'const patch_full = const _Patch("full");',
-  'patch_lazy': 'const patch_lazy = const _Patch("lazy");',
-  'patch_startup': 'const patch_startup = const _Patch("startup");',
-  'requiresPreamble': 'requiresPreamble() {}',
-  'RuntimeFunctionType': 'class RuntimeFunctionType {}',
-  'RuntimeTypeGeneric': 'class RuntimeTypeGeneric {}',
-  'RuntimeTypePlain': 'class RuntimeTypePlain {}',
-  'S': 'S() {}',
-  'setRuntimeTypeInfo': 'setRuntimeTypeInfo(a, b) {}',
-  'subtypeOfRuntimeTypeCast': 'subtypeOfRuntimeTypeCast(object, type) {}',
-  'checkConcurrentModificationError':
-      'checkConcurrentModificationError(collection) {}',
-  'throwConcurrentModificationError':
-      'throwConcurrentModificationError(collection) {}',
-  'throwCyclicInit': 'throwCyclicInit(staticName) {}',
-  'throwExpression': 'throwExpression(e) {}',
-  'throwNoSuchMethod':
-      'throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}',
-  'throwUnsupportedError': 'throwUnsupportedError(message) {}',
-  'unwrapException': 'unwrapException(e) {}',
-  'voidTypeCheck': 'voidTypeCheck(value) {}',
-  'wrapException': 'wrapException(x) { return x; }',
-  'badMain': 'badMain() { throw "bad main"; }',
-  'missingMain': 'missingMain() { throw "missing main"; }',
-  'mainHasTooManyParameters': 'mainHasTooManyParameters() '
-      '{ throw "main has too many parameters"; }',
-};
-
-const Map<String, String> DEFAULT_FOREIGN_HELPER_LIBRARY =
-    const <String, String>{
-  'JS': r'''
-      dynamic JS(String typeDescription, String codeTemplate,
-        [var arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6,
-         var arg7, var arg8, var arg9, var arg10, var arg11]) {}''',
-};
-
-const Map<String, String> DEFAULT_INTERCEPTORS_LIBRARY = const <String, String>{
-  'findIndexForNativeSubclassType': 'findIndexForNativeSubclassType(type) {}',
-  'getDispatchProperty': 'getDispatchProperty(o) {}',
-  'getInterceptor': 'getInterceptor(x) {}',
-  'getNativeInterceptor': 'getNativeInterceptor(x) {}',
-  'initializeDispatchProperty': 'initializeDispatchProperty(f,p,i) {}',
-  'initializeDispatchPropertyCSP': 'initializeDispatchPropertyCSP(f,p,i) {}',
-  'Interceptor': r'''
-      class Interceptor {
-        toString() {}
-        bool operator==(other) => identical(this, other);
-        get hashCode => throw "Interceptor.hashCode not implemented.";
-        noSuchMethod(im) { throw im; }
-      }''',
-  'JSArray': r'''
-          class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
-            JSArray();
-            factory JSArray.typed(a) => a;
-            var length;
-            operator[](index) => this[index];
-            operator[]=(index, value) { this[index] = value; }
-            add(value) { this[length] = value; }
-            insert(index, value) {}
-            E get first => this[0];
-            E get last => this[0];
-            E get single => this[0];
-            E removeLast() => this[0];
-            E removeAt(index) => this[0];
-            E elementAt(index) => this[0];
-            E singleWhere(f) => this[0];
-            Iterator<E> get iterator => null;
-          }''',
-  'JSBool': 'class JSBool extends Interceptor implements bool {}',
-  'JSDouble': 'class JSDouble extends JSNumber implements double {}',
-  'JSExtendableArray': 'class JSExtendableArray extends JSMutableArray {}',
-  'JSFixedArray': 'class JSFixedArray extends JSMutableArray {}',
-  'JSFunction':
-      'abstract class JSFunction extends Interceptor implements Function {}',
-  'JSIndexable': r'''
-      abstract class JSIndexable {
-        get length;
-        operator[](index);
-      }''',
-  'JSInt': r'''
-       class JSInt extends JSNumber implements int {
-         operator~() => this;
-       }''',
-  'JSMutableArray':
-      'class JSMutableArray extends JSArray implements JSMutableIndexable {}',
-  'JSUnmodifiableArray': 'class JSUnmodifiableArray extends JSArray {}',
-  'JSMutableIndexable':
-      'abstract class JSMutableIndexable extends JSIndexable {}',
-  'JSPositiveInt': 'class JSPositiveInt extends JSInt {}',
-  'JSNull': r'''
-      class JSNull extends Interceptor {
-        bool operator==(other) => identical(null, other);
-        get hashCode => throw "JSNull.hashCode not implemented.";
-        String toString() => 'Null';
-        Type get runtimeType => null;
-        noSuchMethod(x) => super.noSuchMethod(x);
-      }''',
-  'JSNumber': r'''
-      class JSNumber extends Interceptor implements num {
-        // All these methods return a number to please type inferencing.
-        operator-() => (this is JSInt) ? 42 : 42.2;
-        operator +(other) => (this is JSInt) ? 42 : 42.2;
-        operator -(other) => (this is JSInt) ? 42 : 42.2;
-        operator ~/(other) => _tdivFast(other);
-        operator /(other) => (this is JSInt) ? 42 : 42.2;
-        operator *(other) => (this is JSInt) ? 42 : 42.2;
-        operator %(other) => (this is JSInt) ? 42 : 42.2;
-        operator <<(other) => _shlPositive(other);
-        operator >>(other) {
-          return _shrBothPositive(other) + _shrReceiverPositive(other) +
-            _shrOtherPositive(other);
-        }
-        operator |(other) => 42;
-        operator &(other) => 42;
-        operator ^(other) => 42;
-
-        operator >(other) => !identical(this, other);
-        operator >=(other) => !identical(this, other);
-        operator <(other) => !identical(this, other);
-        operator <=(other) => !identical(this, other);
-        operator ==(other) => identical(this, other);
-        get hashCode => throw "JSNumber.hashCode not implemented.";
-
-        // We force side effects on _tdivFast to mimic the shortcomings of
-        // the effect analysis: because the `_tdivFast` implementation of
-        // the core library has calls that may not already be analyzed,
-        // the analysis will conclude that `_tdivFast` may have side
-        // effects.
-        _tdivFast(other) => new List()..length = 42;
-        _shlPositive(other) => 42;
-        _shrBothPositive(other) => 42;
-        _shrReceiverPositive(other) => 42;
-        _shrOtherPositive(other) => 42;
-
-        abs() => (this is JSInt) ? 42 : 42.2;
-        remainder(other) => (this is JSInt) ? 42 : 42.2;
-        truncate() => 42;
-      }''',
-  'JSString': r'''
-      class JSString extends Interceptor implements String, JSIndexable {
-        split(pattern) => [];
-        int get length => 42;
-        operator[](index) {}
-        toString() {}
-        operator+(other) => this;
-        codeUnitAt(index) => 42;
-      }''',
-  'JSUInt31': 'class JSUInt31 extends JSUInt32 {}',
-  'JSUInt32': 'class JSUInt32 extends JSPositiveInt {}',
-  'ObjectInterceptor': 'class ObjectInterceptor {}',
-  'JavaScriptObject': 'class JavaScriptObject {}',
-  'PlainJavaScriptObject': 'class PlainJavaScriptObject {}',
-  'UnknownJavaScriptObject': 'class UnknownJavaScriptObject {}',
-  'JavaScriptFunction': 'class JavaScriptFunction {}',
-};
-
-const Map<String, String> DEFAULT_ASYNC_LIBRARY = const <String, String>{
-  'DeferredLibrary': 'class DeferredLibrary {}',
-  'Future': '''
-      class Future<T> {
-        Future.value([value]);
-      }
-      ''',
-  'Stream': 'class Stream<T> {}',
-  'Completer': 'class Completer<T> {}',
-  'StreamIterator': 'class StreamIterator<T> {}',
-};
-
-/// These members are only needed when async/await is used.
-const Map<String, String> ASYNC_AWAIT_LIBRARY = const <String, String>{
-  '_wrapJsFunctionForAsync': '_wrapJsFunctionForAsync(f) {}',
-  '_asyncHelper': '_asyncHelper(o, f, c) {}',
-  '_SyncStarIterable': 'class _SyncStarIterable {}',
-  '_IterationMarker': 'class _IterationMarker {}',
-  '_AsyncStarStreamController': 'class _AsyncStarStreamController {}',
-  '_asyncStarHelper': '_asyncStarHelper(x, y, z) {}',
-  '_streamOfController': '_streamOfController(x) {}',
-};
-
-const String DEFAULT_MIRRORS_SOURCE = r'''
-import 'dart:_js_mirrors' as js;
-class Comment {}
-class MirrorSystem {}
-class MirrorsUsed {
-  final targets;
-  const MirrorsUsed({this.targets});
-}
-void reflectType(Type t) => js.disableTreeShaking();
-''';
-
-const String DEFAULT_JS_MIRRORS_SOURCE = r'''
-disableTreeShaking(){}
-preserveMetadata(){}
-preserveLibraryNames(){}
-''';
diff --git a/tools/VERSION b/tools/VERSION
index f10e4ba..7d84f54 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 283
+PRERELEASE 284
 PRERELEASE_PATCH 0
\ No newline at end of file