Version 2.0.0-dev.64.1

Merge commit '3e85df5167fc8b6c8d1b94a7505d157b9494b7ab' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1287ea8..8c27cf3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 2.0.0-dev.64.0
+## 2.0.0-dev.64.1
 
 ### Language
 
diff --git a/DEPS b/DEPS
index ae550dd..c1107d7 100644
--- a/DEPS
+++ b/DEPS
@@ -110,7 +110,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_tag": "1.3.4",
   "protobuf_tag": "0.7.1",
-  "pub_rev": "8b9526c915bf21627a20cd0104cb6c2be25a879f",
+  "pub_rev": "c84ffa0265fe746824aa6f382cb6c41abc406d42",
   "pub_semver_tag": "1.4.1",
   "quiver_tag": "5aaa3f58c48608af5b027444d561270b53f15dbf",
   "resource_rev":"af5a5bf65511943398146cf146e466e5f0b95cb9",
diff --git a/pkg/analysis_server/test/integration/analysis/package_root_test.dart b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
index 5cca2f0..08c2d8d 100644
--- a/pkg/analysis_server/test/integration/analysis/package_root_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/package_root_test.dart
@@ -83,4 +83,10 @@
 class SetAnalysisRootsTest_UseCFE extends SetAnalysisRootsTest {
   @override
   bool get useCFE => true;
+
+  @override
+  @failingTest
+  test_package_root() {
+    return super.test_package_root();
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
index ff4bb12..a1845c1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
@@ -379,7 +379,7 @@
       ModifierBuilder builder, Scope memberScope, bool isInstanceMember,
       [Scope formalParameterScope,
       TypeInferenceListener<int, int, Node, int> listener]) {
-    ResolutionStorer<int, int, Node, int> storer;
+    ResolutionStorer storer;
     var fileResolutions = _resolutions[builder.fileUri];
     if (fileResolutions == null) {
       fileResolutions = <CollectedResolution>[];
@@ -387,7 +387,7 @@
     }
     var resolution = new CollectedResolution();
     fileResolutions.add(resolution);
-    storer = new ResolutionStorer<int, int, Node, int>(resolution.kernelData);
+    storer = new ResolutionStorer(resolution.kernelData);
     return super.createListener(
         builder, memberScope, isInstanceMember, formalParameterScope, storer);
   }
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index b65aa46..eb2e46b 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -417,6 +417,11 @@
       ConstantVisitor constantVisitor,
       ErrorReporter errorReporter,
       {ConstructorInvocation invocation}) {
+    if (!constructor.isConst) {
+      errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.CONST_WITH_NON_CONST, node);
+      return null;
+    }
     if (!getConstructorImpl(constructor).isCycleFree) {
       // It's not safe to evaluate this constructor, so bail out.
       // TODO(paulberry): ensure that a reasonable error message is produced
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index b34a4c1..54f5982 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2168,7 +2168,6 @@
   @override
   void beginTypeVariable(Token name) {
     debugEvent("beginTypeVariable");
-    push(ast.simpleIdentifier(name, isDeclaration: true));
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/fasta/resolution_storer.dart b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
index ebdd2cc..3713e55 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_storer.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/fasta/resolution_applier.dart';
+import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
 import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_algebra.dart';
@@ -38,15 +39,22 @@
 
 /// Type inference listener that records inferred types for later use by
 /// [ResolutionApplier].
-class ResolutionStorer<Location, Declaration, Reference, PrefixInfo>
-    extends TypeInferenceListener<Location, Declaration, Reference,
-        PrefixInfo> {
+class ResolutionStorer extends _ResolutionStorer<int, int, Node, int> {
+  ResolutionStorer(Map<int, ResolutionData<DartType, int, Node, int>> data)
+      : super(data);
+}
+
+/// Implementation of [ResolutionStorer], with types parameterized to avoid
+/// accidentally peeking into kernel internals.
+///
+/// TODO(paulberry): when the time is right, fuse this with [ResolutionStorer].
+class _ResolutionStorer<Location, Declaration, Reference, PrefixInfo>
+    implements
+        TypeInferenceListener<Location, Declaration, Reference, PrefixInfo> {
   final Map<Location,
       ResolutionData<DartType, Declaration, Reference, PrefixInfo>> _data;
 
-  final _stack = <Function>[];
-
-  ResolutionStorer(this._data);
+  _ResolutionStorer(this._data);
 
   void _store(Location location,
       {List<DartType> argumentTypes,
@@ -85,12 +93,36 @@
   }
 
   @override
-  void asExpressionExit(Location location, DartType inferredType) {
+  void asExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     _store(location, literalType: inferredType, inferredType: inferredType);
   }
 
   @override
-  void cascadeExpressionExit(Location location, DartType inferredType) {
+  void assertInitializer(InitializerJudgment judgment, Location location) {}
+
+  @override
+  void assertStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void awaitExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("awaitExpression", location, inferredType);
+
+  @override
+  void block(StatementJudgment judgment, Location location) {}
+
+  @override
+  void boolLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("boolLiteral", location, inferredType);
+
+  @override
+  void breakStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void cascadeExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     // Overridden so that the type of the expression will not be recorded. We
     // don't need to record the type because the type is always the same as the
     // type of the target, and we don't have the appropriate offset so we can't
@@ -98,7 +130,8 @@
   }
 
   @override
-  void catchStatementEnter(
+  void catchStatement(
+      Catch judgment,
       Location location,
       DartType guardType,
       Location exceptionLocation,
@@ -117,107 +150,161 @@
   }
 
   @override
-  void constructorInvocationEnter(Location location, DartType typeContext) {
-    _push((Reference expressionTarget, DartType inferredType) {
-      // A class reference may have already been stored at this location by
-      // storeClassReference.  We want to replace it with a constructor
-      // reference.
-      _unstore(location);
-      _store(location, inferredType: inferredType, reference: expressionTarget);
-    });
+  void conditionalExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("conditionalExpression", location, inferredType);
+
+  @override
+  void constructorInvocation(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType) {
+    // A class reference may have already been stored at this location by
+    // storeClassReference.  We want to replace it with a constructor
+    // reference.
+    _unstore(location);
+    _store(location, inferredType: inferredType, reference: expressionTarget);
   }
 
   @override
-  void constructorInvocationExit(
-      Location location, Reference expressionTarget, DartType inferredType) {
-    _pop()(expressionTarget, inferredType);
-  }
+  void continueSwitchStatement(StatementJudgment judgment, Location location) {}
 
   @override
-  void fieldInitializerEnter(Location location, Reference initializerField) {
+  void deferredCheck(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("deferredCheck", location, inferredType);
+
+  @override
+  void doStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void doubleLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("doubleLiteral", location, inferredType);
+
+  @override
+  void expressionStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void fieldInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerField) {
     _store(location, reference: initializerField);
   }
 
-  void finished() {
-    assert(_stack.isEmpty);
-  }
-
   @override
-  void forInStatementEnter(
+  void forInStatement(
+      StatementJudgment judgment,
       Location location,
       Location variableLocation,
+      DartType variableType,
       Location writeLocation,
       DartType writeType,
       Declaration writeVariable,
       Reference writeTarget) {
-    _push((DartType variableType) {
-      if (variableLocation != null) {
-        _store(variableLocation, inferredType: variableType);
+    if (variableLocation != null) {
+      _store(variableLocation, inferredType: variableType);
+    } else {
+      if (writeVariable != null) {
+        _store(writeLocation,
+            declaration: writeVariable, inferredType: writeType);
       } else {
-        if (writeVariable != null) {
-          _store(writeLocation,
-              declaration: writeVariable, inferredType: writeType);
-        } else {
-          _store(writeLocation,
-              reference: writeTarget,
-              isWriteReference: true,
-              writeContext: writeType);
-        }
+        _store(writeLocation,
+            reference: writeTarget,
+            isWriteReference: true,
+            writeContext: writeType);
       }
-    });
+    }
   }
 
   @override
-  void forInStatementExit(
-      Location location, bool variablePresent, DartType variableType) {
-    _pop()(variableType);
+  void forStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void functionDeclaration(StatementJudgment judgment, Location location,
+      FunctionType inferredType) {
+    _store(location, inferredType: inferredType);
   }
 
   @override
-  void genericExpressionEnter(
-      String expressionType, Location location, DartType typeContext) {
-    super.genericExpressionEnter(expressionType, location, typeContext);
-  }
+  void functionExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("functionExpression", location, inferredType);
 
-  @override
-  void genericExpressionExit(
+  void genericExpression(
       String expressionType, Location location, DartType inferredType) {
     _store(location, inferredType: inferredType);
-    super.genericExpressionExit(expressionType, location, inferredType);
   }
 
   @override
-  void functionDeclarationExit(Location location, FunctionType inferredType) {
-    _store(location, inferredType: inferredType);
-  }
+  void ifNull(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('ifNull', location, inferredType);
 
   @override
-  void nullLiteralExit(
-      Location location, bool isSynthetic, DartType inferredType) {
+  void ifStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void intLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("intLiteral", location, inferredType);
+
+  @override
+  void invalidInitializer(InitializerJudgment judgment, Location location) {}
+
+  @override
+  void labeledStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void listLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("listLiteral", location, inferredType);
+
+  @override
+  void logicalExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("logicalExpression", location, inferredType);
+
+  @override
+  void mapLiteral(ExpressionJudgment judgment, Location location,
+          DartType typeContext) =>
+      genericExpression("mapLiteral", location, typeContext);
+
+  @override
+  void namedFunctionExpression(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("namedFunctionExpression", location, inferredType);
+
+  @override
+  void not(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("not", location, inferredType);
+
+  @override
+  void nullLiteral(ExpressionJudgment judgment, Location location,
+      bool isSynthetic, DartType inferredType) {
     if (isSynthetic) return null;
-    super.nullLiteralExit(location, isSynthetic, inferredType);
+    genericExpression("nullLiteral", location, inferredType);
   }
 
   @override
-  void indexAssignExit(Location location, Reference writeMember,
-      Reference combiner, DartType inferredType) {
+  void indexAssign(ExpressionJudgment judgment, Location location,
+      Reference writeMember, Reference combiner, DartType inferredType) {
     _store(location,
         reference: writeMember, inferredType: inferredType, combiner: combiner);
   }
 
   @override
-  void isExpressionExit(
-      Location location, DartType testedType, DartType inferredType) {
+  void isExpression(ExpressionJudgment judgment, Location location,
+      DartType testedType, DartType inferredType) {
     _store(location, literalType: testedType, inferredType: inferredType);
   }
 
-  void isNotExpressionExit(
-      Location location, DartType type, DartType inferredType) {
+  void isNotExpression(ExpressionJudgment judgment, Location location,
+      DartType type, DartType inferredType) {
     _store(location, literalType: type, inferredType: inferredType);
   }
 
   @override
-  void methodInvocationExit(
+  void methodInvocation(
+      ExpressionJudgment judgment,
       Location resultOffset,
       List<DartType> argumentsTypes,
       bool isImplicitCall,
@@ -235,12 +322,11 @@
         invokeType: invokeType,
         isImplicitCall: isImplicitCall,
         reference: interfaceMember);
-
-    super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
   }
 
   @override
-  void methodInvocationExitCall(
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
       Location resultOffset,
       List<DartType> argumentsTypes,
       bool isImplicitCall,
@@ -256,13 +342,16 @@
         argumentTypes: argumentsTypes,
         invokeType: invokeType,
         isImplicitCall: isImplicitCall);
-
-    super.genericExpressionExit("methodInvocation", resultOffset, inferredType);
   }
 
   @override
-  void propertyAssignExit(Location location, Reference writeMember,
-      DartType writeContext, Reference combiner, DartType inferredType) {
+  void propertyAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType) {
     _store(location,
         isWriteReference: true,
         reference: writeMember,
@@ -272,110 +361,128 @@
   }
 
   @override
-  void propertyGetExit(
-      Location location, Reference member, DartType inferredType) {
+  void propertySet(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("propertySet", location, inferredType);
+
+  @override
+  void propertyGet(ExpressionJudgment judgment, Location location,
+      Reference member, DartType inferredType) {
     _store(location, reference: member, inferredType: inferredType);
   }
 
   @override
-  void propertyGetExitCall(Location location, DartType inferredType) {
+  void propertyGetCall(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     _store(location, isExplicitCall: true);
   }
 
   @override
-  void redirectingInitializerEnter(
-      Location location, Reference initializerTarget) {
+  void redirectingInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerTarget) {
     _store(location, reference: initializerTarget);
   }
 
   @override
-  void staticAssignEnter(Location location, DartType typeContext) {
-    _push((Reference writeMember, DartType writeContext, Reference combiner,
-        DartType inferredType) {
-      _store(location,
-          reference: writeMember,
-          isWriteReference: true,
-          writeContext: writeContext,
-          combiner: combiner,
-          inferredType: inferredType);
-    });
+  void rethrow_(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('rethrow', location, inferredType);
+
+  @override
+  void returnStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void staticAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType) {
+    _store(location,
+        reference: writeMember,
+        isWriteReference: true,
+        writeContext: writeContext,
+        combiner: combiner,
+        inferredType: inferredType);
   }
 
   @override
-  void staticAssignExit(Location location, Reference writeMember,
-      DartType writeContext, Reference combiner, DartType inferredType) {
-    _pop()(writeMember, writeContext, combiner, inferredType);
+  void staticGet(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType) {
+    _store(location, reference: expressionTarget, inferredType: inferredType);
   }
 
   @override
-  void staticGetEnter(Location location, DartType typeContext) {
-    _push(
-        (Location location, Reference expressionTarget, DartType inferredType) {
-      _store(location, reference: expressionTarget, inferredType: inferredType);
-    });
-  }
-
-  @override
-  void staticGetExit(
-      Location location, Reference expressionTarget, DartType inferredType) {
-    _pop()(location, expressionTarget, inferredType);
-  }
-
-  @override
-  void staticInvocationEnter(Location location,
-      Location expressionArgumentsLocation, DartType typeContext) {
-    _push((Reference expressionTarget,
-        List<DartType> expressionArgumentsTypes,
-        FunctionType calleeType,
-        Substitution substitution,
-        DartType inferredType) {
-      FunctionType invokeType = substitution == null
-          ? calleeType
-          : substitution.substituteType(calleeType.withoutTypeParameters);
-      _store(expressionArgumentsLocation,
-          invokeType: invokeType,
-          argumentTypes: expressionArgumentsTypes,
-          reference: expressionTarget,
-          inferredType: inferredType);
-    });
-  }
-
-  @override
-  void staticInvocationExit(
+  void staticInvocation(
+      ExpressionJudgment judgment,
       Location location,
       Reference expressionTarget,
       List<DartType> expressionArgumentsTypes,
       FunctionType calleeType,
       Substitution substitution,
       DartType inferredType) {
-    _pop()(expressionTarget, expressionArgumentsTypes, calleeType, substitution,
-        inferredType);
+    FunctionType invokeType = substitution == null
+        ? calleeType
+        : substitution.substituteType(calleeType.withoutTypeParameters);
+    _store(location,
+        invokeType: invokeType,
+        argumentTypes: expressionArgumentsTypes,
+        reference: expressionTarget,
+        inferredType: inferredType);
   }
 
   @override
-  void stringConcatenationExit(Location location, DartType inferredType) {
+  void stringConcatenation(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {
     // We don't need the type - we already know that it is String.
     // Moreover, the file offset for StringConcatenation is `-1`.
   }
 
   @override
-  void thisExpressionExit(Location location, DartType inferredType) {}
+  void stringLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("StringLiteral", location, inferredType);
 
   @override
-  void typeLiteralEnter(Location location, DartType typeContext) {
-    _push((Reference expressionType, DartType inferredType) {
-      _store(location, reference: expressionType, inferredType: inferredType);
-    });
-  }
+  void superInitializer(InitializerJudgment judgment, Location location) {}
 
-  void typeLiteralExit(
-      Location location, Reference expressionType, DartType inferredType) {
-    _pop()(expressionType, inferredType);
+  @override
+  void switchStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void symbolLiteral(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("symbolLiteral", location, inferredType);
+
+  @override
+  void thisExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType) {}
+
+  @override
+  void throw_(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression('throw', location, inferredType);
+
+  @override
+  void tryCatch(StatementJudgment judgment, Location location) {}
+
+  @override
+  void tryFinally(StatementJudgment judgment, Location location) {}
+
+  void typeLiteral(ExpressionJudgment judgment, Location location,
+      Reference expressionType, DartType inferredType) {
+    _store(location, reference: expressionType, inferredType: inferredType);
   }
 
   @override
-  void variableAssignExit(Location location, DartType writeContext,
-      Declaration writeVariable, Reference combiner, DartType inferredType) {
+  void variableAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      DartType writeContext,
+      Declaration writeVariable,
+      Reference combiner,
+      DartType inferredType) {
     _store(location,
         declaration: writeVariable,
         isWriteReference: true,
@@ -385,14 +492,14 @@
   }
 
   @override
-  void variableDeclarationExit(
-      Location location, DartType statementType, DartType inferredType) {
+  void variableDeclaration(StatementJudgment judgment, Location location,
+      DartType statementType, DartType inferredType) {
     _store(location, literalType: statementType, inferredType: inferredType);
   }
 
   @override
-  void variableGetExit(Location location, bool isInCascade,
-      Declaration expressionVariable, DartType inferredType) {
+  void variableGet(ExpressionJudgment judgment, Location location,
+      bool isInCascade, Declaration expressionVariable, DartType inferredType) {
     if (isInCascade) {
       return;
     }
@@ -400,13 +507,16 @@
         declaration: expressionVariable, inferredType: inferredType);
   }
 
-  void _push(Function f) {
-    _stack.add(f);
-  }
+  @override
+  void variableSet(ExpressionJudgment judgment, Location location,
+          DartType inferredType) =>
+      genericExpression("variableSet", location, inferredType);
 
-  Function _pop() {
-    return _stack.removeLast();
-  }
+  @override
+  void whileStatement(StatementJudgment judgment, Location location) {}
+
+  @override
+  void yieldStatement(StatementJudgment judgment, Location location) {}
 
   @override
   void storePrefixInfo(Location location, PrefixInfo prefixInfo) {
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index 765ee32..4d9b603 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -533,6 +533,13 @@
 
   @override
   @failingTest
+  test_constWithNonConst_in_const_context() async {
+    // Bad state: No data for () at 58
+    await super.test_constWithNonConst_in_const_context();
+  }
+
+  @override
+  @failingTest
   test_constWithNonConstantArgument_annotation() async {
     // Expected 1 errors of type CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, found 0
     await super.test_constWithNonConstantArgument_annotation();
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 5423d74..6923bc6 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -1630,7 +1630,33 @@
 }
 ''');
     await computeAnalysisResult(source);
-    assertErrors(source, [CompileTimeErrorCode.CONST_WITH_NON_CONST]);
+    // TODO(a14n): the error CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE is
+    // redundant and ought to be suppressed.
+    assertErrors(source, [
+      CompileTimeErrorCode.CONST_WITH_NON_CONST,
+      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+    ]);
+    verify([source]);
+  }
+
+  test_constWithNonConst_in_const_context() async {
+    Source source = addSource(r'''
+class A {
+  const A(x);
+}
+class B {
+}
+main() {
+  const A(B());
+}
+''');
+    await computeAnalysisResult(source);
+    // TODO(a14n): the error CONST_WITH_NON_CONSTANT_ARGUMENT is redundant and
+    // ought to be suppressed.
+    assertErrors(source, [
+      CompileTimeErrorCode.CONST_WITH_NON_CONST,
+      CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT
+    ]);
     verify([source]);
   }
 
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index f94b026..8c5dadf 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -188,13 +188,21 @@
 
   void test_constructorInvocation_noArgs() {
     EvaluationResult result =
-        _getExpressionValue("const C()", context: 'class C {}');
+        _getExpressionValue("const C()", context: 'class C {const C();}');
     expect(result.isValid, isTrue);
     DartObject value = result.value;
     expect(value, isNotNull);
     expect(value.type.name, 'C');
   }
 
+  void test_constructorInvocation_noConstConstructor() {
+    EvaluationResult result =
+        _getExpressionValue("const C()", context: 'class C {}');
+    expect(result.isValid, isFalse);
+    DartObject value = result.value;
+    expect(value, isNull);
+  }
+
   void test_constructorInvocation_simpleArgs() {
     EvaluationResult result = _getExpressionValue("const C(1)", context: '''
 class C {
diff --git a/pkg/analyzer/test/generated/package_build_test.dart b/pkg/analyzer/test/generated/package_build_test.dart
index 47980a8..1cc46a6 100644
--- a/pkg/analyzer/test/generated/package_build_test.dart
+++ b/pkg/analyzer/test/generated/package_build_test.dart
@@ -477,7 +477,8 @@
       String root, List<String> packageNames) {
     final contextBuilder = new MockContextBuilder();
     final packages = new MockPackages();
-    final packageMap = new Map.fromIterable(packageNames, value: ((_) => []));
+    final packageMap = new Map<String, List<Folder>>.fromIterable(packageNames,
+        value: ((_) => []));
     contextBuilder.packagesMapMap[_p(root)] = packages;
     contextBuilder.packagesToMapMap[packages] = packageMap;
     return PackageBuildWorkspace.find(provider, _p(root), contextBuilder);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index a8164c0..8b424b6 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -119,15 +119,12 @@
     int decision = _cachedDecisions[element];
 
     if (decision == null) {
-      // These synthetic elements are not yet present when we initially compute
-      // this cache from metadata annotations, so look for their parent.
-      if (element is ConstructorBodyEntity) {
-        ConstructorBodyEntity body = element;
-        decision = _cachedDecisions[body.constructor];
-      }
-      if (decision == null) {
-        decision = _unknown;
-      }
+      // TODO(sra): Have annotations for mustInline / noInline for constructor
+      // bodies. (There used to be some logic here to have constructor bodies,
+      // inherit the settings from annotations on the generative
+      // constructor. This was conflated with the heuristic decisions, leading
+      // to lack of inlining where it was beneficial.)
+      decision = _unknown;
     }
 
     if (insideLoop) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index fb04063..be3be29 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -5361,6 +5361,10 @@
         nativeData,
         interceptorData);
     localsHandler.scopeInfo = closureDataLookup.getScopeInfo(function);
+
+    CapturedScope scopeData = closureDataLookup.getCapturedScope(function);
+    bool forGenerativeConstructorBody = function is ConstructorBodyEntity;
+
     _returnLocal = new SyntheticLocal("result", function, function);
     localsHandler.updateLocal(_returnLocal, graph.addConstantNull(closedWorld));
 
@@ -5372,12 +5376,29 @@
           compiledArguments[argumentIndex++]);
     }
 
+    bool hasBox = false;
     forEachOrderedParameter(_globalLocalsMap, _elementMap, function,
         (Local parameter) {
+      if (forGenerativeConstructorBody && scopeData.isBoxed(parameter)) {
+        // The parameter will be a field in the box passed as the last
+        // parameter. So no need to have it.
+        hasBox = true;
+        return;
+      }
       HInstruction argument = compiledArguments[argumentIndex++];
       localsHandler.updateLocal(parameter, argument);
     });
 
+    if (hasBox) {
+      HInstruction box = compiledArguments[argumentIndex++];
+      assert(box is HCreateBox);
+      // TODO(sra): Make inlining of closures work. We should always call
+      // enterScope, and pass in the inlined 'this' as well as the 'box'.
+      localsHandler.enterScope(scopeData, null,
+          inlinedBox: box,
+          forGenerativeConstructorBody: forGenerativeConstructorBody);
+    }
+
     ClassEntity enclosing = function.enclosingClass;
     if ((function.isConstructor || function is ConstructorBodyEntity) &&
         rtiNeed.classNeedsTypeArguments(enclosing)) {
@@ -5540,7 +5561,17 @@
 
   bool _isFunctionCalledOnce(FunctionEntity element) {
     // ConstructorBodyElements are not in the type inference graph.
-    if (element is ConstructorBodyEntity) return false;
+    if (element is ConstructorBodyEntity) {
+      // If there are no subclasses with constructors that have this constructor
+      // as a superconstructor, it is called once by the generative
+      // constructor's factory.  A simplified version is to check this is a
+      // constructor body for a leaf class.
+      ClassEntity class_ = element.enclosingClass;
+      if (closedWorld.isDirectlyInstantiated(class_)) {
+        return !closedWorld.isIndirectlyInstantiated(class_);
+      }
+      return false;
+    }
     return globalInferenceResults.resultOfMember(element).isCalledOnce;
   }
 
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index f0a914c..57f2d1d 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -128,17 +128,17 @@
   /// method creates a box and sets up the redirections.
   void enterScope(
       CapturedScope closureInfo, SourceInformation sourceInformation,
-      {bool forGenerativeConstructorBody: false}) {
+      {bool forGenerativeConstructorBody: false, HInstruction inlinedBox}) {
     // See if any variable in the top-scope of the function is captured. If yes
     // we need to create a box-object.
     if (!closureInfo.requiresContextBox) return;
     HInstruction box;
     // The scope has captured variables.
     if (forGenerativeConstructorBody) {
-      // The box is passed as a parameter to a generative
-      // constructor body.
-      box = builder.addParameter(
-          closureInfo.context, _abstractValueDomain.nonNullType);
+      // The box is passed as a parameter to a generative constructor body.
+      box = inlinedBox ??
+          builder.addParameter(
+              closureInfo.context, _abstractValueDomain.nonNullType);
     } else {
       box = createBox(sourceInformation);
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index f4a9d05..1a6e1f0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -3517,8 +3517,8 @@
     for (Expression expression in expressions) {
       expressionOffsets.add(forest.readOffset(expression));
     }
-    push(new SwitchCase(toKernelExpressionList(expressions), expressionOffsets,
-        toKernelStatement(block),
+    push(new SwitchCaseJudgment(toKernelExpressionList(expressions),
+        expressionOffsets, toKernelStatement(block),
         isDefault: defaultKeyword != null)
       ..fileOffset = firstToken.charOffset);
     push(labels);
@@ -3534,7 +3534,7 @@
     exitLocalScope();
     Expression expression = popForValue();
     kernel.Statement result =
-        new ShadowSwitchStatement(toKernelExpression(expression), cases)
+        new SwitchStatementJudgment(toKernelExpression(expression), cases)
           ..fileOffset = switchKeyword.charOffset;
     if (target.hasUsers) {
       result = new LabeledStatementJudgment(result);
@@ -3715,7 +3715,6 @@
   @override
   void beginTypeVariable(Token name) {
     debugEvent("beginTypeVariable");
-    push(new Identifier(name));
   }
 
   @override
@@ -3911,14 +3910,14 @@
 
   kernel.Statement deprecated_buildCompileTimeErrorStatement(error,
       [int charOffset = -1]) {
-    return new ShadowExpressionStatement(toKernelExpression(
+    return new ExpressionStatementJudgment(toKernelExpression(
         deprecated_buildCompileTimeError(error, charOffset)));
   }
 
   kernel.Statement buildCompileTimeErrorStatement(
       Message message, int charOffset,
       {List<LocatedMessage> context}) {
-    return new ShadowExpressionStatement(toKernelExpression(
+    return new ExpressionStatementJudgment(toKernelExpression(
         buildCompileTimeError(message, charOffset, noLength,
             context: context)));
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/factory.dart b/pkg/front_end/lib/src/fasta/kernel/factory.dart
index 0300a2a..ebae116 100644
--- a/pkg/front_end/lib/src/fasta/kernel/factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/factory.dart
@@ -117,7 +117,14 @@
       Expression expression, Token semicolon);
 
   Initializer fieldInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerField);
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token fieldName,
+      Token equals,
+      Expression expression,
+      Node initializerField);
 
   Statement forInStatement(
       StatementJudgment judgment,
@@ -245,7 +252,13 @@
       ExpressionJudgment judgment, int fileOffset, DartType inferredType);
 
   Initializer redirectingInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerTarget);
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token constructorName,
+      covariant Object argumentList,
+      Node initializerTarget);
 
   Expression rethrow_(ExpressionJudgment judgment, int fileOffset,
       Token rethrowKeyword, DartType inferredType);
@@ -279,7 +292,13 @@
   Expression stringLiteral(ExpressionJudgment judgment, int fileOffset,
       Token literal, String value, DartType inferredType);
 
-  Initializer superInitializer(InitializerJudgment judgment, int fileOffset);
+  Initializer superInitializer(
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token superKeyword,
+      Token period,
+      Token constructorName,
+      covariant Object argumentList);
 
   Statement switchStatement(StatementJudgment judgment, int fileOffset);
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index ee066cd..0c4014e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -74,6 +74,7 @@
         BlockJudgment,
         BoolJudgment,
         BreakJudgment,
+        CatchJudgment,
         CheckLibraryIsLoadedJudgment,
         ConditionalJudgment,
         ContinueJudgment,
@@ -86,7 +87,7 @@
         LabeledStatementJudgment,
         LoadLibraryJudgment,
         NullJudgment,
-        ShadowExpressionStatement,
+        ExpressionStatementJudgment,
         ShadowForStatement,
         IfJudgment,
         ShadowListLiteral,
@@ -99,9 +100,9 @@
         ShadowStringLiteral,
         ShadowSymbolLiteral,
         ShadowSyntheticExpression,
-        ShadowTryCatch,
+        TryCatchJudgment,
         ShadowTryFinally,
-        ShadowWhileStatement,
+        WhileJudgment,
         YieldJudgment,
         ThisJudgment,
         ThrowJudgment,
@@ -353,7 +354,7 @@
       DartType stackTraceType,
       Statement body) {
     exceptionType ??= const DynamicType();
-    return new Catch(exceptionParameter, body,
+    return new CatchJudgment(exceptionParameter, body,
         guard: exceptionType, stackTrace: stackTraceParameter)
       ..fileOffset = offsetForToken(onKeyword ?? catchKeyword);
   }
@@ -378,7 +379,7 @@
   }
 
   Statement expressionStatement(Expression expression, Token semicolon) {
-    return new ShadowExpressionStatement(expression);
+    return new ExpressionStatementJudgment(expression);
   }
 
   @override
@@ -450,7 +451,7 @@
 
   @override
   Statement rethrowStatement(Token rethrowKeyword, Token semicolon) {
-    return new ShadowExpressionStatement(
+    return new ExpressionStatementJudgment(
         new ShadowRethrow()..fileOffset = offsetForToken(rethrowKeyword));
   }
 
@@ -489,7 +490,7 @@
       List<Catch> catchClauses, Token finallyKeyword, Statement finallyBlock) {
     Statement tryStatement = body;
     if (catchClauses != null) {
-      tryStatement = new ShadowTryCatch(tryStatement, catchClauses);
+      tryStatement = new TryCatchJudgment(tryStatement, catchClauses);
     }
     if (finallyBlock != null) {
       tryStatement = new ShadowTryFinally(tryStatement, finallyBlock);
@@ -525,7 +526,7 @@
   @override
   Statement whileStatement(
       Token whileKeyword, Expression condition, Statement body) {
-    return new ShadowWhileStatement(condition, body)
+    return new WhileJudgment(condition, body)
       ..fileOffset = whileKeyword.charOffset;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index c331eb7..35a714d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -72,7 +72,7 @@
         ShadowConstructorInvocation,
         ContinueSwitchJudgment,
         ShadowDeferredCheck,
-        ShadowExpressionStatement,
+        ExpressionStatementJudgment,
         ShadowFactoryConstructorInvocation,
         ShadowFieldInitializer,
         ShadowForInStatement,
@@ -100,7 +100,8 @@
         ShadowSuperInitializer,
         ShadowSuperMethodInvocation,
         SuperPropertyGetJudgment,
-        ShadowSwitchStatement,
+        SwitchCaseJudgment,
+        SwitchStatementJudgment,
         ShadowSyntheticExpression,
         VariableAssignmentJudgment,
         VariableDeclarationJudgment,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
index 46e49f1..96f72a9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
@@ -179,7 +179,14 @@
 
   @override
   Initializer fieldInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerField) {
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token fieldName,
+      Token equals,
+      Expression expression,
+      Node initializerField) {
     return judgment;
   }
 
@@ -382,7 +389,13 @@
 
   @override
   Initializer redirectingInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerTarget) {
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token constructorName,
+      Object argumentList,
+      Node initializerTarget) {
     return judgment;
   }
 
@@ -446,7 +459,13 @@
   }
 
   @override
-  Initializer superInitializer(InitializerJudgment judgment, int fileOffset) {
+  Initializer superInitializer(
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token superKeyword,
+      Token period,
+      Token constructorName,
+      Object argumentList) {
     return judgment;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
index 519886d..642fa62 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -5,7 +5,7 @@
 library fasta.kernel_field_builder;
 
 import 'package:kernel/ast.dart'
-    show DartType, Expression, Field, Name, Node, NullLiteral;
+    show DartType, Expression, Field, Name, NullLiteral;
 
 import '../../base/instrumentation.dart'
     show Instrumentation, InstrumentationValueForType;
@@ -17,7 +17,7 @@
 import '../problems.dart' show internalProblem;
 
 import '../type_inference/type_inference_listener.dart'
-    show TypeInferenceListener;
+    show KernelTypeInferenceListener;
 
 import 'kernel_body_builder.dart' show KernelBodyBuilder;
 
@@ -90,7 +90,7 @@
   @override
   void prepareTopLevelInference() {
     if (!isEligibleForInference) return;
-    var listener = new TypeInferenceListener<int, int, Node, int>();
+    var listener = new KernelTypeInferenceListener();
     var typeInferrer = library.loader.typeInferenceEngine
         .createTopLevelTypeInferrer(
             listener, field.enclosingClass?.thisType, field);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 73dee2a..a9b13d6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -168,10 +168,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.asExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = type;
-    inferrer.listener.asExpressionExit(fileOffset, inferredType);
+    inferrer.listener.asExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -187,9 +186,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.assertInitializerEnter(fileOffset);
     inferrer.inferStatement(factory, judgment);
-    inferrer.listener.assertInitializerExit(fileOffset);
+    inferrer.listener.assertInitializer(this, fileOffset);
   }
 }
 
@@ -211,7 +209,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.assertStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     var messageJudgment = this.messageJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
@@ -223,7 +220,7 @@
       inferrer.inferExpression(
           factory, messageJudgment, const UnknownType(), false);
     }
-    inferrer.listener.assertStatementExit(fileOffset);
+    inferrer.listener.assertStatement(this, fileOffset);
   }
 }
 
@@ -240,7 +237,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.awaitExpressionEnter(fileOffset, typeContext);
     if (!inferrer.typeSchemaEnvironment.isEmptyContext(typeContext)) {
       typeContext = inferrer.wrapFutureOrType(typeContext);
     }
@@ -248,7 +244,7 @@
     inferrer.inferExpression(factory, judgment, typeContext, true);
     inferredType =
         inferrer.typeSchemaEnvironment.unfutureType(judgment.inferredType);
-    inferrer.listener.awaitExpressionExit(fileOffset, inferredType);
+    inferrer.listener.awaitExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -263,11 +259,10 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.blockEnter(fileOffset);
     for (var judgment in judgments) {
       inferrer.inferStatement(factory, judgment);
     }
-    inferrer.listener.blockExit(fileOffset);
+    inferrer.listener.block(this, fileOffset);
   }
 }
 
@@ -282,9 +277,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.boolLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.boolClass.rawType;
-    inferrer.listener.boolLiteralExit(fileOffset, inferredType);
+    inferrer.listener.boolLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -309,9 +303,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.breakStatementEnter(fileOffset);
     // No inference needs to be done.
-    inferrer.listener.breakStatementExit(fileOffset);
+    inferrer.listener.breakStatement(this, fileOffset);
   }
 }
 
@@ -375,7 +368,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.cascadeExpressionEnter(fileOffset, typeContext);
     var lhsType = inferrer.inferExpression(
         factory, variable.initializer, typeContext, true);
     if (inferrer.strongMode) {
@@ -388,7 +380,7 @@
       if (section.body is! Let) break;
       section = section.body;
     }
-    inferrer.listener.cascadeExpressionExit(fileOffset, lhsType);
+    inferrer.listener.cascadeExpression(this, fileOffset, lhsType);
     return lhsType;
   }
 }
@@ -666,7 +658,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.conditionalExpressionEnter(fileOffset, typeContext);
     var conditionJudgment = this.conditionJudgment;
     var thenJudgment = this.thenJudgment;
     var otherwiseJudgment = this.otherwiseJudgment;
@@ -685,7 +676,7 @@
     if (inferrer.strongMode) {
       staticType = inferredType;
     }
-    inferrer.listener.conditionalExpressionExit(fileOffset, inferredType);
+    inferrer.listener.conditionalExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -723,7 +714,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.constructorInvocationEnter(fileOffset, typeContext);
     var library = inferrer.engine.beingInferred[target];
     if (library != null) {
       // There is a cyclic dependency where inferring the types of the
@@ -772,7 +762,7 @@
           noLength);
     }
     inferrer.listener
-        .constructorInvocationExit(fileOffset, target, inferredType);
+        .constructorInvocation(this, fileOffset, target, inferredType);
 
     if (isRedirected(this)) {
       InterfaceType returnType = inferredType;
@@ -821,9 +811,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.continueSwitchStatementEnter(fileOffset);
     // No inference needs to be done.
-    inferrer.listener.continueSwitchStatementExit(fileOffset);
+    inferrer.listener.continueSwitchStatement(this, fileOffset);
   }
 }
 
@@ -839,12 +828,11 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.deferredCheckEnter(fileOffset, typeContext);
     // Since the variable is not used in the body we don't need to type infer
     // it.  We can just type infer the body.
     var inferredType =
         inferrer.inferExpression(factory, body, typeContext, true);
-    inferrer.listener.deferredCheckExit(fileOffset, inferredType);
+    inferrer.listener.deferredCheck(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -861,7 +849,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.doStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     inferrer.inferStatement(factory, bodyJudgment);
     var boolType = inferrer.coreTypes.boolClass.rawType;
@@ -869,7 +856,7 @@
         factory, conditionJudgment, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, conditionJudgment.inferredType,
         condition, condition.fileOffset);
-    inferrer.listener.doStatementExit(fileOffset);
+    inferrer.listener.doStatement(this, fileOffset);
   }
 }
 
@@ -884,9 +871,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.doubleLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.doubleClass.rawType;
-    inferrer.listener.doubleLiteralExit(fileOffset, inferredType);
+    inferrer.listener.doubleLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -916,17 +902,18 @@
 }
 
 /// Concrete shadow object representing an expression statement in kernel form.
-class ShadowExpressionStatement extends ExpressionStatement
+class ExpressionStatementJudgment extends ExpressionStatement
     implements StatementJudgment {
-  ShadowExpressionStatement(Expression expression) : super(expression);
+  ExpressionStatementJudgment(Expression expression) : super(expression);
+
+  Expression get judgment => expression;
 
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.expressionStatementEnter(fileOffset);
-    inferrer.inferExpression(factory, expression, const UnknownType(), false);
-    inferrer.listener.expressionStatementExit(fileOffset);
+    inferrer.inferExpression(factory, judgment, const UnknownType(), false);
+    inferrer.listener.expressionStatement(this, fileOffset);
   }
 }
 
@@ -964,7 +951,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.constructorInvocationEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferInvocation(
         factory,
         typeContext,
@@ -973,7 +959,7 @@
         computeConstructorReturnType(_initialTarget),
         arguments);
     inferrer.listener
-        .constructorInvocationExit(fileOffset, target, inferredType);
+        .constructorInvocation(this, fileOffset, target, inferredType);
 
     if (isRedirected(this)) {
       InterfaceType returnType = inferredType;
@@ -1050,11 +1036,10 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.fieldInitializerEnter(fileOffset, field);
     var initializerType =
         inferrer.inferExpression(factory, value, field.type, true);
     inferrer.ensureAssignable(field.type, initializerType, value, fileOffset);
-    inferrer.listener.fieldInitializerExit(fileOffset);
+    inferrer.listener.fieldInitializer(this, fileOffset, field);
   }
 }
 
@@ -1099,38 +1084,6 @@
       context = const UnknownType();
     }
     context = inferrer.wrapType(context, iterableClass);
-    if (syntheticWrite is VariableSet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.variable.type,
-          syntheticWrite.variable.fileOffset,
-          null);
-    } else if (syntheticWrite is PropertySet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.interfaceTarget?.setterType,
-          null,
-          syntheticWrite.interfaceTarget);
-    } else if (syntheticWrite is StaticSet) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset,
-          variable?.fileOffset,
-          syntheticWrite.fileOffset,
-          syntheticWrite.target.setterType,
-          null,
-          syntheticWrite.target);
-    } else if (syntheticWrite == null ||
-        syntheticWrite is ShadowSyntheticExpression) {
-      inferrer.listener.forInStatementEnter(
-          fileOffset, variable?.fileOffset, null, null, null, null);
-    } else {
-      throw new UnimplementedError(
-          '(${syntheticWrite.runtimeType}) $syntheticWrite');
-    }
     var inferredExpressionType = inferrer.resolveTypeParameter(
         inferrer.inferExpression(
             factory, iterable, context, typeNeeded || typeChecksNeeded));
@@ -1186,8 +1139,44 @@
       }
       syntheticAssignment._replaceWithDesugared();
     }
-    inferrer.listener
-        .forInStatementExit(fileOffset, variable != null, variable?.type);
+    if (syntheticWrite is VariableSet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.variable.type,
+          syntheticWrite.variable.fileOffset,
+          null);
+    } else if (syntheticWrite is PropertySet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.interfaceTarget?.setterType,
+          null,
+          syntheticWrite.interfaceTarget);
+    } else if (syntheticWrite is StaticSet) {
+      inferrer.listener.forInStatement(
+          this,
+          fileOffset,
+          variable?.fileOffset,
+          variable?.type,
+          syntheticWrite.fileOffset,
+          syntheticWrite.target.setterType,
+          null,
+          syntheticWrite.target);
+    } else if (syntheticWrite == null ||
+        syntheticWrite is ShadowSyntheticExpression) {
+      inferrer.listener.forInStatement(this, fileOffset, variable?.fileOffset,
+          variable?.type, null, null, null, null);
+    } else {
+      throw new UnimplementedError(
+          '(${syntheticWrite.runtimeType}) $syntheticWrite');
+    }
   }
 }
 
@@ -1201,7 +1190,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.forStatementEnter(fileOffset);
     for (var variable in variables) {
       inferrer.inferStatement(factory, variable);
     }
@@ -1216,7 +1204,7 @@
       inferrer.inferExpression(factory, update, const UnknownType(), false);
     }
     inferrer.inferStatement(factory, body);
-    inferrer.listener.forStatementExit(fileOffset);
+    inferrer.listener.forStatement(this, fileOffset);
   }
 }
 
@@ -1233,7 +1221,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.functionDeclarationEnter(fileOffset);
     inferrer.inferMetadataKeepingHelper(factory, variable.annotations);
     inferrer.inferLocalFunction(
         factory,
@@ -1244,7 +1231,7 @@
             ? (inferrer.strongMode ? null : const DynamicType())
             : function.returnType);
     var inferredType = variable.type = function.functionType;
-    inferrer.listener.functionDeclarationExit(fileOffset, inferredType);
+    inferrer.listener.functionDeclaration(this, fileOffset, inferredType);
   }
 
   static void setHasImplicitReturnType(
@@ -1265,10 +1252,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.functionExpressionEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferLocalFunction(
         factory, function, typeContext, fileOffset, null);
-    inferrer.listener.functionExpressionExit(fileOffset, inferredType);
+    inferrer.listener.functionExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1299,14 +1285,12 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.ifNullEnter(fileOffset, typeContext);
     // To infer `e0 ?? e1` in context K:
     // - Infer e0 in context K to get T0
     var lhsType = inferrer.inferExpression(factory, _lhs, typeContext, true);
     if (inferrer.strongMode) {
       variable.type = lhsType;
     }
-    inferrer.listener.ifNullBeforeRhs(fileOffset);
     // - Let J = T0 if K is `?` else K.
     // - Infer e1 in context J to get T1
     bool useLub = _forceLub || typeContext is UnknownType;
@@ -1322,7 +1306,7 @@
     if (inferrer.strongMode) {
       body.staticType = inferredType;
     }
-    inferrer.listener.ifNullExit(fileOffset, inferredType);
+    inferrer.listener.ifNull(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1342,7 +1326,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.ifStatementEnter(fileOffset);
     var conditionJudgment = this.conditionJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
     inferrer.inferExpression(
@@ -1353,7 +1336,7 @@
     if (otherwiseJudgment != null) {
       inferrer.inferStatement(factory, otherwiseJudgment);
     }
-    inferrer.listener.ifStatementExit(fileOffset);
+    inferrer.listener.ifStatement(this, fileOffset);
   }
 }
 
@@ -1414,9 +1397,7 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.indexAssignEnter(desugared.fileOffset, typeContext);
     var receiverType = _inferReceiver(inferrer, factory);
-    inferrer.listener.indexAssignAfterReceiver(write.fileOffset, typeContext);
     var writeMember = inferrer.findMethodInvocationMember(receiverType, write);
     // To replicate analyzer behavior, we base type inference on the write
     // member.  TODO(paulberry): would it be better to use the read member
@@ -1470,7 +1451,7 @@
       _storeLetType(inferrer, replacedRead, readType);
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.indexAssignExit(write.fileOffset, writeMember,
+    inferrer.listener.indexAssign(this, write.fileOffset, writeMember,
         inferredResult.combiner, inferredResult.type);
     _replaceWithDesugared();
     return inferredResult.type;
@@ -1498,9 +1479,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.intLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.intClass.rawType;
-    inferrer.listener.intLiteralExit(fileOffset, inferredType);
+    inferrer.listener.intLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1514,10 +1494,9 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.invalidInitializerEnter(fileOffset);
     inferrer.inferExpression(
         factory, variable.initializer, const UnknownType(), false);
-    inferrer.listener.invalidInitializerExit(fileOffset);
+    inferrer.listener.invalidInitializer(this, fileOffset);
   }
 }
 
@@ -1534,10 +1513,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.isExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = inferrer.coreTypes.boolClass.rawType;
-    inferrer.listener.isExpressionExit(fileOffset, type, inferredType);
+    inferrer.listener.isExpression(this, fileOffset, type, inferredType);
     return inferredType;
   }
 }
@@ -1561,11 +1539,10 @@
       DartType typeContext) {
     IsExpression isExpression = this.operand;
 
-    inferrer.listener.isNotExpressionEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = inferrer.coreTypes.boolClass.rawType;
     inferrer.listener
-        .isNotExpressionExit(fileOffset, isExpression.type, inferredType);
+        .isNotExpression(this, fileOffset, isExpression.type, inferredType);
     return inferredType;
   }
 }
@@ -1581,9 +1558,8 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.labeledStatementEnter(fileOffset);
     inferrer.inferStatement(factory, judgment);
-    inferrer.listener.labeledStatementExit(fileOffset);
+    inferrer.listener.labeledStatement(this, fileOffset);
   }
 }
 
@@ -1605,7 +1581,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.listLiteralEnter(fileOffset, typeContext);
     var listClass = inferrer.coreTypes.listClass;
     var listType = listClass.thisType;
     List<DartType> inferredTypes;
@@ -1657,7 +1632,7 @@
       }
     }
     var inferredType = new InterfaceType(listClass, [inferredTypeArgument]);
-    inferrer.listener.listLiteralExit(fileOffset, inferredType);
+    inferrer.listener.listLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1675,17 +1650,15 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.logicalExpressionEnter(fileOffset, typeContext);
     var boolType = inferrer.coreTypes.boolClass.rawType;
     var leftType =
         inferrer.inferExpression(factory, left, boolType, !inferrer.isTopLevel);
-    inferrer.listener.logicalExpressionBeforeRhs(fileOffset);
     var rightType = inferrer.inferExpression(
         factory, right, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, leftType, left, left.fileOffset);
     inferrer.ensureAssignable(boolType, rightType, right, right.fileOffset);
     var inferredType = boolType;
-    inferrer.listener.logicalExpressionExit(fileOffset, inferredType);
+    inferrer.listener.logicalExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1726,7 +1699,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.mapLiteralEnter(fileOffset, typeContext);
     var mapClass = inferrer.coreTypes.mapClass;
     var mapType = mapClass.thisType;
     List<DartType> inferredTypes;
@@ -1797,7 +1769,7 @@
     }
     var inferredType =
         new InterfaceType(mapClass, [inferredKeyType, inferredValueType]);
-    inferrer.listener.mapLiteralExit(fileOffset, inferredType);
+    inferrer.listener.mapLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1868,11 +1840,10 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.namedFunctionExpressionEnter(fileOffset, typeContext);
     var inferredType = inferrer.inferExpression(
         factory, variable.initializer, typeContext, true);
     if (inferrer.strongMode) variable.type = inferredType;
-    inferrer.listener.namedFunctionExpressionExit(fileOffset, inferredType);
+    inferrer.listener.namedFunctionExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1888,14 +1859,13 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.notEnter(fileOffset, typeContext);
     // First infer the receiver so we can look up the method that was invoked.
     var boolType = inferrer.coreTypes.boolClass.rawType;
     var actualType = inferrer.inferExpression(
         factory, operand, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, actualType, operand, fileOffset);
     DartType inferredType = boolType;
-    inferrer.listener.notExit(fileOffset, inferredType);
+    inferrer.listener.not(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -1977,10 +1947,9 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.nullLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.nullClass.rawType;
     inferrer.listener
-        .nullLiteralExit(fileOffset, fileOffset == -1, inferredType);
+        .nullLiteral(this, fileOffset, fileOffset == -1, inferredType);
     return inferredType;
   }
 }
@@ -2053,7 +2022,6 @@
       DartType typeContext) {
     var receiverType = _inferReceiver(inferrer, factory);
 
-    inferrer.listener.propertyAssignEnter(write.fileOffset, typeContext);
     DartType readType;
     if (read != null) {
       var readMember =
@@ -2073,7 +2041,8 @@
     var writeContext = inferrer.getSetterType(writeMember, receiverType);
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
     if (inferrer.strongMode) nullAwareGuard?.staticType = inferredResult.type;
-    inferrer.listener.propertyAssignExit(
+    inferrer.listener.propertyAssign(
+        this,
         write.fileOffset,
         inferrer.getRealTarget(writeMember),
         writeContext,
@@ -2119,7 +2088,6 @@
   @override
   infer<Expression, Statement, Initializer, Type>(ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.redirectingInitializerEnter(fileOffset, target);
     List<TypeParameter> classTypeParameters =
         target.enclosingClass.typeParameters;
     List<DartType> typeArguments =
@@ -2132,7 +2100,7 @@
         target.function.functionType, target.enclosingClass.thisType, arguments,
         skipTypeArgumentInference: true);
     ArgumentsJudgment.removeNonInferrableArgumentTypes(arguments);
-    inferrer.listener.redirectingInitializerExit(fileOffset);
+    inferrer.listener.redirectingInitializer(this, fileOffset, target);
   }
 }
 
@@ -2145,9 +2113,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.rethrowEnter(fileOffset, typeContext);
     var inferredType = const BottomType();
-    inferrer.listener.rethrowExit(fileOffset, inferredType);
+    inferrer.listener.rethrow_(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2162,7 +2129,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.returnStatementEnter(fileOffset);
     var judgment = this.judgment;
     var closureContext = inferrer.closureContext;
     var typeContext = !closureContext.isGenerator
@@ -2182,7 +2148,7 @@
       closureContext.handleReturn(
           inferrer, inferredType, expression, fileOffset);
     }
-    inferrer.listener.returnStatementExit(fileOffset);
+    inferrer.listener.returnStatement(this, fileOffset);
   }
 }
 
@@ -2211,7 +2177,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticAssignEnter(this.write?.fileOffset, typeContext);
     DartType readType = const DynamicType(); // Only used in error recovery
     var read = this.read;
     if (read is StaticGet) {
@@ -2230,7 +2195,7 @@
       }
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.staticAssignExit(write?.fileOffset, writeMember,
+    inferrer.listener.staticAssign(this, write?.fileOffset, writeMember,
         writeContext, inferredResult.combiner, inferredResult.type);
     _replaceWithDesugared();
     return inferredResult.type;
@@ -2249,7 +2214,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticGetEnter(fileOffset, typeContext);
     var target = this.target;
     if (target is ShadowField && target.inferenceNode != null) {
       target.inferenceNode.resolve();
@@ -2260,7 +2224,7 @@
       type = inferrer.instantiateTearOff(type, typeContext, this);
     }
     inferredType = type;
-    inferrer.listener.staticGetExit(fileOffset, target, inferredType);
+    inferrer.listener.staticGet(this, fileOffset, target, inferredType);
     return inferredType;
   }
 }
@@ -2279,13 +2243,12 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.staticInvocationEnter(
-        this.fileOffset, arguments.fileOffset, typeContext);
     var calleeType = target.function.functionType;
     var inferredType = inferrer.inferInvocation(factory, typeContext,
         fileOffset, calleeType, calleeType.returnType, arguments);
-    inferrer.listener.staticInvocationExit(
-        fileOffset,
+    inferrer.listener.staticInvocation(
+        this,
+        arguments.fileOffset,
         target,
         arguments.types,
         inferrer.lastCalleeType,
@@ -2307,7 +2270,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.stringConcatenationEnter(fileOffset, typeContext);
     if (!inferrer.isTopLevel) {
       for (kernel.Expression expression in expressions) {
         inferrer.inferExpression(
@@ -2315,7 +2277,7 @@
       }
     }
     var inferredType = inferrer.coreTypes.stringClass.rawType;
-    inferrer.listener.stringConcatenationExit(fileOffset, inferredType);
+    inferrer.listener.stringConcatenation(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2331,9 +2293,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.stringLiteralEnter(fileOffset, typeContext);
     var inferredType = inferrer.coreTypes.stringClass.rawType;
-    inferrer.listener.stringLiteralExit(fileOffset, inferredType);
+    inferrer.listener.stringLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2348,7 +2309,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.superInitializerEnter(fileOffset);
     var substitution = Substitution.fromSupertype(inferrer.classHierarchy
         .getClassAsInstanceOf(
             inferrer.thisType.classNode, target.enclosingClass));
@@ -2361,7 +2321,7 @@
         inferrer.thisType,
         arguments,
         skipTypeArgumentInference: true);
-    inferrer.listener.superInitializerExit(fileOffset);
+    inferrer.listener.superInitializer(this, fileOffset);
   }
 }
 
@@ -2414,27 +2374,48 @@
   }
 }
 
+/// Concrete shadow object representing a switch case.
+class SwitchCaseJudgment extends SwitchCase {
+  SwitchCaseJudgment(
+      List<Expression> expressions, List<int> expressionOffsets, Statement body,
+      {bool isDefault: false})
+      : super(expressions, expressionOffsets, body, isDefault: isDefault);
+
+  SwitchCaseJudgment.defaultCase(Statement body) : super.defaultCase(body);
+
+  SwitchCaseJudgment.empty() : super.empty();
+
+  List<ExpressionJudgment> get expressionJudgments => expressions.cast();
+
+  StatementJudgment get bodyJudgment => body;
+}
+
 /// Concrete shadow object representing a switch statement in kernel form.
-class ShadowSwitchStatement extends SwitchStatement
+class SwitchStatementJudgment extends SwitchStatement
     implements StatementJudgment {
-  ShadowSwitchStatement(Expression expression, List<SwitchCase> cases)
+  SwitchStatementJudgment(Expression expression, List<SwitchCase> cases)
       : super(expression, cases);
 
+  ExpressionJudgment get expressionJudgment => expression;
+
+  List<SwitchCaseJudgment> get caseJudgments => cases.cast();
+
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.switchStatementEnter(fileOffset);
-    var expressionType = inferrer.inferExpression(
-        factory, expression, const UnknownType(), true);
-    for (var switchCase in cases) {
-      for (var caseExpression in switchCase.expressions) {
+    var expressionJudgment = this.expressionJudgment;
+    inferrer.inferExpression(
+        factory, expressionJudgment, const UnknownType(), true);
+    var expressionType = expressionJudgment.inferredType;
+    for (var switchCase in caseJudgments) {
+      for (var caseExpression in switchCase.expressionJudgments) {
         inferrer.inferExpression(
             factory, caseExpression, expressionType, false);
       }
-      inferrer.inferStatement(factory, switchCase.body);
+      inferrer.inferStatement(factory, switchCase.bodyJudgment);
     }
-    inferrer.listener.switchStatementExit(fileOffset);
+    inferrer.listener.switchStatement(this, fileOffset);
   }
 }
 
@@ -2449,9 +2430,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.symbolLiteralEnter(fileOffset, typeContext);
     var inferredType = inferrer.coreTypes.symbolClass.rawType;
-    inferrer.listener.symbolLiteralExit(fileOffset, inferredType);
+    inferrer.listener.symbolLiteral(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2532,9 +2512,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.thisExpressionEnter(fileOffset, typeContext);
     inferredType = inferrer.thisType ?? const DynamicType();
-    inferrer.listener.thisExpressionExit(fileOffset, inferredType);
+    inferrer.listener.thisExpression(this, fileOffset, inferredType);
     return inferredType;
   }
 }
@@ -2551,36 +2530,51 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.throwEnter(fileOffset, typeContext);
     inferrer.inferExpression(factory, judgment, const UnknownType(), false);
     inferredType = const BottomType();
-    inferrer.listener.throwExit(fileOffset, inferredType);
+    inferrer.listener.throw_(this, fileOffset, inferredType);
     return inferredType;
   }
 }
 
+/// Concrete shadow object representing a catch clause.
+class CatchJudgment extends Catch {
+  CatchJudgment(VariableDeclaration exception, Statement body,
+      {DartType guard: const DynamicType(), VariableDeclaration stackTrace})
+      : super(exception, body, guard: guard, stackTrace: stackTrace);
+
+  VariableDeclarationJudgment get exceptionJudgment => exception;
+
+  VariableDeclarationJudgment get stackTraceJudgment => stackTrace;
+
+  StatementJudgment get bodyJudgment => body;
+}
+
 /// Concrete shadow object representing a try-catch block in kernel form.
-class ShadowTryCatch extends TryCatch implements StatementJudgment {
-  ShadowTryCatch(Statement body, List<Catch> catches) : super(body, catches);
+class TryCatchJudgment extends TryCatch implements StatementJudgment {
+  TryCatchJudgment(Statement body, List<Catch> catches) : super(body, catches);
+
+  StatementJudgment get bodyJudgment => body;
+
+  List<CatchJudgment> get catchJudgments => catches.cast();
 
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.tryCatchEnter(fileOffset);
-    inferrer.inferStatement(factory, body);
-    for (var catch_ in catches) {
-      inferrer.listener.catchStatementEnter(
+    inferrer.inferStatement(factory, bodyJudgment);
+    for (var catch_ in catchJudgments) {
+      inferrer.inferStatement(factory, catch_.bodyJudgment);
+      inferrer.listener.catchStatement(
+          catch_,
           catch_.fileOffset,
           catch_.guard,
-          catch_.exception?.fileOffset,
-          catch_.exception?.type,
-          catch_.stackTrace?.fileOffset,
-          catch_.stackTrace?.type);
-      inferrer.inferStatement(factory, catch_.body);
-      inferrer.listener.catchStatementExit(catch_.fileOffset);
+          catch_.exceptionJudgment?.fileOffset,
+          catch_.exceptionJudgment?.type,
+          catch_.stackTraceJudgment?.fileOffset,
+          catch_.stackTraceJudgment?.type);
     }
-    inferrer.listener.tryCatchExit(fileOffset);
+    inferrer.listener.tryCatch(this, fileOffset);
   }
 }
 
@@ -2593,10 +2587,9 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.tryFinallyEnter(fileOffset);
     inferrer.inferStatement(factory, body);
     inferrer.inferStatement(factory, finalizer);
-    inferrer.listener.tryFinallyExit(fileOffset);
+    inferrer.listener.tryFinally(this, fileOffset);
   }
 }
 
@@ -2758,9 +2751,8 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.typeLiteralEnter(fileOffset, typeContext);
     inferredType = inferrer.coreTypes.typeClass.rawType;
-    inferrer.listener.typeLiteralExit(fileOffset, type, inferredType);
+    inferrer.listener.typeLiteral(this, fileOffset, type, inferredType);
     return inferredType;
   }
 }
@@ -2848,7 +2840,6 @@
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory,
       DartType typeContext) {
-    inferrer.listener.variableAssignEnter(this.write.fileOffset, typeContext);
     DartType readType;
     var read = this.read;
     if (read is VariableGet) {
@@ -2863,7 +2854,8 @@
       }
     }
     var inferredResult = _inferRhs(inferrer, factory, readType, writeContext);
-    inferrer.listener.variableAssignExit(
+    inferrer.listener.variableAssign(
+        this,
         write.fileOffset,
         writeContext,
         write is VariableSet ? write.variable.fileOffset : null,
@@ -2925,7 +2917,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.variableDeclarationEnter(fileOffset);
     if (annotationJudgments.isNotEmpty) {
       inferrer.inferMetadataKeepingHelper(factory, annotationJudgments);
 
@@ -2972,8 +2963,8 @@
         initializer = replacedInitializer;
       }
     }
-    inferrer.listener.variableDeclarationExit(
-        fileOffset, type, _implicitlyTyped ? inferredType : type);
+    inferrer.listener.variableDeclaration(
+        this, fileOffset, type, _implicitlyTyped ? inferredType : type);
   }
 
   /// Determine whether the given [VariableDeclarationJudgment] had an implicit
@@ -3026,7 +3017,6 @@
     bool mutatedInClosure = variable._mutatedInClosure;
     DartType declaredOrInferredType = variable.type;
 
-    inferrer.listener.variableGetEnter(fileOffset, typeContext);
     DartType promotedType = inferrer.typePromoter
         .computePromotedType(_fact, _scope, mutatedInClosure);
     if (promotedType != null) {
@@ -3039,29 +3029,32 @@
       type = inferrer.instantiateTearOff(type, typeContext, this);
     }
     inferredType = type;
-    inferrer.listener.variableGetExit(
-        fileOffset, _isInCascade(), variable.fileOffset, inferredType);
+    inferrer.listener.variableGet(
+        this, fileOffset, _isInCascade(), variable.fileOffset, inferredType);
     return inferredType;
   }
 }
 
 /// Concrete shadow object representing a while loop in kernel form.
-class ShadowWhileStatement extends WhileStatement implements StatementJudgment {
-  ShadowWhileStatement(Expression condition, Statement body)
-      : super(condition, body);
+class WhileJudgment extends WhileStatement implements StatementJudgment {
+  WhileJudgment(Expression condition, Statement body) : super(condition, body);
+
+  ExpressionJudgment get conditionJudgment => condition;
+
+  StatementJudgment get bodyJudgment => body;
 
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.whileStatementEnter(fileOffset);
+    var conditionJudgment = this.conditionJudgment;
     var expectedType = inferrer.coreTypes.boolClass.rawType;
-    var actualType = inferrer.inferExpression(
-        factory, condition, expectedType, !inferrer.isTopLevel);
-    inferrer.ensureAssignable(
-        expectedType, actualType, condition, condition.fileOffset);
-    inferrer.inferStatement(factory, body);
-    inferrer.listener.whileStatementExit(fileOffset);
+    inferrer.inferExpression(
+        factory, conditionJudgment, expectedType, !inferrer.isTopLevel);
+    inferrer.ensureAssignable(expectedType, conditionJudgment.inferredType,
+        condition, condition.fileOffset);
+    inferrer.inferStatement(factory, bodyJudgment);
+    inferrer.listener.whileStatement(this, fileOffset);
   }
 }
 
@@ -3076,7 +3069,6 @@
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
-    inferrer.listener.yieldStatementEnter(fileOffset);
     var judgment = this.judgment;
     var closureContext = inferrer.closureContext;
     if (closureContext.isGenerator) {
@@ -3094,7 +3086,7 @@
     }
     closureContext.handleYield(
         inferrer, isYieldStar, judgment.inferredType, expression, fileOffset);
-    inferrer.listener.yieldStatementExit(fileOffset);
+    inferrer.listener.yieldStatement(this, fileOffset);
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart b/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
index 54bc2a2..e3aac90 100644
--- a/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
@@ -141,7 +141,14 @@
 
   @override
   void fieldInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerField) {}
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token fieldName,
+      Token equals,
+      void expression,
+      Node initializerField) {}
 
   @override
   void forInStatement(
@@ -289,7 +296,13 @@
 
   @override
   void redirectingInitializer(
-      InitializerJudgment judgment, int fileOffset, Node initializerTarget) {}
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token thisKeyword,
+      Token period,
+      Token constructorName,
+      Object argumentList,
+      Node initializerTarget) {}
 
   @override
   void rethrow_(ExpressionJudgment judgment, int fileOffset,
@@ -337,7 +350,13 @@
       String value, DartType inferredType) {}
 
   @override
-  void superInitializer(InitializerJudgment judgment, int fileOffset) {}
+  void superInitializer(
+      InitializerJudgment judgment,
+      int fileOffset,
+      Token superKeyword,
+      Token period,
+      Token constructorName,
+      Object argumentList) {}
 
   @override
   void switchStatement(StatementJudgment judgment, int fileOffset) {}
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index dba1f6c..b75076e 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -903,6 +903,7 @@
   /// Handle the begin of a type formal parameter (e.g. "X extends Y").
   /// Substructures:
   /// - Metadata
+  /// - Name (identifier)
   void beginTypeVariable(Token name) {}
 
   /// Handle the end of a type formal parameter (e.g. "X extends Y").
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index f70d408..4921416 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -1947,10 +1947,7 @@
   /// ```
   Token parseTypeVariable(Token token) {
     token = parseMetadataStar(token);
-    token = token.next.kind == IDENTIFIER_TOKEN
-        ? token.next
-        : IdentifierContext.typeVariableDeclaration
-            .ensureIdentifier(token, this);
+    token = ensureIdentifier(token, IdentifierContext.typeVariableDeclaration);
     listener.beginTypeVariable(token);
     Token extendsOrSuper = null;
     Token next = token.next;
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 2b8f311..1370d5a 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -511,6 +511,7 @@
     token = token.next;
     listener.beginMetadataStar(token);
     listener.endMetadataStar(0);
+    listener.handleIdentifier(token, IdentifierContext.typeVariableDeclaration);
     listener.beginTypeVariable(token);
     listener.handleNoType(token);
     token = processEndGroup(token, start, parser);
@@ -658,10 +659,8 @@
     int count = 0;
     while (true) {
       token = parser.parseMetadataStar(next);
-      token = token.next.kind == IDENTIFIER_TOKEN
-          ? token.next
-          : IdentifierContext.typeVariableDeclaration
-              .ensureIdentifier(token, parser);
+      token = parser.ensureIdentifier(
+          token, IdentifierContext.typeVariableDeclaration);
       parser.listener.beginTypeVariable(token);
       Token extendsOrSuper = null;
       next = token.next;
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 516a6b6..961ebe3 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -42,7 +42,7 @@
 import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
 
 import '../type_inference/type_inference_listener.dart'
-    show TypeInferenceListener;
+    show KernelTypeInferenceListener, TypeInferenceListener;
 
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 
@@ -449,7 +449,7 @@
   @override
   void endTypeVariable(Token token, Token extendsOrSuper) {
     debugEvent("TypeVariable");
-    discard(1); // Metadata.
+    discard(2); // Name and metadata.
   }
 
   @override
@@ -534,7 +534,7 @@
       ModifierBuilder builder, Scope memberScope, bool isInstanceMember,
       [Scope formalParameterScope,
       TypeInferenceListener<int, int, Node, int> listener]) {
-    listener ??= new TypeInferenceListener<int, int, Node, int>();
+    listener ??= new KernelTypeInferenceListener();
     // Note: we set thisType regardless of whether we are building a static
     // member, since that provides better error recovery.
     InterfaceType thisType = currentClass?.target?.thisType;
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index f0e69b9..3a98d19 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -1109,8 +1109,6 @@
   @override
   void beginTypeVariable(Token token) {
     debugEvent("beginTypeVariable");
-    push(token.lexeme);
-    push(token.charOffset);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
index 28ea849..fcf385f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
@@ -2,29 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
-import 'package:kernel/ast.dart' show DartType, FunctionType;
+import 'package:kernel/ast.dart' show Catch, DartType, FunctionType, Node;
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
-/// Base class for [TypeInferenceListener] that defines the API for debugging.
-///
-/// By default no debug info is printed.  To enable debug printing, mix in
-/// [TypeInferenceDebugging].
-class TypeInferenceBase<Location> {
-  void genericExpressionEnter(
-      String expressionType, Location location, DartType typeContext) {}
-
-  void genericExpressionExit(
-      String expressionType, Location location, DartType inferredType) {}
-
-  void genericInitializerEnter(String initializerType, Location location) {}
-
-  void genericInitializerExit(String initializerType, Location location) {}
-
-  void genericStatementEnter(String statementType, Location location) {}
-
-  void genericStatementExit(String statementType, Location location) {}
-}
+import '../kernel/kernel_shadow_ast.dart'
+    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
 
 /// Callback interface used by [TypeInferrer] to report the results of type
 /// inference to a client.
@@ -38,444 +21,502 @@
 /// The default implementation (in this base class) does nothing, however it can
 /// be used to debug type inference by uncommenting the
 /// "with TypeInferenceDebugging" clause below.
-class TypeInferenceListener<Location, Declaration, Reference, PrefixInfo>
-    extends TypeInferenceBase<Location> {
-  void asExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("asExpression", location, typeContext);
+abstract class TypeInferenceListener<Location, Declaration, Reference,
+    PrefixInfo> {
+  void asExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void asExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("asExpression", location, inferredType);
+  void assertInitializer(InitializerJudgment judgment, Location location);
 
-  void assertInitializerEnter(Location location) =>
-      genericInitializerEnter("assertInitializer", location);
+  void assertStatement(StatementJudgment judgment, Location location);
 
-  void assertInitializerExit(Location location) =>
-      genericInitializerExit("assertInitializer", location);
+  void awaitExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void assertStatementEnter(Location location) =>
-      genericStatementEnter('assertStatement', location);
+  void block(StatementJudgment judgment, Location location);
 
-  void assertStatementExit(Location location) =>
-      genericStatementExit('assertStatement', location);
+  void boolLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void awaitExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("awaitExpression", location, typeContext);
+  void breakStatement(StatementJudgment judgment, Location location);
 
-  void awaitExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("awaitExpression", location, inferredType);
+  void cascadeExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void blockEnter(Location location) =>
-      genericStatementEnter('block', location);
-
-  void blockExit(Location location) => genericStatementExit('block', location);
-
-  void boolLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("boolLiteral", location, typeContext);
-
-  void boolLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("boolLiteral", location, inferredType);
-
-  void breakStatementEnter(Location location) =>
-      genericStatementEnter('breakStatement', location);
-
-  void breakStatementExit(Location location) =>
-      genericStatementExit('breakStatement', location);
-
-  void cascadeExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("cascade", location, typeContext);
-
-  void cascadeExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("cascade", location, inferredType);
-
-  void catchStatementEnter(
+  void catchStatement(
+      Catch judgment,
       Location location,
       DartType guardType,
       Location exceptionLocation,
       DartType exceptionType,
       Location stackTraceLocation,
-      DartType stackTraceType) {}
+      DartType stackTraceType);
 
-  void catchStatementExit(Location location) {}
+  void conditionalExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void conditionalExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("conditionalExpression", location, typeContext);
+  void constructorInvocation(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType);
 
-  void conditionalExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("conditionalExpression", location, inferredType);
+  void continueSwitchStatement(StatementJudgment judgment, Location location);
 
-  void constructorInvocationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("constructorInvocation", location, typeContext);
+  void deferredCheck(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void constructorInvocationExit(Location location, Reference expressionTarget,
-          DartType inferredType) =>
-      genericExpressionExit("constructorInvocation", location, inferredType);
+  void doStatement(StatementJudgment judgment, Location location);
 
-  void continueSwitchStatementEnter(Location location) =>
-      genericStatementEnter('continueSwitchStatement', location);
+  void doubleLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void continueSwitchStatementExit(Location location) =>
-      genericStatementExit('continueSwitchStatement', location);
+  void expressionStatement(StatementJudgment judgment, Location location);
 
-  void deferredCheckEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("deferredCheck", location, typeContext);
+  void fieldInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerField);
 
-  void deferredCheckExit(Location location, DartType inferredType) =>
-      genericExpressionExit("deferredCheck", location, inferredType);
+  void forInStatement(
+      StatementJudgment judgment,
+      Location location,
+      Location variableLocation,
+      DartType variableType,
+      Location writeLocation,
+      DartType writeVariableType,
+      Declaration writeVariable,
+      Reference writeTarget);
 
-  void doStatementEnter(Location location) =>
-      genericStatementEnter("doStatement", location);
+  void forStatement(StatementJudgment judgment, Location location);
 
-  void doStatementExit(Location location) =>
-      genericStatementExit("doStatement", location);
+  void functionDeclaration(
+      StatementJudgment judgment, Location location, FunctionType inferredType);
 
-  void doubleLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("doubleLiteral", location, typeContext);
+  void functionExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void doubleLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("doubleLiteral", location, inferredType);
+  void ifNull(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void dryRunEnter(Location location) =>
-      genericExpressionEnter("dryRun", location, null);
+  void ifStatement(StatementJudgment judgment, Location location);
 
-  void dryRunExit(Location location) =>
-      genericExpressionExit("dryRun", location, null);
+  void indexAssign(ExpressionJudgment judgment, Location location,
+      Reference writeMember, Reference combiner, DartType inferredType);
 
-  void expressionStatementEnter(Location location) =>
-      genericStatementEnter('expressionStatement', location);
+  void intLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void expressionStatementExit(Location location) =>
-      genericStatementExit('expressionStatement', location);
+  void invalidInitializer(InitializerJudgment judgment, Location location);
 
-  void fieldInitializerEnter(Location location, Reference initializerField) =>
-      genericInitializerEnter("fieldInitializer", location);
+  void isExpression(ExpressionJudgment judgment, Location location,
+      DartType testedType, DartType inferredType);
 
-  void fieldInitializerExit(Location location) =>
-      genericInitializerExit("fieldInitializer", location);
+  void isNotExpression(ExpressionJudgment judgment, Location location,
+      DartType type, DartType inferredType);
 
-  void forInStatementEnter(
-          Location location,
-          Location variableLocation,
-          Location writeLocation,
-          DartType writeVariableType,
-          Declaration writeVariable,
-          Reference writeTarget) =>
-      genericStatementEnter('forInStatement', location);
+  void labeledStatement(StatementJudgment judgment, Location location);
 
-  void forInStatementExit(
-          Location location, bool variablePresent, DartType variableType) =>
-      genericStatementExit('forInStatement', location);
+  void listLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void forStatementEnter(Location location) =>
-      genericStatementEnter('forStatement', location);
+  void logicalExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void forStatementExit(Location location) =>
-      genericStatementExit('forStatement', location);
+  void mapLiteral(
+      ExpressionJudgment judgment, Location location, DartType typeContext);
 
-  void functionDeclarationEnter(Location location) =>
-      genericStatementEnter('functionDeclaration', location);
+  void methodInvocation(
+      ExpressionJudgment judgment,
+      Location resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      Reference interfaceMember,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void functionDeclarationExit(Location location, FunctionType inferredType) =>
-      genericStatementExit('functionDeclaration', location);
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
+      Location resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void functionExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("functionExpression", location, typeContext);
+  void namedFunctionExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void functionExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("functionExpression", location, inferredType);
+  void not(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void ifNullBeforeRhs(Location location) {}
+  void nullLiteral(ExpressionJudgment judgment, Location location,
+      bool isSynthetic, DartType inferredType);
 
-  void ifNullEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('ifNull', location, typeContext);
+  void propertyAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType);
 
-  void ifNullExit(Location location, DartType inferredType) =>
-      genericExpressionExit('ifNull', location, inferredType);
+  void propertyGet(ExpressionJudgment judgment, Location location,
+      Reference member, DartType inferredType);
 
-  void ifStatementEnter(Location location) =>
-      genericStatementEnter('ifStatement', location);
+  void propertyGetCall(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void ifStatementExit(Location location) =>
-      genericStatementExit('ifStatement', location);
+  void propertySet(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void indexAssignAfterReceiver(Location location, DartType typeContext) {}
+  void redirectingInitializer(InitializerJudgment judgment, Location location,
+      Reference initializerTarget);
 
-  void indexAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("indexAssign", location, typeContext);
+  void rethrow_(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void indexAssignExit(Location location, Reference writeMember,
-          Reference combiner, DartType inferredType) =>
-      genericExpressionExit("indexAssign", location, inferredType);
+  void returnStatement(StatementJudgment judgment, Location location);
 
-  void intLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("intLiteral", location, typeContext);
+  void staticAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference writeMember,
+      DartType writeContext,
+      Reference combiner,
+      DartType inferredType);
 
-  void intLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("intLiteral", location, inferredType);
+  void staticGet(ExpressionJudgment judgment, Location location,
+      Reference expressionTarget, DartType inferredType);
 
-  void invalidInitializerEnter(Location location) =>
-      genericInitializerEnter("invalidInitializer", location);
+  void staticInvocation(
+      ExpressionJudgment judgment,
+      Location location,
+      Reference expressionTarget,
+      List<DartType> expressionArgumentsTypes,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType);
 
-  void invalidInitializerExit(Location location) =>
-      genericInitializerExit("invalidInitializer", location);
+  void stringConcatenation(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void isExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("isExpression", location, typeContext);
+  void stringLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void isExpressionExit(
-          Location location, DartType testedType, DartType inferredType) =>
-      genericExpressionExit("isExpression", location, inferredType);
+  void superInitializer(InitializerJudgment judgment, Location location);
 
-  void isNotExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("isNotExpression", location, typeContext);
+  void switchStatement(StatementJudgment judgment, Location location);
 
-  void isNotExpressionExit(
-          Location location, DartType type, DartType inferredType) =>
-      genericExpressionExit("isNotExpression", location, inferredType);
+  void symbolLiteral(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void labeledStatementEnter(Location location) =>
-      genericStatementEnter('labeledStatement', location);
+  void thisExpression(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void labeledStatementExit(Location location) =>
-      genericStatementExit('labeledStatement', location);
+  void throw_(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void listLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("listLiteral", location, typeContext);
+  void tryCatch(StatementJudgment judgment, Location location);
 
-  void listLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("listLiteral", location, inferredType);
+  void tryFinally(StatementJudgment judgment, Location location);
 
-  void logicalExpressionBeforeRhs(Location location) {}
+  void typeLiteral(ExpressionJudgment judgment, Location location,
+      Reference expressionType, DartType inferredType);
 
-  void logicalExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("logicalExpression", location, typeContext);
-
-  void logicalExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("logicalExpression", location, inferredType);
-
-  void mapLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("mapLiteral", location, typeContext);
-
-  void mapLiteralExit(Location location, DartType typeContext) =>
-      genericExpressionExit("mapLiteral", location, typeContext);
-
-  void methodInvocationBeforeArgs(Location location, bool isImplicitCall) {}
-
-  void methodInvocationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("methodInvocation", location, typeContext);
-
-  void methodInvocationExit(
-          Location resultOffset,
-          List<DartType> argumentsTypes,
-          bool isImplicitCall,
-          Reference interfaceMember,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("methodInvocation", resultOffset, inferredType);
-
-  void methodInvocationExitCall(
-          Location resultOffset,
-          List<DartType> argumentsTypes,
-          bool isImplicitCall,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("methodInvocation", resultOffset, inferredType);
-
-  void namedFunctionExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("namedFunctionExpression", location, typeContext);
-
-  void namedFunctionExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("namedFunctionExpression", location, inferredType);
-
-  void notEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("not", location, typeContext);
-
-  void notExit(Location location, DartType inferredType) =>
-      genericExpressionExit("not", location, inferredType);
-
-  void nullLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("nullLiteral", location, typeContext);
-
-  void nullLiteralExit(
-          Location location, bool isSynthetic, DartType inferredType) =>
-      genericExpressionExit("nullLiteral", location, inferredType);
-
-  void propertyAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertyAssign", location, typeContext);
-
-  void propertyAssignExit(Location location, Reference writeMember,
-          DartType writeContext, Reference combiner, DartType inferredType) =>
-      genericExpressionExit("propertyAssign", location, inferredType);
-
-  void propertyGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertyGet", location, typeContext);
-
-  void propertyGetExit(
-          Location location, Reference member, DartType inferredType) =>
-      genericExpressionExit("propertyGet", location, inferredType);
-
-  void propertyGetExitCall(Location location, DartType inferredType) =>
-      genericExpressionExit("propertyGet", location, inferredType);
-
-  void propertySetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("propertySet", location, typeContext);
-
-  void propertySetExit(Location location, DartType inferredType) =>
-      genericExpressionExit("propertySet", location, inferredType);
-
-  void redirectingInitializerEnter(
-          Location location, Reference initializerTarget) =>
-      genericInitializerEnter("redirectingInitializer", location);
-
-  void redirectingInitializerExit(Location location) =>
-      genericInitializerExit("redirectingInitializer", location);
-
-  void rethrowEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('rethrow', location, typeContext);
-
-  void rethrowExit(Location location, DartType inferredType) =>
-      genericExpressionExit('rethrow', location, inferredType);
-
-  void returnStatementEnter(Location location) =>
-      genericStatementEnter('returnStatement', location);
-
-  void returnStatementExit(Location location) =>
-      genericStatementExit('returnStatement', location);
-
-  void staticAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("staticAssign", location, typeContext);
-
-  void staticAssignExit(Location location, Reference writeMember,
-          DartType writeContext, Reference combiner, DartType inferredType) =>
-      genericExpressionExit("staticAssign", location, inferredType);
-
-  void staticGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("staticGet", location, typeContext);
-
-  void staticGetExit(Location location, Reference expressionTarget,
-          DartType inferredType) =>
-      genericExpressionExit("staticGet", location, inferredType);
-
-  void staticInvocationEnter(Location location,
-          Location expressionArgumentsLocation, DartType typeContext) =>
-      genericExpressionEnter("staticInvocation", location, typeContext);
-
-  void staticInvocationExit(
-          Location location,
-          Reference expressionTarget,
-          List<DartType> expressionArgumentsTypes,
-          FunctionType calleeType,
-          Substitution substitution,
-          DartType inferredType) =>
-      genericExpressionExit("staticInvocation", location, inferredType);
-
-  void stringConcatenationEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("stringConcatenation", location, typeContext);
-
-  void stringConcatenationExit(Location location, DartType inferredType) =>
-      genericExpressionExit("stringConcatenation", location, inferredType);
-
-  void stringLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("StringLiteral", location, typeContext);
-
-  void stringLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("StringLiteral", location, inferredType);
-
-  void superInitializerEnter(Location location) =>
-      genericInitializerEnter("superInitializer", location);
-
-  void superInitializerExit(Location location) =>
-      genericInitializerExit("superInitializer", location);
-
-  void switchStatementEnter(Location location) =>
-      genericStatementEnter('switchStatement', location);
-
-  void switchStatementExit(Location location) =>
-      genericStatementExit('switchStatement', location);
-
-  void symbolLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("symbolLiteral", location, typeContext);
-
-  void symbolLiteralExit(Location location, DartType inferredType) =>
-      genericExpressionExit("symbolLiteral", location, inferredType);
-
-  void thisExpressionEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("thisExpression", location, typeContext);
-
-  void thisExpressionExit(Location location, DartType inferredType) =>
-      genericExpressionExit("thisExpression", location, inferredType);
-
-  void throwEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter('throw', location, typeContext);
-
-  void throwExit(Location location, DartType inferredType) =>
-      genericExpressionExit('throw', location, inferredType);
-
-  void tryCatchEnter(Location location) =>
-      genericStatementEnter('tryCatch', location);
-
-  void tryCatchExit(Location location) =>
-      genericStatementExit('tryCatch', location);
-
-  void tryFinallyEnter(Location location) =>
-      genericStatementEnter('tryFinally', location);
-
-  void tryFinallyExit(Location location) =>
-      genericStatementExit('tryFinally', location);
-
-  void typeLiteralEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("typeLiteral", location, typeContext);
-
-  void typeLiteralExit(
-          Location location, Reference expressionType, DartType inferredType) =>
-      genericExpressionExit("typeLiteral", location, inferredType);
-
-  void variableAssignEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableAssign", location, typeContext);
-
-  void variableAssignExit(
-          Location location,
-          DartType writeContext,
-          Declaration writeVariable,
-          Reference combiner,
-          DartType inferredType) =>
-      genericExpressionExit("variableAssign", location, inferredType);
-
-  void variableDeclarationEnter(Location location) =>
-      genericStatementEnter('variableDeclaration', location);
-
-  void variableDeclarationExit(
-          Location location, DartType statementType, DartType inferredType) =>
-      genericStatementExit('variableDeclaration', location);
-
-  void variableGetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableGet", location, typeContext);
-
-  void variableGetExit(Location location, bool isInCascade,
-          Declaration expressionVariable, DartType inferredType) =>
-      genericExpressionExit("variableGet", location, inferredType);
-
-  void variableSetEnter(Location location, DartType typeContext) =>
-      genericExpressionEnter("variableSet", location, typeContext);
+  void variableAssign(
+      ExpressionJudgment judgment,
+      Location location,
+      DartType writeContext,
+      Declaration writeVariable,
+      Reference combiner,
+      DartType inferredType);
 
-  void variableSetExit(Location location, DartType inferredType) =>
-      genericExpressionExit("variableSet", location, inferredType);
+  void variableDeclaration(StatementJudgment judgment, Location location,
+      DartType statementType, DartType inferredType);
 
-  void whileStatementEnter(Location location) =>
-      genericStatementEnter("whileStatement", location);
+  void variableGet(ExpressionJudgment judgment, Location location,
+      bool isInCascade, Declaration expressionVariable, DartType inferredType);
 
-  void whileStatementExit(Location location) =>
-      genericStatementExit("whileStatement", location);
+  void variableSet(
+      ExpressionJudgment judgment, Location location, DartType inferredType);
 
-  void yieldStatementEnter(Location location) =>
-      genericStatementEnter('yieldStatement', location);
+  void whileStatement(StatementJudgment judgment, Location location);
 
-  void yieldStatementExit(Location location) =>
-      genericStatementExit('yieldStatement', location);
+  void yieldStatement(StatementJudgment judgment, Location location);
 
-  void storePrefixInfo(Location location, PrefixInfo prefixInfo) {}
+  void storePrefixInfo(Location location, PrefixInfo prefixInfo);
 
   void storeClassReference(
-      Location location, Reference reference, DartType rawType) {}
+      Location location, Reference reference, DartType rawType);
+}
+
+/// Kernel implementation of TypeInferenceListener; does nothing.
+///
+/// TODO(paulberry): fuse this with KernelFactory.
+class KernelTypeInferenceListener
+    implements TypeInferenceListener<int, int, Node, int> {
+  @override
+  void asExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void assertInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void assertStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void awaitExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void block(StatementJudgment judgment, location) {}
+
+  @override
+  void boolLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void breakStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void cascadeExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void catchStatement(
+      Catch judgment,
+      location,
+      DartType guardType,
+      exceptionLocation,
+      DartType exceptionType,
+      stackTraceLocation,
+      DartType stackTraceType) {}
+
+  @override
+  void conditionalExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void constructorInvocation(ExpressionJudgment judgment, location,
+      expressionTarget, DartType inferredType) {}
+
+  @override
+  void continueSwitchStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void deferredCheck(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void doStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void doubleLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void expressionStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void fieldInitializer(
+      InitializerJudgment judgment, location, initializerField) {}
+
+  @override
+  void forInStatement(
+      StatementJudgment judgment,
+      location,
+      variableLocation,
+      DartType variableType,
+      writeLocation,
+      DartType writeVariableType,
+      writeVariable,
+      writeTarget) {}
+
+  @override
+  void forStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void functionDeclaration(
+      StatementJudgment judgment, location, FunctionType inferredType) {}
+
+  @override
+  void functionExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void ifNull(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void ifStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void indexAssign(ExpressionJudgment judgment, location, writeMember, combiner,
+      DartType inferredType) {}
+
+  @override
+  void intLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void invalidInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void isExpression(ExpressionJudgment judgment, location, DartType testedType,
+      DartType inferredType) {}
+
+  @override
+  void isNotExpression(ExpressionJudgment judgment, location, DartType type,
+      DartType inferredType) {}
+
+  @override
+  void labeledStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void listLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void logicalExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void mapLiteral(
+      ExpressionJudgment judgment, location, DartType typeContext) {}
+
+  @override
+  void methodInvocation(
+      ExpressionJudgment judgment,
+      resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      interfaceMember,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void methodInvocationCall(
+      ExpressionJudgment judgment,
+      resultOffset,
+      List<DartType> argumentsTypes,
+      bool isImplicitCall,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void namedFunctionExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void not(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void nullLiteral(ExpressionJudgment judgment, location, bool isSynthetic,
+      DartType inferredType) {}
+
+  @override
+  void propertyAssign(ExpressionJudgment judgment, location, writeMember,
+      DartType writeContext, combiner, DartType inferredType) {}
+
+  @override
+  void propertyGet(
+      ExpressionJudgment judgment, location, member, DartType inferredType) {}
+
+  @override
+  void propertyGetCall(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void propertySet(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void redirectingInitializer(
+      InitializerJudgment judgment, location, initializerTarget) {}
+
+  @override
+  void rethrow_(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void returnStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void staticAssign(ExpressionJudgment judgment, location, writeMember,
+      DartType writeContext, combiner, DartType inferredType) {}
+
+  @override
+  void staticGet(ExpressionJudgment judgment, location, expressionTarget,
+      DartType inferredType) {}
+
+  @override
+  void staticInvocation(
+      ExpressionJudgment judgment,
+      location,
+      expressionTarget,
+      List<DartType> expressionArgumentsTypes,
+      FunctionType calleeType,
+      Substitution substitution,
+      DartType inferredType) {}
+
+  @override
+  void storeClassReference(location, reference, DartType rawType) {}
+
+  @override
+  void storePrefixInfo(location, prefixInfo) {}
+
+  @override
+  void stringConcatenation(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void stringLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void superInitializer(InitializerJudgment judgment, location) {}
+
+  @override
+  void switchStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void symbolLiteral(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void thisExpression(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void throw_(ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void tryCatch(StatementJudgment judgment, location) {}
+
+  @override
+  void tryFinally(StatementJudgment judgment, location) {}
+
+  @override
+  void typeLiteral(ExpressionJudgment judgment, location, expressionType,
+      DartType inferredType) {}
+
+  @override
+  void variableAssign(ExpressionJudgment judgment, location,
+      DartType writeContext, writeVariable, combiner, DartType inferredType) {}
+
+  @override
+  void variableDeclaration(StatementJudgment judgment, location,
+      DartType statementType, DartType inferredType) {}
+
+  @override
+  void variableGet(ExpressionJudgment judgment, location, bool isInCascade,
+      expressionVariable, DartType inferredType) {}
+
+  @override
+  void variableSet(
+      ExpressionJudgment judgment, location, DartType inferredType) {}
+
+  @override
+  void whileStatement(StatementJudgment judgment, location) {}
+
+  @override
+  void yieldStatement(StatementJudgment judgment, location) {}
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 95e550b..521c12f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -1425,12 +1425,10 @@
       Object interfaceMember,
       Name methodName,
       Arguments arguments}) {
-    listener.methodInvocationEnter(expression.fileOffset, typeContext);
     // First infer the receiver so we can look up the method that was invoked.
     var receiverType = receiver == null
         ? thisType
         : inferExpression(factory, receiver, const UnknownType(), true);
-    listener.methodInvocationBeforeArgs(expression.fileOffset, isImplicitCall);
     if (strongMode) {
       receiverVariable?.type = receiverType;
     }
@@ -1462,7 +1460,8 @@
         ? arguments.fileOffset
         : expression.fileOffset;
     if (identical(interfaceMember, 'call')) {
-      listener.methodInvocationExitCall(
+      listener.methodInvocationCall(
+          expression,
           resultOffset,
           arguments.types,
           isImplicitCall,
@@ -1482,7 +1481,8 @@
             templateImplicitCallOfNonMethod.withArguments(receiverType));
         parent?.replaceChild(expression, errorNode);
       }
-      listener.methodInvocationExit(
+      listener.methodInvocation(
+          expression,
           resultOffset,
           arguments.types,
           isImplicitCall,
@@ -1521,7 +1521,6 @@
       PropertyGet desugaredGet,
       Object interfaceMember,
       Name propertyName}) {
-    listener.propertyGetEnter(expression.fileOffset, typeContext);
     // First infer the receiver so we can look up the getter that was invoked.
     DartType receiverType;
     if (receiver == null) {
@@ -1557,10 +1556,10 @@
           instantiateTearOff(inferredType, typeContext, replacedExpression);
     }
     if (identical(interfaceMember, 'call')) {
-      listener.propertyGetExitCall(expression.fileOffset, inferredType);
+      listener.propertyGetCall(expression, expression.fileOffset, inferredType);
     } else {
-      listener.propertyGetExit(
-          expression.fileOffset, interfaceMember, inferredType);
+      listener.propertyGet(
+          expression, expression.fileOffset, interfaceMember, inferredType);
     }
     expression.inferredType = inferredType;
   }
diff --git a/pkg/front_end/test/fasta/parser/type_info_test.dart b/pkg/front_end/test/fasta/parser/type_info_test.dart
index 1299b8d..9889ccd 100644
--- a/pkg/front_end/test/fasta/parser/type_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/type_info_test.dart
@@ -284,6 +284,7 @@
       'beginTypeVariables <',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -316,6 +317,7 @@
       'beginTypeVariables <',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -684,6 +686,7 @@
           'beginTypeVariables <',
           'beginMetadataStar T',
           'endMetadataStar 0',
+          'handleIdentifier T typeVariableDeclaration',
           'beginTypeVariable T',
           'handleNoType T',
           'endTypeVariable > null',
@@ -692,6 +695,7 @@
           'beginTypeVariables <',
           'beginMetadataStar T',
           'endMetadataStar 0',
+          'handleIdentifier T typeVariableDeclaration',
           'beginTypeVariable T',
           'handleNoType T',
           'endTypeVariable > null',
@@ -861,6 +865,7 @@
       'beginTypeVariables <',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -1038,11 +1043,13 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -1052,6 +1059,7 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleIdentifier T typeReference',
       'handleNoTypeArguments >',
@@ -1063,6 +1071,7 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleIdentifier T typeReference',
       'handleNoTypeArguments >',
@@ -1074,6 +1083,7 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleIdentifier List typeReference',
       'beginTypeArguments <',
@@ -1089,11 +1099,13 @@
       'beginTypeVariables <',
       'beginMetadataStar R',
       'endMetadataStar 0',
+      'handleIdentifier R typeVariableDeclaration',
       'beginTypeVariable R',
       'handleNoType R',
       'endTypeVariable , null',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoTypeVariables (',
       'beginFunctionType void',
@@ -1113,11 +1125,13 @@
       'handleNoArguments S',
       'endMetadata @ null S',
       'endMetadataStar 1',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -1133,11 +1147,13 @@
       'endArguments 0 ( )',
       'endMetadata @ null S',
       'endMetadataStar 1',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -1158,11 +1174,13 @@
       'handleNoArguments S',
       'endMetadata @ null S',
       'endMetadataStar 2',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
+      'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
       'handleNoType T',
       'endTypeVariable > null',
@@ -1177,6 +1195,7 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable Function null',
@@ -1189,6 +1208,7 @@
       'beginTypeVariables <',
       'beginMetadataStar void',
       'endMetadataStar 0',
+      'handleIdentifier  typeVariableDeclaration',
       'beginTypeVariable ',
       'handleNoType ',
       'endTypeVariable void null',
@@ -1200,6 +1220,7 @@
       'beginTypeVariables <',
       'beginMetadataStar S',
       'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
       'handleNoType S',
       'endTypeVariable < null',
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 7a258a5..cc1fb23 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -96,6 +96,7 @@
 kernel/test/*: RuntimeError, OK # Issue 26103. Timers are not supported.
 
 [ $runtime == vm ]
+analysis_server/test/benchmarks_test: Pass, Slow
 analysis_server/test/completion_test: Pass, Slow
 analysis_server/test/integration/analysis/error_test: Pass, Slow
 analysis_server/test/integration/analysis/lint_test: Pass, Slow
@@ -255,7 +256,6 @@
 front_end/tool/perf_test: Slow, Pass
 
 [ $runtime == vm && $checked ]
-analysis_server/test/benchmarks_test: Pass, Slow
 analysis_server/test/completion_test: Pass, Slow
 analysis_server/test/integration/edit/sort_members_test: Pass, Slow
 analysis_server/test/services/correction/fix_test: Pass, Slow
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index c0c07ff..753bb61 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -133,7 +133,7 @@
 type ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
   Byte tag = 19;
   CanonicalNameReference instantiatingClass;
-  ConstantIndex typeArguments;
+  List<DartType> types;
 }
 
 type ConstantContextOffset extends ConstantPoolEntry {
@@ -896,16 +896,15 @@
 
 class ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
   final Reference _instantiatingClassRef;
-  final int _typeArgumentsConstantIndex;
+  final List<DartType> typeArgs;
 
   Class get instantiatingClass => _instantiatingClassRef.asClass;
 
   ConstantTypeArgumentsForInstanceAllocation(
-      Class instantiatingClass, int typeArgumentsConstantIndex)
-      : this.byReference(
-            instantiatingClass.reference, typeArgumentsConstantIndex);
+      Class instantiatingClass, List<DartType> typeArgs)
+      : this.byReference(instantiatingClass.reference, typeArgs);
   ConstantTypeArgumentsForInstanceAllocation.byReference(
-      this._instantiatingClassRef, this._typeArgumentsConstantIndex);
+      this._instantiatingClassRef, this.typeArgs);
 
   @override
   ConstantTag get tag => ConstantTag.kTypeArgumentsForInstanceAllocation;
@@ -914,27 +913,29 @@
   void writeValueToBinary(BinarySink sink) {
     sink.writeCanonicalNameReference(
         getCanonicalNameOfClass(instantiatingClass));
-    sink.writeUInt30(_typeArgumentsConstantIndex);
+    sink.writeUInt30(typeArgs.length);
+    typeArgs.forEach(sink.writeDartType);
   }
 
   ConstantTypeArgumentsForInstanceAllocation.readFromBinary(BinarySource source)
       : _instantiatingClassRef =
             source.readCanonicalNameReference().getReference(),
-        _typeArgumentsConstantIndex = source.readUInt();
+        typeArgs = new List<DartType>.generate(
+            source.readUInt(), (_) => source.readDartType());
 
   @override
   String toString() =>
-      'TypeArgumentsForInstanceAllocation $instantiatingClass type-args CP#$_typeArgumentsConstantIndex';
+      'TypeArgumentsForInstanceAllocation $instantiatingClass $typeArgs';
 
   @override
   int get hashCode =>
-      _combineHashes(instantiatingClass.hashCode, _typeArgumentsConstantIndex);
+      _combineHashes(instantiatingClass.hashCode, listHashCode(typeArgs));
 
   @override
   bool operator ==(other) =>
       other is ConstantTypeArgumentsForInstanceAllocation &&
       this.instantiatingClass == other.instantiatingClass &&
-      this._typeArgumentsConstantIndex == other._typeArgumentsConstantIndex;
+      listEquals(this.typeArgs, other.typeArgs);
 }
 
 class ConstantContextOffset extends ConstantPoolEntry {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 953ae1c..599d4c1 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -150,13 +150,10 @@
     final function = enclosingMember.function;
     assert(function != null);
 
-    if (locals.hasTypeArgsVar) {
-      asm.emitPush(locals.typeArgsVarIndexInFrame);
-    } else if (enclosingMember is Procedure &&
-        (enclosingMember as Procedure).isFactory) {
-      // Null type arguments are passed to factory constructors even if class
-      // is not generic. TODO(alexmarkov): Clean this up.
-      _genPushNull();
+    if (locals.hasFactoryTypeArgsVar) {
+      asm.emitPush(locals.getVarIndexInFrame(locals.factoryTypeArgsVar));
+    } else if (locals.hasFunctionTypeArgsVar) {
+      asm.emitPush(locals.functionTypeArgsVarIndexInFrame);
     }
     if (locals.hasReceiver) {
       asm.emitPush(locals.getVarIndexInFrame(locals.receiverVar));
@@ -326,12 +323,12 @@
 
   void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
     int typeArgsCPIndex() {
-      int cpIndex = cp.add(new ConstantTypeArguments(typeArgs));
       if (instantiatingClass != null) {
-        cpIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation(
-            instantiatingClass, cpIndex));
+        return cp.add(new ConstantTypeArgumentsForInstanceAllocation(
+            instantiatingClass, typeArgs));
+      } else {
+        return cp.add(new ConstantTypeArguments(typeArgs));
       }
-      return cpIndex;
     }
 
     if (typeArgs.isEmpty || !hasTypeParameters(typeArgs)) {
@@ -341,7 +338,14 @@
         _genPushInstantiatorTypeArguments();
       } else {
         _genPushInstantiatorAndFunctionTypeArguments(typeArgs);
-        asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex());
+        // TODO(alexmarkov): Optimize type arguments instantiation
+        // by passing rA = 1 in InstantiateTypeArgumentsTOS.
+        // For this purpose, we need to detect if type arguments
+        // would be all-dynamic in case of all-dynamic instantiator and
+        // function type arguments.
+        // Corresponding check is implemented in VM in
+        // TypeArguments::IsRawWhenInstantiatedFromRaw.
+        asm.emitInstantiateTypeArgumentsTOS(0, typeArgsCPIndex());
       }
     }
   }
@@ -364,10 +368,16 @@
 
   void _genPushInstantiatorTypeArguments() {
     if (instantiatorTypeArguments != null) {
-      _genPushReceiver();
-      final int cpIndex =
-          cp.add(new ConstantTypeArgumentsFieldOffset(enclosingClass));
-      asm.emitLoadFieldTOS(cpIndex);
+      if (locals.hasFactoryTypeArgsVar) {
+        assert(enclosingMember is Procedure &&
+            (enclosingMember as Procedure).isFactory);
+        _genLoadVar(locals.factoryTypeArgsVar);
+      } else {
+        _genPushReceiver();
+        final int cpIndex =
+            cp.add(new ConstantTypeArgumentsFieldOffset(enclosingClass));
+        asm.emitLoadFieldTOS(cpIndex);
+      }
     } else {
       _genPushNull();
     }
@@ -416,8 +426,8 @@
   }
 
   void _genPushFunctionTypeArguments() {
-    if (locals.hasTypeArgsVar) {
-      asm.emitPush(locals.typeArgsVarIndexInFrame);
+    if (locals.hasFunctionTypeArgsVar) {
+      asm.emitPush(locals.functionTypeArgsVarIndexInFrame);
     } else {
       _genPushNull();
     }
@@ -536,10 +546,17 @@
   void start(Member node) {
     enclosingClass = node.enclosingClass;
     enclosingMember = node;
-    if (enclosingMember.isInstanceMember || enclosingMember is Constructor) {
+    if (node.isInstanceMember ||
+        node is Constructor ||
+        (node is Procedure && node.isFactory)) {
       if (enclosingClass.typeParameters.isNotEmpty) {
         classTypeParameters =
             new Set<TypeParameter>.from(enclosingClass.typeParameters);
+        // Treat type arguments of factory constructors as class
+        // type parameters.
+        if (node is Procedure && node.isFactory) {
+          classTypeParameters.addAll(node.function.typeParameters);
+        }
       }
       if (hasInstantiatorTypeArguments(enclosingClass)) {
         final typeParameters = enclosingClass.typeParameters
@@ -670,22 +687,22 @@
       asm.emitPopLocal(locals.contextVarIndexInFrame);
     }
 
-    if (locals.hasTypeArgsVar && isClosure) {
+    if (locals.hasFunctionTypeArgsVar && isClosure) {
       if (function.typeParameters.isNotEmpty) {
         final int numParentTypeArgs = locals.numParentTypeArguments;
-        asm.emitPush(locals.typeArgsVarIndexInFrame);
+        asm.emitPush(locals.functionTypeArgsVarIndexInFrame);
         asm.emitPush(locals.closureVarIndexInFrame);
         asm.emitLoadFieldTOS(
             cp.add(new ConstantFieldOffset(closureFunctionTypeArguments)));
         _genPushInt(numParentTypeArgs);
         _genPushInt(numParentTypeArgs + function.typeParameters.length);
         _genStaticCall(prependTypeArguments, new ConstantArgDesc(4), 4);
-        asm.emitPopLocal(locals.typeArgsVarIndexInFrame);
+        asm.emitPopLocal(locals.functionTypeArgsVarIndexInFrame);
       } else {
         asm.emitPush(locals.closureVarIndexInFrame);
         asm.emitLoadFieldTOS(
             cp.add(new ConstantFieldOffset(closureFunctionTypeArguments)));
-        asm.emitPopLocal(locals.typeArgsVarIndexInFrame);
+        asm.emitPopLocal(locals.functionTypeArgsVarIndexInFrame);
       }
     }
 
@@ -699,6 +716,9 @@
 
     if (locals.hasCapturedParameters) {
       // Copy captured parameters to their respective locations in the context.
+      if (locals.hasFactoryTypeArgsVar) {
+        _copyParamIfCaptured(locals.factoryTypeArgsVar);
+      }
       if (locals.hasReceiver) {
         _copyParamIfCaptured(locals.receiverVar);
       }
@@ -1234,7 +1254,11 @@
       }
     }
 
-    _genStaticCall(mapFromLiteral, new ConstantArgDesc(1, numTypeArgs: 1), 2);
+    // Map._fromLiteral is a factory constructor.
+    // Type arguments passed to a factory constructor are counted as a normal
+    // argument and not counted in number of type arguments.
+    assert(mapFromLiteral.isFactory);
+    _genStaticCall(mapFromLiteral, new ConstantArgDesc(2, numTypeArgs: 0), 2);
   }
 
   @override
@@ -1246,9 +1270,12 @@
         cp.add(new ConstantArgDesc.fromArguments(args, hasReceiver: true));
     final icdataIndex = cp.add(
         new ConstantICData(InvocationKind.method, node.name, argDescIndex));
+    final totalArgCount = args.positional.length +
+        args.named.length +
+        1 /* receiver */ +
+        (args.types.isNotEmpty ? 1 : 0) /* type arguments */;
     // TODO(alexmarkov): figure out when generate InstanceCall2 (2 checked arguments).
-    asm.emitInstanceCall1(
-        args.positional.length + args.named.length + 1, icdataIndex);
+    asm.emitInstanceCall1(totalArgCount, icdataIndex);
   }
 
   @override
@@ -1285,7 +1312,7 @@
           'Unsupported SuperMethodInvocation without target');
     }
     if (target is Procedure && !target.isGetter) {
-      _genStaticCallWithArgs(target, args);
+      _genStaticCallWithArgs(target, args, hasReceiver: true);
     } else {
       throw new UnsupportedOperationError(
           'Unsupported SuperMethodInvocation with target ${target.runtimeType} $target');
@@ -1378,11 +1405,20 @@
 
   @override
   visitStaticInvocation(StaticInvocation node) {
-    final args = node.arguments;
-    if (node.target.isFactory && args.types.isEmpty) {
-      // VM needs type arguments for every invocation of a factory constructor.
-      // TODO(alexmarkov): Clean this up.
-      _genPushNull();
+    Arguments args = node.arguments;
+    if (node.target.isFactory) {
+      final constructedClass = node.target.enclosingClass;
+      if (hasInstantiatorTypeArguments(constructedClass)) {
+        _genTypeArguments(args.types,
+            instantiatingClass: node.target.enclosingClass);
+      } else {
+        assert(args.types.isEmpty);
+        // VM needs type arguments for every invocation of a factory
+        // constructor. TODO(alexmarkov): Clean this up.
+        _genPushNull();
+      }
+      args =
+          new Arguments(node.arguments.positional, named: node.arguments.named);
     }
     _genArguments(null, args);
     _genStaticCallWithArgs(node.target, args, isFactory: node.target.isFactory);
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index d779939..5bea5f6 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -88,11 +88,17 @@
           .scratchVar ??
       (throw 'Scratch variable is not declared in ${_currentFrame.function}'));
 
-  int get typeArgsVarIndexInFrame => getVarIndexInFrame(_currentFrame
-          .typeArgsVar ??
-      (throw 'TypeArgs variable is not declared in ${_currentFrame.function}'));
+  int get functionTypeArgsVarIndexInFrame => getVarIndexInFrame(_currentFrame
+          .functionTypeArgsVar ??
+      (throw 'FunctionTypeArgs variable is not declared in ${_currentFrame.function}'));
 
-  bool get hasTypeArgsVar => _currentFrame.typeArgsVar != null;
+  bool get hasFunctionTypeArgsVar => _currentFrame.functionTypeArgsVar != null;
+
+  VariableDeclaration get factoryTypeArgsVar =>
+      _currentFrame.factoryTypeArgsVar ??
+      (throw 'FactoryTypeArgs variable is not declared in ${_currentFrame.function}');
+
+  bool get hasFactoryTypeArgsVar => _currentFrame.factoryTypeArgsVar != null;
 
   VariableDeclaration get receiverVar =>
       _currentFrame.receiverVar ??
@@ -204,7 +210,8 @@
   bool isDartSync = true;
   bool isSyncYielding = false;
   VariableDeclaration receiverVar;
-  VariableDeclaration typeArgsVar;
+  VariableDeclaration functionTypeArgsVar;
+  VariableDeclaration factoryTypeArgsVar;
   VariableDeclaration closureVar;
   VariableDeclaration contextVar;
   VariableDeclaration scratchVar;
@@ -275,15 +282,29 @@
       _currentFrame.isSyncYielding =
           function.asyncMarker == AsyncMarker.SyncYielding;
 
-      _currentFrame.numTypeArguments =
-          (_currentFrame.parent?.numTypeArguments ?? 0) +
-              function.typeParameters.length;
+      if (node is Procedure && node.isFactory) {
+        assert(_currentFrame.parent == null);
+        _currentFrame.numTypeArguments = 0;
+        _currentFrame.factoryTypeArgsVar =
+            new VariableDeclaration(':type_arguments');
+        _declareVariable(_currentFrame.factoryTypeArgsVar);
+      } else {
+        _currentFrame.numTypeArguments =
+            (_currentFrame.parent?.numTypeArguments ?? 0) +
+                function.typeParameters.length;
 
-      if (_currentFrame.numTypeArguments > 0) {
-        _currentFrame.typeArgsVar =
-            new VariableDeclaration(':function_type_arguments_var');
-        _declareVariable(_currentFrame.typeArgsVar);
+        if (_currentFrame.numTypeArguments > 0) {
+          _currentFrame.functionTypeArgsVar =
+              new VariableDeclaration(':function_type_arguments_var');
+          _declareVariable(_currentFrame.functionTypeArgsVar);
+        }
+
+        if (_currentFrame.parent?.factoryTypeArgsVar != null) {
+          _currentFrame.factoryTypeArgsVar =
+              _currentFrame.parent.factoryTypeArgsVar;
+        }
       }
+
       if (node is Constructor || (node is Procedure && !node.isStatic)) {
         _currentFrame.receiverVar = new VariableDeclaration('this');
         _declareVariable(_currentFrame.receiverVar);
@@ -383,7 +404,7 @@
     final transient = new Set<VariableDeclaration>();
     transient
       ..addAll([
-        _currentFrame.typeArgsVar,
+        _currentFrame.functionTypeArgsVar,
         _currentFrame.closureVar,
         _currentFrame.contextVar,
         _currentFrame.scratchVar,
@@ -501,8 +522,15 @@
 
   @override
   visitTypeParameterType(TypeParameterType node) {
-    if (node.parameter.parent is Class) {
+    var parent = node.parameter.parent;
+    if (parent is Class) {
       _useThis();
+    } else if (parent is FunctionNode) {
+      parent = parent.parent;
+      if (parent is Procedure && parent.isFactory) {
+        assert(_currentFrame.factoryTypeArgsVar != null);
+        _useVariable(_currentFrame.factoryTypeArgsVar);
+      }
     }
     node.visitChildren(this);
   }
@@ -746,13 +774,11 @@
             function.namedParameters.any(locals.isCaptured);
 
     int count = 0;
-    if (hasTypeArgs) {
-      assert(!locals.isCaptured(_currentFrame.typeArgsVar));
-      _allocateParameter(_currentFrame.typeArgsVar, count++);
-    } else if (isFactory) {
-      // Null type arguments are passed to factory constructors even if class
-      // is not generic. TODO(alexmarkov): Clean this up.
-      count++;
+    if (isFactory) {
+      _allocateParameter(_currentFrame.factoryTypeArgsVar, count++);
+    } else if (hasTypeArgs) {
+      assert(!locals.isCaptured(_currentFrame.functionTypeArgsVar));
+      _allocateParameter(_currentFrame.functionTypeArgsVar, count++);
     }
     if (hasReceiver) {
       _allocateParameter(_currentFrame.receiverVar, count++);
@@ -776,7 +802,7 @@
   }
 
   void _allocateSpecialVariables() {
-    _ensureVariableAllocated(_currentFrame.typeArgsVar);
+    _ensureVariableAllocated(_currentFrame.functionTypeArgsVar);
     _ensureVariableAllocated(_currentFrame.contextVar);
     _ensureVariableAllocated(_currentFrame.scratchVar);
   }
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index f9bc6de..60a3f58 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -80,7 +80,7 @@
 }
 ConstantPool {
   [0] = ContextOffset parent
-  [1] = TypeArgs [dart.core::int]
+  [1] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
   [2] = ArgDesc num-args 1, num-type-args 0, names []
   [3] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#2
   [4] = ContextOffset var [3]
@@ -105,7 +105,7 @@
   [23] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#2
   [24] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#2
   [25] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#2
-  [26] = TypeArgs [dynamic]
+  [26] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
   [27] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#13
   [28] = ICData get target-name 'future', arg-desc CP#2
 }
@@ -306,7 +306,7 @@
   [0] = ContextOffset parent
   [1] = ContextOffset var [0]
   [2] = ContextOffset var [1]
-  [3] = TypeArgs [dart.core::int]
+  [3] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
   [4] = ArgDesc num-args 1, num-type-args 0, names []
   [5] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#4
   [6] = ContextOffset var [8]
@@ -339,7 +339,7 @@
   [33] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#4
   [34] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#4
   [35] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#4
-  [36] = TypeArgs [dynamic]
+  [36] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
   [37] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#22
   [38] = ICData get target-name 'future', arg-desc CP#4
 }
@@ -619,7 +619,7 @@
 ConstantPool {
   [0] = ContextOffset parent
   [1] = ContextOffset var [0]
-  [2] = TypeArgs [dart.core::int]
+  [2] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
   [3] = ArgDesc num-args 1, num-type-args 0, names []
   [4] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#3
   [5] = ContextOffset var [9]
@@ -666,7 +666,7 @@
   [46] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#3
   [47] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#3
   [48] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#3
-  [49] = TypeArgs [dynamic]
+  [49] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
   [50] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#18
   [51] = ICData get target-name 'future', arg-desc CP#3
 }
@@ -1127,7 +1127,7 @@
   [1] = ContextOffset var [0]
   [2] = ContextOffset var [1]
   [3] = ContextOffset var [2]
-  [4] = TypeArgs [dart.core::int]
+  [4] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
   [5] = ArgDesc num-args 1, num-type-args 0, names []
   [6] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#5
   [7] = ContextOffset var [12]
@@ -1181,7 +1181,7 @@
   [55] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#5
   [56] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#5
   [57] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#5
-  [58] = TypeArgs [dynamic]
+  [58] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
   [59] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#24
   [60] = ICData get target-name 'future', arg-desc CP#5
 }
@@ -1810,7 +1810,7 @@
   [2] = Int 3
   [3] = ClosureFunction nested () → dart.async::Future<dart.core::int> /* originally async */ ;
   [4] = FieldOffset dart.core::_Closure::_context
-  [5] = TypeArgs [dart.core::int]
+  [5] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
   [6] = ArgDesc num-args 1, num-type-args 0, names []
   [7] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#6
   [8] = ContextOffset var [8]
@@ -1847,7 +1847,7 @@
   [39] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#6
   [40] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#6
   [41] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#6
-  [42] = TypeArgs [dynamic]
+  [42] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
   [43] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#24
   [44] = ICData get target-name 'future', arg-desc CP#6
   [45] = EndClosureFunctionScope
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index cd54d28..2080a18 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -222,11 +222,11 @@
   PopLocal             r2
   PushConstant         CP#49
   Push                 r2
-  InstanceCall1        1, CP#50
+  InstanceCall1        2, CP#50
   Drop1
   PushConstant         CP#51
   Push                 r2
-  InstanceCall1        1, CP#52
+  InstanceCall1        2, CP#52
   Drop1
   PushConstant         CP#18
   ReturnTOS
@@ -362,7 +362,7 @@
   LoadFieldTOS         CP#1
   LoadFieldTOS         CP#17
   Push                 r0
-  InstantiateTypeArgumentsTOS 1, CP#34
+  InstantiateTypeArgumentsTOS 0, CP#34
   PushConstant         CP#36
   IndirectStaticCall   1, CP#35
   Drop1
@@ -443,11 +443,11 @@
   PopLocal             r2
   PushConstant         CP#43
   Push                 r2
-  InstanceCall1        1, CP#45
+  InstanceCall1        2, CP#45
   Drop1
   PushConstant         CP#46
   Push                 r2
-  InstanceCall1        1, CP#47
+  InstanceCall1        2, CP#47
   Drop1
   PushConstant         CP#18
   ReturnTOS
@@ -1351,58 +1351,56 @@
   Entry                1
   CheckStack
   PushConstant         CP#0
-  PushConstant         CP#3
+  PushConstant         CP#2
   PushConstant         CP#1
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#5
-  IndirectStaticCall   1, CP#4
+  PushConstant         CP#4
+  IndirectStaticCall   1, CP#3
   Drop1
-  InstanceCall1        1, CP#7
+  InstanceCall1        2, CP#6
   Drop1
+  PushConstant         CP#7
+  PushConstant         CP#2
+  PushConstant         CP#1
+  AllocateT
+  StoreLocal           r0
+  Push                 r0
   PushConstant         CP#8
-  PushConstant         CP#3
+  IndirectStaticCall   1, CP#3
+  Drop1
+  InstanceCall1        2, CP#9
+  Drop1
+  PushConstant         CP#7
+  PushConstant         CP#10
   PushConstant         CP#1
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#9
-  IndirectStaticCall   1, CP#4
+  PushConstant         CP#11
+  IndirectStaticCall   1, CP#3
   Drop1
-  InstanceCall1        1, CP#10
+  InstanceCall1        2, CP#12
   Drop1
-  PushConstant         CP#8
-  PushConstant         CP#12
-  PushConstant         CP#1
-  AllocateT
-  StoreLocal           r0
-  Push                 r0
   PushConstant         CP#13
-  IndirectStaticCall   1, CP#4
-  Drop1
-  InstanceCall1        1, CP#14
-  Drop1
-  PushConstant         CP#15
   ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgs [#lib::C3, #lib::C4]
   [1] = Class #lib::A
-  [2] = TypeArgs [#lib::C1, #lib::C2]
-  [3] = TypeArgumentsForInstanceAllocation #lib::A type-args CP#2
-  [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target '#lib::A::', arg-desc CP#4
-  [6] = ArgDesc num-args 1, num-type-args 2, names []
-  [7] = ICData target-name 'foo', arg-desc CP#6
-  [8] = TypeArgs [dart.core::List<#lib::C3>, dart.core::List<#lib::C4>]
-  [9] = StaticICData target '#lib::A::', arg-desc CP#4
-  [10] = ICData target-name 'foo', arg-desc CP#6
-  [11] = TypeArgs [dart.core::List<#lib::C1>, dart.core::List<#lib::C2>]
-  [12] = TypeArgumentsForInstanceAllocation #lib::A type-args CP#11
-  [13] = StaticICData target '#lib::A::', arg-desc CP#4
-  [14] = ICData target-name 'foo', arg-desc CP#6
-  [15] = Null
+  [2] = TypeArgumentsForInstanceAllocation #lib::A [#lib::C1, #lib::C2]
+  [3] = ArgDesc num-args 1, num-type-args 0, names []
+  [4] = StaticICData target '#lib::A::', arg-desc CP#3
+  [5] = ArgDesc num-args 1, num-type-args 2, names []
+  [6] = ICData target-name 'foo', arg-desc CP#5
+  [7] = TypeArgs [dart.core::List<#lib::C3>, dart.core::List<#lib::C4>]
+  [8] = StaticICData target '#lib::A::', arg-desc CP#3
+  [9] = ICData target-name 'foo', arg-desc CP#5
+  [10] = TypeArgumentsForInstanceAllocation #lib::A [dart.core::List<#lib::C1>, dart.core::List<#lib::C2>]
+  [11] = StaticICData target '#lib::A::', arg-desc CP#3
+  [12] = ICData target-name 'foo', arg-desc CP#5
+  [13] = Null
 }
 ]static method callA() → void {
   new self::A::•<self::C1, self::C2>().{self::A::foo}<self::C3, self::C4>();
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index be92aa5..2ba4d37 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -292,15 +292,15 @@
 Bytecode {
   Entry                1
   CheckStack
-  PushConstant         CP#1
   Push                 FP[-5]
-  InstantiateTypeArgumentsTOS 1, CP#3
+  PushConstant         CP#1
+  InstantiateTypeArgumentsTOS 0, CP#2
   PushConstant         CP#0
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#5
-  IndirectStaticCall   1, CP#4
+  PushConstant         CP#4
+  IndirectStaticCall   1, CP#3
   Drop1
   ReturnTOS
   PushConstant         CP#1
@@ -309,10 +309,9 @@
 ConstantPool {
   [0] = Class #lib::H
   [1] = Null
-  [2] = TypeArgs [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
-  [3] = TypeArgumentsForInstanceAllocation #lib::H type-args CP#2
-  [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target '#lib::H::', arg-desc CP#4
+  [2] = TypeArgumentsForInstanceAllocation #lib::H [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
+  [3] = ArgDesc num-args 1, num-type-args 0, names []
+  [4] = StaticICData target '#lib::H::', arg-desc CP#3
 }
 ]  static factory test_factory<K extends core::Object = dynamic, V extends core::Object = dynamic>() → self::G<self::G::test_factory::K, self::G::test_factory::V>
     return new self::H::•<core::String, self::G::test_factory::K, self::G::test_factory::V>();
@@ -391,13 +390,12 @@
 Bytecode {
   Entry                0
   CheckStack
-  PushConstant         CP#0
-  NativeCall           CP#1
+  Push                 FP[-5]
+  NativeCall           CP#0
   ReturnTOS
 }
 ConstantPool {
-  [0] = Null
-  [1] = NativeEntry agent_J
+  [0] = NativeEntry agent_J
 }
 ]  @_in::ExternalName::•("agent_J")
   external static factory •() → self::J;
@@ -430,41 +428,39 @@
 Bytecode {
   Entry                1
   CheckStack
-  PushConstant         CP#2
+  PushConstant         CP#1
   PushConstant         CP#0
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#3
-  PushConstant         CP#5
-  IndirectStaticCall   2, CP#4
+  PushConstant         CP#2
+  PushConstant         CP#4
+  IndirectStaticCall   2, CP#3
   Drop1
   Drop1
-  PushConstant         CP#8
   PushConstant         CP#6
+  PushConstant         CP#5
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#10
-  IndirectStaticCall   1, CP#9
+  PushConstant         CP#8
+  IndirectStaticCall   1, CP#7
   Drop1
   Drop1
-  PushConstant         CP#11
+  PushConstant         CP#9
   ReturnTOS
 }
 ConstantPool {
   [0] = Class #lib::A
-  [1] = TypeArgs []
-  [2] = TypeArgumentsForInstanceAllocation #lib::A type-args CP#1
-  [3] = String 'hi'
-  [4] = ArgDesc num-args 2, num-type-args 0, names []
-  [5] = StaticICData target '#lib::A::', arg-desc CP#4
-  [6] = Class #lib::B
-  [7] = TypeArgs [dart.core::int]
-  [8] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#7
-  [9] = ArgDesc num-args 1, num-type-args 0, names []
-  [10] = StaticICData target '#lib::B::', arg-desc CP#9
-  [11] = Null
+  [1] = TypeArgumentsForInstanceAllocation #lib::A []
+  [2] = String 'hi'
+  [3] = ArgDesc num-args 2, num-type-args 0, names []
+  [4] = StaticICData target '#lib::A::', arg-desc CP#3
+  [5] = Class #lib::B
+  [6] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::int]
+  [7] = ArgDesc num-args 1, num-type-args 0, names []
+  [8] = StaticICData target '#lib::B::', arg-desc CP#7
+  [9] = Null
 }
 ]static method foo2() → void {
   new self::A::•("hi");
@@ -476,13 +472,13 @@
   CheckStack
   PushConstant         CP#1
   Push                 FP[-5]
-  InstantiateTypeArgumentsTOS 1, CP#3
+  InstantiateTypeArgumentsTOS 0, CP#2
   PushConstant         CP#0
   AllocateT
   StoreLocal           r0
   Push                 r0
-  PushConstant         CP#5
-  IndirectStaticCall   1, CP#4
+  PushConstant         CP#4
+  IndirectStaticCall   1, CP#3
   Drop1
   Drop1
   PushConstant         CP#1
@@ -491,10 +487,9 @@
 ConstantPool {
   [0] = Class #lib::B
   [1] = Null
-  [2] = TypeArgs [dart.core::List<#lib::foo3::T>]
-  [3] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#2
-  [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target '#lib::B::', arg-desc CP#4
+  [2] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::List<#lib::foo3::T>]
+  [3] = ArgDesc num-args 1, num-type-args 0, names []
+  [4] = StaticICData target '#lib::B::', arg-desc CP#3
 }
 ]static method foo3<T extends core::Object = dynamic>() → void {
   new self::B::•<core::List<self::foo3::T>>();
@@ -511,7 +506,7 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::int, dart.core::List<dart.core::String>]
+  [0] = TypeArgumentsForInstanceAllocation #lib::G [dart.core::int, dart.core::List<dart.core::String>]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
   [2] = StaticICData target '#lib::G::test_factory', arg-desc CP#1
   [3] = Null
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index c248ce0..a3c9ec2 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -553,7 +553,7 @@
   Drop1
   PushConstant         CP#16
   Push                 FP[-8]
-  InstantiateTypeArgumentsTOS 1, CP#17
+  InstantiateTypeArgumentsTOS 0, CP#17
   PushConstant         CP#18
   PushConstant         CP#19
   IndirectStaticCall   2, CP#7
@@ -562,7 +562,7 @@
   Drop1
   PushConstant         CP#16
   Push                 FP[-8]
-  InstantiateTypeArgumentsTOS 1, CP#21
+  InstantiateTypeArgumentsTOS 0, CP#21
   PushConstant         CP#1
   PushConstant         CP#5
   CreateArrayTOS
@@ -591,7 +591,7 @@
   [4] = Int 1
   [5] = Int 2
   [6] = Int 3
-  [7] = ArgDesc num-args 1, num-type-args 1, names []
+  [7] = ArgDesc num-args 2, num-type-args 0, names []
   [8] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#7
   [9] = ArgDesc num-args 1, num-type-args 0, names []
   [10] = StaticICData target 'dart.core::print', arg-desc CP#9
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index eb5a775..cf66e57 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -253,7 +253,7 @@
   Push                 FP[-6]
   LoadFieldTOS         CP#0
   PushConstant         CP#1
-  InstantiateTypeArgumentsTOS 1, CP#2
+  InstantiateTypeArgumentsTOS 0, CP#2
   StoreLocal           r1
   Push                 r1
   PushConstant         CP#3
diff --git a/pkg/vm/tool/test_bytecode b/pkg/vm/tool/test_bytecode
index 7b05997..3c1d0e1 100755
--- a/pkg/vm/tool/test_bytecode
+++ b/pkg/vm/tool/test_bytecode
@@ -68,7 +68,7 @@
 #   $BUILD_DIR/test_bytecode.dill $BUILD_DIR/test_bytecode.txt
 
 # Required flags.
-DART_VM_FLAGS="--preview-dart-2 --optimization-counter-threshold=-1 $DART_VM_FLAGS"
+DART_VM_FLAGS="--optimization-counter-threshold=-1 $DART_VM_FLAGS"
 
 # Optional flags examples. Uncomment as needed.
 # DART_VM_FLAGS="--force-log-flush --isolate-log-filter=\"\" $DART_VM_FLAGS"
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index d7734c1..4d54a54 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1509,6 +1509,14 @@
 DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
 
 /**
+ * Returns the name for the provided class type.
+ *
+ * \return A valid string handle if no error occurs during the
+ *   operation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type);
+
+/**
  * Returns the name for the provided function or method.
  *
  * \return A valid string handle if no error occurs during the
@@ -1553,6 +1561,15 @@
  */
 DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
 
+/**
+ * Returns a handle to the library which contains class.
+ *
+ * \return A valid handle to the library with owns class, null if the class
+ *   has no library or an error handle if the argument is not a valid handle
+ *   to a class type.
+ */
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type);
+
 /*
  * =============================
  * Numbers, Integers and Doubles
@@ -1686,6 +1703,20 @@
 DART_EXPORT Dart_Handle Dart_GetClosure(Dart_Handle library,
                                         Dart_Handle function_name);
 
+/**
+ * Returns a closure of static function 'function_name' in the class 'class_name'
+ * in the exported namespace of specified 'library'.
+ *
+ * \param library Library object
+ * \param cls_type Type object representing a Class
+ * \param function_name Name of the static function in the class
+ *
+ * \return A valid Dart instance if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+                                                    Dart_Handle cls_type,
+                                                    Dart_Handle function_name);
+
 /*
  * ========
  * Booleans
diff --git a/runtime/platform/atomic.h b/runtime/platform/atomic.h
index 4a468e5..37836e0 100644
--- a/runtime/platform/atomic.h
+++ b/runtime/platform/atomic.h
@@ -30,6 +30,10 @@
   // Atomically decrement the value at p by 'value'.
   static void DecrementBy(intptr_t* p, intptr_t value);
 
+  // Atomically perform { tmp = *ptr; *ptr = (tmp OP value); return tmp; }.
+  static uint32_t FetchOrRelaxedUint32(uint32_t* ptr, uint32_t value);
+  static uint32_t FetchAndRelaxedUint32(uint32_t* ptr, uint32_t value);
+
   // Atomically compare *ptr to old_value, and if equal, store new_value.
   // Returns the original value at ptr.
   static uword CompareAndSwapWord(uword* ptr, uword old_value, uword new_value);
diff --git a/runtime/platform/atomic_android.h b/runtime/platform/atomic_android.h
index 42dda56..f95ba02 100644
--- a/runtime/platform/atomic_android.h
+++ b/runtime/platform/atomic_android.h
@@ -46,6 +46,16 @@
   __sync_fetch_and_sub(p, value);
 }
 
+inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
+                                                       uint32_t value) {
+  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
+                                                        uint32_t value) {
+  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
+}
+
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_fuchsia.h b/runtime/platform/atomic_fuchsia.h
index 5434fb7..2883e1e 100644
--- a/runtime/platform/atomic_fuchsia.h
+++ b/runtime/platform/atomic_fuchsia.h
@@ -43,6 +43,16 @@
   __sync_fetch_and_sub(p, value);
 }
 
+inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
+                                                       uint32_t value) {
+  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
+                                                        uint32_t value) {
+  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
+}
+
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_linux.h b/runtime/platform/atomic_linux.h
index 3db8d73..fd1773f 100644
--- a/runtime/platform/atomic_linux.h
+++ b/runtime/platform/atomic_linux.h
@@ -46,6 +46,16 @@
   __sync_fetch_and_sub(p, value);
 }
 
+inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
+                                                       uint32_t value) {
+  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
+                                                        uint32_t value) {
+  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
+}
+
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_macos.h b/runtime/platform/atomic_macos.h
index b08ba4f..b0bd31f 100644
--- a/runtime/platform/atomic_macos.h
+++ b/runtime/platform/atomic_macos.h
@@ -46,6 +46,16 @@
   __sync_fetch_and_sub(p, value);
 }
 
+inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
+                                                       uint32_t value) {
+  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
+                                                        uint32_t value) {
+  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
+}
+
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_win.h b/runtime/platform/atomic_win.h
index f7fc322..5e6db1b 100644
--- a/runtime/platform/atomic_win.h
+++ b/runtime/platform/atomic_win.h
@@ -102,6 +102,18 @@
 #endif
 }
 
+inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
+                                                       uint32_t value) {
+  return static_cast<uint32_t>(InterlockedOrNoFence(
+      reinterpret_cast<LONG*>(ptr), static_cast<LONG>(value)));
+}
+
+inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
+                                                        uint32_t value) {
+  return static_cast<uint32_t>(InterlockedAndNoFence(
+      reinterpret_cast<LONG*>(ptr), static_cast<LONG>(value)));
+}
+
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/vm/atomic_test.cc b/runtime/vm/atomic_test.cc
index c9afc97..5f1d565 100644
--- a/runtime/vm/atomic_test.cc
+++ b/runtime/vm/atomic_test.cc
@@ -50,6 +50,20 @@
   EXPECT_EQ(static_cast<intptr_t>(1), v);
 }
 
+VM_UNIT_TEST_CASE(FetchOrRelaxed) {
+  uint32_t v = 42;
+  uint32_t previous = AtomicOperations::FetchOrRelaxedUint32(&v, 3);
+  EXPECT_EQ(static_cast<uint32_t>(42), previous);
+  EXPECT_EQ(static_cast<uint32_t>(43), v);
+}
+
+VM_UNIT_TEST_CASE(FetchAndRelaxed) {
+  uint32_t v = 42;
+  uint32_t previous = AtomicOperations::FetchAndRelaxedUint32(&v, 3);
+  EXPECT_EQ(static_cast<uint32_t>(42), previous);
+  EXPECT_EQ(static_cast<uint32_t>(2), v);
+}
+
 VM_UNIT_TEST_CASE(LoadRelaxed) {
   uword v = 42;
   EXPECT_EQ(static_cast<uword>(42), AtomicOperations::LoadRelaxed(&v));
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index c418f4f..49bded1 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1581,7 +1581,7 @@
   Label done;
   StoreIntoObjectFilter(object, value, &done, can_be_smi, kJumpToNoUpdate);
   // A store buffer update is required.
-  RegList regs = (1 << CODE_REG) | (1 << LR);
+  RegList regs = (1 << LR);
   if (value != R0) {
     regs |= (1 << R0);  // Preserve R0.
   }
@@ -1590,7 +1590,6 @@
     mov(R0, Operand(object));
   }
   ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset()));
-  ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   blx(LR);
   PopList(regs);
   Bind(&done);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 305b3a9..dee219c 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -953,7 +953,6 @@
     mov(R0, object);
   }
   ldr(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset()));
-  ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   blr(TMP);
   Pop(LR);
   if (value != R0) {
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 76f051f..4f06cd8 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1258,12 +1258,8 @@
   if (object != RDX) {
     movq(RDX, object);
   }
-  pushq(CODE_REG);
-  movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset()));
-  movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
-  call(TMP);
+  call(Address(THR, Thread::update_store_buffer_entry_point_offset()));
 
-  popq(CODE_REG);
   if (value != RDX) popq(RDX);
   Bind(&done);
 }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 6a91d21..c62e0dd 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -1193,9 +1193,15 @@
       __ movq(destination.reg(), source.reg());
     } else {
       ASSERT(destination.IsStackSlot());
+      ASSERT((destination.base_reg() != FPREG) ||
+             ((-VariableIndexForFrameSlot(destination.stack_index())) <
+              compiler_->StackSize()));
       __ movq(destination.ToStackSlotAddress(), source.reg());
     }
   } else if (source.IsStackSlot()) {
+    ASSERT((source.base_reg() != FPREG) ||
+           ((-VariableIndexForFrameSlot(source.stack_index())) <
+            compiler_->StackSize()));
     if (destination.IsRegister()) {
       __ movq(destination.reg(), source.ToStackSlotAddress());
     } else {
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index 4b6a94d..6ddddb9 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -2977,7 +2977,19 @@
   last_used_register_ = -1;
 #endif
 
-  cpu_spill_slot_count_ = spill_slots_.length();
+#if defined(TARGET_ARCH_DBC)
+  // Spilling is unsupported on DBC.
+  ASSERT(spill_slots_.length() == 0);
+  cpu_spill_slot_count_ = 0;
+#else
+  // GraphEntryInstr::fixed_slot_count() stack slots are reserved for catch
+  // entries. When allocating a spill slot, AllocateSpillSlotFor() accounts for
+  // these reserved slots and allocates spill slots on top of them.
+  // However, if there are no spill slots allocated, we still need to reserve
+  // slots for catch entries in the spill area.
+  cpu_spill_slot_count_ = Utils::Maximum(
+      spill_slots_.length(), flow_graph_.graph_entry()->fixed_slot_count());
+#endif
   spill_slots_.Clear();
   quad_spill_slots_.Clear();
   untagged_spill_slots_.Clear();
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index c440292..19a77d3 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1203,15 +1203,14 @@
         obj = H.DartSymbolPlain(builder_->ReadStringReference()).raw();
         ASSERT(String::Cast(obj).IsSymbol());
         break;
-      case kTypeArgumentsForInstanceAllocation: {
+      case ConstantPoolTag::kTypeArgumentsForInstanceAllocation: {
         cls =
             H.LookupClassByKernelClass(builder_->ReadCanonicalNameReference());
-        intptr_t type_args_index = builder_->ReadUInt();
-        ASSERT(type_args_index < i);
-        type_args ^= pool.ObjectAt(type_args_index);
-        elem = Type::New(cls, type_args, TokenPosition::kNoSource);
-        elem = ClassFinalizer::FinalizeType(cls, Type::Cast(elem));
-        obj = Type::Cast(elem).arguments();
+        obj =
+            builder_->type_translator_
+                .BuildInstantiatedTypeArguments(cls, builder_->ReadListLength())
+                .raw();
+        ASSERT(obj.IsNull() || obj.IsTypeArguments());
       } break;
       case ConstantPoolTag::kContextOffset: {
         intptr_t index = builder_->ReadUInt();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index ebee057..761e198 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2066,6 +2066,20 @@
   return Api::NewHandle(T, func.UserVisibleName());
 }
 
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type) {
+  DARTSCOPE(Thread::Current());
+  const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+  if (type_obj.IsNull()) {
+    RETURN_TYPE_ERROR(Z, cls_type, Type);
+  }
+  const Class& klass = Class::Handle(Z, type_obj.type_class());
+  if (klass.IsNull()) {
+    return Api::NewError(
+        "cls_type must be a Type object which represents a Class.");
+  }
+  return Api::NewHandle(T, klass.UserVisibleName());
+}
+
 DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
   DARTSCOPE(Thread::Current());
   const Function& func = Api::UnwrapFunctionHandle(Z, function);
@@ -2120,6 +2134,21 @@
   return Api::NewHandle(T, rf);
 }
 
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type) {
+  DARTSCOPE(Thread::Current());
+  const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+  const Class& klass = Class::Handle(Z, type_obj.type_class());
+  if (klass.IsNull()) {
+    return Api::NewError(
+        "cls_type must be a Type object which represents a Class.");
+  }
+  const Library& library = Library::Handle(klass.library());
+  if (library.IsNull()) {
+    return Dart_Null();
+  }
+  return Api::NewHandle(Thread::Current(), library.raw());
+}
+
 // --- Numbers, Integers and Doubles ----
 
 DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
@@ -2300,6 +2329,53 @@
   return Api::NewHandle(T, lib.GetFunctionClosure(name));
 }
 
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+                                                    Dart_Handle cls_type,
+                                                    Dart_Handle function_name) {
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(Z, library);
+  if (lib.IsNull()) {
+    RETURN_TYPE_ERROR(Z, library, Library);
+  }
+
+  const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+  if (type_obj.IsNull()) {
+    RETURN_TYPE_ERROR(Z, cls_type, Type);
+  }
+
+  const Class& klass = Class::Handle(Z, type_obj.type_class());
+  if (klass.IsNull()) {
+    return Api::NewError(
+        "cls_type must be a Type object which represents a Class");
+  }
+
+  const String& func_name = Api::UnwrapStringHandle(Z, function_name);
+  if (func_name.IsNull()) {
+    RETURN_TYPE_ERROR(Z, function_name, String);
+  }
+
+  Function& func =
+      Function::Handle(Z, klass.LookupStaticFunctionAllowPrivate(func_name));
+  if (func.IsNull()) {
+    return Dart_Null();
+  }
+
+  if (!func.is_static()) {
+    return Api::NewError("function_name must refer to a static method.");
+  }
+
+  if (func.kind() != RawFunction::kRegularFunction) {
+    return Api::NewError(
+        "function_name must be the name of a regular function.");
+  }
+  func ^= func.ImplicitClosureFunction();
+  if (func.IsNull()) {
+    return Dart_Null();
+  }
+
+  return Api::NewHandle(T, func.ImplicitStaticClosure());
+}
+
 // --- Booleans ----
 
 DART_EXPORT Dart_Handle Dart_True() {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index b88dd39..8b7fe6b 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -898,6 +898,77 @@
   EXPECT(strstr(result, "getInt"));
 }
 
+TEST_CASE(DartAPI_GetStaticMethodClosure) {
+  const char* kScriptChars =
+      "class Foo {\n"
+      "  static int getInt() {\n"
+      "    return 1;\n"
+      "  }\n"
+      "  double getDouble() {\n"
+      "    return 1.0;\n"
+      "  }\n"
+      "}\n";
+  // Create a test library and Load up a test script in it.
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  EXPECT_VALID(lib);
+  Dart_Handle foo_cls = Dart_GetClass(lib, NewString("Foo"));
+  EXPECT_VALID(foo_cls);
+
+  Dart_Handle closure =
+      Dart_GetStaticMethodClosure(lib, foo_cls, NewString("getInt"));
+  EXPECT_VALID(closure);
+  EXPECT(Dart_IsClosure(closure));
+  Dart_Handle closure_str = Dart_ToString(closure);
+  const char* result = "";
+  Dart_StringToCString(closure_str, &result);
+  EXPECT_SUBSTRING("getInt", result);
+
+  Dart_Handle function = Dart_ClosureFunction(closure);
+  EXPECT_VALID(function);
+  EXPECT(Dart_IsFunction(function));
+  Dart_Handle func_str = Dart_ToString(function);
+  Dart_StringToCString(func_str, &result);
+  EXPECT_SUBSTRING("getInt", result);
+
+  Dart_Handle cls = Dart_FunctionOwner(function);
+  EXPECT_VALID(cls);
+  EXPECT(Dart_IsInstance(cls));
+  Dart_Handle cls_str = Dart_ClassName(cls);
+  Dart_StringToCString(cls_str, &result);
+  EXPECT_SUBSTRING("Foo", result);
+
+  EXPECT_ERROR(Dart_ClassName(Dart_Null()),
+               "Dart_ClassName expects argument 'cls_type' to be non-null.");
+  EXPECT_ERROR(
+      Dart_GetStaticMethodClosure(Dart_Null(), foo_cls, NewString("getInt")),
+      "Dart_GetStaticMethodClosure expects argument 'library' to be non-null.");
+  EXPECT_ERROR(
+      Dart_GetStaticMethodClosure(lib, Dart_Null(), NewString("getInt")),
+      "Dart_GetStaticMethodClosure expects argument 'cls_type' to be "
+      "non-null.");
+  EXPECT_ERROR(Dart_GetStaticMethodClosure(lib, foo_cls, Dart_Null()),
+               "Dart_GetStaticMethodClosure expects argument 'function_name' "
+               "to be non-null.");
+}
+
+TEST_CASE(DartAPI_ClassLibrary) {
+  Dart_Handle lib = Dart_LookupLibrary(NewString("dart:core"));
+  EXPECT_VALID(lib);
+  Dart_Handle type = Dart_GetType(lib, NewString("int"), 0, NULL);
+  EXPECT_VALID(type);
+  Dart_Handle result = Dart_ClassLibrary(type);
+  EXPECT_VALID(result);
+  Dart_Handle lib_url = Dart_LibraryUrl(result);
+  const char* str = NULL;
+  Dart_StringToCString(lib_url, &str);
+  EXPECT_STREQ("dart:core", str);
+
+  // Case with no library.
+  type = Dart_GetType(lib, NewString("dynamic"), 0, NULL);
+  EXPECT_VALID(type);
+  EXPECT(Dart_IsNull(Dart_ClassLibrary(type)));
+}
+
 TEST_CASE(DartAPI_BooleanValues) {
   Dart_Handle str = NewString("test");
   EXPECT(!Dart_IsBoolean(str));
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 5dbbdd5..2d4305b 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -911,7 +911,13 @@
     RawCode* code = function->ptr()->code_;
     ASSERT(code != StubCode::LazyCompile_entry()->code());
     // TODO(regis): Once we share the same stack, try to invoke directly.
-
+#if defined(DEBUG)
+    if (IsTracingExecution()) {
+      THR_Print("%" Pu64 " ", icount_);
+      THR_Print("invoking compiled %s\n",
+                Function::Handle(function).ToCString());
+    }
+#endif
     // On success, returns a RawInstance.  On failure, a RawError.
     typedef RawObject* (*invokestub)(RawCode * code, RawArray * argdesc,
                                      RawObject * *arg0, Thread * thread);
@@ -953,6 +959,12 @@
   ASSERT(Function::HasBytecode(function));
   // Bytecode was loaded in the above compilation step.
   // Stay in interpreter.
+#if defined(DEBUG)
+  if (IsTracingExecution()) {
+    THR_Print("%" Pu64 " ", icount_);
+    THR_Print("invoking %s\n", Function::Handle(function).ToCString());
+  }
+#endif
   RawCode* bytecode = function->ptr()->bytecode_;
   RawObject** callee_fp = call_top + kKBCDartFrameFixedSize;
   callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
@@ -978,17 +990,17 @@
   RawObject** callee_fp = call_top + kKBCDartFrameFixedSize;
 
   RawFunction* function = FrameFunction(callee_fp);
+  if (Function::HasCode(function) || !Function::HasBytecode(function)) {
+    // TODO(regis): If the function is a dispatcher, execute the dispatch here.
+    return InvokeCompiled(thread, function, argdesc_, call_base, call_top, pc,
+                          FP, SP);
+  }
 #if defined(DEBUG)
   if (IsTracingExecution()) {
     THR_Print("%" Pu64 " ", icount_);
     THR_Print("invoking %s\n", Function::Handle(function).ToCString());
   }
 #endif
-  if (Function::HasCode(function) || !Function::HasBytecode(function)) {
-    // TODO(regis): If the function is a dispatcher, execute the dispatch here.
-    return InvokeCompiled(thread, function, argdesc_, call_base, call_top, pc,
-                          FP, SP);
-  }
   RawCode* bytecode = function->ptr()->bytecode_;
   callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
   callee_fp[kKBCSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index d8b7048..bf7d68f 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -623,28 +623,20 @@
 
   template <class TagBitField>
   void UpdateTagBit(bool value) {
-    uint32_t tags = ptr()->tags_;
-    uint32_t old_tags;
-    do {
-      old_tags = tags;
-      uint32_t new_tags = TagBitField::update(value, old_tags);
-      tags = AtomicOperations::CompareAndSwapUint32(&ptr()->tags_, old_tags,
-                                                    new_tags);
-    } while (tags != old_tags);
+    if (value) {
+      AtomicOperations::FetchOrRelaxedUint32(&ptr()->tags_,
+                                             TagBitField::encode(true));
+    } else {
+      AtomicOperations::FetchAndRelaxedUint32(&ptr()->tags_,
+                                              ~TagBitField::encode(true));
+    }
   }
 
   template <class TagBitField>
   bool TryAcquireTagBit() {
-    uint32_t tags = ptr()->tags_;
-    uint32_t old_tags;
-    do {
-      old_tags = tags;
-      if (TagBitField::decode(tags)) return false;
-      uint32_t new_tags = TagBitField::update(true, old_tags);
-      tags = AtomicOperations::CompareAndSwapUint32(&ptr()->tags_, old_tags,
-                                                    new_tags);
-    } while (tags != old_tags);
-    return true;
+    uint32_t old_tags = AtomicOperations::FetchOrRelaxedUint32(
+        &ptr()->tags_, TagBitField::encode(true));
+    return !TagBitField::decode(old_tags);
   }
 
   // All writes to heap objects should ultimately pass through one of the
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 4069e998..2cbab48 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -90,9 +90,9 @@
 #if !defined(TARGET_ARCH_DBC)
   ASSERT(HasBeenInitialized());
 #if defined(DART_USE_INTERPRETER)
-  // Recognize special marker set up by interpreter in entry frame.
-  if (is_interpreted_frame && (pc & 2) != 0) {
-    return true;
+  if (is_interpreted_frame) {
+    // Recognize special marker set up by interpreter in entry frame.
+    return (pc & 2) != 0;
   }
   {
     uword entry = StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint();
@@ -106,7 +106,7 @@
   uword size = StubCode::InvokeDartCodeSize();
   return (pc >= entry) && (pc < (entry + size));
 #elif defined(DART_USE_INTERPRETER)
-#error "Simultaneous usage of simulator and interpreter not yet supported."
+#error "Simultaneous usage of DBC simulator and interpreter not yet supported."
 #else
   // On DBC we use a special marker PC to signify entry frame because there is
   // no such thing as invocation stub.
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 37aa4b6..493329f 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1030,21 +1030,21 @@
 // Input parameters:
 //   R0: address (i.e. object) being stored into.
 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
-  // Save values being destroyed.
-  __ PushList((1 << R1) | (1 << R2) | (1 << R3));
-
   Label add_to_buffer;
   // Check whether this object has already been remembered. Skip adding to the
   // store buffer if the object is in the store buffer already.
   // Spilled: R1, R2, R3
   // R0: Address being stored
-  __ ldr(R2, FieldAddress(R0, Object::tags_offset()));
-  __ tst(R2, Operand(1 << RawObject::kRememberedBit));
+  __ ldr(TMP, FieldAddress(R0, Object::tags_offset()));
+  __ tst(TMP, Operand(1 << RawObject::kRememberedBit));
   __ b(&add_to_buffer, EQ);
-  __ PopList((1 << R1) | (1 << R2) | (1 << R3));
   __ Ret();
 
   __ Bind(&add_to_buffer);
+
+  // Save values being destroyed.
+  __ PushList((1 << R1) | (1 << R2) | (1 << R3));
+
   // R2: Header word.
   if (TargetCPUFeatures::arm_version() == ARMv5TE) {
 // TODO(21263): Implement 'swp' and use it below.
@@ -1077,24 +1077,27 @@
   // Increment top_ and check for overflow.
   // R2: top_.
   // R1: StoreBufferBlock.
-  Label L;
+  Label overflow;
   __ add(R2, R2, Operand(1));
   __ str(R2, Address(R1, StoreBufferBlock::top_offset()));
   __ CompareImmediate(R2, StoreBufferBlock::kSize);
   // Restore values.
   __ PopList((1 << R1) | (1 << R2) | (1 << R3));
-  __ b(&L, EQ);
+  __ b(&overflow, EQ);
   __ Ret();
 
   // Handle overflow: Call the runtime leaf function.
-  __ Bind(&L);
+  __ Bind(&overflow);
   // Setup frame, push callee-saved registers.
 
+  __ Push(CODE_REG);
+  __ ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   __ EnterCallRuntimeFrame(0 * kWordSize);
   __ mov(R0, Operand(THR));
   __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1);
   // Restore callee-saved registers, tear down frame.
   __ LeaveCallRuntimeFrame();
+  __ Pop(CODE_REG);
   __ Ret();
 }
 
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 647ae0b..c38de9a 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -958,8 +958,138 @@
   __ ret();
 }
 
+// Called when invoking compiled Dart code from interpreted Dart code.
+// Input parameters:
+//   LR : points to return address.
+//   R0 : raw code object of the Dart function to call.
+//   R1 : arguments raw descriptor array.
+//   R2 : address of first argument.
+//   R3 : current thread.
 void StubCode::GenerateInvokeDartCodeFromBytecodeStub(Assembler* assembler) {
-  __ Unimplemented("Interpreter not yet supported");
+#if defined(DART_USE_INTERPRETER)
+  // Copy the C stack pointer (R31) into the stack pointer we'll actually use
+  // to access the stack.
+  __ SetupDartSP();
+  __ EnterFrame(0);
+
+  // Push code object to PC marker slot.
+  __ ldr(TMP,
+         Address(R3, Thread::invoke_dart_code_from_bytecode_stub_offset()));
+  __ Push(TMP);
+
+  // Save the callee-saved registers.
+  for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) {
+    const Register r = static_cast<Register>(i);
+    // We use str instead of the Push macro because we will be pushing the PP
+    // register when it is not holding a pool-pointer since we are coming from
+    // C++ code.
+    __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex));
+  }
+
+  // Save the bottom 64-bits of callee-saved V registers.
+  for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) {
+    const VRegister r = static_cast<VRegister>(i);
+    __ PushDouble(r);
+  }
+
+  // Set up THR, which caches the current thread in Dart code.
+  if (THR != R3) {
+    __ mov(THR, R3);
+  }
+
+  // Save the current VMTag on the stack.
+  __ LoadFromOffset(R4, THR, Thread::vm_tag_offset());
+  __ Push(R4);
+
+  // Mark that the thread is executing Dart code.
+  __ LoadImmediate(R6, VMTag::kDartTagId);
+  __ StoreToOffset(R6, THR, Thread::vm_tag_offset());
+
+  // Save top resource and top exit frame info. Use R6 as a temporary register.
+  // StackFrameIterator reads the top exit frame info saved in this frame.
+  __ LoadFromOffset(R6, THR, Thread::top_resource_offset());
+  __ StoreToOffset(ZR, THR, Thread::top_resource_offset());
+  __ Push(R6);
+  __ LoadFromOffset(R6, THR, Thread::top_exit_frame_info_offset());
+  __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
+  // kExitLinkSlotFromEntryFp must be kept in sync with the code below.
+  ASSERT(kExitLinkSlotFromEntryFp == -22);
+  __ Push(R6);
+
+  // Load arguments descriptor array into R4, which is passed to Dart code.
+  __ mov(R4, R1);
+
+  // Load number of arguments into R5 and adjust count for type arguments.
+  __ LoadFieldFromOffset(R5, R4, ArgumentsDescriptor::count_offset());
+  __ LoadFieldFromOffset(R3, R4, ArgumentsDescriptor::type_args_len_offset());
+  __ AddImmediate(TMP, R5, 1);  // Include the type arguments.
+  __ cmp(R3, Operand(0));
+  __ csinc(R5, R5, TMP, EQ);  // R5 <- (R3 == 0) ? R5 : TMP + 1 (R5 : R5 + 2).
+  __ SmiUntag(R5);
+
+  // R2 points to first argument.
+  // Set up arguments for the Dart call.
+  Label push_arguments;
+  Label done_push_arguments;
+  __ cmp(R5, Operand(0));
+  __ b(&done_push_arguments, EQ);  // check if there are arguments.
+  __ LoadImmediate(R1, 0);
+  __ Bind(&push_arguments);
+  __ ldr(R3, Address(R2));
+  __ Push(R3);
+  __ add(R1, R1, Operand(1));
+  __ add(R2, R2, Operand(kWordSize));
+  __ cmp(R1, Operand(R5));
+  __ b(&push_arguments, LT);
+  __ Bind(&done_push_arguments);
+
+  // We now load the pool pointer(PP) with a GC safe value as we are about to
+  // invoke dart code. We don't need a real object pool here.
+  // Smi zero does not work because ARM64 assumes PP to be untagged.
+  __ LoadObject(PP, Object::null_object());
+
+  // Call the Dart code entrypoint.
+  __ mov(CODE_REG, R0);
+  __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset()));
+  __ blr(R0);  // R4 is the arguments descriptor array.
+
+  // Get rid of arguments pushed on the stack.
+  __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
+
+  // Restore the saved top exit frame info and top resource back into the
+  // Isolate structure. Uses R6 as a temporary register for this.
+  __ Pop(R6);
+  __ StoreToOffset(R6, THR, Thread::top_exit_frame_info_offset());
+  __ Pop(R6);
+  __ StoreToOffset(R6, THR, Thread::top_resource_offset());
+
+  // Restore the current VMTag from the stack.
+  __ Pop(R4);
+  __ StoreToOffset(R4, THR, Thread::vm_tag_offset());
+
+  // Restore the bottom 64-bits of callee-saved V registers.
+  for (int i = kAbiLastPreservedFpuReg; i >= kAbiFirstPreservedFpuReg; i--) {
+    const VRegister r = static_cast<VRegister>(i);
+    __ PopDouble(r);
+  }
+
+  // Restore C++ ABI callee-saved registers.
+  for (int i = kAbiLastPreservedCpuReg; i >= kAbiFirstPreservedCpuReg; i--) {
+    Register r = static_cast<Register>(i);
+    // We use ldr instead of the Pop macro because we will be popping the PP
+    // register when it is not holding a pool-pointer since we are returning to
+    // C++ code. We also skip the dart stack pointer SP, since we are still
+    // using it as the stack pointer.
+    __ ldr(r, Address(SP, 1 * kWordSize, Address::PostIndex));
+  }
+
+  // Restore the frame pointer and C stack pointer and return.
+  __ LeaveFrame();
+  __ RestoreCSP();
+  __ ret();
+#else
+  __ Stop("Not using interpreter");
+#endif  // defined(DART_USE_INTERPRETER)
 }
 
 // Called for inline allocation of contexts.
@@ -1081,8 +1211,7 @@
   // Check whether this object has already been remembered. Skip adding to the
   // store buffer if the object is in the store buffer already.
   __ LoadFieldFromOffset(TMP, R0, Object::tags_offset(), kWord);
-  __ tsti(TMP, Immediate(1 << RawObject::kRememberedBit));
-  __ b(&add_to_buffer, EQ);
+  __ tbz(&add_to_buffer, TMP, RawObject::kRememberedBit);
   __ ret();
 
   __ Bind(&add_to_buffer);
@@ -1102,8 +1231,7 @@
   __ ldxr(R2, R3, kWord);
   __ orri(R2, R2, Immediate(1 << RawObject::kRememberedBit));
   __ stxr(R1, R2, R3, kWord);
-  __ cmp(R1, Operand(1));
-  __ b(&retry, EQ);
+  __ cbnz(&retry, R1);
 
   // Load the StoreBuffer block out of the thread. Then load top_ out of the
   // StoreBufferBlock and add the address to the pointers_.
@@ -1115,7 +1243,7 @@
   // Increment top_ and check for overflow.
   // R2: top_.
   // R1: StoreBufferBlock.
-  Label L;
+  Label overflow;
   __ add(R2, R2, Operand(1));
   __ StoreToOffset(R2, R1, StoreBufferBlock::top_offset(), kUnsignedWord);
   __ CompareImmediate(R2, StoreBufferBlock::kSize);
@@ -1123,18 +1251,21 @@
   __ Pop(R3);
   __ Pop(R2);
   __ Pop(R1);
-  __ b(&L, EQ);
+  __ b(&overflow, EQ);
   __ ret();
 
   // Handle overflow: Call the runtime leaf function.
-  __ Bind(&L);
+  __ Bind(&overflow);
   // Setup frame, push callee-saved registers.
 
+  __ Push(CODE_REG);
+  __ ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   __ EnterCallRuntimeFrame(0 * kWordSize);
   __ mov(R0, THR);
   __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1);
   // Restore callee-saved registers, tear down frame.
   __ LeaveCallRuntimeFrame();
+  __ Pop(CODE_REG);
   __ ret();
 }
 
@@ -1746,8 +1877,115 @@
   __ br(R2);
 }
 
+// Stub for interpreting a function call.
+// R5: IC-Data (for methods).
+// R4: Arguments descriptor.
+// R0: Function.
 void StubCode::GenerateInterpretCallStub(Assembler* assembler) {
-  __ Unimplemented("Interpreter not yet supported");
+#if defined(DART_USE_INTERPRETER)
+  const intptr_t thread_offset = NativeArguments::thread_offset();
+  const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset();
+  const intptr_t argv_offset = NativeArguments::argv_offset();
+  const intptr_t retval_offset = NativeArguments::retval_offset();
+
+  __ SetPrologueOffset();
+  __ EnterStubFrame();
+
+  // Save exit frame information to enable stack walking as we are about
+  // to transition to Dart VM C++ code.
+  __ StoreToOffset(FP, THR, Thread::top_exit_frame_info_offset());
+
+#if defined(DEBUG)
+  {
+    Label ok;
+    // Check that we are always entering from Dart code.
+    __ LoadFromOffset(R8, THR, Thread::vm_tag_offset());
+    __ CompareImmediate(R8, VMTag::kDartTagId);
+    __ b(&ok, EQ);
+    __ Stop("Not coming from Dart code.");
+    __ Bind(&ok);
+  }
+#endif
+
+  // Mark that the thread is executing VM code.
+  __ StoreToOffset(R5, THR, Thread::vm_tag_offset());
+
+  // Setup space on stack for result of the interpreted function call.
+  __ Push(ZR);
+
+  // Set callee-saved R23 to point to return value slot.
+  __ mov(R23, SP);
+
+  // Push first 3 arguments of the interpreted function call.
+  __ Push(R0);  // Function.
+  __ Push(R5);  // ICData/MegamorphicCache.
+  __ Push(R4);  // Arguments descriptor array.
+
+  // Adjust arguments count.
+  __ LoadFieldFromOffset(R3, R4, ArgumentsDescriptor::type_args_len_offset());
+  __ AddImmediate(TMP, R2, 1);  // Include the type arguments.
+  __ cmp(R3, Operand(0));
+  __ csinc(R2, R2, TMP, EQ);  // R2 <- (R3 == 0) ? R2 : TMP + 1 (R2 : R2 + 2).
+
+  // Push 4th Dart argument of the interpreted function call.
+  // R2: Smi-tagged arguments array length.
+  PushArrayOfArguments(assembler);
+  const intptr_t kNumArgs = 4;
+
+  // Reserve space for arguments and align frame before entering C++ world.
+  // NativeArguments are passed in registers.
+  ASSERT(sizeof(NativeArguments) == 4 * kWordSize);
+  __ ReserveAlignedFrameSpace(sizeof(NativeArguments));
+
+  // Pass NativeArguments structure by value and call runtime.
+  // Registers R0, R1, R2, and R3 are used.
+
+  ASSERT(thread_offset == 0 * kWordSize);
+  __ mov(R0, THR);  // Set thread in NativeArgs.
+
+  ASSERT(argc_tag_offset == 1 * kWordSize);
+  __ LoadImmediate(R1, kNumArgs);  // Set argc in NativeArguments.
+
+  ASSERT(argv_offset == 2 * kWordSize);
+  __ AddImmediate(R2, R23, -kWordSize);  // Set argv in NativeArguments.
+
+  ASSERT(retval_offset == 3 * kWordSize);
+  __ mov(R3, R23);  // Set retval in NativeArguments.
+
+  __ StoreToOffset(R0, SP, thread_offset);
+  __ StoreToOffset(R1, SP, argc_tag_offset);
+  __ StoreToOffset(R2, SP, argv_offset);
+  __ StoreToOffset(R3, SP, retval_offset);
+  __ mov(R0, SP);  // Pass the pointer to the NativeArguments.
+
+  // We are entering runtime code, so the C stack pointer must be restored from
+  // the stack limit to the top of the stack. We cache the stack limit address
+  // in a callee-saved register.
+  __ mov(R25, CSP);
+  __ mov(CSP, SP);
+
+  __ LoadImmediate(R5, kInterpretCallRuntimeEntry.GetEntryPoint());
+  __ blr(R5);
+
+  // Restore SP and CSP.
+  __ mov(SP, CSP);
+  __ mov(CSP, R25);
+
+  // Mark that the thread is executing Dart code.
+  __ LoadImmediate(R2, VMTag::kDartTagId);
+  __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
+
+  // Reset exit frame information in Isolate structure.
+  __ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset());
+
+  // Load result of interpreted function call into R0.
+  __ LoadFromOffset(R0, R23, 0);
+
+  __ LeaveStubFrame();
+  __ ret();
+#else
+  __ Stop("Not using interpreter");
+#endif  // defined(DART_USE_INTERPRETER)
 }
 
 // R5: Contains an ICData.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index bdc494b..60a107b 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -961,8 +961,6 @@
   // store buffer if the object is in the store buffer already.
   // Spilled: EAX, ECX
   // EDX: Address being stored
-  Label reload;
-  __ Bind(&reload);
   __ movl(EAX, FieldAddress(EDX, Object::tags_offset()));
   __ testl(EAX, Immediate(1 << RawObject::kRememberedBit));
   __ j(EQUAL, &add_to_buffer, Assembler::kNearJump);
@@ -974,11 +972,10 @@
   // EDX: Address being stored
   // EAX: Current tag value
   __ Bind(&add_to_buffer);
-  __ movl(ECX, EAX);
-  __ orl(ECX, Immediate(1 << RawObject::kRememberedBit));
-  // Compare the tag word with EAX, update to ECX if unchanged.
-  __ LockCmpxchgl(FieldAddress(EDX, Object::tags_offset()), ECX);
-  __ j(NOT_EQUAL, &reload);
+  // lock+orl is an atomic read-modify-write.
+  __ lock();
+  __ orl(FieldAddress(EDX, Object::tags_offset()),
+         Immediate(1 << RawObject::kRememberedBit));
 
   // Load the StoreBuffer block out of the thread. Then load top_ out of the
   // StoreBufferBlock and add the address to the pointers_.
@@ -992,7 +989,7 @@
   // Spilled: EAX, ECX
   // ECX: top_
   // EAX: StoreBufferBlock
-  Label L;
+  Label overflow;
   __ incl(ECX);
   __ movl(Address(EAX, StoreBufferBlock::top_offset()), ECX);
   __ cmpl(ECX, Immediate(StoreBufferBlock::kSize));
@@ -1000,11 +997,11 @@
   // Spilled: EAX, ECX
   __ popl(ECX);
   __ popl(EAX);
-  __ j(EQUAL, &L, Assembler::kNearJump);
+  __ j(EQUAL, &overflow, Assembler::kNearJump);
   __ ret();
 
   // Handle overflow: Call the runtime leaf function.
-  __ Bind(&L);
+  __ Bind(&overflow);
   // Setup frame, push callee-saved registers.
 
   __ EnterCallRuntimeFrame(1 * kWordSize);
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 111357c..22da3fe 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -980,6 +980,7 @@
   __ movq(Address(THR, Thread::top_resource_offset()), Immediate(0));
   __ movq(RAX, Address(THR, Thread::top_exit_frame_info_offset()));
   __ pushq(RAX);
+  __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
 
 // The constant kExitLinkSlotFromEntryFp must be kept in sync with the
 // code below.
@@ -994,8 +995,6 @@
   }
 #endif
 
-  __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0));
-
   // Load arguments descriptor array into R10, which is passed to Dart code.
   __ movq(R10, kArgDescReg);
 
@@ -1015,7 +1014,9 @@
   __ SmiUntag(RBX);
 
   // Compute address of first argument into RDX.
-  ASSERT(kArg0Reg == RDX);
+  if (kArg0Reg != RDX) {  // Different registers on WIN64.
+    __ movq(RDX, kArg0Reg);
+  }
 
   // Set up arguments for the Dart call.
   Label push_arguments;
@@ -1060,7 +1061,7 @@
   __ ret();
 #else
   __ Stop("Not using interpreter");
-#endif
+#endif  // defined(DART_USE_INTERPRETER)
 }
 
 // Called for inline allocation of contexts.
@@ -1193,22 +1194,13 @@
 // Input parameters:
 //   RDX: Address being stored
 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
-  // Save registers being destroyed.
-  __ pushq(RAX);
-  __ pushq(RCX);
-
   Label add_to_buffer;
   // Check whether this object has already been remembered. Skip adding to the
   // store buffer if the object is in the store buffer already.
-  // Spilled: RAX, RCX
   // RDX: Address being stored
-  Label reload;
-  __ Bind(&reload);
-  __ movl(RAX, FieldAddress(RDX, Object::tags_offset()));
-  __ testl(RAX, Immediate(1 << RawObject::kRememberedBit));
+  __ movl(TMP, FieldAddress(RDX, Object::tags_offset()));
+  __ testl(TMP, Immediate(1 << RawObject::kRememberedBit));
   __ j(EQUAL, &add_to_buffer, Assembler::kNearJump);
-  __ popq(RCX);
-  __ popq(RAX);
   __ ret();
 
   // Update the tags that this object has been remembered.
@@ -1217,11 +1209,14 @@
   // RDX: Address being stored
   // RAX: Current tag value
   __ Bind(&add_to_buffer);
-  __ movl(RCX, RAX);
-  __ orl(RCX, Immediate(1 << RawObject::kRememberedBit));
-  // Compare the tag word with RAX, update to RCX if unchanged.
-  __ LockCmpxchgl(FieldAddress(RDX, Object::tags_offset()), RCX);
-  __ j(NOT_EQUAL, &reload);
+  // lock+orl is an atomic read-modify-write.
+  __ lock();
+  __ orl(FieldAddress(RDX, Object::tags_offset()),
+         Immediate(1 << RawObject::kRememberedBit));
+
+  // Save registers being destroyed.
+  __ pushq(RAX);
+  __ pushq(RCX);
 
   // Load the StoreBuffer block out of the thread. Then load top_ out of the
   // StoreBufferBlock and add the address to the pointers_.
@@ -1233,23 +1228,26 @@
   // Increment top_ and check for overflow.
   // RCX: top_
   // RAX: StoreBufferBlock
-  Label L;
+  Label overflow;
   __ incq(RCX);
   __ movl(Address(RAX, StoreBufferBlock::top_offset()), RCX);
   __ cmpl(RCX, Immediate(StoreBufferBlock::kSize));
   // Restore values.
   __ popq(RCX);
   __ popq(RAX);
-  __ j(EQUAL, &L, Assembler::kNearJump);
+  __ j(EQUAL, &overflow, Assembler::kNearJump);
   __ ret();
 
   // Handle overflow: Call the runtime leaf function.
-  __ Bind(&L);
+  __ Bind(&overflow);
   // Setup frame, push callee-saved registers.
+  __ pushq(CODE_REG);
+  __ movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
   __ EnterCallRuntimeFrame(0);
   __ movq(CallingConventions::kArg1Reg, THR);
   __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1);
   __ LeaveCallRuntimeFrame();
+  __ popq(CODE_REG);
   __ ret();
 }
 
@@ -1950,7 +1948,7 @@
   __ ret();
 #else
   __ Stop("Not using interpreter");
-#endif
+#endif  // defined(DART_USE_INTERPRETER)
 }
 
 // RBX: Contains an ICData.
diff --git a/sdk/lib/vmservice/running_isolates.dart b/sdk/lib/vmservice/running_isolates.dart
index 4ef37d1..5e7b6dd 100644
--- a/sdk/lib/vmservice/running_isolates.dart
+++ b/sdk/lib/vmservice/running_isolates.dart
@@ -152,7 +152,11 @@
       return completer.future
           .then((String s) => jsonDecode(s))
           .then((dynamic json) {
-        return json['result']['result']['kernelBytes'];
+        Map<String, dynamic> jsonMap = json;
+        if (jsonMap.containsKey('error')) {
+          throw jsonMap['error'];
+        }
+        return jsonMap['result']['result']['kernelBytes'];
       });
     } else {
       // fallback to compile using kernel service
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/sync_throw_in_constructor_from_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/sync_throw_in_constructor_from_async.dart
index 5889055..610895a 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/sync_throw_in_constructor_from_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/sync_throw_in_constructor_from_async.dart
@@ -17,7 +17,7 @@
 
 class Class {
   @NoInline()
-  /*5:Class*/ Class() {
+  Class() {
     /*6:Class*/ throw '>ExceptionMarker<';
   }
 }
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor.dart
index 2b7780a..6d7a7f2 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor.dart
@@ -11,7 +11,7 @@
 
 class Class {
   @NoInline()
-  /*2:Class*/ Class() {
+  Class() {
     /*3:Class*/ throw '>ExceptionMarker<';
   }
 }
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
index 0120aa3..7d78c18 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace/throw_in_constructor_from_async.dart
@@ -17,7 +17,7 @@
 
 class Class {
   @NoInline()
-  /*2:Class*/ Class() {
-    /*3:Class*/ throw '>ExceptionMarker<';
+  Class() {
+    /*2:Class*/ throw '>ExceptionMarker<';
   }
 }
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
index d9ad5e6..d28f3a2 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -94,6 +94,7 @@
 /// methods.
 const List<LineException> beforeExceptions = const [
   const LineException('wrapException', 'js_helper.dart'),
+  const LineException('throwExpression', 'js_helper.dart'),
 ];
 
 /// Lines allowed after the intended stack trace. Typically from the event
diff --git a/tools/VERSION b/tools/VERSION
index cb38d48..c3f1dcf 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 0
 PATCH 0
 PRERELEASE 64
-PRERELEASE_PATCH 0
+PRERELEASE_PATCH 1