Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(542)

Unified Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 12018015: Implement substitution for type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Regenerate checks if necessary. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..01140492c16c9cea719ce7108a6269da1059dbf2 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,25 @@ $lazyInitializerLogic
code = new js.LiteralBool(true);
}
builder.addProperty(namer.operatorIs(other), code);
- });
+ }
+
+ void generateSubstitution(Element other, {bool emitNull: false}) {
+ 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));
+ } else if (emitNull) {
+ builder.addProperty(namer.substitutionName(other),
+ new js.LiteralNull());
+ }
+ }
+ }
+
+ generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
if (identical(classElement, compiler.objectClass)
&& compiler.enabledNoSuchMethod) {
@@ -805,23 +823,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-checks 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 +850,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,13 +1210,45 @@ $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 may need to generate the
+ * substitutions, because they may have changed.
*/
void generateIsTestsOn(ClassElement cls,
- void emitIsTest(Element element)) {
+ void emitIsTest(Element element),
+ void emitSubstitution(Element element, {emitNull})) {
if (checkedClasses.contains(cls)) {
emitIsTest(cls);
+ emitSubstitution(cls);
+ }
+
+ JavaScriptBackend jsBackend = compiler.backend;
+ RuntimeTypeInformation rti = jsBackend.rti;
+ ClassElement superclass = cls.superclass;
+
+ bool haveSameTypeVariables(ClassElement a, ClassElement b) {
+ if (a.isClosure()) return true;
+ return a.typeVariables == b.typeVariables;
+ }
+
+ if (superclass != null && superclass != compiler.objectClass &&
+ !haveSameTypeVariables(cls, superclass)) {
+ // We cannot inherit the generated substitutions, because the type
+ // variable layout for this class is different. Instead we generate
+ // substitutions for all checks and make emitSubstitution a NOP for the
+ // rest of this function.
+ for (ClassElement check in checkedClasses) {
+ for (DartType supertype in cls.allSupertypes) {
+ if (supertype.element == check) {
+ // Generate substitution. If no substitution is necessary, emit
+ // [:null:] to overwrite a (possibly) existing substitution from the
+ // super classes.
+ emitSubstitution(check, emitNull: true);
+ }
+ }
+ }
+ emitSubstitution = (_) => {};
}
Set<Element> generated = new Set<Element>();
@@ -1213,13 +1264,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 +1281,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 +1292,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 +1307,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);
}
}

Powered by Google App Engine
This is Rietveld 408576698