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

Unified Diff: pkg/compiler/lib/src/cps_ir/type_propagation.dart

Issue 1409803003: dart2js cps: More interceptor optimizations and fixes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix indentation 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/type_mask_system.dart ('k') | pkg/compiler/lib/src/js_backend/backend.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 493201f397869d45228db117788fbe6399bf04c4..a4b9acf6dc3c72089f53d5fbe123021852f82d73 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -666,6 +666,7 @@ class TransformingVisitor extends DeepRecursiveVisitor {
JavaScriptBackend get backend => compiler.backend;
TypeMaskSystem get typeSystem => lattice.typeSystem;
types.DartTypes get dartTypes => lattice.dartTypes;
+ World get classWorld => typeSystem.classWorld;
Map<Variable, ConstantValue> get values => analyzer.values;
final InternalErrorFunction internalError;
@@ -2202,39 +2203,131 @@ class TransformingVisitor extends DeepRecursiveVisitor {
Primitive visitInterceptor(Interceptor node) {
AbstractValue value = getValue(node.input.definition);
- // If the exact class of the input is known, replace with a constant
- // or the input itself.
- ClassElement singleClass;
- if (lattice.isDefinitelyInt(value)) {
- // Classes like JSUInt31 and JSUInt32 do not exist at runtime, so ensure
- // all the int classes get mapped tor their runtime class.
- singleClass = backend.jsIntClass;
- } else if (lattice.isDefinitelyNum(value)) {
- if (jsNumberClassSuffices(node)) {
- singleClass = backend.jsNumberClass;
+ TypeMask interceptedInputs = value.type.intersection(
+ typeSystem.interceptorType.nullable(), classWorld);
+ bool interceptNull =
+ node.interceptedClasses.contains(backend.jsNullClass) ||
+ node.interceptedClasses.contains(backend.jsInterceptorClass);
+
+ void filterInterceptedClasses() {
+ if (lattice.isDefinitelyInt(value, allowNull: !interceptNull)) {
+ node.interceptedClasses..clear()..add(backend.jsIntClass);
+ return;
}
- } else if (lattice.isDefinitelyNativeList(value)) {
- // Ensure all the array subclasses get mapped to the array class.
- singleClass = backend.jsArrayClass;
- } else {
- singleClass = typeSystem.singleClass(value.type);
- }
- if (singleClass != null &&
- singleClass.isSubclassOf(backend.jsInterceptorClass)) {
- node.constantValue = new InterceptorConstantValue(singleClass.rawType);
- }
- // Filter out intercepted classes that do not match the input type.
- node.interceptedClasses.retainWhere((ClassElement clazz) {
- if (clazz == typeSystem.jsNullClass) {
- return value.isNullable;
- } else {
- TypeMask classMask = typeSystem.nonNullSubclass(clazz);
- return !typeSystem.areDisjoint(value.type, classMask);
+ if (lattice.isDefinitelyNum(value, allowNull: !interceptNull) &&
+ jsNumberClassSuffices(node)) {
+ node.interceptedClasses..clear()..add(backend.jsNumberClass);
+ return;
}
- });
+ TypeMask interceptedClassesType = new TypeMask.unionOf(
+ node.interceptedClasses.map(typeSystem.getInterceptorSubtypes),
+ classWorld);
+ TypeMask interceptedAndCaught =
+ interceptedInputs.intersection(interceptedClassesType, classWorld);
+ ClassElement single = interceptedAndCaught.singleClass(classWorld);
+ if (single != null) {
+ node.interceptedClasses..clear()..add(backend.getRuntimeClass(single));
+ return;
+ }
+
+ // Filter out intercepted classes that do not match the input type.
+ node.interceptedClasses.retainWhere((ClassElement clazz) {
+ return !typeSystem.areDisjoint(
+ value.type,
+ typeSystem.getInterceptorSubtypes(clazz));
+ });
+
+ // The interceptor root class will usually not be filtered out because all
+ // intercepted values are subtypes of it. But it can be "shadowed" by a
+ // more specific interceptor classes if all possible intercepted values
+ // will hit one of the more specific classes.
+ //
+ // For example, if all classes can respond to a given call, but we know
+ // the input is a string or an unknown JavaScript object, we want to
+ // use a specialized interceptor:
+ //
+ // getInterceptor(x).get$hashCode(x);
+ // ==>
+ // getInterceptor$su(x).get$hashCode(x)
+ //
+ // In this case, the intercepted classes that were not filtered out above
+ // are {UnknownJavaScriptObject, JSString, Interceptor}, but there is no
+ // need to include the Interceptor class.
+ //
+ // We only do this optimization if the resulting interceptor call is
+ // sufficiently specialized to be worth it (#classes <= 2).
+ // TODO(asgerf): Reconsider when TypeTest interceptors don't intercept
+ // ALL interceptor classes.
+ if (node.interceptedClasses.length > 1 &&
+ node.interceptedClasses.length < 4 &&
+ node.interceptedClasses.contains(backend.jsInterceptorClass)) {
+ TypeMask specificInterceptors = new TypeMask.unionOf(
+ node.interceptedClasses
+ .where((cl) => cl != backend.jsInterceptorClass)
+ .map(typeSystem.getInterceptorSubtypes),
+ classWorld);
+ if (specificInterceptors.containsMask(interceptedInputs, classWorld)) {
+ // All possible inputs are caught by an Interceptor subclass (or are
+ // self-interceptors), so there is no need to have the check for
+ // the Interceptor root class (which is expensive).
+ node.interceptedClasses.remove(backend.jsInterceptorClass);
+ }
+ }
+ }
+
+ filterInterceptedClasses();
+
// Remove the interceptor call if it can only return its input.
if (node.interceptedClasses.isEmpty) {
node.input.definition.substituteFor(node);
+ return null;
+ }
+
+ node.flags = Interceptor.ALL_FLAGS;
+
+ // If there is only one caught interceptor class, determine more precisely
+ // how this might resolve at runtime. Later optimizations depend on this,
+ // but do not have refined type information available.
+ if (node.interceptedClasses.length == 1) {
+ ClassElement class_ = node.interceptedClasses.single;
+ if (value.isDefinitelyNotNull) {
+ node.clearFlag(Interceptor.NULL);
+ } else if (interceptNull) {
+ node.clearFlag(Interceptor.NULL_BYPASS);
+ if (class_ == backend.jsNullClass) {
+ node.clearFlag(Interceptor.NULL_INTERCEPT_SUBCLASS);
+ } else {
+ node.clearFlag(Interceptor.NULL_INTERCEPT_EXACT);
+ }
+ } else {
+ node.clearFlag(Interceptor.NULL_INTERCEPT);
+ }
+ if (typeSystem.isDefinitelyIntercepted(value.type, allowNull: true)) {
+ node.clearFlag(Interceptor.SELF_INTERCEPT);
+ }
+ TypeMask interceptedInputsNonNullable = interceptedInputs.nonNullable();
+ TypeMask interceptedType = typeSystem.getInterceptorSubtypes(class_);
+ if (interceptedType.containsMask(interceptedInputsNonNullable,
+ classWorld)) {
+ node.clearFlag(Interceptor.NON_NULL_BYPASS);
+ }
+ if (class_ == backend.jsNumberClass) {
+ // See [jsNumberClassSuffices]. We know that JSInt and JSDouble are
+ // not intercepted classes so JSNumber is sufficient.
+ node.clearFlag(Interceptor.NON_NULL_INTERCEPT_SUBCLASS);
+ } else if (class_ == backend.jsArrayClass) {
+ // JSArray has compile-time subclasses like JSFixedArray, but should
+ // still be considered "exact" if the input is any subclass of JSArray.
+ if (typeSystem.isDefinitelyNativeList(interceptedInputsNonNullable)) {
+ node.clearFlag(Interceptor.NON_NULL_INTERCEPT_SUBCLASS);
+ }
+ } else {
+ TypeMask exactInterceptedType = typeSystem.nonNullExact(class_);
+ if (exactInterceptedType.containsMask(interceptedInputsNonNullable,
+ classWorld)) {
+ node.clearFlag(Interceptor.NON_NULL_INTERCEPT_SUBCLASS);
+ }
+ }
}
return null;
}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/type_mask_system.dart ('k') | pkg/compiler/lib/src/js_backend/backend.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698