Fix missing classes in native emitters superclass info.

Also tidied up the dispatch metadata generator.

Review URL: https://codereview.chromium.org//11421049

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15340 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index 6e87ec4..c2542ef 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -285,16 +285,12 @@
     void visit(ClassElement cls) {
       if (seen.contains(cls)) return;
       seen.add(cls);
-      for (final ClassElement subclass in getDirectSubclasses(cls)) {
-        visit(subclass);
-      }
+      getDirectSubclasses(cls).forEach(visit);
       classes.add(cls);
     }
-    for (final ClassElement classElement in classesWithDynamicDispatch) {
-      visit(classElement);
-    }
+    classesWithDynamicDispatch.forEach(visit);
 
-    Collection<ClassElement> dispatchClasses = classes.filter(
+    Collection<ClassElement> preorderDispatchClasses = classes.filter(
         (cls) => !getDirectSubclasses(cls).isEmpty &&
                   classesWithDynamicDispatch.contains(cls));
 
@@ -318,9 +314,12 @@
 
     // Temporary variables for common substrings.
     List<String> varNames = <String>[];
-    // var -> expression
-    Map<dynamic, js.Expression> varDefns = new Map<dynamic, js.Expression>();
-    // tag -> expression (a string or a variable)
+    // Values of temporary variables.
+    Map<String, js.Expression> varDefns = new Map<String, js.Expression>();
+
+    // Expression to compute tags string for a class.  The expression will
+    // initially be a string or expression building a string, but may be
+    // replaced with a variable reference to the common substring.
     Map<ClassElement, js.Expression> tagDefns =
         new Map<ClassElement, js.Expression>();
 
@@ -332,13 +331,21 @@
       void walk(ClassElement cls) {
         for (final ClassElement subclass in getDirectSubclasses(cls)) {
           ClassElement tag = subclass;
-          var existing = tagDefns[tag];
+          js.Expression existing = tagDefns[tag];
           if (existing == null) {
+            // [subclass] is still within the subtree between dispatch classes.
             subtags.add(toNativeName(tag));
             walk(subclass);
           } else {
-            if (varDefns.containsKey(existing)) {
-              expressions.add(existing);
+            // [subclass] is one of the preorderDispatchClasses, so CSE this
+            // reference with the previous reference.
+            if (existing is js.VariableUse &&
+                varDefns.containsKey(existing.name)) {
+              // We end up here if the subclasses have a DAG structure.  We
+              // don't have DAGs yet, but if the dispatch is used for mixins
+              // that will be a possibility.
+              // Re-use the previously created temporary variable.
+              expressions.add(new js.VariableUse(existing.name));
             } else {
               String varName = 'v${varNames.length}_${tag.name.slowToString()}';
               varNames.add(varName);
@@ -350,6 +357,7 @@
         }
       }
       walk(classElement);
+
       if (!subtags.isEmpty) {
         expressions.add(
             new js.LiteralString("'${Strings.join(subtags, '|')}'"));
@@ -366,7 +374,7 @@
       return expression;
     }
 
-    for (final ClassElement classElement in dispatchClasses) {
+    for (final ClassElement classElement in preorderDispatchClasses) {
       tagDefns[classElement] = makeExpression(classElement);
     }
 
@@ -394,7 +402,7 @@
       //   [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
       js.Expression table =
           new js.ArrayInitializer.from(
-              dispatchClasses.map((cls) =>
+              preorderDispatchClasses.map((cls) =>
                   new js.ArrayInitializer.from([
                       new js.LiteralString("'${toNativeName(cls)}'"),
                       tagDefns[cls]])));
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 0c1579b..8de208f 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -296,6 +296,8 @@
 
   final CodeEmitterTask emitter;
 
+  final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>();
+
   NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter)
     : super(world, compiler, compiler.enableNativeLiveTypeAnalysis);
 
@@ -320,6 +322,14 @@
   }
 
   void addSubtypes(ClassElement cls, NativeEmitter emitter) {
+    if (!cls.isNative()) return;
+    if (doneAddSubtypes.contains(cls)) return;
+    doneAddSubtypes.add(cls);
+
+    // Walk the superclass chain since classes on the superclass chain might not
+    // be instantiated (abstract or simply unused).
+    addSubtypes(cls.superclass, emitter);
+
     for (DartType type in cls.allSupertypes) {
       List<Element> subtypes = emitter.subtypes.putIfAbsent(
           type.element,