| Index: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
|
| index 8869076cdf9e1a14d082f3f330f18c07d4760f5c..74b4ec64bd26f46944458e0e2739f1297c7ea7ed 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
|
| @@ -843,52 +843,72 @@ class FragmentEmitter {
|
| /// In this section prototype chains are updated and mixin functions are
|
| /// copied.
|
| js.Statement emitInheritance(Fragment fragment) {
|
| - List<js.Expression> inheritCalls = <js.Expression>[];
|
| - List<js.Expression> mixinCalls = <js.Expression>[];
|
| + List<js.Statement> inheritCalls = <js.Statement>[];
|
| + List<js.Statement> mixinCalls = <js.Statement>[];
|
|
|
| Set<Class> classesInFragment = new Set<Class>();
|
| for (Library library in fragment.libraries) {
|
| classesInFragment.addAll(library.classes);
|
| }
|
|
|
| - Set<Class> emittedClasses = new Set<Class>();
|
| + Map<Class, List<Class>> subclasses = <Class, List<Class>>{};
|
| + Set<Class> seen = new Set<Class>();
|
|
|
| - void emitInheritanceForClass(cls) {
|
| - if (cls == null || emittedClasses.contains(cls)) return;
|
| + void collect(cls) {
|
| + if (cls == null || seen.contains(cls)) return;
|
|
|
| Class superclass = cls.superclass;
|
| if (classesInFragment.contains(superclass)) {
|
| - emitInheritanceForClass(superclass);
|
| + collect(superclass);
|
| }
|
|
|
| - js.Expression superclassReference = (superclass == null)
|
| - ? new js.LiteralNull()
|
| - : classReference(superclass);
|
| -
|
| - inheritCalls.add(
|
| - js.js('inherit(#, #)', [classReference(cls), superclassReference]));
|
| + subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls);
|
|
|
| - emittedClasses.add(cls);
|
| + seen.add(cls);
|
| }
|
|
|
| for (Library library in fragment.libraries) {
|
| for (Class cls in library.classes) {
|
| - emitInheritanceForClass(cls);
|
| + collect(cls);
|
|
|
| if (cls.isMixinApplication) {
|
| MixinApplication mixin = cls;
|
| - mixinCalls.add(js.js('mixin(#, #)',
|
| + mixinCalls.add(js.js.statement('mixin(#, #)',
|
| [classReference(cls), classReference(mixin.mixinClass)]));
|
| }
|
| }
|
| }
|
|
|
| + js.Expression temp = null;
|
| + for (Class superclass in subclasses.keys) {
|
| + List<Class> list = subclasses[superclass];
|
| + js.Expression superclassReference = (superclass == null)
|
| + ? new js.LiteralNull()
|
| + : classReference(superclass);
|
| + if (list.length == 1) {
|
| + inheritCalls.add(js.js.statement('inherit(#, #)',
|
| + [classReference(list.single), superclassReference]));
|
| + } else {
|
| + // Hold common superclass in temporary for sequence of calls.
|
| + if (temp == null) {
|
| + String tempName = '_';
|
| + temp = new js.VariableUse(tempName);
|
| + var declaration = new js.VariableDeclaration(tempName);
|
| + inheritCalls.add(
|
| + js.js.statement('var # = #', [declaration, superclassReference]));
|
| + } else {
|
| + inheritCalls
|
| + .add(js.js.statement('# = #', [temp, superclassReference]));
|
| + }
|
| + for (Class cls in list) {
|
| + inheritCalls.add(
|
| + js.js.statement('inherit(#, #)', [classReference(cls), temp]));
|
| + }
|
| + }
|
| + }
|
| +
|
| return wrapPhase(
|
| - 'inheritance',
|
| - js.js.statement('{#; #;}', [
|
| - inheritCalls.map((e) => new js.ExpressionStatement(e)),
|
| - mixinCalls.map((e) => new js.ExpressionStatement(e))
|
| - ]));
|
| + 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls]));
|
| }
|
|
|
| /// Emits the setup of method aliases.
|
|
|