Index: sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart |
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 6e87ec401683e521c81a6ab0848feee0eabdd555..c2542ef768db514920b37b0537583c57d667b6bb 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 @@ function(cls, desc) { |
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 @@ function(cls, desc) { |
// 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 @@ function(cls, desc) { |
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 @@ function(cls, desc) { |
} |
} |
walk(classElement); |
+ |
if (!subtags.isEmpty) { |
expressions.add( |
new js.LiteralString("'${Strings.join(subtags, '|')}'")); |
@@ -366,7 +374,7 @@ function(cls, desc) { |
return expression; |
} |
- for (final ClassElement classElement in dispatchClasses) { |
+ for (final ClassElement classElement in preorderDispatchClasses) { |
tagDefns[classElement] = makeExpression(classElement); |
} |
@@ -394,7 +402,7 @@ function(cls, desc) { |
// [['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]]))); |