fix #33103, switch dartdevk to use Kernel nSM stubs

Change-Id: I383b36809b1e8b43f9f7a36ca84d8db5da7cef67
Reviewed-on: https://dart-review.googlesource.com/55266
Commit-Queue: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Vijay Menon <vsm@google.com>
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 4888f4b..c53371c 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -77,7 +77,7 @@
         ClosureAnnotator,
         JSTypeRefCodegen,
         NullableTypeInference,
-        SharedCompiler
+        SharedCompiler<LibraryElement>
     implements AstVisitor<JS.Node> {
   final AnalysisContext context;
   final SummaryDataStore summaryData;
@@ -100,9 +100,6 @@
   /// in the SDK to be generated before anything else.
   final _internalSdkFunctions = <JS.ModuleItem>[];
 
-  /// The list of output module items, in the order they need to be emitted in.
-  final _moduleItems = <JS.ModuleItem>[];
-
   /// Table of named and possibly hoisted types.
   TypeTable _typeTable;
 
@@ -121,9 +118,6 @@
   /// In an async* function, this represents the stream controller parameter.
   JS.TemporaryId _asyncStarController;
 
-  // TODO(jmesserly): fuse this with notNull check.
-  final _privateNames =
-      new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
   final _initializingFormalTemps =
       new HashMap<ParameterElement, JS.TemporaryId>();
 
@@ -320,7 +314,7 @@
   }
 
   JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) {
-    if (_moduleItems.isNotEmpty) {
+    if (moduleItems.isNotEmpty) {
       throw new StateError('Can only call emitModule once.');
     }
 
@@ -424,7 +418,7 @@
     items.addAll(_internalSdkFunctions);
 
     // Add the module's code (produced by visiting compilation units, above)
-    _copyAndFlattenBlocks(items, _moduleItems);
+    _copyAndFlattenBlocks(items, moduleItems);
 
     // Build the module.
     return new JS.Program(items, name: _buildUnit.name);
@@ -442,7 +436,7 @@
 
     // Track the module name for each library in the module.
     // This data is only required for debugging.
-    _moduleItems.add(js
+    moduleItems.add(js
         .statement('#.trackLibraries(#, #, ${JSModuleFile.sourceMapHoleID});', [
       runtimeModule,
       js.string(name),
@@ -604,7 +598,7 @@
     // only run this on the outermost function, and not any closures.
     inferNullableTypes(node);
 
-    _moduleItems.add(node.accept(this) as JS.ModuleItem);
+    moduleItems.add(node.accept(this) as JS.ModuleItem);
 
     _currentElement = savedElement;
   }
@@ -667,7 +661,7 @@
       if (isInternalSdk && element is FunctionElement) {
         _internalSdkFunctions.add(item);
       } else {
-        _moduleItems.add(item);
+        moduleItems.add(item);
       }
     }
 
@@ -728,7 +722,7 @@
       if (currentNames.containsKey(export.name)) return null;
 
       var name = _emitTopLevelName(export);
-      _moduleItems.add(js.statement(
+      moduleItems.add(js.statement(
           '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name]));
     }
   }
@@ -1187,7 +1181,7 @@
       // TODO(jmesserly): we could export these symbols, if we want to mark
       // implemented interfaces for user-defined classes.
       var id = new JS.TemporaryId("_is_${classElem.name}_default");
-      _moduleItems.add(
+      moduleItems.add(
           js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
       isClassSymbol = id;
     }
@@ -4284,7 +4278,7 @@
 
   /// Emits a list of top-level field.
   void _emitTopLevelFields(List<VariableDeclaration> fields) {
-    _moduleItems.add(_emitLazyFields(
+    moduleItems.add(_emitLazyFields(
         emitLibraryName(currentLibrary), fields, _emitTopLevelMemberName));
   }
 
@@ -4304,7 +4298,7 @@
           _isJSInvocation(init) ||
           init is InstanceCreationExpression &&
               isSdkInternalRuntime(init.staticElement.library)) {
-        _moduleItems.add(closureAnnotate(
+        moduleItems.add(closureAnnotate(
             js.statement('# = #;', [
               _emitTopLevelName(field.element),
               _visitInitializer(field.initializer, field.element)
@@ -4986,7 +4980,7 @@
     if (_currentFunction == null || usesTypeParams) return jsExpr;
 
     var temp = new JS.TemporaryId('const');
-    _moduleItems.add(js.statement('let #;', [temp]));
+    moduleItems.add(js.statement('let #;', [temp]));
     return js.call('# || (# = #)', [temp, temp, jsExpr]);
   }
 
@@ -5726,7 +5720,7 @@
     var last = name.substring(name.lastIndexOf('.') + 1);
     var jsName = js.string(name, "'");
     if (last.startsWith('_')) {
-      var nativeSymbol = _emitPrivateNameSymbol(currentLibrary, last);
+      var nativeSymbol = emitPrivateNameSymbol(currentLibrary, last);
       return js.call('new #.new(#, #)', [
         _emitConstructorAccess(privateSymbolClass.type),
         jsName,
@@ -6083,7 +6077,7 @@
     }
 
     if (name.startsWith('_')) {
-      return _emitPrivateNameSymbol(currentLibrary, name);
+      return emitPrivateNameSymbol(currentLibrary, name);
     }
 
     useExtension ??= _isSymbolizedMember(type, name);
@@ -6205,17 +6199,6 @@
     return false;
   }
 
-  JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
-    return _privateNames
-        .putIfAbsent(library, () => new HashMap())
-        .putIfAbsent(name, () {
-      var id = new JS.TemporaryId(name);
-      _moduleItems.add(
-          js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
-      return id;
-    });
-  }
-
   /// Returns the canonical name to refer to the Dart library.
   JS.Identifier emitLibraryName(LibraryElement library) {
     // It's either one of the libraries in this module, or it's an import.
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index 10e9782..d2fa9c5 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:collection';
 import '../compiler/js_metalet.dart' as JS;
 import '../compiler/js_names.dart' as JS;
 import '../compiler/js_utils.dart' as JS;
@@ -12,7 +13,7 @@
 ///
 /// This class should only implement functionality that depends purely on JS
 /// classes, rather than on Analyzer/Kernel types.
-abstract class SharedCompiler {
+abstract class SharedCompiler<Library> {
   /// When inside a `[]=` operator, this will be a non-null value that should be
   /// returned by any `return;` statement.
   ///
@@ -22,6 +23,11 @@
   JS.Identifier runtimeModule;
   final namedArgumentTemp = new JS.TemporaryId('opts');
 
+  final _privateNames = new HashMap<Library, HashMap<String, JS.TemporaryId>>();
+
+  /// The list of output module items, in the order they need to be emitted in.
+  final moduleItems = <JS.ModuleItem>[];
+
   /// When compiling the body of a `operator []=` method, this will be non-null
   /// and will indicate the the value that should be returned from any `return;`
   /// statements.
@@ -122,4 +128,19 @@
   JS.Statement runtimeStatement(String code, [args]) {
     return runtimeCall(code, args).toStatement();
   }
+
+  JS.TemporaryId emitPrivateNameSymbol(Library library, String name) {
+    return _privateNames
+        .putIfAbsent(library, () => new HashMap())
+        .putIfAbsent(name, () {
+      var idName = name;
+      if (idName.endsWith('=')) {
+        idName = idName.replaceAll('=', '_');
+      }
+      var id = new JS.TemporaryId(idName);
+      moduleItems.add(
+          js.statement('const # = Symbol(#);', [id, js.string(name, "'")]));
+      return id;
+    });
+  }
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 141ffcf..0a66690 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -31,15 +31,12 @@
 import 'type_table.dart';
 
 class ProgramCompiler extends Object
-    with SharedCompiler
+    with SharedCompiler<Library>
     implements
         StatementVisitor<JS.Statement>,
         ExpressionVisitor<JS.Expression>,
         DartTypeVisitor<JS.Expression>,
         ConstantVisitor<JS.Expression> {
-  /// The list of output module items, in the order they need to be emitted in.
-  final _moduleItems = <JS.ModuleItem>[];
-
   /// The set of libraries we are currently compiling, and the temporaries used
   /// to refer to them.
   ///
@@ -63,9 +60,6 @@
   /// In an async* function, this represents the stream controller parameter.
   JS.TemporaryId _asyncStarController;
 
-  // TODO(jmesserly): fuse this with notNull check.
-  final _privateNames = new HashMap<Library, HashMap<String, JS.TemporaryId>>();
-
   JS.Identifier _extensionSymbolsModule;
   final _extensionSymbols = new Map<String, JS.TemporaryId>();
 
@@ -246,7 +240,7 @@
 
   JS.Program emitModule(
       Component buildUnit, List<Component> summaries, List<Uri> summaryUris) {
-    if (_moduleItems.isNotEmpty) {
+    if (moduleItems.isNotEmpty) {
       throw new StateError('Can only call emitModule once.');
     }
     _component = buildUnit;
@@ -341,7 +335,7 @@
     items.addAll(_typeTable.discharge());
 
     // Add the module's code (produced by visiting compilation units, above)
-    _copyAndFlattenBlocks(items, _moduleItems);
+    _copyAndFlattenBlocks(items, moduleItems);
 
     // Build the module.
     return new JS.Program(items, name: buildUnit.root.name);
@@ -480,7 +474,7 @@
     if (node is Procedure && node.name.name == 'main') {
       // Don't allow redefining names from this library.
       var name = _emitTopLevelName(export.node);
-      _moduleItems.add(js.statement(
+      moduleItems.add(js.statement(
           '#.# = #;', [emitLibraryName(library), name.selector, name]));
     }
   }
@@ -504,7 +498,7 @@
     _currentLibrary = c.enclosingLibrary;
     _currentUri = c.fileUri;
 
-    _moduleItems.add(_emitClassDeclaration(c));
+    moduleItems.add(_emitClassDeclaration(c));
 
     _currentClass = savedClass;
     types.thisType = savedClass?.thisType;
@@ -1051,7 +1045,7 @@
       // TODO(jmesserly): we could export these symbols, if we want to mark
       // implemented interfaces for user-defined classes.
       var id = new JS.TemporaryId("_is_${getLocalClassName(c)}_default");
-      _moduleItems.add(
+      moduleItems.add(
           js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
       isClassSymbol = id;
     }
@@ -1211,9 +1205,6 @@
     }
 
     var classProcedures = c.procedures.where((p) => !p.isAbstract).toList();
-    for (var m in _classProperties.mockMembers.values) {
-      if (m is Procedure) classProcedures.add(m);
-    }
     for (var member in classProcedures) {
       // Static getters/setters/methods cannot be called with dynamic dispatch,
       // nor can they be torn off.
@@ -1268,9 +1259,6 @@
     var staticFields = <JS.Property>[];
 
     var classFields = c.fields.toList();
-    for (var m in _classProperties.mockMembers.values) {
-      if (m is Field) classFields.add(m);
-    }
     for (var field in classFields) {
       // Only instance fields need to be saved for dynamic dispatch.
       var isStatic = field.isStatic;
@@ -1636,11 +1624,6 @@
     }
     _currentUri = savedUri;
 
-    _classProperties.mockMembers.forEach((String name, Member member) {
-      jsMethods
-          .add(_implementMockMember(member, c, isSetter: name.endsWith('=')));
-    });
-
     // If the type doesn't have an `iterator`, but claims to implement Iterable,
     // we inject the adaptor method here, as it's less code size to put the
     // helper on a parent class. This pattern is common in the core libraries
@@ -1666,7 +1649,7 @@
     }
 
     JS.Fun fn;
-    if (member.isExternal) {
+    if (member.isExternal && !member.isNoSuchMethodForwarder) {
       if (member.isStatic) {
         // TODO(vsm): Do we need to handle this case?
         return null;
@@ -1812,122 +1795,6 @@
     return _emitJSInterop(type.classNode) ?? visitInterfaceType(type);
   }
 
-  /// Given a class C that implements method M from interface I, but does not
-  /// declare M, this will generate an implementation that forwards to
-  /// noSuchMethod.
-  ///
-  /// For example:
-  ///
-  ///     class Cat {
-  ///       bool eatFood(String food) => true;
-  ///     }
-  ///     class MockCat implements Cat {
-  ///        noSuchMethod(Invocation invocation) => 3;
-  ///     }
-  ///
-  /// It will generate an `eatFood` that looks like:
-  ///
-  ///     eatFood(...args) {
-  ///       return core.bool.as(this.noSuchMethod(
-  ///           new dart.InvocationImpl.new('eatFood', args)));
-  ///     }
-  ///
-  /// Same technique is applied if interface I has fields, and C doesn't declare
-  /// neither the fields nor the corresponding getters and setters.
-  JS.Method _implementMockMember(Member member, Class c, {bool isSetter}) {
-    JS.Method implementMockMember(
-        ProcedureKind procedureKind, DartType returnType,
-        [List<TypeParameter> typeParameters,
-        List<JS.Parameter> positionalParameters,
-        List<VariableDeclaration> namedParameters]) {
-      assert(procedureKind != ProcedureKind.Factory);
-
-      var invocationProps = <JS.Property>[];
-      addProperty(String name, JS.Expression value) {
-        invocationProps.add(new JS.Property(js.string(name), value));
-      }
-
-      var typeParams = _emitTypeFormals(typeParameters ?? []);
-      var fnArgs = new List<JS.Parameter>.from(typeParams);
-      JS.Expression positionalArgs;
-      if (procedureKind == ProcedureKind.Getter) {
-        addProperty('isGetter', js.boolean(true));
-        positionalArgs = new JS.ArrayInitializer([]);
-      } else if (procedureKind == ProcedureKind.Setter) {
-        addProperty('isSetter', js.boolean(true));
-        var valueArg = new JS.TemporaryId('value');
-        positionalArgs = new JS.ArrayInitializer([valueArg]);
-        fnArgs.add(valueArg);
-      } else {
-        addProperty('isMethod', js.boolean(true));
-        if (namedParameters.isNotEmpty) {
-          // Named parameters need to be emitted in the correct position (after
-          // positional arguments) so we can detect them reliably.
-          addProperty('namedArguments', namedArgumentTemp);
-          positionalArgs = new JS.ArrayInitializer(positionalParameters);
-          fnArgs.addAll(positionalParameters);
-          fnArgs.add(namedArgumentTemp);
-        } else {
-          // In case we have optional parameters, we need to use rest args,
-          // because sometimes mocks want to detect whether optional arguments
-          // were passed, and this does not work reliably with undefined (should
-          // not normally appear in DDC, but it can result from JS interop).
-          //
-          // TODO(jmesserly): perhaps we need to use rest args or destructuring
-          // to get reliable optional argument passing in other scenarios? It
-          // doesn't seem to occur outside of tests, perhaps due to the
-          // combination of mockito and protobufs.
-          positionalArgs = new JS.TemporaryId('args');
-          fnArgs.add(new JS.RestParameter(positionalArgs));
-        }
-      }
-
-      if (typeParams.isNotEmpty) {
-        addProperty('typeArguments', new JS.ArrayInitializer(typeParams));
-      }
-
-      var fnBody =
-          js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [
-        runtimeModule,
-        _declareMemberName(member),
-        positionalArgs,
-        new JS.ObjectInitializer(invocationProps)
-      ]);
-
-      returnType = _getTypeFromClass(returnType, member.enclosingClass, c);
-      fnBody = _emitImplicitCast(fnBody, returnType);
-
-      var fn = new JS.Fun(fnArgs, fnBody.toReturn().toBlock(),
-          typeParams: typeParams);
-
-      return new JS.Method(
-          _declareMemberName(member,
-              useExtension: _extensionTypes.isNativeClass(c)),
-          fn,
-          isGetter: procedureKind == ProcedureKind.Getter,
-          isSetter: procedureKind == ProcedureKind.Setter,
-          isStatic: false);
-    }
-
-    if (member is Field) {
-      if (isSetter) {
-        return implementMockMember(ProcedureKind.Setter, new VoidType());
-      } else {
-        return implementMockMember(ProcedureKind.Getter, member.type);
-      }
-    } else {
-      var procedure = member as Procedure;
-      var f = procedure.function;
-      assert(procedure.isSetter == isSetter);
-      return implementMockMember(
-          procedure.kind,
-          f.returnType,
-          f.typeParameters,
-          f.positionalParameters.map(_emitVariableRef).toList(),
-          f.namedParameters);
-    }
-  }
-
   /// This is called whenever a derived class needs to introduce a new field,
   /// shadowing a field or getter/setter pair on its parent.
   ///
@@ -1937,34 +1804,27 @@
   /// wrong behavior if a new field was declared.
   List<JS.Method> _emitVirtualFieldAccessor(Field field) {
     var virtualField = _classProperties.virtualFields[field];
-    var result = <JS.Method>[];
     var name = _declareMemberName(field);
 
-    var mocks = _classProperties.mockMembers;
-    if (!mocks.containsKey(field.name.name)) {
-      var getter = js.fun('function() { return this[#]; }', [virtualField]);
-      result.add(new JS.Method(name, getter, isGetter: true)
-        ..sourceInformation = _nodeStart(field));
+    var getter = js.fun('function() { return this[#]; }', [virtualField]);
+    var jsGetter = new JS.Method(name, getter, isGetter: true)
+      ..sourceInformation = _nodeStart(field);
+
+    var args =
+        field.isFinal ? [new JS.Super(), name] : [new JS.This(), virtualField];
+
+    JS.Expression value = new JS.Identifier('value');
+    if (!field.isFinal && field.isGenericCovariantImpl) {
+      value = _emitImplicitCast(value, field.type);
     }
+    args.add(value);
 
-    if (!mocks.containsKey(field.name.name + '=')) {
-      var args = field.isFinal
-          ? [new JS.Super(), name]
-          : [new JS.This(), virtualField];
+    var jsSetter = new JS.Method(
+        name, js.fun('function(value) { #[#] = #; }', args),
+        isSetter: true)
+      ..sourceInformation = _nodeStart(field);
 
-      JS.Expression value = new JS.Identifier('value');
-      if (!field.isFinal && field.isGenericCovariantImpl) {
-        value = _emitImplicitCast(value, field.type);
-      }
-      args.add(value);
-
-      result.add(new JS.Method(
-          name, js.fun('function(value) { #[#] = #; }', args),
-          isSetter: true)
-        ..sourceInformation = _nodeStart(field));
-    }
-
-    return result;
+    return [jsGetter, jsSetter];
   }
 
   /// Provide Dart getters and setters that forward to the underlying native
@@ -2103,7 +1963,7 @@
     }
 
     _currentUri = savedUri;
-    _moduleItems.add(result);
+    moduleItems.add(result);
   }
 
   void _emitTopLevelFields(List<Field> fields) {
@@ -2121,7 +1981,7 @@
             init is BasicLiteral ||
             init is StaticInvocation && isInlineJS(init.target)) {
           _currentUri = field.fileUri;
-          _moduleItems.add(js.statement('# = #;', [
+          moduleItems.add(js.statement('# = #;', [
             _emitTopLevelName(field),
             _visitInitializer(init, field.annotations)
           ]));
@@ -2135,7 +1995,7 @@
     }
 
     if (fields.isEmpty) return;
-    _moduleItems.add(_emitLazyFields(
+    moduleItems.add(_emitLazyFields(
         emitLibraryName(_currentLibrary), fields, _emitTopLevelMemberName));
   }
 
@@ -2283,7 +2143,7 @@
     }
 
     if (name.startsWith('_')) {
-      return _emitPrivateNameSymbol(_currentLibrary, name);
+      return emitPrivateNameSymbol(_currentLibrary, name);
     }
 
     useExtension ??= _isSymbolizedMember(type, name);
@@ -2364,17 +2224,6 @@
             hierarchy.getDispatchTarget(c, new Name(name), setter: true));
   }
 
-  JS.TemporaryId _emitPrivateNameSymbol(Library library, String name) {
-    return _privateNames
-        .putIfAbsent(library, () => new HashMap())
-        .putIfAbsent(name, () {
-      var id = new JS.TemporaryId(name);
-      _moduleItems.add(
-          js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
-      return id;
-    });
-  }
-
   JS.Expression _emitStaticMemberName(String name, [NamedNode member]) {
     if (member != null) {
       var jsName = _emitJSInteropStaticMemberName(member);
@@ -2466,7 +2315,7 @@
     var procedures = library.procedures
         .where((p) => !p.isExternal && !p.isAbstract)
         .toList();
-    _moduleItems.addAll(procedures
+    moduleItems.addAll(procedures
         .where((p) => !p.isAccessor)
         .map(_emitLibraryFunction)
         .toList());
@@ -2475,7 +2324,7 @@
 
   void _emitLibraryAccessors(Iterable<Procedure> accessors) {
     if (accessors.isEmpty) return;
-    _moduleItems.add(runtimeStatement('copyProperties(#, { # })', [
+    moduleItems.add(runtimeStatement('copyProperties(#, { # })', [
       emitLibraryName(_currentLibrary),
       accessors.map(_emitLibraryAccessor).toList()
     ]));
@@ -4864,7 +4713,7 @@
       var last = node.value.split('.').last;
       var name = js.escapedString(node.value, "'");
       if (last.startsWith('_')) {
-        var nativeSymbol = _emitPrivateNameSymbol(_currentLibrary, last);
+        var nativeSymbol = emitPrivateNameSymbol(_currentLibrary, last);
         return js.call('new #.new(#, #)', [
           _emitConstructorAccess(privateSymbolClass.rawType),
           name,
@@ -4894,7 +4743,7 @@
     if (_currentFunction == null || usesTypeParams) return jsExpr;
 
     var temp = new JS.TemporaryId('const');
-    _moduleItems.add(js.statement('let #;', [temp]));
+    moduleItems.add(js.statement('let #;', [temp]));
     return js.call('# || (# = #)', [temp, temp, jsExpr]);
   }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index 51cad84..e630821 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -196,8 +196,6 @@
   /// super.
   final inheritedSetters = new HashSet<String>();
 
-  final mockMembers = <String, Member>{};
-
   final extensionMethods = new Set<String>();
 
   final extensionAccessors = new Set<String>();
@@ -231,14 +229,12 @@
       }
     }
 
-    _collectMockMembers(class_);
     _collectExtensionMembers(class_);
 
     var virtualAccessorNames = new HashSet<String>()
       ..addAll(inheritedGetters)
       ..addAll(inheritedSetters)
-      ..addAll(extensionAccessors)
-      ..addAll(mockMembers.values.map((m) => m.name.name));
+      ..addAll(extensionAccessors);
 
     // Visit accessors in the current class, and see if they need to be
     // generated differently based on the inherited fields/accessors.
@@ -258,62 +254,6 @@
 
   CoreTypes get coreTypes => extensionTypes.coreTypes;
 
-  void _collectMockMembers(Class class_) {
-    // TODO(jmesserly): every type with nSM will generate new stubs for all
-    // abstract members. For example:
-    //
-    //     class C { m(); noSuchMethod(...) { ... } }
-    //     class D extends C { m(); noSuchMethod(...) { ... } }
-    //
-    // We'll generate D.m even though it is not necessary.
-    //
-    // Doing better is a bit tricky, as our current codegen strategy for the
-    // mock methods encodes information about the number of arguments (and type
-    // arguments) that D expects.
-    if (!_hasNoSuchMethod(class_)) return;
-
-    // Collect all unimplemented members.
-    //
-    // Initially, we track abstract and concrete members separately, then
-    // remove concrete from the abstract set. This is done because abstract
-    // members are allowed to "override" concrete ones in Dart.
-    // (In that case, it will still be treated as a concrete member and can be
-    // called at runtime.)
-    var concreteMembers = new HashSet<String>();
-
-    void addMember(Member m, bool classIsAbstract, {bool isSetter: false}) {
-      var name = m.name.name;
-      if (isSetter) name += '=';
-      if (classIsAbstract || m.isAbstract) {
-        mockMembers[name] = m;
-      } else {
-        concreteMembers.add(name);
-      }
-    }
-
-    void visit(Class c, bool classIsAbstract) {
-      if (c == null) return;
-      visit(c.superclass, classIsAbstract);
-      visit(c.mixedInClass, classIsAbstract);
-      for (var i in c.implementedTypes) visit(i.classNode, true);
-
-      for (var m in c.members) {
-        if (m is Field) {
-          if (m.isStatic) continue;
-          addMember(m, classIsAbstract);
-          if (m.hasSetter) addMember(m, classIsAbstract, isSetter: true);
-        } else if (m is Procedure) {
-          if (m.isStatic) continue;
-          addMember(m, classIsAbstract, isSetter: m.isSetter);
-        }
-      }
-    }
-
-    visit(class_, false);
-
-    concreteMembers.forEach(mockMembers.remove);
-  }
-
   void _collectExtensionMembers(Class class_) {
     if (extensionTypes.isNativeClass(class_)) return;
 
@@ -327,17 +267,6 @@
     // For members on this class, check them against all generic interfaces.
     var seenConcreteMembers = new HashSet<String>();
     _findExtensionMembers(class_, seenConcreteMembers, allNatives);
-    // Add mock members. These are compiler-generated concrete members that
-    // forward to `noSuchMethod`.
-    for (var m in mockMembers.values) {
-      var name = m.name.name;
-      if (seenConcreteMembers.add(name) && allNatives.contains(name)) {
-        var extMembers = m is Procedure && !m.isAccessor
-            ? extensionMethods
-            : extensionAccessors;
-        extMembers.add(name);
-      }
-    }
 
     // For members of the superclass, we may need to add checks because this
     // class adds a new unsafe interface. Collect those checks.
@@ -421,17 +350,4 @@
     var s = c.superclass;
     if (s != null) _collectNativeMembers(s, members);
   }
-
-  /// Return `true` if the given [classElement] has a noSuchMethod() method
-  /// distinct from the one declared in class Object, as per the Dart Language
-  /// Specification (section 10.4).
-  // TODO(jmesserly): this was taken from error_verifier.dart
-  bool _hasNoSuchMethod(Class c) {
-    // TODO(jmesserly): is this lookup fast in Kernel?
-    // TODO(jmesserly): our old code may have matched an abstract nSM, but
-    // that seems incorrect. So we now look for a dispatch target.
-    var method = types.hierarchy.getDispatchTarget(c, new Name('noSuchMethod'));
-    var definingClass = method?.enclosingClass;
-    return definingClass != null && definingClass != coreTypes.objectClass;
-  }
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index b1888c6..26dbc21 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:core' hide MapEntry;
 import 'package:kernel/kernel.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/class_hierarchy.dart';
@@ -57,6 +58,9 @@
   bool get nativeExtensionExpectsString => false;
 
   @override
+  bool get enableNoSuchMethodForwarders => true;
+
+  @override
   void performModularTransformationsOnLibraries(
       CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
       {void logger(String msg)}) {}
@@ -68,8 +72,40 @@
   @override
   Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
       String name, Arguments arguments, int offset, bool isSuper) {
-    // TODO(sigmund): implement;
-    return new InvalidExpression(null);
+    // TODO(jmesserly): preserve source information?
+    // (These method are synthetic. Also unclear if the offset will correspond
+    // to the file where the class resides, or the file where the method we're
+    // mocking resides).
+    Expression createInvocation(String name, List<Expression> positional) {
+      var ctor = coreTypes.invocationClass.procedures
+          .firstWhere((c) => c.name.name == name);
+      return new StaticInvocation(ctor, new Arguments(positional));
+    }
+
+    if (name.startsWith('get:')) {
+      return createInvocation('getter', [new SymbolLiteral(name.substring(4))]);
+    }
+    if (name.startsWith('set:')) {
+      return createInvocation('setter', [
+        new SymbolLiteral(name.substring(4) + '='),
+        arguments.positional.single
+      ]);
+    }
+    var ctorArgs = <Expression>[new SymbolLiteral(name)];
+    bool isGeneric = arguments.types.isNotEmpty;
+    if (isGeneric) {
+      ctorArgs.add(new ListLiteral(
+          arguments.types.map((t) => new TypeLiteral(t)).toList()));
+    }
+    ctorArgs.add(new ListLiteral(arguments.positional));
+    if (arguments.named.isNotEmpty) {
+      ctorArgs.add(new MapLiteral(
+          arguments.named
+              .map((n) => new MapEntry(new SymbolLiteral(n.name), n.value))
+              .toList(),
+          keyType: coreTypes.symbolClass.rawType));
+    }
+    return createInvocation(isGeneric ? 'genericMethod' : 'method', ctorArgs);
   }
 
   @override
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index ca353ba..b8b88e2 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -6,6 +6,7 @@
 /// generator.
 part of dart._runtime;
 
+// TODO(jmesserly): remove this in favor of _Invocation.
 class InvocationImpl extends Invocation {
   final Symbol memberName;
   final List positionalArguments;
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index 51b502e..2bfb404 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -521,12 +521,13 @@
 mixin_supertype_subclass_test/05: MissingCompileTimeError
 mixin_type_parameters_errors_test/03: MissingCompileTimeError
 mixin_type_parameters_errors_test/04: MissingCompileTimeError
+mock_writable_final_field_test: RuntimeError # Issue 30847
 mock_writable_final_private_field_test: RuntimeError
 multiline_newline_test/06: MissingCompileTimeError
 multiline_newline_test/06r: MissingCompileTimeError
 named_constructor_test/01: MissingCompileTimeError
 named_parameters_default_eq_test/02: MissingCompileTimeError
-no_such_method_mock_test: RuntimeError # Issue 33103, switch DDK to kernel stubs
+no_such_method_mock_test: RuntimeError # Issue 31426 - Kernel does not introduce nSM for implemented fields.
 null2_test: RuntimeError # Issue 32194
 null_method_test: RuntimeError # Issue 32194
 null_no_such_method_test: CompileTimeError # Issue 31533
@@ -617,7 +618,6 @@
 void_type_usage_test/conditional3_return_to_void: MissingCompileTimeError, Crash
 void_type_usage_test/conditional_return_to_void: MissingCompileTimeError, Crash
 wrong_number_type_arguments_test/01: MissingCompileTimeError
-nosuchmethod_forwarding/nosuchmethod_forwarding_arguments_test: RuntimeError
 
 [ $compiler == dartdevk && $checked ]
 assertion_initializer_const_error2_test/*: MissingCompileTimeError