Run dartdevk against its own compiled SDK and packages

Currently we test dartdevk against SDK/packages that were compiled with
dartdevc (DDC+Analyzer). This CL migrates to having those files compiled
with DDC+Kernel. dartdevc testing is unchanged.

Most of the fixes are around things like special optimized annotations
used in our SDK code, that were not understood by DDK. Also some inline
JS type annoations were not correct.

Change-Id: Iccf4427e4b9beffd6d97a4be654253d91f6cb89e
Reviewed-on: https://dart-review.googlesource.com/57800
Reviewed-by: Vijay Menon <vsm@google.com>
diff --git a/pkg/dev_compiler/bin/dartdevk.dart b/pkg/dev_compiler/bin/dartdevk.dart
index 0d01d78..98f3907 100755
--- a/pkg/dev_compiler/bin/dartdevk.dart
+++ b/pkg/dev_compiler/bin/dartdevk.dart
@@ -21,8 +21,7 @@
     await new _CompilerWorker(parsedArgs.args).run();
   } else {
     var result = await compile(parsedArgs.args);
-    var succeeded = result.result;
-    exitCode = succeeded ? 0 : 1;
+    exitCode = result.success ? 0 : 1;
   }
 }
 
@@ -45,8 +44,7 @@
     try {
       var result = await compile(args, compilerState: compilerState);
       compilerState = result.compilerState;
-      var succeeded = result.result;
-      outcome = succeeded ? 'PASS' : 'FAIL';
+      outcome = result.success ? 'PASS' : 'FAIL';
     } catch (e, s) {
       outcome = 'CRASH';
       print('Unhandled exception:');
@@ -82,7 +80,7 @@
       output.writeln(message.toString());
     }));
     return new WorkResponse()
-      ..exitCode = result.result ? 0 : 1
+      ..exitCode = result.success ? 0 : 1
       ..output = output.toString();
   }
 }
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 54740a8..707576a 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -1654,7 +1654,7 @@
       // Pass along all arguments verbatim, and let the callee handle them.
       // TODO(jmesserly): we'll need something different once we have
       // rest/spread support, but this should work for now.
-      var params = _emitFormalParameters(node.parameters?.parameters);
+      var params = _emitParameters(node.parameters?.parameters);
 
       fun = new JS.Fun(
           params,
@@ -1671,7 +1671,7 @@
       if (init != null) body.add(init);
       body.add(_visitStatement(node.body));
 
-      var params = _emitFormalParameters(node.parameters?.parameters);
+      var params = _emitParameters(node.parameters?.parameters);
       fun = new JS.Fun(params, new JS.Block(body), returnType: returnType);
     }
 
@@ -2272,7 +2272,7 @@
 
   JS.Expression _emitConstructor(ConstructorDeclaration node,
       List<VariableDeclaration> fields, JS.Expression className) {
-    var params = _emitFormalParameters(node.parameters?.parameters);
+    var params = _emitParameters(node.parameters?.parameters);
 
     var savedFunction = _currentFunction;
     _currentFunction = node.body;
@@ -2584,7 +2584,7 @@
     if (node.isGetter) {
       return new JS.Fun([], js.block('{ return this.#; }', [name]));
     } else if (node.isSetter) {
-      var params = _emitFormalParameters(node.parameters?.parameters);
+      var params = _emitParameters(node.parameters?.parameters);
       return new JS.Fun(
           params, js.block('{ this.# = #; }', [name, params.last]));
     } else {
@@ -2788,7 +2788,7 @@
 
     // normal function (sync), vs (sync*, async, async*)
     var isSync = !(element.isAsynchronous || element.isGenerator);
-    var formals = _emitFormalParameters(parameters?.parameters);
+    var formals = _emitParameters(parameters?.parameters);
     var typeFormals = _emitTypeFormals(type.typeFormals);
     if (_reifyGeneric(element)) formals.insertAll(0, typeFormals);
 
@@ -2917,7 +2917,7 @@
 
       var params = parameters?.parameters;
 
-      var jsParams = _emitFormalParameters(
+      var jsParams = _emitParameters(
           params?.where((p) => isPotentiallyMutated(body, p.element)));
 
       var gen = emitGeneratorFn(jsParams);
@@ -4092,8 +4092,7 @@
     return jsParams;
   }
 
-  List<JS.Parameter> _emitFormalParameters(
-      Iterable<FormalParameter> parameters) {
+  List<JS.Parameter> _emitParameters(Iterable<FormalParameter> parameters) {
     if (parameters == null) return [];
 
     var result = <JS.Parameter>[];
@@ -6315,7 +6314,7 @@
   @override
   visitExtendsClause(node) => _unreachable(node);
 
-  /// Unused, see [_emitFormalParameters].
+  /// Unused, see [_emitParameters].
   @override
   visitFormalParameterList(node) => _unreachable(node);
 
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index f8a4624..cd9aaf9 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -11,8 +11,10 @@
 import 'package:front_end/src/api_prototype/standard_file_system.dart';
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
 import 'package:kernel/kernel.dart';
+import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
+import 'package:kernel/binary/ast_to_binary.dart' as kernel show BinaryPrinter;
 import 'package:path/path.dart' as path;
-import 'package:source_maps/source_maps.dart';
+import 'package:source_maps/source_maps.dart' show SourceMapBuilder;
 
 import '../compiler/js_names.dart' as JS;
 import '../compiler/module_builder.dart';
@@ -98,11 +100,11 @@
 
 class CompilerResult {
   final fe.InitializedCompilerState compilerState;
-  final bool result;
+  final bool success;
 
-  CompilerResult(this.compilerState, this.result);
+  CompilerResult(this.compilerState, this.success);
 
-  CompilerResult.noState(this.result) : compilerState = null;
+  CompilerResult.noState(this.success) : compilerState = null;
 }
 
 Future<CompilerResult> _compile(List<String> args,
@@ -113,9 +115,31 @@
         abbr: 'h', help: 'Display this message.', negatable: false)
     ..addOption('out', abbr: 'o', help: 'Output file (required).')
     ..addOption('packages', help: 'The package spec file to use.')
+    ..addFlag('summarize',
+        help: 'emit API summary in a .dill file', defaultsTo: true)
+    // TODO(jmesserly): should default to `false` and be hidden.
+    // For now this is very helpful in debugging the compiler.
+    ..addFlag('summarize-text',
+        help: 'emit API summary in a .js.txt file', defaultsTo: true)
     // TODO(jmesserly): add verbose help to show hidden options
     ..addOption('dart-sdk-summary',
         help: 'The path to the Dart SDK summary file.', hide: true)
+    // TODO(jmesserly): this help description length is too long.
+    //
+    // Also summary-input-dir and custom-app-scheme should be removed.
+    // They are undocumented and not necessary.
+    //
+    // URIs can be passed to `--summary` (including relative ones if desired),
+    // and we can easily add logic to prevert absolute file URIs in source maps.
+    //
+    // It appears to have been added in this change, but none of the flags are
+    // described there:
+    // https://github.com/dart-lang/sdk/commit/226602dc189555d9a43785c2a2f599b1622c1890
+    //
+    // Looking at the code, it appears to be solving a similar problem as
+    // `--module-root` in our old Analyzer-based backend.
+    // See https://github.com/dart-lang/sdk/issues/32272 for context on removing
+    // --module-root.
     ..addMultiOption('summary',
         abbr: 's',
         help: 'path to a summary of a transitive dependency of this module.\n'
@@ -186,8 +210,9 @@
   var fileSystem = new MultiRootFileSystem(
       customScheme, multiRoots, StandardFileSystem.instance);
 
+  var oldCompilerState = compilerState;
   compilerState = await fe.initializeCompiler(
-      compilerState,
+      oldCompilerState,
       stringToUri(sdkSummaryPath),
       stringToUri(packageFile),
       summaryUris,
@@ -206,13 +231,29 @@
 
   String output = argResults['out'];
   var file = new File(output);
-  if (!file.parent.existsSync()) file.parent.createSync(recursive: true);
+  await file.parent.create(recursive: true);
 
-  // TODO(jmesserly): Save .dill file so other modules can link in this one.
-  //await writeComponentToBinary(component, output);
-
-  // Useful for debugging:
-  writeComponentToText(component, path: output + '.txt');
+  // Output files can be written in parallel, so collect the futures.
+  var outFiles = <Future>[];
+  if (argResults['summarize'] as bool) {
+    // TODO(jmesserly): CFE mutates the Kernel tree, so we can't save the dill
+    // file if we successfully reused a cached library. If compiler state is
+    // unchanged, it means we used the cache.
+    //
+    // In that case, we need to unbind canonical names, because they could be
+    // bound already from the previous compile.
+    if (identical(compilerState, oldCompilerState)) {
+      component.unbindCanonicalNames();
+    }
+    var sink = new File(path.withoutExtension(output) + '.dill').openWrite();
+    new kernel.BinaryPrinter(sink).writeComponentFile(component);
+    outFiles.add(sink.flush().then((_) => sink.close()));
+  }
+  if (argResults['summarize-text'] as bool) {
+    var sink = new File(output + '.txt').openWrite();
+    new kernel.Printer(sink, showExternal: false).writeComponentFile(component);
+    outFiles.add(sink.flush().then((_) => sink.close()));
+  }
 
   var compiler = new ProgramCompiler(component,
       declaredVariables: declaredVariables,
@@ -226,14 +267,14 @@
       jsUrl: path.toUri(output).toString(),
       mapUrl: path.toUri(output + '.map').toString(),
       customScheme: customScheme);
-  file.writeAsStringSync(jsCode.code);
 
+  outFiles.add(file.writeAsString(jsCode.code));
   if (jsCode.sourceMap != null) {
-    file = new File(output + '.map');
-    if (!file.parent.existsSync()) file.parent.createSync(recursive: true);
-    file.writeAsStringSync(json.encode(jsCode.sourceMap));
+    outFiles.add(
+        new File(output + '.map').writeAsString(json.encode(jsCode.sourceMap)));
   }
 
+  await Future.wait(outFiles);
   return new CompilerResult(compilerState, true);
 }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 5fdf42b..bf7fea8 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -712,7 +712,7 @@
       for (var ctor in superclass.constructors) {
         var savedUri = _currentUri;
         _currentUri = ctor.enclosingClass.fileUri;
-        var jsParams = _emitFormalParameters(ctor.function);
+        var jsParams = _emitParameters(ctor.function);
         _currentUri = savedUri;
         var ctorBody = <JS.Statement>[];
         if (mixinCtor != null) ctorBody.add(mixinCtor);
@@ -1171,7 +1171,8 @@
       ]));
     }
 
-    var extMembers = _classProperties.extensionMethods;
+    var extMethods = _classProperties.extensionMethods;
+    var extAccessors = _classProperties.extensionAccessors;
     var staticMethods = <JS.Property>[];
     var instanceMethods = <JS.Property>[];
     var staticGetters = <JS.Property>[];
@@ -1235,7 +1236,8 @@
         var property = new JS.Property(_declareMemberName(member), type);
         var signatures = getSignatureList(member);
         signatures.add(property);
-        if (!member.isStatic && extMembers.contains(name)) {
+        if (!member.isStatic &&
+            (extMethods.contains(name) || extAccessors.contains(name))) {
           signatures.add(new JS.Property(
               _declareMemberName(member, useExtension: true), type));
         }
@@ -1343,7 +1345,7 @@
       Constructor node, List<Field> fields, JS.Expression className) {
     var savedUri = _currentUri;
     _currentUri = node.fileUri ?? savedUri;
-    var params = _emitFormalParameters(node.function);
+    var params = _emitParameters(node.function);
     var body = _withCurrentFunction(
         node.function,
         () => _superDisallowed(
@@ -1415,7 +1417,7 @@
     return js.statement('#.#.call(this, #);', [
       className,
       _constructorName(ctor.name.name),
-      _emitArgumentList(node.arguments)
+      _emitArgumentList(node.arguments, types: false)
     ]);
   }
 
@@ -1431,7 +1433,7 @@
       args = [];
     } else {
       ctor = superInit.target;
-      args = _emitArgumentList(superInit.arguments);
+      args = _emitArgumentList(superInit.arguments, types: false);
     }
     // We can skip the super call if it's empty. Most commonly this happens for
     // things that extend Object, and don't have any field initializers or their
@@ -1598,7 +1600,7 @@
     var savedUri = _currentUri;
     for (var m in c.procedures) {
       _currentUri = m.fileUri ?? savedUri;
-      if (m.isForwardingStub) {
+      if (_isForwardingStub(m)) {
         // TODO(jmesserly): is there any other kind of forwarding stub?
         jsMethods.addAll(_emitCovarianceCheckStub(m));
       } else if (m.isFactory) {
@@ -1636,6 +1638,27 @@
     return jsMethods.where((m) => m != null).toList();
   }
 
+  bool _isForwardingStub(Procedure member) {
+    if (member.isForwardingStub || member.isForwardingSemiStub) {
+      if (_currentLibrary.importUri.scheme != 'dart') return true;
+      // TODO(jmesserly): external methods in the SDK seem to get incorrectly
+      // tagged as forwarding stubs even if they are patched. Perhaps there is
+      // an ordering issue in CFE. So for now we pattern match to see if it
+      // looks like an actual forwarding stub.
+      //
+      // We may be able to work around this in a cleaner way by simply emitting
+      // the code, and letting the normal covariance check logic handle things.
+      // But currently we use _emitCovarianceCheckStub to work around some
+      // issues in the stubs.
+      var body = member.function.body;
+      if (body is ReturnStatement) {
+        var expr = body.expression;
+        return expr is SuperMethodInvocation || expr is SuperPropertySet;
+      }
+    }
+    return false;
+  }
+
   /// Emits a method, getter, or setter.
   JS.Method _emitMethodDeclaration(Procedure member) {
     if (member.isAbstract) {
@@ -1665,7 +1688,7 @@
     if (node.isGetter) {
       return new JS.Fun([], js.block('{ return this.#; }', [name]));
     } else if (node.isSetter) {
-      var params = _emitFormalParameters(node.function);
+      var params = _emitParameters(node.function);
       return new JS.Fun(
           params, js.block('{ this.# = #; }', [name, params.last]));
     } else {
@@ -1681,13 +1704,13 @@
     //   ensure soundness of the super member, so we must lookup the super
     //   member and determine checks ourselves.
     // - it generates getter stubs, but these are not used
-    if (member.isGetter) return [];
+    if (member.isGetter) return const [];
 
     var enclosingClass = member.enclosingClass;
     var superMember = member.forwardingStubSuperTarget ??
         member.forwardingStubInterfaceTarget;
 
-    if (superMember == null) return [];
+    if (superMember == null) return const [];
 
     substituteType(DartType t) {
       return _getTypeFromClass(t, superMember.enclosingClass, enclosingClass);
@@ -1698,16 +1721,15 @@
       if (superMember is Field && superMember.isGenericCovariantImpl ||
           superMember is Procedure &&
               isCovariant(superMember.function.positionalParameters[0])) {
-        return [];
+        return const [];
       }
+      var setterType = substituteType(superMember.setterType);
+      if (types.isTop(setterType)) return const [];
       return [
         new JS.Method(
             name,
-            js.fun('function(x) { return super.# = #; }', [
-              name,
-              _emitImplicitCast(new JS.Identifier('x'),
-                  substituteType(superMember.setterType))
-            ]),
+            js.fun('function(x) { return super.# = #; }',
+                [name, _emitImplicitCast(new JS.Identifier('x'), setterType)]),
             isSetter: true),
         new JS.Method(name, js.fun('function() { return super.#; }', [name]),
             isGetter: true)
@@ -1759,16 +1781,11 @@
       }
     }
 
-    if (namedParameters.isNotEmpty) jsParams.add(namedArgumentTemp);
+    if (body.isEmpty) return const []; // No checks were needed.
 
-    if (typeFormals.isEmpty) {
-      body.add(js.statement('return super.#(#);', [name, jsParams]));
-    } else {
-      body.add(
-          js.statement('return super.#(#)(#);', [name, typeFormals, jsParams]));
-    }
-    var fn = new JS.Fun(jsParams, new JS.Block(body));
-    return [new JS.Method(name, fn)];
+    if (namedParameters.isNotEmpty) jsParams.add(namedArgumentTemp);
+    body.add(js.statement('return super.#(#);', [name, jsParams]));
+    return [new JS.Method(name, new JS.Fun(jsParams, new JS.Block(body)))];
   }
 
   /// Emits a Dart factory constructor to a JS static method.
@@ -1776,10 +1793,8 @@
     if (isUnsupportedFactoryConstructor(node)) return null;
 
     var function = node.function;
-    return new JS.Method(
-        _constructorName(node.name.name),
-        new JS.Fun(
-            _emitFormalParameters(function), _emitFunctionBody(function)),
+    return new JS.Method(_constructorName(node.name.name),
+        new JS.Fun(_emitParameters(function), _emitFunctionBody(function)),
         isStatic: true)
       ..sourceInformation = _nodeEnd(node.fileEndOffset);
   }
@@ -1913,7 +1928,7 @@
         js.call('Symbol.iterator'),
         js.call('function() { return new #.JsIterator(this.#); }', [
           runtimeModule,
-          _emitMemberName('iterator', type: iterable.asInterfaceType)
+          _emitMemberName('iterator', memberClass: coreTypes.iterableClass)
         ]) as JS.Fun);
   }
 
@@ -2110,10 +2125,10 @@
   /// helper, that checks for null. The user defined method is called '=='.
   ///
   JS.Expression _emitMemberName(String name,
-      {DartType type,
-      bool isStatic: false,
+      {bool isStatic: false,
       bool useExtension,
-      NamedNode member}) {
+      Member member,
+      Class memberClass}) {
     // Static members skip the rename steps and may require JS interop renames.
     if (isStatic) {
       return _emitStaticMemberName(name, member);
@@ -2140,7 +2155,8 @@
       return emitPrivateNameSymbol(_currentLibrary, name);
     }
 
-    useExtension ??= _isSymbolizedMember(type, name);
+    memberClass ??= member?.enclosingClass;
+    useExtension ??= _isSymbolizedMember(memberClass, name);
     name = JS.memberNameForDartMember(
         name, member is Procedure && member.isExternal);
     if (useExtension) {
@@ -2169,38 +2185,29 @@
   /// Note, this is an underlying assumption here that, if another native type
   /// subtypes this one, it also forwards this member to its underlying native
   /// one without renaming.
-  bool _isSymbolizedMember(DartType type, String name) {
-    while (type is TypeParameterType) {
-      type = (type as TypeParameterType).bound;
-    }
-    if (type == null ||
-        type == const DynamicType() ||
-        type == coreTypes.objectClass) {
+  bool _isSymbolizedMember(Class c, String name) {
+    if (c == null) {
       return isObjectMember(name);
-    } else if (type is InterfaceType) {
-      var c = _typeRep.getImplementationClass(type) ?? type.classNode;
-      if (_extensionTypes.isNativeClass(c)) {
-        var member = _lookupForwardedMember(c, name);
-
-        // Fields on a native class are implicitly native.
-        // Methods/getters/setters are marked external/native.
-        if (member is Field || member is Procedure && member.isExternal) {
-          var jsName = getAnnotationName(member, isJSName);
-          return jsName != null && jsName != name;
-        } else {
-          // Non-external members must be symbolized.
-          return true;
-        }
-      }
-      // If the receiver *may* be a native type (i.e., an interface allowed to
-      // be implemented by a native class), conservatively symbolize - we don't
-      // know whether it'll be implemented via forwarding.
-      // TODO(vsm): Consider CHA here to be less conservative.
-      return _extensionTypes.isNativeInterface(c);
-    } else if (type is FunctionType) {
-      return true;
     }
-    return false;
+    c = _typeRep.getImplementationClass(c.rawType) ?? c;
+    if (_extensionTypes.isNativeClass(c)) {
+      var member = _lookupForwardedMember(c, name);
+
+      // Fields on a native class are implicitly native.
+      // Methods/getters/setters are marked external/native.
+      if (member is Field || member is Procedure && member.isExternal) {
+        var jsName = getAnnotationName(member, isJSName);
+        return jsName != null && jsName != name;
+      } else {
+        // Non-external members must be symbolized.
+        return true;
+      }
+    }
+    // If the receiver *may* be a native type (i.e., an interface allowed to
+    // be implemented by a native class), conservatively symbolize - we don't
+    // know whether it'll be implemented via forwarding.
+    // TODO(vsm): Consider CHA here to be less conservative.
+    return _extensionTypes.isNativeInterface(c);
   }
 
   var _forwardingCache = new HashMap<Class, Map<String, Member>>();
@@ -2634,9 +2641,13 @@
   JS.Fun _emitFunction(FunctionNode f, String name) {
     // normal function (sync), vs (sync*, async, async*)
     var isSync = f.asyncMarker == AsyncMarker.Sync;
-    var formals = _emitFormalParameters(f);
+    var formals = _emitParameters(f);
     var typeFormals = _emitTypeFormals(f.typeParameters);
-    formals.insertAll(0, typeFormals);
+
+    var parent = f.parent;
+    if (_reifyGenericFunction(parent is Member ? parent : null)) {
+      formals.insertAll(0, typeFormals);
+    }
 
     // TODO(jmesserly): need a way of determining if parameters are
     // potentially mutated in Kernel. For now we assume all parameters are.
@@ -2654,9 +2665,14 @@
     return new JS.Fun(formals, code);
   }
 
-  // TODO(jmesserly): rename _emitParameters
-  List<JS.Parameter> _emitFormalParameters(FunctionNode f) {
-    var result = f.positionalParameters.map(_emitVariableDef).toList();
+  List<JS.Parameter> _emitParameters(FunctionNode f) {
+    var positional = f.positionalParameters;
+    var result = new List<JS.Parameter>.from(positional.map(_emitVariableDef));
+    if (positional.isNotEmpty &&
+        f.requiredParameterCount == positional.length &&
+        positional.last.annotations.any(isJsRestAnnotation)) {
+      result.last = new JS.RestParameter(result.last);
+    }
     if (f.namedParameters.isNotEmpty) result.add(namedArgumentTemp);
     return result;
   }
@@ -2730,7 +2746,7 @@
       //
       // In the future, we might be able to simplify this, see:
       // https://github.com/dart-lang/sdk/issues/28320
-      var jsParams = _emitFormalParameters(function);
+      var jsParams = _emitParameters(function);
       var gen = emitGeneratorFn((fnBody) => jsParams =
           jsParams.where(JS.findMutatedVariables(fnBody).contains).toList());
       if (jsParams.isNotEmpty) gen = js.call('() => #(#)', [gen, jsParams]);
@@ -2880,6 +2896,12 @@
   bool _annotatedNullCheck(List<Expression> annotations) =>
       annotations.any(_nullableInference.isNullCheckAnnotation);
 
+  bool _reifyGenericFunction(Member m) =>
+      m == null ||
+      m.enclosingLibrary.importUri.scheme != 'dart' ||
+      !m.annotations
+          .any((a) => isBuiltinAnnotation(a, '_js_helper', 'NoReifyGeneric'));
+
   JS.Statement _nullParameterCheck(JS.Expression param) {
     var call = runtimeCall('argumentError((#))', [param]);
     return js.statement('if (# == null) #;', [param, call]);
@@ -3628,32 +3650,36 @@
   JS.Expression _emitPropertyGet(Expression receiver, Member member,
       [String memberName]) {
     memberName ??= member.name.name;
-    var receiverType = receiver.getStaticType(types);
     // TODO(jmesserly): should tearoff of `.call` on a function type be
     // encoded as a different node, or possibly eliminated?
     // (Regardless, we'll still need to handle the callable JS interop classes.)
-    if (memberName == 'call' && _isDirectCallable(receiverType)) {
+    if (memberName == 'call' &&
+        _isDirectCallable(receiver.getStaticType(types))) {
       // Tearoff of `call` on a function type is a no-op;
       return _visitExpression(receiver);
     }
-    var jsName =
-        _emitMemberName(memberName, type: receiverType, member: member);
+    var jsName = _emitMemberName(memberName, member: member);
     var jsReceiver = _visitExpression(receiver);
 
     // TODO(jmesserly): we need to mark an end span for property accessors so
     // they can be hovered. Unfortunately this is not possible as Kernel does
     // not store this data.
-    if (member == null) {
+    if (isObjectMember(memberName)) {
+      if (isNullable(receiver)) {
+        // If the receiver is nullable, use a helper so calls like
+        // `null.hashCode` and `null.runtimeType` will work.
+        // Also method tearoffs like `null.toString`.
+        if (_isObjectMethod(memberName)) {
+          return runtimeCall('bind(#, #)', [jsReceiver, jsName]);
+        }
+        return runtimeCall('#(#)', [memberName, jsReceiver]);
+      }
+      // Otherwise generate this as a normal typed property get.
+    } else if (member == null) {
       return runtimeCall('dload$_replSuffix(#, #)', [jsReceiver, jsName]);
     }
 
-    if (_isObjectMemberCall(receiver, memberName)) {
-      if (_isObjectMethod(memberName)) {
-        return runtimeCall('bind(#, #)', [jsReceiver, jsName]);
-      } else {
-        return runtimeCall('#(#)', [memberName, jsReceiver]);
-      }
-    } else if (_reifyTearoff(member)) {
+    if (_reifyTearoff(member)) {
       return runtimeCall('bind(#, #)', [jsReceiver, jsName]);
     } else {
       return new JS.PropertyAccess(jsReceiver, jsName);
@@ -3668,8 +3694,8 @@
   JS.Expression _emitPropertySet(
       Expression receiver, Member member, Expression value,
       [String memberName]) {
-    var jsName = _emitMemberName(memberName ?? member.name.name,
-        type: receiver.getStaticType(types), member: member);
+    var jsName =
+        _emitMemberName(memberName ?? member.name.name, member: member);
 
     var jsReceiver = _visitExpression(receiver);
     var jsValue = _visitExpression(value);
@@ -3748,13 +3774,13 @@
     }
 
     var jsReceiver = _visitExpression(receiver);
-    var args = _emitArgumentList(arguments);
-    var receiverType = receiver.getStaticType(types);
+    var args = _emitArgumentList(arguments, target: target);
 
     bool isCallingDynamicField = target is Member &&
         target.hasGetter &&
         _isDynamicOrFunction(target.getterType);
     if (name == 'call') {
+      var receiverType = receiver.getStaticType(types);
       if (isCallingDynamicField || _isDynamicOrFunction(receiverType)) {
         return _emitDynamicInvoke(jsReceiver, null, args, arguments);
       } else if (_isDirectCallable(receiverType)) {
@@ -3763,13 +3789,17 @@
       }
     }
 
-    var jsName = _emitMemberName(name, type: receiverType, member: target);
-    if (target == null || isCallingDynamicField) {
-      return _emitDynamicInvoke(jsReceiver, jsName, args, arguments);
-    }
-    if (_isObjectMemberCall(receiver, name)) {
+    var jsName = _emitMemberName(name, member: target);
+    if (isObjectMember(name)) {
       assert(arguments.types.isEmpty); // Object methods don't take type args.
-      return runtimeCall('#(#, #)', [name, jsReceiver, args]);
+      if (isNullable(receiver)) {
+        // If the receiver is nullable, use a helper so calls like
+        // `null.toString()` will work.
+        return runtimeCall('#(#, #)', [name, jsReceiver, args]);
+      }
+      // Otherwise generate this as a normal typed method call.
+    } else if (target == null || isCallingDynamicField) {
+      return _emitDynamicInvoke(jsReceiver, jsName, args, arguments);
     }
     // TODO(jmesserly): remove when Kernel desugars this for us.
     // Handle `o.m(a)` where `o.m` is a getter returning a class with `call`.
@@ -3827,7 +3857,7 @@
     var c = from.classNode;
     var member = hierarchy.getInterfaceMember(c, new Name("call"));
     if (member is Procedure && !member.isAccessor && !usesJSInterop(c)) {
-      return _emitMemberName('call', type: from, member: member);
+      return _emitMemberName('call', member: member);
     }
     return null;
   }
@@ -3838,19 +3868,20 @@
   JS.Expression _emitUnaryOperator(
       Expression expr, Member target, InvocationExpression node) {
     var op = node.name.name;
-    var dispatchType = expr.getStaticType(types);
-    if (_typeRep.unaryOperationIsPrimitive(dispatchType)) {
-      if (op == '~') {
-        if (_typeRep.isNumber(dispatchType)) {
-          return _coerceBitOperationResultToUnsigned(
-              node, js.call('~#', notNull(expr)));
+    if (target != null) {
+      var dispatchType = target.enclosingClass.rawType;
+      if (_typeRep.unaryOperationIsPrimitive(dispatchType)) {
+        if (op == '~') {
+          if (_typeRep.isNumber(dispatchType)) {
+            return _coerceBitOperationResultToUnsigned(
+                node, js.call('~#', notNull(expr)));
+          }
+          return _emitOperatorCall(expr, target, op, []);
         }
-        return _emitOperatorCall(expr, target, op, []);
+        if (op == 'unary-') op = '-';
+        return js.call('$op#', notNull(expr));
       }
-      if (op == 'unary-') op = '-';
-      return js.call('$op#', notNull(expr));
     }
-
     return _emitOperatorCall(expr, target, op, []);
   }
 
@@ -4004,76 +4035,82 @@
     var op = node.name.name;
     if (op == '==') return _emitEqualityOperator(left, target, right);
 
-    var leftType = left.getStaticType(types);
-    var rightType = right.getStaticType(types);
+    // TODO(jmesserly): using the target type here to work around:
+    // https://github.com/dart-lang/sdk/issues/33293
+    if (target != null) {
+      var targetClass = target.enclosingClass;
+      var leftType = targetClass.rawType;
+      var rightType = right.getStaticType(types);
 
-    if (_typeRep.binaryOperationIsPrimitive(leftType, rightType) ||
-        leftType == types.stringType && op == '+') {
-      // special cases where we inline the operation
-      // these values are assumed to be non-null (determined by the checker)
-      // TODO(jmesserly): it would be nice to just inline the method from core,
-      // instead of special cases here.
-      JS.Expression binary(String code) {
-        return js.call(code, [notNull(left), notNull(right)]);
-      }
+      if (_typeRep.binaryOperationIsPrimitive(leftType, rightType) ||
+          leftType == types.stringType && op == '+') {
+        // special cases where we inline the operation
+        // these values are assumed to be non-null (determined by the checker)
+        // TODO(jmesserly): it would be nice to just inline the method from core,
+        // instead of special cases here.
+        JS.Expression binary(String code) {
+          return js.call(code, [notNull(left), notNull(right)]);
+        }
 
-      JS.Expression bitwise(String code) {
-        return _coerceBitOperationResultToUnsigned(node, binary(code));
-      }
+        JS.Expression bitwise(String code) {
+          return _coerceBitOperationResultToUnsigned(node, binary(code));
+        }
 
-      switch (op) {
-        case '~/':
-          // `a ~/ b` is equivalent to `(a / b).truncate()`
-          return js.call('(# / #).#()', [
-            notNull(left),
-            notNull(right),
-            _emitMemberName('truncate', type: leftType)
-          ]);
+        switch (op) {
+          case '~/':
+            // `a ~/ b` is equivalent to `(a / b).truncate()`
+            return js.call('(# / #).#()', [
+              notNull(left),
+              notNull(right),
+              _emitMemberName('truncate', memberClass: targetClass)
+            ]);
 
-        case '%':
-          // TODO(sra): We can generate `a % b + 0` if both are non-negative
-          // (the `+ 0` is to coerce -0.0 to 0).
-          return _emitOperatorCall(left, target, op, [right]);
+          case '%':
+            // TODO(sra): We can generate `a % b + 0` if both are non-negative
+            // (the `+ 0` is to coerce -0.0 to 0).
+            return _emitOperatorCall(left, target, op, [right]);
 
-        case '&':
-          return bitwise('# & #');
+          case '&':
+            return bitwise('# & #');
 
-        case '|':
-          return bitwise('# | #');
+          case '|':
+            return bitwise('# | #');
 
-        case '^':
-          return bitwise('# ^ #');
+          case '^':
+            return bitwise('# ^ #');
 
-        case '>>':
-          int shiftCount = _asIntInRange(right, 0, 31);
-          if (_is31BitUnsigned(left) && shiftCount != null) {
-            return binary('# >> #');
-          }
-          if (_isDefinitelyNonNegative(left) && shiftCount != null) {
-            return binary('# >>> #');
-          }
-          // If the context selects out only bits that can't be affected by the
-          // sign position we can use any JavaScript shift, `(x >> 6) & 3`.
-          if (shiftCount != null &&
-              _parentMasksToWidth(node, 31 - shiftCount)) {
-            return binary('# >> #');
-          }
-          return _emitOperatorCall(left, target, op, [right]);
+          case '>>':
+            int shiftCount = _asIntInRange(right, 0, 31);
+            if (_is31BitUnsigned(left) && shiftCount != null) {
+              return binary('# >> #');
+            }
+            if (_isDefinitelyNonNegative(left) && shiftCount != null) {
+              return binary('# >>> #');
+            }
+            // If the context selects out only bits that can't be affected by the
+            // sign position we can use any JavaScript shift, `(x >> 6) & 3`.
+            if (shiftCount != null &&
+                _parentMasksToWidth(node, 31 - shiftCount)) {
+              return binary('# >> #');
+            }
+            return _emitOperatorCall(left, target, op, [right]);
 
-        case '<<':
-          if (_is31BitUnsigned(node)) {
-            // Result is 31 bit unsigned which implies the shift count was small
-            // enough not to pollute the sign bit.
-            return binary('# << #');
-          }
-          if (_asIntInRange(right, 0, 31) != null) {
-            return _coerceBitOperationResultToUnsigned(node, binary('# << #'));
-          }
-          return _emitOperatorCall(left, target, op, [right]);
+          case '<<':
+            if (_is31BitUnsigned(node)) {
+              // Result is 31 bit unsigned which implies the shift count was small
+              // enough not to pollute the sign bit.
+              return binary('# << #');
+            }
+            if (_asIntInRange(right, 0, 31) != null) {
+              return _coerceBitOperationResultToUnsigned(
+                  node, binary('# << #'));
+            }
+            return _emitOperatorCall(left, target, op, [right]);
 
-        default:
-          // TODO(vsm): When do Dart ops not map to JS?
-          return binary('# $op #');
+          default:
+            // TODO(vsm): When do Dart ops not map to JS?
+            return binary('# $op #');
+        }
       }
     }
 
@@ -4083,7 +4120,8 @@
   JS.Expression _emitEqualityOperator(
       Expression left, Member target, Expression right,
       {bool negated = false}) {
-    var leftType = left.getStaticType(types);
+    var targetClass = target?.enclosingClass;
+    var leftType = targetClass?.rawType ?? left.getStaticType(types);
 
     // Conceptually `x == y` in Dart is defined as:
     //
@@ -4101,14 +4139,15 @@
     // TODO(leafp,jmesserly): we could use class hierarchy analysis to check
     // if `operator ==` was overridden, similar to how we devirtualize private
     // fields.
+    //
+    // If we know that the left type uses identity for equality, we can
+    // sometimes emit better code, either `===` or `==`.
     var isEnum = leftType is InterfaceType && leftType.classNode.isEnum;
     var usesIdentity = _typeRep.isPrimitive(leftType) ||
         isEnum ||
         _isNull(left) ||
         _isNull(right);
 
-    // If we know that the left type uses identity for equality, we can
-    // sometimes emit better code, either `===` or `==`.
     if (usesIdentity) {
       return _emitCoreIdenticalCall([left, right], negated: negated);
     }
@@ -4125,7 +4164,7 @@
     // Otherwise we emit a call to the == method.
     return js.call(negated ? '!#[#](#)' : '#[#](#)', [
       _visitExpression(left),
-      _emitMemberName('==', type: leftType),
+      _emitMemberName('==', memberClass: targetClass),
       _visitExpression(right)
     ]);
   }
@@ -4139,8 +4178,7 @@
       Expression receiver, Member target, String name, List<Expression> args) {
     // TODO(jmesserly): calls that don't pass `element` are probably broken for
     // `super` calls from disallowed super locations.
-    var type = receiver.getStaticType(types);
-    var memberName = _emitMemberName(name, type: type, member: target);
+    var memberName = _emitMemberName(name, member: target);
     if (target == null) {
       // dynamic dispatch
       var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name];
@@ -4164,15 +4202,15 @@
   // TODO(jmesserly): optimize super operators for kernel
   @override
   visitSuperMethodInvocation(SuperMethodInvocation node) {
-    return new JS.Call(_emitSuperTarget(node.interfaceTarget),
-        _emitArgumentList(node.arguments));
+    var target = node.interfaceTarget;
+    return new JS.Call(_emitSuperTarget(target),
+        _emitArgumentList(node.arguments, target: target));
   }
 
   /// Emits the [JS.PropertyAccess] for accessors or method calls to
   /// [jsTarget].[jsName], replacing `super` if it is not allowed in scope.
   JS.PropertyAccess _emitSuperTarget(Member member, {bool setter: false}) {
-    var type = member.enclosingClass.rawType;
-    var jsName = _emitMemberName(member.name.name, type: type, member: member);
+    var jsName = _emitMemberName(member.name.name, member: member);
     if (member is Field && !virtualFields.isVirtual(member)) {
       return new JS.PropertyAccess(new JS.This(), jsName);
     }
@@ -4246,7 +4284,7 @@
     }
 
     var fn = _emitStaticTarget(target);
-    var args = _emitArgumentList(node.arguments);
+    var args = _emitArgumentList(node.arguments, target: target);
     return new JS.Call(fn, args);
   }
 
@@ -4296,13 +4334,25 @@
   JS.Expression _emitStaticTarget(Member target) {
     var c = target.enclosingClass;
     if (c != null) {
+      // A static native element should just forward directly to the
+      // JS type's member.
+      if (target is Procedure && target.isStatic && target.isExternal) {
+        var nativeName = _extensionTypes.getNativePeers(c);
+        if (nativeName.isNotEmpty) {
+          var memberName = getAnnotationName(target, isJSName) ??
+              _emitStaticMemberName(target.name.name, target);
+          return runtimeCall('global.#.#', [nativeName[0], memberName]);
+        }
+      }
       return new JS.PropertyAccess(_emitStaticClassName(c),
           _emitStaticMemberName(target.name.name, target));
     }
     return _emitTopLevelName(target);
   }
 
-  List<JS.Expression> _emitArgumentList(Arguments node, {bool types: true}) {
+  List<JS.Expression> _emitArgumentList(Arguments node,
+      {bool types: true, Member target}) {
+    types = types && _reifyGenericFunction(target);
     var args = <JS.Expression>[];
     if (types) {
       for (var typeArg in node.types) {
@@ -4531,7 +4581,7 @@
   }
 
   JS.Expression _emitObjectLiteral(Arguments node) {
-    var args = _emitArgumentList(node);
+    var args = _emitArgumentList(node, types: false);
     if (args.isEmpty) return js.call('{}');
     assert(args.single is JS.ObjectInitializer);
     return args.single;
@@ -4677,8 +4727,10 @@
           nativeSymbol
         ]);
       } else {
-        return js.call('#.new(#)',
-            [_emitConstructorAccess(coreTypes.symbolClass.rawType), name]);
+        return js.call('new #.new(#)', [
+          _emitConstructorAccess(coreTypes.internalSymbolClass.rawType),
+          name
+        ]);
       }
     }
 
@@ -4914,16 +4966,6 @@
         _reifyFunctionType(member.function);
   }
 
-  /// Everything in Dart is an Object and supports the 4 members on Object,
-  /// so we have to use a runtime helper to handle values such as `null` and
-  /// native types.
-  ///
-  /// For example `null.toString()` is legal in Dart, so we need to generate
-  /// that as `dart.toString(obj)`.
-  bool _isObjectMemberCall(Expression target, String memberName) {
-    return isObjectMember(memberName) && isNullable(target);
-  }
-
   /// Returns the name value of the `JSExportName` annotation (when compiling
   /// the SDK), or `null` if there's none. This is used to control the name
   /// under which functions are compiled and exported.
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 44a8f0f..b9b6412 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -83,8 +83,10 @@
     Expression value, String libraryName, String expectedName) {
   if (value is ConstructorInvocation) {
     var c = value.target.enclosingClass;
-    return c.name == expectedName &&
-        c.enclosingLibrary.importUri.toString() == libraryName;
+    if (c.name == expectedName) {
+      var uri = c.enclosingLibrary.importUri;
+      return uri.scheme == 'dart' && uri.path == libraryName;
+    }
   }
   return false;
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/native_types.dart b/pkg/dev_compiler/lib/src/kernel/native_types.dart
index 78876b4..cde8c08 100644
--- a/pkg/dev_compiler/lib/src/kernel/native_types.dart
+++ b/pkg/dev_compiler/lib/src/kernel/native_types.dart
@@ -83,7 +83,7 @@
   void _addExtensionTypesForLibrary(String library, List<String> classNames) {
     var sdk = coreTypes.index;
     for (var className in classNames) {
-      _addExtensionType(sdk.getClass(library, className), true);
+      _addExtensionType(sdk.getClass(library, className));
     }
   }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index e630821..1edc3b7 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -310,13 +310,13 @@
   ///
   /// By tracking the set of seen members, we can visit superclasses and mixins
   /// and ultimately collect every most-derived member exposed by a given type.
-  void _findExtensionMembers(Class class_, HashSet<String> seenConcreteMembers,
-      Set<String> allNatives) {
+  void _findExtensionMembers(
+      Class c, HashSet<String> seenConcreteMembers, Set<String> allNatives) {
     // We only visit each most derived concrete member.
     // To avoid visiting an overridden superclass member, we skip members
     // we've seen, and visit starting from the class, then mixins in
     // reverse order, then superclasses.
-    for (var m in class_.members) {
+    for (var m in c.members) {
       var name = m.name.name;
       if (m.isAbstract || m is Constructor) continue;
       if (m is Procedure) {
@@ -338,8 +338,11 @@
   /// types.
   void _collectNativeMembers(Class c, Set<String> members) {
     if (extensionTypes.hasNativeSubtype(c)) {
-      for (var m in c.procedures) {
-        if (!m.name.isPrivate && !m.isStatic) members.add(m.name.name);
+      for (var m in c.members) {
+        if (!m.name.isPrivate &&
+            (m is Procedure && !m.isStatic || m is Field && !m.isStatic)) {
+          members.add(m.name.name);
+        }
       }
     }
     var m = c.mixedInClass;
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 26dbc21..5996ea5 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -77,9 +77,15 @@
     // 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
+      // TODO(jmesserly): this uses the implementation _Invocation class,
+      // because the CFE does not resolve the redirecting factory constructors
+      // like it would for user code. Our code generator expects all redirecting
+      // factories to be resolved to the real constructor.
+      var ctor = coreTypes.index
+          .getClass('dart:core', '_Invocation')
+          .constructors
           .firstWhere((c) => c.name.name == name);
-      return new StaticInvocation(ctor, new Arguments(positional));
+      return new ConstructorInvocation(ctor, new Arguments(positional));
     }
 
     if (name.startsWith('get:')) {
@@ -96,6 +102,8 @@
     if (isGeneric) {
       ctorArgs.add(new ListLiteral(
           arguments.types.map((t) => new TypeLiteral(t)).toList()));
+    } else {
+      ctorArgs.add(new NullLiteral());
     }
     ctorArgs.add(new ListLiteral(arguments.positional));
     if (arguments.named.isNotEmpty) {
@@ -105,7 +113,7 @@
               .toList(),
           keyType: coreTypes.symbolClass.rawType));
     }
-    return createInvocation(isGeneric ? 'genericMethod' : 'method', ctorArgs);
+    return createInvocation('method', ctorArgs);
   }
 
   @override
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
index d93083c..0870331 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
@@ -69,7 +69,7 @@
     try {
       var result = await compile(args, compilerState: context.compilerState);
       context.compilerState = result.compilerState;
-      succeeded = result.result;
+      succeeded = result.success;
     } catch (e, s) {
       print('Unhandled exception:');
       print(e);
diff --git a/pkg/dev_compiler/tool/build_pkgs.dart b/pkg/dev_compiler/tool/build_pkgs.dart
index 91bea3a..57c7e30 100755
--- a/pkg/dev_compiler/tool/build_pkgs.dart
+++ b/pkg/dev_compiler/tool/build_pkgs.dart
@@ -3,13 +3,10 @@
 import 'dart:io';
 
 import 'package:args/args.dart';
-import 'package:front_end/src/api_prototype/compilation_message.dart';
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/api_prototype/summary_generator.dart';
 import 'package:path/path.dart' as p;
 
-import 'package:dev_compiler/src/analyzer/command.dart' as analyzer;
-import 'package:dev_compiler/src/kernel/target.dart';
+import 'package:dev_compiler/src/analyzer/command.dart' as dartdevc;
+import 'package:dev_compiler/src/kernel/command.dart' as dartdevk;
 
 final String scriptDirectory = p.dirname(p.fromUri(Platform.script));
 
@@ -27,8 +24,6 @@
 /// packages will be placed in a "pkg" subdirectory of this.
 String outputDirectory;
 
-String get pkgDirectory => p.join(outputDirectory, "pkg");
-
 /// Compiles the packages that the DDC tests use to JS into the given output
 /// directory.
 ///
@@ -70,8 +65,6 @@
   kernelSummary = argResults["kernel-sdk"] as String;
   outputDirectory = argResults["output"] as String;
 
-  new Directory(pkgDirectory).createSync(recursive: true);
-
   // Build leaf packages. These have no other package dependencies.
 
   // Under pkg.
@@ -108,7 +101,6 @@
 
   if (!isTravis) {
     await compileModule('unittest', deps: [
-      'matcher',
       'path',
       'stack_trace'
     ], libs: [
@@ -135,81 +127,35 @@
 /// [libs] and [deps] on other modules.
 Future compileModule(String module,
     {List<String> libs = const [], List<String> deps = const []}) async {
-  if (analyzerSummary != null) compileModuleUsingAnalyzer(module, libs, deps);
-  if (kernelSummary != null) await compileKernelSummary(module, libs, deps);
-}
+  makeArgs(bool kernel) {
+    var pkgDirectory = p.join(outputDirectory, kernel ? 'pkg_kernel' : 'pkg');
+    new Directory(pkgDirectory).createSync(recursive: true);
 
-void compileModuleUsingAnalyzer(
-    String module, List<String> libraries, List<String> dependencies) {
-  var args = [
-    '--dart-sdk-summary=$analyzerSummary',
-    '-o${pkgDirectory}/$module.js',
-    // There is always a library that matches the module.
-    'package:$module/$module.dart'
-  ];
-
-  // Add any additional libraries.
-  for (var lib in libraries) {
-    args.add('package:$module/$lib.dart');
+    var args = [
+      '--dart-sdk-summary=${kernel ? kernelSummary : analyzerSummary}',
+      '-o${pkgDirectory}/$module.js',
+      'package:$module/$module.dart'
+    ];
+    for (var lib in libs) {
+      args.add('package:$module/$lib.dart');
+    }
+    for (var dep in deps) {
+      args.add('-s${pkgDirectory}/$dep.${kernel ? "dill" : "sum"}');
+    }
+    if (kernel) {
+      args.add('--summary-input-dir=$pkgDirectory');
+    }
+    return args;
   }
 
-  // Add summaries for any modules this depends on.
-  for (var dep in dependencies) {
-    args.add('-s${pkgDirectory}/$dep.sum');
+  if (analyzerSummary != null) {
+    var args = makeArgs(false);
+    var exitCode = dartdevc.compile(args);
+    if (exitCode != 0) exit(exitCode);
   }
-  var exitCode = analyzer.compile(args);
-  if (exitCode != 0) exit(exitCode);
-}
-
-Future compileKernelSummary(
-    String module, List<String> libraries, List<String> dependencies) async {
-  var succeeded = true;
-
-  void errorHandler(CompilationMessage error) {
-    if (error.severity == Severity.error) succeeded = false;
+  if (kernelSummary != null) {
+    var args = makeArgs(true);
+    var result = await dartdevk.compile(args);
+    if (!result.success) exit(1);
   }
-
-  var options = new CompilerOptions()
-    ..sdkSummary = p.toUri(kernelSummary)
-    ..packagesFileUri = _uriInRepo(".packages")
-    ..strongMode = true
-    ..debugDump = true
-    ..onError = errorHandler
-    ..reportMessages = true
-    ..target = new DevCompilerTarget();
-
-  // There is always a library that matches the module.
-  var inputs = [Uri.parse("package:$module/$module.dart")];
-
-  // Add any other libraries too.
-  for (var lib in libraries) {
-    inputs.add(Uri.parse("package:$module/$lib.dart"));
-  }
-
-  // Add summaries for any modules this depends on.
-  var uris = <Uri>[];
-  for (var dep in dependencies) {
-    uris.add(p.toUri(p.absolute(p.join(pkgDirectory, "$dep.dill"))));
-  }
-  options.inputSummaries = uris;
-
-  // Compile the summary.
-  var bytes = await summaryFor(inputs, options);
-  var dillFile = new File(p.join(pkgDirectory, "$module.dill"));
-  if (succeeded) {
-    dillFile.writeAsBytesSync(bytes);
-  } else {
-    // Don't leave the previous version of the file on failure.
-    if (dillFile.existsSync()) dillFile.deleteSync();
-
-    stderr.writeln("Could not generate kernel summary for $module.");
-    exit(1);
-  }
-}
-
-Uri _uriInRepo(String pathInRepo) {
-  // Walk up to repo root.
-  var result = p.join(scriptDirectory, "../../../");
-  result = p.join(result, pathInRepo);
-  return p.toUri(p.absolute(p.normalize(result)));
 }
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index a02b4cf..c6e5ab7 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -59,7 +59,11 @@
   ProcessResult runDdc(String command, List<String> args) {
     if (debug) {
       // Use unbuilt script.  This only works from a source checkout.
-      args.insertAll(0, ['--preview-dart-2', '--enable-asserts', path.join(ddcPath, 'bin', '${command}.dart')]);
+      args.insertAll(0, [
+        '--preview-dart-2',
+        '--enable-asserts',
+        path.join(ddcPath, 'bin', '${command}.dart')
+      ]);
       command = dartBinary;
     } else {
       // Use built snapshot.
@@ -86,8 +90,17 @@
       mod = 'amd';
       break;
   }
-  var sdkJsPath = path.join(dartSdk, 'lib', 'dev_compiler', mod);
 
+  String sdkJsPath;
+  if (debug) {
+    var sdkRoot = path.dirname(path.dirname(ddcPath));
+    var buildDir = path.join(sdkRoot, Platform.isMacOS ? 'xcodebuild' : 'out');
+    var genDir = path.join(buildDir, 'ReleaseX64', 'gen', 'utils', 'dartdevc');
+    sdkJsPath = path.join(genDir, kernel ? 'kernel' : 'js', mod);
+  } else {
+    var suffix = kernel ? path.join('kernel', mod) : mod;
+    sdkJsPath = path.join(dartSdk, 'lib', 'dev_compiler', suffix);
+  }
   ProcessResult result;
   if (kernel) {
     var ddcSdk = path.join(dartSdk, 'lib', '_internal', 'ddc_sdk.dill');
diff --git a/pkg/dev_compiler/tool/ddc b/pkg/dev_compiler/tool/ddc
index addb332..937accd 100755
--- a/pkg/dev_compiler/tool/ddc
+++ b/pkg/dev_compiler/tool/ddc
@@ -63,8 +63,6 @@
 BASENAME=$( basename "${1%.*}")
 LIBROOT=$(cd $( dirname "${1%.*}") && pwd)
 
-export NODE_PATH=$GEN_DIR/js/common:$LIBROOT:$NODE_PATH
-
 if [ "$KERNEL" = true ]; then
 
   if [ ! -e $GEN_DIR/kernel/ddc_sdk.dill ]; then
@@ -74,6 +72,8 @@
     exit 1
   fi
 
+  NODE_PATH=$GEN_DIR/kernel/common:$LIBROOT:$NODE_PATH
+
   $SDK_DIR/sdk/bin/dartdevk --modules=node \
       --dart-sdk-summary=$GEN_DIR/kernel/ddc_sdk.dill \
       -o $LIBROOT/$BASENAME.js $*
@@ -86,6 +86,8 @@
     exit 1
   fi
 
+  NODE_PATH=$GEN_DIR/js/common:$LIBROOT:$NODE_PATH
+
   $SDK_DIR/sdk/bin/dartdevc --modules=node \
       --library-root=$LIBROOT --dart-sdk-summary=$GEN_DIR/ddc_sdk.sum \
       -o $LIBROOT/$BASENAME.js $*
diff --git a/pkg/dev_compiler/tool/ddw b/pkg/dev_compiler/tool/ddw
index 4941c00..86ecf9b 100755
--- a/pkg/dev_compiler/tool/ddw
+++ b/pkg/dev_compiler/tool/ddw
@@ -63,8 +63,6 @@
 BASENAME=$( basename "${1%.*}")
 LIBROOT=$(cd $( dirname "${1%.*}") && pwd)
 
-export NODE_PATH=$GEN_DIR/js/common:$LIBROOT:$NODE_PATH
-
 if [ "$KERNEL" = true ]; then
 
   if [ ! -e $GEN_DIR/kernel/ddc_sdk.dill ]; then
@@ -74,6 +72,8 @@
     exit 1
   fi
 
+  NODE_PATH=$GEN_DIR/kernel/common:$LIBROOT:$NODE_PATH
+
   dart -c $SDK_DIR/pkg/dev_compiler/bin/dartdevk.dart --modules=node \
       --dart-sdk-summary=$GEN_DIR/kernel/ddc_sdk.dill \
       -o $LIBROOT/$BASENAME.js $*
@@ -86,6 +86,8 @@
     exit 1
   fi
 
+  NODE_PATH=$GEN_DIR/js/common:$LIBROOT:$NODE_PATH
+
   dart -c $SDK_DIR/pkg/dev_compiler/bin/dartdevc.dart --modules=node \
       --library-root=$LIBROOT --dart-sdk-summary=$GEN_DIR/ddc_sdk.sum \
       -o $LIBROOT/$BASENAME.js $*
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
index 163e26c..0dd4e3e 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/classes.dart
@@ -28,8 +28,8 @@
 
 void _copyMembers(to, from) {
   var names = getOwnNamesAndSymbols(from);
-  for (var i = 0, n = JS('int', '#.length', names); i < n; ++i) {
-    var name = JS('', '#[#]', names, i);
+  for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+    String name = JS('', '#[#]', names, i);
     if (name == 'constructor') continue;
     _copyMember(to, from, name);
   }
@@ -38,14 +38,14 @@
 
 void _copyMember(to, from, name) {
   var desc = getOwnPropertyDescriptor(from, name);
-  if (JS('bool', '# == Symbol.iterator', name)) {
+  if (JS('!', '# == Symbol.iterator', name)) {
     // On native types, Symbol.iterator may already be present.
     // TODO(jmesserly): investigate if we still need this.
     // If so, we need to find a better solution.
     // See https://github.com/dart-lang/sdk/issues/28324
     var existing = getOwnPropertyDescriptor(to, name);
     if (existing != null) {
-      if (JS('bool', '#.writable', existing)) {
+      if (JS('!', '#.writable', existing)) {
         JS('', '#[#] = #.value', to, name, desc);
       }
       return;
@@ -201,18 +201,18 @@
 
 bool isJsInterop(obj) {
   if (obj == null) return false;
-  if (JS('bool', 'typeof # === "function"', obj)) {
+  if (JS('!', 'typeof # === "function"', obj)) {
     // A function is a Dart function if it has runtime type information.
-    return JS('bool', '#[#] == null', obj, _runtimeType);
+    return JS('!', '#[#] == null', obj, _runtimeType);
   }
   // Primitive types are not JS interop types.
-  if (JS('bool', 'typeof # !== "object"', obj)) return false;
+  if (JS('!', 'typeof # !== "object"', obj)) return false;
 
   // Extension types are not considered JS interop types.
   // Note that it is still possible to call typed JS interop methods on
   // extension types but the calls must be statically typed.
-  if (JS('bool', '#[#] != null', obj, _extensionType)) return false;
-  return JS('bool', '!($obj instanceof $Object)');
+  if (JS('!', '#[#] != null', obj, _extensionType)) return false;
+  return JS('!', '!($obj instanceof $Object)');
 }
 
 /// Get the type of a method from a type using the stored signature
@@ -227,7 +227,7 @@
   if (setters != null) {
     var type = JS('', '#[#]', setters, name);
     if (type != null) {
-      if (JS('bool', '# instanceof Array', type)) {
+      if (JS('!', '# instanceof Array', type)) {
         // The type has metadata attached.  Pull out just the type.
         // TODO(jmesserly): remove when we remove mirrors
         return JS('', '#[0]', type);
@@ -238,7 +238,7 @@
   var fields = getFields(type);
   if (fields != null) {
     var fieldInfo = JS('', '#[#]', fields, name);
-    if (fieldInfo != null && JS('bool', '!#.isFinal', fieldInfo)) {
+    if (fieldInfo != null && JS<bool>('!', '!#.isFinal', fieldInfo)) {
       return JS('', '#.type', fieldInfo);
     }
   }
@@ -285,14 +285,14 @@
 
 _getMembers(type, kind) {
   var sig = JS('', '#[#]', type, kind);
-  return JS('bool', 'typeof # == "function"', sig)
-      ? JS('', '#[#] = #', type, kind, sig())
+  return JS<bool>('!', 'typeof # == "function"', sig)
+      ? JS('', '#[#] = #()', type, kind, sig)
       : sig;
 }
 
 bool _hasMember(type, kind, name) {
   var sig = _getMembers(type, kind);
-  return sig != null && JS('bool', '# in #', name, sig);
+  return sig != null && JS<bool>('!', '# in #', name, sig);
 }
 
 bool hasMethod(type, name) => _hasMember(type, _methodSig, name);
@@ -307,14 +307,14 @@
 /// Install properties in prototype-first order.  Properties / descriptors from
 /// more specific types should overwrite ones from less specific types.
 void _installProperties(jsProto, dartType, installedParent) {
-  if (JS('bool', '# === #', dartType, Object)) {
+  if (JS('!', '# === #', dartType, Object)) {
     _installPropertiesForObject(jsProto);
     return;
   }
   // If the extension methods of the parent have been installed on the parent
   // of [jsProto], the methods will be available via prototype inheritance.
   var dartSupertype = JS('', '#.__proto__', dartType);
-  if (JS('bool', '# !== #', dartSupertype, installedParent)) {
+  if (JS('!', '# !== #', dartSupertype, installedParent)) {
     _installProperties(jsProto, dartSupertype, installedParent);
   }
 
@@ -350,7 +350,7 @@
   var jsProto = JS('', '#.prototype', jsType);
   if (jsProto == null) return;
 
-  if (JS('bool', '# === #', dartExtType, Object)) {
+  if (JS('!', '# === #', dartExtType, Object)) {
     _installPropertiesForGlobalObject(jsProto);
     return;
   }
@@ -359,7 +359,7 @@
       jsProto, dartExtType, JS('', '#[#]', jsProto, _extensionType));
 
   // Mark the JS type's instances so we can easily check for extensions.
-  if (JS('bool', '# !== #', dartExtType, JSFunction)) {
+  if (JS('!', '# !== #', dartExtType, JSFunction)) {
     JS('', '#[#] = #', jsProto, _extensionType, dartExtType);
   }
   JS('', '#[#] = #[#]', jsType, _methodSig, dartExtType, _methodSig);
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
index f9b8390..115a550 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
@@ -23,22 +23,22 @@
 }
 
 argumentError(value) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new ArgumentError.value(value);
 }
 
 throwUnimplementedError(String message) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new UnimplementedError(message);
 }
 
 assertFailed(message) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new AssertionErrorImpl(message);
 }
 
 throwCyclicInitializationError([Object field]) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new CyclicInitializationError(field);
 }
 
@@ -46,7 +46,7 @@
   // TODO(vsm): Per spec, we should throw an NSM here.  Technically, we ought
   // to thread through method info, but that uglifies the code and can't
   // actually be queried ... it only affects how the error is printed.
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new NoSuchMethodError(
       null, new Symbol('<Unexpected Null Value>'), null, null, null);
 }
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 213307f..cbeda90 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
@@ -98,7 +98,7 @@
 // implemented by the Object base class as those methods can always be
 // statically resolved.
 dload(obj, field, [mirrors = undefined]) {
-  if (JS('bool', 'typeof # == "function" && # == "call"', obj, field)) {
+  if (JS('!', 'typeof # == "function" && # == "call"', obj, field)) {
     return obj;
   }
   var f = _canonicalMember(obj, field);
@@ -111,7 +111,7 @@
     if (hasMethod(type, f)) return bind(obj, f, null);
 
     // Always allow for JS interop objects.
-    if (!JS('bool', '#', mirrors) && isJsInterop(obj)) {
+    if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
       return JS('', '#[#]', obj, f);
     }
   }
@@ -143,12 +143,12 @@
   if (f != null) {
     var setterType = getSetterType(getType(obj), f);
     if (setterType != null) {
-      if (JS('bool', '#', mirrors))
+      if (JS('!', '#', mirrors))
         setterType = _stripGenericArguments(setterType);
       return JS('', '#[#] = #._check(#)', obj, f, setterType, value);
     }
     // Always allow for JS interop objects.
-    if (!JS('bool', '#', mirrors) && isJsInterop(obj)) {
+    if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
       return JS('', '#[#] = #', obj, f, value);
     }
   }
@@ -161,15 +161,15 @@
 /// actuals.
 bool _checkApply(FunctionType type, List actuals, namedActuals) {
   // Check for too few required arguments.
-  var actualsCount = JS('int', '#.length', actuals);
+  int actualsCount = JS('!', '#.length', actuals);
   var required = type.args;
-  var requiredCount = JS('int', '#.length', required);
+  int requiredCount = JS('!', '#.length', required);
   if (actualsCount < requiredCount) return false;
 
   // Check for too many postional arguments.
   var extras = actualsCount - requiredCount;
   var optionals = type.optionals;
-  if (extras > JS('int', '#.length', optionals)) return false;
+  if (extras > JS<int>('!', '#.length', optionals)) return false;
 
   // Check if we have invalid named arguments.
   Iterable names;
@@ -177,7 +177,7 @@
   if (namedActuals != null) {
     names = getOwnPropertyNames(namedActuals);
     for (var name in names) {
-      if (!JS('bool', '#.hasOwnProperty(#)', named, name)) return false;
+      if (!JS('!', '#.hasOwnProperty(#)', named, name)) return false;
     }
   }
   // Now that we know the signature matches, we can perform type checks.
@@ -222,17 +222,19 @@
   })()''');
 
 Symbol _dartSymbol(name) {
-  return (JS('bool', 'typeof # === "symbol"', name))
+  return (JS<bool>('!', 'typeof # === "symbol"', name))
       ? JS('Symbol', '#(new #.new(#, #))', const_, PrivateSymbol,
           _toSymbolName(name), name)
-      : JS('Symbol', '#(#.new(#))', const_, Symbol, _toDisplayName(name));
+      : JS('Symbol', '#(new #.new(#))', const_, internal.Symbol,
+          _toDisplayName(name));
 }
 
 Symbol _setterSymbol(name) {
-  return (JS('bool', 'typeof # === "symbol"', name))
+  return (JS<bool>('!', 'typeof # === "symbol"', name))
       ? JS('Symbol', '#(new #.new(# + "=", #))', const_, PrivateSymbol,
           _toSymbolName(name), name)
-      : JS('Symbol', '#(#.new(# + "="))', const_, Symbol, _toDisplayName(name));
+      : JS('Symbol', '#(new #.new(# + "="))', const_, internal.Symbol,
+          _toDisplayName(name));
 }
 
 _checkAndCall(f, ftype, obj, typeArgs, args, named, displayName) =>
@@ -358,7 +360,7 @@
 
 /// Shared code for dsend, dindex, and dsetindex.
 callMethod(obj, name, typeArgs, args, named, displayName) {
-  if (JS('bool', 'typeof # == "function" && # == "call"', obj, name)) {
+  if (JS('!', 'typeof # == "function" && # == "call"', obj, name)) {
     return dgcall(obj, typeArgs, args, named);
   }
   var symbol = _canonicalMember(obj, name);
@@ -434,12 +436,13 @@
   });
 })()''');
 
+@notNull
 @JSExportName('is')
 bool instanceOf(obj, type) {
   if (obj == null) {
-    return JS('bool', '# == # || #', type, Null, _isTop(type));
+    return JS('!', '# == # || #', type, Null, _isTop(type));
   }
-  return JS('#', '!!#', isSubtype(getReifiedType(obj), type));
+  return JS('!', '!!#', isSubtype(getReifiedType(obj), type));
 }
 
 @JSExportName('as')
@@ -448,7 +451,7 @@
   var actual = getReifiedType(obj);
   var result = isSubtype(actual, type);
   if (JS(
-      'bool',
+      '!',
       '# === true || # === null && # && '
       'dart.__ignoreWhitelistedErrors && #(#, #)',
       result,
@@ -484,7 +487,7 @@
 asInt(obj) {
   if (obj == null) return null;
 
-  if (JS('bool', 'Math.floor(#) != #', obj, obj)) {
+  if (JS('!', 'Math.floor(#) != #', obj, obj)) {
     castError(obj, JS('', '#', int), false);
   }
   return obj;
@@ -527,7 +530,7 @@
 }
 
 bool dassert(value) {
-  if (JS('bool', '# != null && #[#] instanceof #', value, value, _runtimeType,
+  if (JS('!', '# != null && #[#] instanceof #', value, value, _runtimeType,
       AbstractFunctionType)) {
     value = dcall(value, []);
   }
@@ -542,8 +545,8 @@
 const _maxErrorCache = 10;
 
 bool _isJsError(exception) {
-  return JS('bool', '#.Error != null && # instanceof #.Error', global_,
-      exception, global_);
+  return JS('!', '#.Error != null && # instanceof #.Error', global_, exception,
+      global_);
 }
 
 // Record/return the JS error for an exception.  If an error was already
@@ -552,7 +555,7 @@
   if (_isJsError(exception)) return exception;
 
   var useExpando =
-      exception != null && JS('bool', 'typeof # == "object"', exception);
+      exception != null && JS<bool>('!', 'typeof # == "object"', exception);
   var error;
   if (useExpando) {
     error = JS('', '#[#]', exception, _error);
@@ -734,23 +737,12 @@
   // function minimal.
   // This pattern resulted from performance testing; it found that dispatching
   // was the fastest solution, even for primitive types.
-  return JS('bool', '# == null ? # == null : #[#](#)', x, y, x,
+  return JS('!', '# == null ? # == null : #[#](#)', x, y, x,
       extensionSymbol('_equals'), y);
 }
 
 int hashCode(obj) {
-  return obj == null ? 0 : JS('int', '#[#]', obj, extensionSymbol('hashCode'));
-}
-
-hashKey(k) {
-  if (k == null) return 0;
-  switch (JS('String', 'typeof #', k)) {
-    case "object":
-    case "function":
-      return JS('int', '#[#] & 0x3ffffff', k, extensionSymbol('hashCode'));
-  }
-  // For primitive types we can store the key directly in an ES6 Map.
-  return k;
+  return obj == null ? 0 : JS('!', '#[#]', obj, extensionSymbol('hashCode'));
 }
 
 @JSExportName('toString')
@@ -779,7 +771,7 @@
 
 /// The default implementation of `noSuchMethod` to match `Object.noSuchMethod`.
 defaultNoSuchMethod(obj, Invocation i) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new NoSuchMethodError.withInvocation(obj, i);
 }
 
@@ -808,14 +800,14 @@
 
 _canonicalMember(obj, name) {
   // Private names are symbols and are already canonical.
-  if (JS('bool', 'typeof # === "symbol"', name)) return name;
+  if (JS('!', 'typeof # === "symbol"', name)) return name;
 
-  if (obj != null && JS('bool', '#[#] != null', obj, _extensionType)) {
+  if (obj != null && JS<bool>('!', '#[#] != null', obj, _extensionType)) {
     return JS('', 'dartx.#', name);
   }
 
   // Check for certain names that we can't use in JS
-  if (JS('bool', '# == "constructor" || # == "prototype"', name, name)) {
+  if (JS('!', '# == "constructor" || # == "prototype"', name, name)) {
     JS('', '# = "+" + #', name, name);
   }
   return name;
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart
index 874a3fa..95af629 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart
@@ -85,10 +85,10 @@
 /// different from the user-visible Type object returned by calling
 /// `runtimeType` on some Dart object.
 getReifiedType(obj) {
-  switch (JS('String', 'typeof #', obj)) {
+  switch (JS<String>('!', 'typeof #', obj)) {
     case "object":
       if (obj == null) return JS('', '#', Null);
-      if (JS('bool', '# instanceof #', obj, Object)) {
+      if (JS('!', '# instanceof #', obj, Object)) {
         return JS('', '#.constructor', obj);
       }
       var result = JS('', '#[#]', obj, _extensionType);
@@ -118,7 +118,7 @@
 Type wrapType(type) {
   // If we've already wrapped this type once, use the previous wrapper. This
   // way, multiple references to the same type return an identical Type.
-  if (JS('bool', '#.hasOwnProperty(#)', type, _typeObject)) {
+  if (JS('!', '#.hasOwnProperty(#)', type, _typeObject)) {
     return JS('', '#[#]', type, _typeObject);
   }
   return JS('Type', '#[#] = #', type, _typeObject, new WrappedType(type));
@@ -141,7 +141,7 @@
 }
 
 String getSourceMap(module) {
-  return JS('String', '#.get(#)', _loadedSourceMaps, module);
+  return JS<String>('!', '#.get(#)', _loadedSourceMaps, module);
 }
 
 /// Return all library objects in the specified module.
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/runtime.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/runtime.dart
index be587bb..fd5a32b 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/runtime.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/runtime.dart
@@ -10,6 +10,7 @@
 
 import 'dart:_foreign_helper' show JS, JSExportName, rest, spread;
 import 'dart:_interceptors' show JSArray, jsNull, JSFunction;
+import 'dart:_internal' as internal show Symbol;
 import 'dart:_js_helper'
     show
         AssertionErrorImpl,
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
index d85716f..8ac9b89 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
@@ -79,7 +79,7 @@
   check_T(object) => object;
 }
 
-bool _isJsObject(obj) => JS('bool', '# === #', getReifiedType(obj), jsobject);
+bool _isJsObject(obj) => JS('!', '# === #', getReifiedType(obj), jsobject);
 
 class LazyJSType extends TypeRep {
   final Function() _rawJSType;
@@ -106,7 +106,7 @@
 
   bool isRawType(obj) {
     var raw = _raw();
-    if (raw != null) return JS('bool', '# instanceof #', obj, raw);
+    if (raw != null) return JS('!', '# instanceof #', obj, raw);
     // Treat as anonymous: return true for any JS object.
     return _isJsObject(obj);
   }
@@ -302,7 +302,7 @@
     // identical function types that don't canonicalize
     // to the same object since we won't fall into this
     // fast path.
-    if (extra == null && JS('bool', '#.length < 3', args)) {
+    if (extra == null && JS<bool>('!', '#.length < 3', args)) {
       return _createSmall(returnType, args);
     }
     args = _canonicalizeArray(args, _fnTypeArrayArgMap);
@@ -311,7 +311,7 @@
     if (extra == null) {
       keys = [returnType, args];
       create = () => new FunctionType(returnType, args, [], JS('', '{}'));
-    } else if (JS('bool', '# instanceof Array', extra)) {
+    } else if (JS('!', '# instanceof Array', extra)) {
       var optionals =
           _canonicalizeArray(JS('', '#', extra), _fnTypeArrayArgMap);
       keys = [returnType, args, optionals];
@@ -327,9 +327,9 @@
 
   List _process(List array) {
     var result = [];
-    for (var i = 0; JS('bool', '# < #.length', i, array); ++i) {
+    for (var i = 0; JS<bool>('!', '# < #.length', i, array); ++i) {
       var arg = JS('', '#[#]', array, i);
-      if (JS('bool', '# instanceof Array', arg)) {
+      if (JS('!', '# instanceof Array', arg)) {
         JS('', '#.push(#.slice(1))', metadata, arg);
         JS('', '#.push(#[0])', result, arg);
       } else {
@@ -360,7 +360,7 @@
     var result = <String, Object>{};
     var names = getOwnPropertyNames(named);
     JS('', '#.sort()', names);
-    for (var i = 0; JS('bool', '# < #.length', i, names); ++i) {
+    for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
       String name = JS('!', '#[#]', names, i);
       result[name] = JS('', '#[#]', named, name);
     }
@@ -371,28 +371,28 @@
     if (_stringValue != null) return _stringValue;
 
     var buffer = '(';
-    for (var i = 0; JS('bool', '# < #.length', i, args); ++i) {
+    for (var i = 0; JS<bool>('!', '# < #.length', i, args); ++i) {
       if (i > 0) {
         buffer += ', ';
       }
       buffer += typeName(JS('', '#[#]', args, i));
     }
-    if (JS('bool', '#.length > 0', optionals)) {
-      if (JS('bool', '#.length > 0', args)) buffer += ', ';
+    if (JS('!', '#.length > 0', optionals)) {
+      if (JS('!', '#.length > 0', args)) buffer += ', ';
       buffer += '[';
-      for (var i = 0; JS('bool', '# < #.length', i, optionals); ++i) {
+      for (var i = 0; JS<bool>('!', '# < #.length', i, optionals); ++i) {
         if (i > 0) {
           buffer += ', ';
         }
         buffer += typeName(JS('', '#[#]', optionals, i));
       }
       buffer += ']';
-    } else if (JS('bool', 'Object.keys(#).length > 0', named)) {
-      if (JS('bool', '#.length > 0', args)) buffer += ', ';
+    } else if (JS('!', 'Object.keys(#).length > 0', named)) {
+      if (JS('!', '#.length > 0', args)) buffer += ', ';
       buffer += '{';
       var names = getOwnPropertyNames(named);
       JS('', '#.sort()', names);
-      for (var i = 0; JS('bool', '# < #.length', i, names); ++i) {
+      for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
         if (i > 0) {
           buffer += ', ';
         }
@@ -410,11 +410,11 @@
 
   @JSExportName('is')
   bool is_T(obj) {
-    if (JS('bool', 'typeof # == "function"', obj)) {
+    if (JS('!', 'typeof # == "function"', obj)) {
       var actual = JS('', '#[#]', obj, _runtimeType);
       // If there's no actual type, it's a JS function.
       // Allow them to subtype all Dart function types.
-      return JS('bool', '# == null || !!#', actual, isSubtype(actual, this));
+      return JS('!', '# == null || !!#', actual, isSubtype(actual, this));
     }
     return false;
   }
@@ -429,7 +429,7 @@
   @JSExportName('as')
   as_T(obj, [@notNull bool isImplicit = false]) {
     if (obj == null) return obj;
-    if (JS('bool', 'typeof # == "function"', obj)) {
+    if (JS('!', 'typeof # == "function"', obj)) {
       var actual = JS('', '#[#]', obj, _runtimeType);
       // If there's no actual type, it's a JS function.
       // Allow them to subtype all Dart function types.
@@ -466,14 +466,14 @@
     for (int i = 0, n = JS('!', '#.length', typeArgs); i < n; ++i) {
       if (i > 0) result += ', ';
       var typeArg = JS('', '#[#]', typeArgs, i);
-      if (JS('bool', '# !== #', typeArg, _dynamic)) allDynamic = false;
+      if (JS('!', '# !== #', typeArg, _dynamic)) allDynamic = false;
       result += typeName(typeArg);
     }
     result += '>';
     return allDynamic ? name : result;
   }
 
-  String get name => JS('String', '#', _name);
+  String get name => JS('!', '#', _name);
 
   AbstractFunctionType get functionType {
     var ft = _functionType;
@@ -507,7 +507,7 @@
 
   GenericFunctionType(instantiateTypeParts, this._instantiateTypeBounds)
       : _instantiateTypeParts = instantiateTypeParts,
-        formalCount = JS('int', '#.length', instantiateTypeParts);
+        formalCount = JS('!', '#.length', instantiateTypeParts);
 
   List<TypeVariable> get typeFormals {
     if (_typeFormals != null) return _typeFormals;
@@ -548,7 +548,7 @@
       if (i != 0) s += ", ";
       s += JS<String>('!', '#[#].name', typeFormals, i);
       var bound = typeBounds[i];
-      if (JS('bool', '# !== # && # !== #', bound, dynamic, bound, Object)) {
+      if (JS('!', '# !== # && # !== #', bound, dynamic, bound, Object)) {
         s += " extends $bound";
       }
     }
@@ -635,24 +635,25 @@
     return defaults;
   }
 
+  @notNull
   @JSExportName('is')
   bool is_T(obj) {
-    if (JS('bool', 'typeof # == "function"', obj)) {
+    if (JS('!', 'typeof # == "function"', obj)) {
       var actual = JS('', '#[#]', obj, _runtimeType);
-      return JS('bool', '# != null && !!#', actual, isSubtype(actual, this));
+      return JS('!', '# != null && !!#', actual, isSubtype(actual, this));
     }
     return false;
   }
 
   @JSExportName('as')
   as_T(obj) {
-    if (obj == null || JS('bool', '#', is_T(obj))) return obj;
+    if (obj == null || is_T(obj)) return obj;
     return castError(obj, this, false);
   }
 
   @JSExportName('_check')
   check_T(obj) {
-    if (obj == null || JS('bool', '#', is_T(obj))) return obj;
+    if (obj == null || is_T(obj)) return obj;
     return castError(obj, this, true);
   }
 }
@@ -715,7 +716,7 @@
 bool isType(obj) => JS('', '#[#] === #', obj, _runtimeType, Type);
 
 void checkTypeBound(type, bound, name) {
-  if (JS('bool', '#', isSubtype(type, bound))) return;
+  if (JS('!', '#', isSubtype(type, bound))) return;
 
   throwTypeError('type `$type` does not extend `$bound`'
       ' of `$name`.');
@@ -835,12 +836,12 @@
   // code generator happy though.
   var map;
   bool result;
-  if (JS('bool', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
+  if (JS('!', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
     JS('', '#[#] = # = new Map()', t1, _subtypeCache, map);
   } else {
     map = JS('', '#[#]', t1, _subtypeCache);
     result = JS('bool|Null', '#.get(#)', map, t2);
-    if (JS('bool', '# !== void 0', result)) return result;
+    if (JS('!', '# !== void 0', result)) return result;
   }
   result =
       JS('bool|Null', '# === # || #(#, #, true)', t1, t2, _isSubtype, t1, t2);
@@ -850,13 +851,15 @@
 
 final _subtypeCache = JS('', 'Symbol("_subtypeCache")');
 
-_isBottom(type) => JS('bool', '# == # || # == #', type, bottom, type, Null);
+@notNull
+bool _isBottom(type) => JS('!', '# == # || # == #', type, bottom, type, Null);
 
-_isTop(type) {
+@notNull
+bool _isTop(type) {
   if (_isFutureOr(type)) {
     return _isTop(JS('', '#[0]', getGenericArgs(type)));
   }
-  return JS('bool', '# == # || # == # || # == #', type, Object, type, dynamic,
+  return JS('!', '# == # || # == # || # == #', type, Object, type, dynamic,
       type, void_);
 }
 
@@ -979,7 +982,7 @@
   return ${_isFunctionSubtype(t1, t2, isCovariant)};
 })()''');
 
-_isInterfaceSubtype(t1, t2, isCovariant) => JS('', '''(() => {
+bool _isInterfaceSubtype(t1, t2, isCovariant) => JS('', '''(() => {
   // We support Dart's covariant generics with the caveat that we do not
   // substitute bottom for dynamic in subtyping rules.
   // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index 87b3cbb..8e3b738 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -39,13 +39,13 @@
 /// This error indicates a strong mode specific failure, other than a type
 /// assertion failure (TypeError) or CastError.
 void throwTypeError(String message) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   throw new TypeErrorImpl(message);
 }
 
 /// This error indicates a bug in the runtime or the compiler.
 void throwInternalError(String message) {
-  if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
+  if (JS('!', 'dart.__trapRuntimeErrors')) JS('', 'debugger');
   JS('', 'throw Error(#)', message);
 }
 
@@ -103,14 +103,14 @@
 
 copyProperty(to, from, name) {
   var desc = getOwnPropertyDescriptor(from, name);
-  if (JS('bool', '# == Symbol.iterator', name)) {
+  if (JS('!', '# == Symbol.iterator', name)) {
     // On native types, Symbol.iterator may already be present.
     // TODO(jmesserly): investigate if we still need this.
     // If so, we need to find a better solution.
     // See https://github.com/dart-lang/sdk/issues/28324
     var existing = getOwnPropertyDescriptor(to, name);
     if (existing != null) {
-      if (JS('bool', '#.writable', existing)) {
+      if (JS('!', '#.writable', existing)) {
         JS('', '#[#] = #.value', to, name, desc);
       }
       return;
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 38e9e65..ae5273a 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -22,10 +22,18 @@
   var parserOptions = parser.parse(args);
   var rest = parserOptions.rest;
 
-  Directory.current = path.dirname(path.dirname(path.fromUri(Platform.script)));
+  var ddcPath = path.dirname(path.dirname(path.fromUri(Platform.script)));
+  Directory.current = ddcPath;
 
-  var outputPath =
-      path.absolute(rest.length > 0 ? rest[0] : 'gen/sdk/kernel/ddc_sdk.dill');
+  String outputPath;
+  if (rest.isNotEmpty) {
+    outputPath = path.absolute(rest[0]);
+  } else {
+    var sdkRoot = path.absolute(path.dirname(path.dirname(ddcPath)));
+    var buildDir = path.join(sdkRoot, Platform.isMacOS ? 'xcodebuild' : 'out');
+    var genDir = path.join(buildDir, 'ReleaseX64', 'gen', 'utils', 'dartdevc');
+    outputPath = path.join(genDir, 'kernel', 'ddc_sdk.dill');
+  }
 
   var inputPath = path.absolute('tool/input_sdk');
   var target = new DevCompilerTarget();
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 92a2607..069a2f2 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -401,7 +401,7 @@
 typed_data_with_limited_ints_test: Skip # Requires fixed-size int64 support.
 
 [ $runtime != none && ($compiler == dartdevc || $compiler == dartdevk) ]
-bigint_test: Pass, Slow
+bigint_test: Pass, Slow, Timeout
 compare_to2_test: RuntimeError # Issue 30170
 date_time10_test: RuntimeError # Issue 29921
 error_stack_trace_test/nullThrown: RuntimeError # .stackTrace not present for exception caught from 'throw null;'
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index d534e75..ce25653 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -298,9 +298,9 @@
 bad_override_test/01: MissingCompileTimeError
 bad_override_test/02: MissingCompileTimeError
 bad_override_test/03: MissingCompileTimeError
-built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 32194
-built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 32194
-built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 32194
+built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 30450, test name contains hyphen
+built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 30450, test name contains hyphen
+built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 30450, test name contains hyphen
 call_method_as_cast_test/06: RuntimeError # Kernel allows classes to subtype `Function` so DDK elides the explicit cast.
 call_method_implicit_tear_off_implements_function_test/05: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
 call_method_implicit_tear_off_implements_function_test/06: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index 584596a..bbfa3a4 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -4,6 +4,7 @@
 
 [ $compiler == dartdevc ]
 html/element_types_keygen_test: CompileTimeError # Chrome 57 keygen removed
+html/mediasource_test: RuntimeError # Issue 29922
 html/xhr_test: Pass, Slow
 
 [ $compiler == dartdevk ]
@@ -31,6 +32,7 @@
 html/client_rect_test: Pass, RuntimeError # Issue 31019
 html/css_test: Pass, RuntimeError # Issue 31019
 html/fileapi_entry_test: Pass, RuntimeError # Issue 31019
+html/interactive_media_test: Skip # Requires interactive camera, microphone permissions.
 
 [ $system == windows && ($compiler == dartdevc || $compiler == dartdevk) ]
 html/xhr_test: Skip # Times out. Issue 21527
@@ -88,7 +90,6 @@
 html/js_typed_interop_type_test: RuntimeError # Issue 30947
 html/js_util_test: RuntimeError # Issue 29922
 html/media_stream_test: RuntimeError # Issue 29922
-html/mediasource_test: RuntimeError # Issue 29922
 html/no_linked_scripts_htmltest: Skip # Issue 29919
 html/notification_permission_test: Timeout # Issue 32002
 html/scripts_htmltest: Skip # Issue 29919
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 4d60b05..1cf0526 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'utils.dart';
+import 'configuration.dart' show Compiler;
 
 String dart2jsHtml(String title, String scriptPath) {
   return """
@@ -40,10 +41,12 @@
 /// The [testName] is the short name of the test without any subdirectory path
 /// or extension, like "math_test". The [testJSDir] is the relative path to the
 /// build directory where the dartdevc-generated JS file is stored.
-String dartdevcHtml(String testName, String testJSDir, String buildDir) {
+String dartdevcHtml(String testName, String testJSDir, Compiler compiler) {
+  var isKernel = compiler == Compiler.dartdevk;
+  var sdkPath = isKernel ? 'kernel/amd/dart_sdk' : 'js/amd/dart_sdk';
+  var pkgDir = isKernel ? 'pkg_kernel' : 'pkg';
   var packagePaths = testPackages
-      .map((package) => '    "$package": "/root_dart/$buildDir/gen/utils/'
-          'dartdevc/pkg/$package",')
+      .map((p) => '    "$p": "/root_build/gen/utils/dartdevc/$pkgDir/$p",')
       .join("\n");
 
   return """
@@ -69,7 +72,7 @@
 var require = {
   baseUrl: "/root_dart/$testJSDir",
   paths: {
-    "dart_sdk": "/root_build/gen/utils/dartdevc/js/amd/dart_sdk",
+    "dart_sdk": "/root_build/gen/utils/dartdevc/$sdkPath",
 $packagePaths
   },
   waitSeconds: 30,
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 9661adc..15ac03d 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -605,13 +605,14 @@
         .toNativePath();
 
     var summaryInputDir = new Path(_configuration.buildDirectory)
-        .append("/gen/utils/dartdevc/pkg")
+        .append("/gen/utils/dartdevc/pkg_kernel")
         .absolute
         .toNativePath();
 
     args.addAll([
       "--dart-sdk-summary",
       sdkSummary,
+      "--no-summarize",
       "-o",
       outputFile,
       inputFile,
@@ -622,7 +623,7 @@
     // get recompiled into the test's own module.
     for (var package in testPackages) {
       var summary = new Path(_configuration.buildDirectory)
-          .append("/gen/utils/dartdevc/pkg/$package.dill")
+          .append("/gen/utils/dartdevc/pkg_kernel/$package.dill")
           .absolute
           .toNativePath();
       args.add("-s");
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index d7beed3..4a16a03 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1061,7 +1061,7 @@
         // Always run with synchronous starts of `async` functions.
         // If we want to make this dependent on other parameters or flags,
         // this flag could be become conditional.
-        content = dartdevcHtml(nameNoExt, jsDir, buildDir);
+        content = dartdevcHtml(nameNoExt, jsDir, configuration.compiler);
       }
     }
 
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index d6fcbaa..abadd8d 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -128,6 +128,7 @@
   # tools/patch_sdk.dart and then change this to use generate_patch_sdk().
   deps = [
     ":dartdevc_files_stamp",
+    ":dartdevc_sdk_patch_stamp",
 
     # The patch script uses several packages, including analyzer, so consider
     # it dirty if any of those change.
@@ -252,6 +253,11 @@
   output = "$target_gen_dir/dartdevc_files.stamp"
 }
 
+create_timestamp_file("dartdevc_sdk_patch_stamp") {
+  path = rebase_path("../../pkg/dev_compiler/tool/input_sdk")
+  output = "$target_gen_dir/dartdevc_sdk_patch_stamp.stamp"
+}
+
 # Compiles the packages used by the tests to JS with dartdevc so that they are
 # available for loading by the tests.
 prebuilt_dart_action("dartdevc_test_pkg") {
@@ -318,6 +324,7 @@
 prebuilt_dart_action("dartdevk_sdk") {
   deps = [
     ":dartdevc_files_stamp",
+    ":dartdevc_sdk_patch_stamp",
   ]
 
   inputs = [