Index: pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart |
index 1e9d702b2fde03c69223f085621ae93657bc168c..9f05e390f6f6ca038def6a44ce5ebaf3c481c099 100644 |
--- a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart |
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart |
@@ -14,6 +14,7 @@ import '../js_backend/backend_helpers.dart' show BackendHelpers; |
import '../js_backend/js_backend.dart' show JavaScriptBackend; |
import '../types/types.dart' show TypeMask; |
import '../io/source_information.dart' show SourceInformation; |
+import '../universe/selector.dart'; |
/// Replaces `getInterceptor` calls with interceptor constants when possible, |
/// or with "almost constant" expressions like "x && CONST" when the input |
@@ -31,6 +32,8 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass { |
BackendHelpers get helpers => backend.helpers; |
+ Map<Interceptor, Continuation> loopHeaderFor = <Interceptor, Continuation>{}; |
+ |
void rewrite(FunctionDefinition node) { |
// TODO(asgerf): Computing the LoopHierarchy here may be overkill when all |
// we want is to hoist constants out of loops. |
@@ -101,11 +104,11 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass { |
return prim; |
} |
- void constifyInterceptor(Interceptor interceptor) { |
+ bool constifyInterceptor(Interceptor interceptor) { |
LetPrim let = interceptor.parent; |
InterceptorConstantValue constant = getInterceptorConstant(interceptor); |
- if (constant == null) return; |
+ if (constant == null) return false; |
if (interceptor.isAlwaysIntercepted) { |
Primitive constantPrim = makeConstantFor(constant, |
@@ -141,16 +144,54 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass { |
interceptor..replaceUsesWith(param)..destroy(); |
let.remove(); |
} |
+ return true; |
} |
@override |
Expression traverseLetPrim(LetPrim node) { |
Expression next = node.body; |
- if (node.primitive is Interceptor) { |
- constifyInterceptor(node.primitive); |
- } |
+ visit(node.primitive); |
return next; |
} |
+ |
+ @override |
+ void visitInterceptor(Interceptor node) { |
+ if (constifyInterceptor(node)) return; |
+ if (node.hasExactlyOneUse) { |
+ // Set the loop header on single-use interceptors so [visitInvokeMethod] |
+ // can determine if it should become a one-shot interceptor. |
+ loopHeaderFor[node] = currentLoopHeader; |
+ } |
+ } |
+ |
+ @override |
+ void visitInvokeMethod(InvokeMethod node) { |
+ if (node.callingConvention != CallingConvention.Intercepted) return; |
+ Primitive interceptor = node.receiver.definition; |
+ if (interceptor is! Interceptor || |
+ interceptor.hasMultipleUses || |
+ loopHeaderFor[interceptor] != currentLoopHeader) { |
+ return; |
+ } |
+ // TODO(asgerf): Consider heuristics for when to use one-shot interceptors. |
+ // E.g. using only one-shot interceptors with a fast path. |
+ node.callingConvention = CallingConvention.OneShotIntercepted; |
+ node..receiver.unlink()..receiver = node.arguments.removeAt(0); |
+ } |
+ |
+ @override |
+ void visitTypeTestViaFlag(TypeTestViaFlag node) { |
+ Primitive interceptor = node.interceptor.definition; |
+ if (interceptor is! Interceptor || |
+ interceptor.hasMultipleUses || |
+ loopHeaderFor[interceptor] != currentLoopHeader || |
+ !backend.mayGenerateInstanceofCheck(node.dartType)) { |
+ return; |
+ } |
+ Interceptor inter = interceptor; |
+ Primitive value = inter.input.definition; |
+ node.replaceWith(new TypeTest(value, node.dartType, [])..type = node.type); |
+ } |
} |
/// Shares interceptor constants when one is in scope of another. |