Index: pkg/compiler/lib/src/cps_ir/share_interceptors.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart |
index 7b360d4d7e6b588899fe9f340f726c54f1a23fa0..5b2ef78b17415ebb40958be69c3f5644eeef65c6 100644 |
--- a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart |
+++ b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart |
@@ -6,6 +6,7 @@ library dart2js.cps_ir.share_interceptors; |
import 'cps_ir_nodes.dart'; |
import 'optimizers.dart'; |
+import '../constants/values.dart'; |
/// Merges calls to `getInterceptor` when one call dominates the other. |
/// |
@@ -14,8 +15,11 @@ import 'optimizers.dart'; |
class ShareInterceptors extends RecursiveVisitor implements Pass { |
String get passName => 'Share interceptors'; |
- final Map<Primitive, Interceptor> interceptorFor = |
- <Primitive, Interceptor>{}; |
+ final Map<Primitive, Primitive> interceptorFor = |
+ <Primitive, Primitive>{}; |
+ |
+ final Map<ConstantValue, Primitive> sharedConstantFor = |
+ <ConstantValue, Primitive>{}; |
void rewrite(FunctionDefinition node) { |
visit(node.body); |
@@ -28,8 +32,47 @@ class ShareInterceptors extends RecursiveVisitor implements Pass { |
Primitive input = interceptor.input.definition; |
Interceptor existing = interceptorFor[input]; |
if (existing != null) { |
- existing.interceptedClasses.addAll(interceptor.interceptedClasses); |
+ if (existing is Interceptor) { |
+ existing.interceptedClasses.addAll(interceptor.interceptedClasses); |
+ } |
existing.substituteFor(interceptor); |
+ } else if (interceptor.constantValue != null) { |
+ InterceptorConstantValue value = interceptor.constantValue; |
+ // There is no interceptor obtained from this particular input, but |
+ // there might one obtained from another input that is known to |
+ // have the same result, so try to reuse that. |
+ Primitive shared = sharedConstantFor[value]; |
+ if (shared != null) { |
+ shared.substituteFor(interceptor); |
+ } else { |
+ Constant constant = new Constant(value); |
+ constant.hint = interceptor.hint; |
+ node.primitive = constant; |
+ constant.parent = node; |
+ interceptor.input.unlink(); |
+ constant.substituteFor(interceptor); |
+ interceptorFor[input] = constant; |
+ sharedConstantFor[value] = constant; |
+ pushAction(() { |
+ interceptorFor.remove(input); |
+ sharedConstantFor.remove(value); |
+ |
+ if (constant.hasExactlyOneUse) { |
+ // As a heuristic, always sink single-use interceptor constants |
+ // to their use, even if it is inside a loop. |
+ Expression use = getEnclosingExpression(constant.firstRef.parent); |
+ InteriorNode parent = node.parent; |
+ parent.body = node.body; |
+ node.body.parent = parent; |
+ |
+ InteriorNode useParent = use.parent; |
+ useParent.body = node; |
+ node.body = use; |
+ use.parent = node; |
+ node.parent = useParent; |
+ } |
+ }); |
+ } |
} else { |
interceptorFor[input] = interceptor; |
pushAction(() { |
@@ -39,4 +82,11 @@ class ShareInterceptors extends RecursiveVisitor implements Pass { |
} |
return node.body; |
} |
+ |
+ Expression getEnclosingExpression(Node node) { |
+ while (node is! Expression) { |
+ node = node.parent; |
+ } |
+ return node; |
+ } |
} |