Index: pkg/compiler/lib/src/ssa/codegen_helpers.dart |
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
index 5a0f55803394c8bc279e2ea8f3fea59c293a7c39..dca34c5016f91460465e5e1c30a635756294c06f 100644 |
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
@@ -96,49 +96,61 @@ class SsaInstructionSelection extends HBaseVisitor { |
HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
if (node.isInterceptedCall) { |
- // Calls of the form |
- // |
- // a.foo$1(a, x) |
- // |
- // where the interceptor calling convention is used come from recognizing |
- // that 'a' is a 'self-interceptor'. If the selector matches only methods |
- // that ignore the explicit receiver parameter, replace occurences of the |
- // receiver argument with a dummy receiver '0': |
- // |
- // a.foo$1(a, x) ---> a.foo$1(0, x) |
- // |
- // This often reduces the number of references to 'a' to one, allowing 'a' |
- // to be generated at use to avoid a temporary, e.g. |
- // |
- // t1 = b.get$thing(); |
- // t1.foo$1(t1, x) |
- // ---> |
- // b.get$thing().foo$1(0, x) |
- // |
- Selector selector = node.selector; |
- TypeMask mask = node.mask; |
+ tryReplaceInterceptorWithDummy(node, node.selector, node.mask); |
+ } |
+ return node; |
+ } |
+ |
+ HInstruction visitInvokeSuper(HInvokeSuper node) { |
+ if (node.isInterceptedCall) { |
+ TypeMask mask = node.getDartReceiver(compiler).instructionType; |
+ tryReplaceInterceptorWithDummy(node, node.selector, mask); |
+ } |
+ return node; |
+ } |
+ |
+ void tryReplaceInterceptorWithDummy( |
+ HInvoke node, Selector selector, TypeMask mask) { |
+ // Calls of the form |
+ // |
+ // a.foo$1(a, x) |
+ // |
+ // where the interceptor calling convention is used come from recognizing |
+ // that 'a' is a 'self-interceptor'. If the selector matches only methods |
+ // that ignore the explicit receiver parameter, replace occurences of the |
+ // receiver argument with a dummy receiver '0': |
+ // |
+ // a.foo$1(a, x) ---> a.foo$1(0, x) |
+ // |
+ // This often reduces the number of references to 'a' to one, allowing 'a' |
+ // to be generated at use to avoid a temporary, e.g. |
+ // |
+ // t1 = b.get$thing(); |
+ // t1.foo$1(t1, x) |
+ // ---> |
+ // b.get$thing().foo$1(0, x) |
+ // |
+ |
+ // TODO(15933): Make automatically generated property extraction closures |
+ // work with the dummy receiver optimization. |
+ if (selector.isGetter) return; |
+ |
+ // This assignment of inputs is uniform for HInvokeDynamic and HInvokeSuper. |
+ HInstruction interceptor = node.inputs[0]; |
+ HInstruction receiverArgument = node.inputs[1]; |
+ |
+ if (interceptor.nonCheck() == receiverArgument.nonCheck()) { |
if (backend.isInterceptedSelector(selector) && |
!backend.isInterceptedMixinSelector(selector, mask)) { |
- HInstruction interceptor = node.inputs[0]; |
- HInstruction receiverArgument = node.inputs[1]; |
- |
- if (interceptor.nonCheck() == receiverArgument.nonCheck()) { |
- // TODO(15933): Make automatically generated property extraction |
- // closures work with the dummy receiver optimization. |
- if (!selector.isGetter) { |
- ConstantValue constant = new SyntheticConstantValue( |
- SyntheticConstantKind.DUMMY_INTERCEPTOR, |
- receiverArgument.instructionType); |
- HConstant dummy = graph.addConstant(constant, compiler); |
- receiverArgument.usedBy.remove(node); |
- node.inputs[1] = dummy; |
- dummy.usedBy.add(node); |
- } |
- } |
+ ConstantValue constant = new SyntheticConstantValue( |
+ SyntheticConstantKind.DUMMY_INTERCEPTOR, |
+ receiverArgument.instructionType); |
+ HConstant dummy = graph.addConstant(constant, compiler); |
+ receiverArgument.usedBy.remove(node); |
+ node.inputs[1] = dummy; |
+ dummy.usedBy.add(node); |
} |
} |
- |
- return node; |
} |
HInstruction visitFieldSet(HFieldSet setter) { |