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

Unified Diff: pkg/compiler/lib/src/js_backend/runtime_types.dart

Issue 1394213002: Split RuntimesTypes into RuntimeTypes and RuntimeTypesEncoder (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 5 years, 2 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: pkg/compiler/lib/src/js_backend/runtime_types.dart
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 81b4dd50dd1170b733113c011b1114060fd2d2fb..8e31d939df334c3b1e8768cb38c9473d42535c83 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -15,29 +15,122 @@ abstract class TypeChecks {
typedef jsAst.Expression OnVariableCallback(TypeVariableType variable);
typedef bool ShouldEncodeTypedefCallback(TypedefType variable);
-class RuntimeTypes {
+// TODO(johnniwinther): Rename to something like [RuntimeTypeUsageCollector]
+// we semantics is more clear.
+abstract class RuntimeTypes {
+ TypeChecks get requiredChecks;
+ Iterable<ClassElement> get classesNeedingRti;
+ Iterable<Element> get methodsNeedingRti;
+
+ /// The set of classes that use one of their type variables as expressions
+ /// to get the runtime type.
+ Iterable<ClassElement> get classesUsingTypeVariableExpression;
+
+ void registerClassUsingTypeVariableExpression(ClassElement cls);
+ void registerRtiDependency(Element element, Element dependency);
+ void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
+ DartType bound);
+
+ Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend,
+ TypeChecks checks);
+ void computeClassesNeedingRti();
+
+ /// Compute the required type checkes and substitutions for the given
+ /// instantitated and checked classes.
+ TypeChecks computeChecks(Set<ClassElement> instantiated,
+ Set<ClassElement> checked);
+
+ /// Compute type arguments of classes that use one of their type variables in
+ /// is-checks and add the is-checks that they imply.
+ ///
+ /// This function must be called after all is-checks have been registered.
+ void addImplicitChecks(Universe universe,
+ Iterable<ClassElement> classesUsingChecks);
+
+ /// Return all classes that are referenced in the type of the function, i.e.,
+ /// in the return type or the argument types.
+ Set<ClassElement> getReferencedClasses(FunctionType type);
+
+ /// Return all classes that are uses a type arguments.
+ Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend);
+
+ bool isTrivialSubstitution(ClassElement cls, ClassElement check);
+
+ Substitution getSubstitution(ClassElement cls, ClassElement other);
+
+ static bool hasTypeArguments(DartType type) {
+ if (type is InterfaceType) {
+ InterfaceType interfaceType = type;
+ return !interfaceType.treatAsRaw;
+ }
+ return false;
+ }
+}
+
+abstract class RuntimeTypesEncoder {
+ bool isSimpleFunctionType(FunctionType type);
+
+ jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_);
+
+ jsAst.Expression getSubstitutionRepresentation(
+ List<DartType> types,
+ OnVariableCallback onVariable);
+ jsAst.Expression getSubstitutionCode(Substitution substitution);
+ jsAst.Expression getSubstitutionCodeForVariable(
+ Substitution substitution, int index);
+
+ /// Returns the JavaScript template to determine at runtime if a type object
+ /// is a function type.
+ jsAst.Template get templateForIsFunctionType;
+
+ /// Returns the JavaScript template that creates at runtime a new function
+ /// type object.
+ jsAst.Template get templateForCreateFunctionType;
+ jsAst.Name get getFunctionThatReturnsNullName;
+
+ jsAst.Expression getTypeRepresentation(
+ DartType type,
+ OnVariableCallback onVariable,
+ [ShouldEncodeTypedefCallback shouldEncodeTypedef]);
+ /**
+ * Returns a [jsAst.Expression] representing the given [type]. Type
+ * variables are replaced by placeholders in the ast.
+ *
+ * [firstPlaceholderIndex] is the index to use for the first placeholder.
+ * This is useful if the returned [jsAst.Expression] is only part of a
+ * larger template. By default, indexing starts with 0.
+ */
+ jsAst.Expression getTypeRepresentationWithPlaceholders(DartType type,
+ OnVariableCallback onVariable, {int firstPlaceholderIndex : 0});
+
+ String getTypeRepresentationForTypeConstant(DartType type);
+}
+
+class _RuntimeTypes implements RuntimeTypes {
final Compiler compiler;
- final TypeRepresentationGenerator representationGenerator;
final Map<ClassElement, Set<ClassElement>> rtiDependencies;
+
+ @override
final Set<ClassElement> classesNeedingRti;
+
+ @override
final Set<Element> methodsNeedingRti;
- // The set of classes that use one of their type variables as expressions
- // to get the runtime type.
+
+ @override
final Set<ClassElement> classesUsingTypeVariableExpression;
+
// The set of type arguments tested against type variable bounds.
final Set<DartType> checkedTypeArguments;
// The set of tested type variable bounds.
final Set<DartType> checkedBounds;
- JavaScriptBackend get backend => compiler.backend;
+ TypeChecks cachedRequiredChecks;
- jsAst.Name get getFunctionThatReturnsNullName
- => backend.namer.internalGlobal('functionThatReturnsNull');
+ JavaScriptBackend get backend => compiler.backend;
- RuntimeTypes(Compiler compiler)
+ _RuntimeTypes(Compiler compiler)
: this.compiler = compiler,
- representationGenerator = new TypeRepresentationGenerator(compiler),
classesNeedingRti = new Set<ClassElement>(),
methodsNeedingRti = new Set<Element>(),
rtiDependencies = new Map<ClassElement, Set<ClassElement>>(),
@@ -49,6 +142,12 @@ class RuntimeTypes {
Set<ClassElement> allInstantiatedArguments;
Set<ClassElement> checkedArguments;
+ @override
+ void registerClassUsingTypeVariableExpression(ClassElement cls) {
+ classesUsingTypeVariableExpression.add(cls);
+ }
+
+ @override
void registerRtiDependency(Element element, Element dependency) {
// We're not dealing with typedef for now.
if (!element.isClass || !dependency.isClass) return;
@@ -57,6 +156,7 @@ class RuntimeTypes {
classes.add(dependency);
}
+ @override
void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
DartType bound) {
checkedTypeArguments.add(typeArgument);
@@ -77,6 +177,7 @@ class RuntimeTypes {
* TODO(karlklose): move these computations into a function producing an
* immutable datastructure.
*/
+ @override
void addImplicitChecks(Universe universe,
Iterable<ClassElement> classesUsingChecks) {
// If there are no classes that use their variables in checks, there is
@@ -121,6 +222,7 @@ class RuntimeTypes {
}
}
+ @override
void computeClassesNeedingRti() {
// Find the classes that need runtime type information. Such
// classes are:
@@ -217,8 +319,7 @@ class RuntimeTypes {
classesUsingTypeVariableExpression.forEach(potentiallyAddForRti);
}
- TypeChecks cachedRequiredChecks;
-
+ @override
TypeChecks get requiredChecks {
if (cachedRequiredChecks == null) {
computeRequiredChecks();
@@ -227,8 +328,7 @@ class RuntimeTypes {
return cachedRequiredChecks;
}
- /// Compute the required type checkes and substitutions for the given
- /// instantitated and checked classes.
+ @override
TypeChecks computeChecks(Set<ClassElement> instantiated,
Set<ClassElement> checked) {
// Run through the combination of instantiated and checked
@@ -373,6 +473,7 @@ class RuntimeTypes {
collector.classes..addAll(functionArgumentCollector.classes);
}
+ @override
Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend,
TypeChecks checks) {
Set<ClassElement> instantiated = new Set<ClassElement>();
@@ -389,6 +490,7 @@ class RuntimeTypes {
return instantiated..addAll(collector.classes);
}
+ @override
Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend) {
Set<ClassElement> requiredArgumentClasses =
new Set<ClassElement>.from(
@@ -398,26 +500,16 @@ class RuntimeTypes {
..addAll(checkedArguments);
}
- String getTypeRepresentationForTypeConstant(DartType type) {
- JavaScriptBackend backend = compiler.backend;
- Namer namer = backend.namer;
- if (type.isDynamic) return "dynamic";
- String name = namer.uniqueNameForTypeConstantElement(type.element);
- if (!type.element.isClass) return name;
- InterfaceType interface = type;
- List<DartType> variables = interface.element.typeVariables;
- // Type constants can currently only be raw types, so there is no point
- // adding ground-term type parameters, as they would just be 'dynamic'.
- // TODO(sra): Since the result string is used only in constructing constant
- // names, it would result in more readable names if the final string was a
- // legal JavaScript identifer.
- if (variables.isEmpty) return name;
- String arguments =
- new List.filled(variables.length, 'dynamic').join(', ');
- return '$name<$arguments>';
+ @override
+ Set<ClassElement> getReferencedClasses(FunctionType type) {
+ FunctionArgumentCollector collector =
+ new FunctionArgumentCollector(backend);
+ collector.collect(type);
+ return collector.classes;
}
// TODO(karlklose): maybe precompute this value and store it in typeChecks?
+ @override
bool isTrivialSubstitution(ClassElement cls, ClassElement check) {
if (cls.isClosure) {
// TODO(karlklose): handle closures.
@@ -452,31 +544,7 @@ class RuntimeTypes {
return true;
}
- /**
- * Compute a JavaScript expression that describes the necessary substitution
- * for type arguments in a subtype test.
- *
- * The result can be:
- * 1) `null`, if no substituted check is necessary, because the
- * type variables are the same or there are no type variables in the class
- * that is checked for.
- * 2) A list expression describing the type arguments to be used in the
- * subtype check, if the type arguments to be used in the check do not
- * depend on the type arguments of the object.
- * 3) A function mapping the type variables of the object to be checked to
- * a list expression.
- */
- jsAst.Expression getSupertypeSubstitution(
- ClassElement cls,
- ClassElement check) {
- Substitution substitution = getSubstitution(cls, check);
- if (substitution != null) {
- return substitution.getCode(this);
- } else {
- return null;
- }
- }
-
+ @override
Substitution getSubstitution(ClassElement cls, ClassElement other) {
// Look for a precomputed check.
for (TypeCheck check in cachedRequiredChecks[cls]) {
@@ -505,7 +573,56 @@ class RuntimeTypes {
return new Substitution.function(target.typeArguments, typeVariables);
}
}
+}
+
+class _RuntimeTypesEncoder implements RuntimeTypesEncoder {
+ final Compiler compiler;
+ @override
+ final TypeRepresentationGenerator representationGenerator;
+
+ _RuntimeTypesEncoder(Compiler compiler)
+ : this.compiler = compiler,
+ representationGenerator = new TypeRepresentationGenerator(compiler);
+
+ JavaScriptBackend get backend => compiler.backend;
+
+ /// Returns the JavaScript template to determine at runtime if a type object
+ /// is a function type.
+ @override
+ jsAst.Template get templateForIsFunctionType {
+ return representationGenerator.templateForIsFunctionType;
+ }
+
+ /// Returns the JavaScript template that creates at runtime a new function
+ /// type object.
+ @override
+ jsAst.Template get templateForCreateFunctionType {
+ return representationGenerator.templateForCreateFunctionType;
+ }
+
+ @override
+ jsAst.Expression getTypeRepresentation(
+ DartType type,
+ OnVariableCallback onVariable,
+ [ShouldEncodeTypedefCallback shouldEncodeTypedef]) {
+ return representationGenerator.getTypeRepresentation(
+ type, onVariable, shouldEncodeTypedef);
+ }
+ @override
+ jsAst.Expression getTypeRepresentationWithPlaceholders(DartType type,
+ OnVariableCallback onVariable, {int firstPlaceholderIndex : 0}) {
+ // Create a type representation. For type variables call the original
+ // callback for side effects and return a template placeholder.
+ int positions = firstPlaceholderIndex;
+ jsAst.Expression representation = getTypeRepresentation(type, (variable) {
+ onVariable(variable);
+ return new jsAst.InterpolatedExpression(positions++);
+ });
+ return representation;
+ }
+
+ @override
jsAst.Expression getSubstitutionRepresentation(
List<DartType> types,
OnVariableCallback onVariable) {
@@ -535,6 +652,7 @@ class RuntimeTypes {
}
}
+ @override
jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_) {
ClassElement contextClass = Types.getClassContext(type);
jsAst.Expression encoding =
@@ -551,33 +669,95 @@ class RuntimeTypes {
}
/**
- * Returns a [jsAst.Expression] representing the given [type]. Type
- * variables are replaced by placeholders in the ast.
+ * Compute a JavaScript expression that describes the necessary substitution
+ * for type arguments in a subtype test.
*
- * [firstPlaceholderIndex] is the index to use for the first placeholder.
- * This is useful if the returned [jsAst.Expression] is only part of a
- * larger template. By default, indexing starts with 0.
+ * The result can be:
+ * 1) `null`, if no substituted check is necessary, because the
+ * type variables are the same or there are no type variables in the class
+ * that is checked for.
+ * 2) A list expression describing the type arguments to be used in the
+ * subtype check, if the type arguments to be used in the check do not
+ * depend on the type arguments of the object.
+ * 3) A function mapping the type variables of the object to be checked to
+ * a list expression.
*/
- jsAst.Expression getTypeRepresentationWithPlaceholders(DartType type,
- OnVariableCallback onVariable, {int firstPlaceholderIndex : 0}) {
- // Create a type representation. For type variables call the original
- // callback for side effects and return a template placeholder.
- int positions = firstPlaceholderIndex;
- jsAst.Expression representation = getTypeRepresentation(type, (variable) {
- onVariable(variable);
- return new jsAst.InterpolatedExpression(positions++);
- });
- return representation;
+ @override
+ jsAst.Expression getSubstitutionCode(Substitution substitution) {
+ jsAst.Expression declaration(TypeVariableType variable) {
+ return new jsAst.Parameter(getVariableName(variable.name));
+ }
+
+ jsAst.Expression use(TypeVariableType variable) {
+ return new jsAst.VariableUse(getVariableName(variable.name));
+ }
+
+ if (substitution.arguments.every((DartType type) => type.isDynamic)) {
+ return backend.emitter.emitter.generateFunctionThatReturnsNull();
+ } else {
+ jsAst.Expression value =
+ getSubstitutionRepresentation(substitution.arguments, use);
+ if (substitution.isFunction) {
+ Iterable<jsAst.Expression> formals =
+ substitution.parameters.map(declaration);
+ return js('function(#) { return # }', [formals, value]);
+ } else {
+ return js('function() { return # }', value);
+ }
+ }
}
- jsAst.Expression getTypeRepresentation(
- DartType type,
- OnVariableCallback onVariable,
- [ShouldEncodeTypedefCallback shouldEncodeTypedef]) {
- return representationGenerator.getTypeRepresentation(
- type, onVariable, shouldEncodeTypedef);
+ @override
+ jsAst.Expression getSubstitutionCodeForVariable(Substitution substitution,
+ int index) {
+ jsAst.Expression declaration(TypeVariableType variable) {
+ return new jsAst.Parameter(getVariableName(variable.name));
+ }
+
+ jsAst.Expression use(TypeVariableType variable) {
+ return new jsAst.VariableUse(getVariableName(variable.name));
+ }
+
+ if (substitution.arguments[index].isDynamic) {
+ return backend.emitter.emitter.generateFunctionThatReturnsNull();
+ } else {
+ jsAst.Expression value =
+ getTypeRepresentation(substitution.arguments[index], use);
+ Iterable<jsAst.Expression> formals =
+ substitution.parameters.map(declaration);
+ return js('function(#) { return # }', [formals, value]);
+ }
+ }
+
+ String getVariableName(String name) {
+ return backend.namer.safeVariableName(name);
}
+ @override
+ jsAst.Name get getFunctionThatReturnsNullName
+ => backend.namer.internalGlobal('functionThatReturnsNull');
+
+ @override
+ String getTypeRepresentationForTypeConstant(DartType type) {
+ JavaScriptBackend backend = compiler.backend;
+ Namer namer = backend.namer;
+ if (type.isDynamic) return "dynamic";
+ String name = namer.uniqueNameForTypeConstantElement(type.element);
+ if (!type.element.isClass) return name;
+ InterfaceType interface = type;
+ List<DartType> variables = interface.element.typeVariables;
+ // Type constants can currently only be raw types, so there is no point
+ // adding ground-term type parameters, as they would just be 'dynamic'.
+ // TODO(sra): Since the result string is used only in constructing constant
+ // names, it would result in more readable names if the final string was a
+ // legal JavaScript identifer.
+ if (variables.isEmpty) return name;
+ String arguments =
+ new List.filled(variables.length, 'dynamic').join(', ');
+ return '$name<$arguments>';
+ }
+
+ @override
bool isSimpleFunctionType(FunctionType type) {
if (!type.returnType.isDynamic) return false;
if (!type.optionalParameterTypes.isEmpty) return false;
@@ -587,33 +767,6 @@ class RuntimeTypes {
}
return true;
}
-
- static bool hasTypeArguments(DartType type) {
- if (type is InterfaceType) {
- InterfaceType interfaceType = type;
- return !interfaceType.treatAsRaw;
- }
- return false;
- }
-
- static int getTypeVariableIndex(TypeVariableElement variable) {
- ClassElement classElement = variable.enclosingClass;
- List<DartType> variables = classElement.typeVariables;
- for (int index = 0; index < variables.length; index++) {
- if (variables[index].element == variable) return index;
- }
- throw invariant(variable, false,
- message: "Couldn't find type-variable index");
- }
-
- /// Return all classes that are referenced in the type of the function, i.e.,
- /// in the return type or the argument types.
- Set<ClassElement> getReferencedClasses(FunctionType type) {
- FunctionArgumentCollector collector =
- new FunctionArgumentCollector(backend);
- collector.collect(type);
- return collector.classes;
- }
}
class TypeRepresentationGenerator implements DartTypeVisitor {
@@ -883,52 +1036,6 @@ class Substitution {
Substitution.function(this.arguments, this.parameters)
: isFunction = true;
-
- jsAst.Expression getCode(RuntimeTypes rti) {
- jsAst.Expression declaration(TypeVariableType variable) {
- return new jsAst.Parameter(
- rti.backend.namer.safeVariableName(variable.name));
- }
-
- jsAst.Expression use(TypeVariableType variable) {
- return new jsAst.VariableUse(
- rti.backend.namer.safeVariableName(variable.name));
- }
-
- if (arguments.every((DartType type) => type.isDynamic)) {
- return rti.backend.emitter.emitter.generateFunctionThatReturnsNull();
- } else {
- jsAst.Expression value =
- rti.getSubstitutionRepresentation(arguments, use);
- if (isFunction) {
- Iterable<jsAst.Expression> formals = parameters.map(declaration);
- return js('function(#) { return # }', [formals, value]);
- } else {
- return js('function() { return # }', value);
- }
- }
- }
-
- jsAst.Expression getCodeForVariable(int index, RuntimeTypes rti) {
- jsAst.Expression declaration(TypeVariableType variable) {
- return new jsAst.Parameter(
- rti.backend.namer.safeVariableName(variable.name));
- }
-
- jsAst.Expression use(TypeVariableType variable) {
- return new jsAst.VariableUse(
- rti.backend.namer.safeVariableName(variable.name));
- }
-
- if (arguments[index].isDynamic) {
- return rti.backend.emitter.emitter.generateFunctionThatReturnsNull();
- } else {
- jsAst.Expression value =
- rti.getTypeRepresentation(arguments[index], use);
- Iterable<jsAst.Expression> formals = parameters.map(declaration);
- return js('function(#) { return # }', [formals, value]);
- }
- }
}
/**
« no previous file with comments | « pkg/compiler/lib/src/js_backend/namer.dart ('k') | pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698