Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| index 44577dc9e2afd94aebf9475424d8e55da806b078..0d0f27881b43ecb21e2e2c17fc132b95dcf75478 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| @@ -763,7 +763,7 @@ $lazyInitializerLogic |
| includeBackendMembers: true, |
| includeSuperMembers: false); |
| - generateIsTestsOn(classElement, (Element other) { |
| + void generateIsTest(Element other) { |
| js.Expression code; |
| if (compiler.objectClass == other) return; |
| if (nativeEmitter.requiresNativeIsCheck(other)) { |
| @@ -772,7 +772,22 @@ $lazyInitializerLogic |
| code = new js.LiteralBool(true); |
| } |
| builder.addProperty(namer.operatorIs(other), code); |
| - }); |
| + } |
| + |
| + void generateSubstitution(Element other) { |
| + RuntimeTypeInformation rti = backend.rti; |
| + // TODO(karlklose): support typedefs with variables. |
| + if (other.kind == ElementKind.CLASS) { |
| + String substitution = rti.getSupertypeSubstitution(classElement, other, |
| + alwaysGenerateFunction: true); |
| + if (substitution != null) { |
| + builder.addProperty(namer.substitutionName(other), |
| + new js.LiteralExpression(substitution)); |
| + } |
| + } |
| + } |
| + |
| + generateIsTestsOn(classElement, generateIsTest, generateSubstitution); |
| if (identical(classElement, compiler.objectClass) |
| && compiler.enabledNoSuchMethod) { |
| @@ -805,23 +820,24 @@ $lazyInitializerLogic |
| void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| JavaScriptBackend backend = compiler.backend; |
| RuntimeTypeInformation rti = backend.rti; |
| - |
| - TypeChecks typeChecks = rti.computeRequiredChecks(); |
| + TypeChecks typeChecks = rti.getRequiredChecks(); |
| bool needsHolder(ClassElement cls) { |
| return !neededClasses.contains(cls) || cls.isNative() || |
| rti.isJsNative(cls); |
| } |
| + /** |
| + * Generates a holder object if it is needed. A holder is a JavaScript |
| + * object literal with a field [builtin$cls] that contains the name of the |
| + * class as a string (just like object constructors do). The is-checkes |
|
ngeoffray
2013/01/31 08:28:08
checkes -> checks
karlklose
2013/02/01 07:36:36
Done.
|
| + * for the class are are added to the holder object later. |
| + */ |
| void maybeGenerateHolder(ClassElement cls) { |
| if (!needsHolder(cls)) return; |
| - |
| String holder = namer.isolateAccess(cls); |
| String name = namer.getName(cls); |
| buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); |
| - for (ClassElement check in typeChecks[cls]) { |
| - buffer.add(',$_${namer.operatorIs(check)}:${_}true'); |
| - }; |
| buffer.add('}$N'); |
| } |
| @@ -831,16 +847,16 @@ $lazyInitializerLogic |
| maybeGenerateHolder(cls); |
| } |
| - // Add checks to the constructors of instantiated classes. |
| + // Add checks to the constructors of instantiated classes or to the created |
| + // holder object. |
| for (ClassElement cls in typeChecks) { |
| - if (needsHolder(cls)) { |
| - // We already emitted the is-checks in the object definition for this |
| - // class. |
| - continue; |
| - } |
| String holder = namer.isolateAccess(cls); |
| for (ClassElement check in typeChecks[cls]) { |
| buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| + String body = rti.getSupertypeSubstitution(cls, check); |
| + if (body != null) { |
| + buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); |
| + } |
| }; |
| } |
| } |
| @@ -1191,15 +1207,22 @@ $lazyInitializerLogic |
| /** |
| * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| - * classes it implements. We don't need to add the "is tests" of the |
| - * super class because they will be inherited at runtime. |
| + * classes it implements and type argument substitution functions for these |
| + * tests. We don't need to add the "is tests" of the super class because |
| + * they will be inherited at runtime, but we need to generate the substitution, |
|
ngeoffray
2013/01/31 08:28:08
line too long
karlklose
2013/02/01 07:36:36
Done.
|
| + * because it may have changed. |
|
ngeoffray
2013/01/31 08:28:08
Please provide an example.
karlklose
2013/02/01 07:36:36
Done.
|
| */ |
| void generateIsTestsOn(ClassElement cls, |
| - void emitIsTest(Element element)) { |
| + void emitIsTest(Element element), |
| + void emitSubstitution(Element element)) { |
| if (checkedClasses.contains(cls)) { |
| emitIsTest(cls); |
| + emitSubstitution(cls); |
| + } |
| + if (cls.superclass != null && checkedClasses.contains(cls.superclass)) { |
| + // TODO(karlklose): do not regenerate it, if it has not changed. |
| + emitSubstitution(cls.superclass); |
| } |
| - |
| Set<Element> generated = new Set<Element>(); |
| // A class that defines a [:call:] method implicitly implements |
| // [Function] and needs checks for all typedefs that are used in is-checks. |
| @@ -1213,13 +1236,15 @@ $lazyInitializerLogic |
| if (call != null) { |
| generateInterfacesIsTests(compiler.functionClass, |
| emitIsTest, |
| + emitSubstitution, |
| generated); |
| getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| } |
| } |
| for (DartType interfaceType in cls.interfaces) { |
| - generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); |
| + generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| + emitSubstitution, generated); |
| } |
| // For native classes, we also have to run through their mixin |
| @@ -1228,7 +1253,8 @@ $lazyInitializerLogic |
| visitNativeMixins(cls, (MixinApplicationElement mixin) { |
| for (DartType interfaceType in mixin.interfaces) { |
| ClassElement interfaceElement = interfaceType.element; |
| - generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); |
| + generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| + emitSubstitution, generated); |
| } |
| }); |
| } |
| @@ -1238,11 +1264,13 @@ $lazyInitializerLogic |
| */ |
| void generateInterfacesIsTests(ClassElement cls, |
| void emitIsTest(ClassElement element), |
| + void emitSubstitution(ClassElement element), |
| Set<Element> alreadyGenerated) { |
| - void tryEmitTest(ClassElement cls) { |
| - if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { |
| - alreadyGenerated.add(cls); |
| - emitIsTest(cls); |
| + void tryEmitTest(ClassElement check) { |
| + if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
| + alreadyGenerated.add(check); |
| + emitIsTest(check); |
| + emitSubstitution(check); |
| } |
| }; |
| @@ -1251,14 +1279,16 @@ $lazyInitializerLogic |
| for (DartType interfaceType in cls.interfaces) { |
| Element element = interfaceType.element; |
| tryEmitTest(element); |
| - generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); |
| + generateInterfacesIsTests(element, emitIsTest, emitSubstitution, |
| + alreadyGenerated); |
| } |
| // We need to also emit "is checks" for the superclass and its supertypes. |
| ClassElement superclass = cls.superclass; |
| if (superclass != null) { |
| tryEmitTest(superclass); |
| - generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); |
| + generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
| + alreadyGenerated); |
| } |
| } |