| Index: sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
|
| index e4a4ad825268f78016408b3c07a567ed5a23077c..5cf43924e5d08b5526a3a23941a21a9cbfaef34b 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
|
| @@ -186,7 +186,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
|
| if (interceptedClasses.contains(backend.jsNumberClass)
|
| && !(interceptedClasses.contains(backend.jsDoubleClass)
|
| || interceptedClasses.contains(backend.jsIntClass))) {
|
| - for (var user in node.usedBy) {
|
| + for (HInstruction user in node.usedBy) {
|
| if (user is! HInvoke) continue;
|
| Set<ClassElement> intercepted =
|
| backend.getInterceptedClassesOn(user.selector.name);
|
| @@ -200,7 +200,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
|
| }
|
| } else {
|
| interceptedClasses = new Set<ClassElement>();
|
| - for (var user in node.usedBy) {
|
| + for (HInstruction user in node.usedBy) {
|
| if (user is HIs) {
|
| // Is-checks can be performed on any intercepted class.
|
| interceptedClasses.addAll(backend.interceptedClasses);
|
| @@ -215,8 +215,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
|
|
|
| HInstruction receiver = node.receiver;
|
| if (canUseSelfForInterceptor(receiver, interceptedClasses)) {
|
| - node.block.rewrite(node, receiver);
|
| - return false;
|
| + return rewriteToUseSelfAsInterceptor(node, receiver);
|
| }
|
|
|
| // Try computing a constant interceptor.
|
| @@ -254,6 +253,51 @@ class SsaSimplifyInterceptors extends HBaseVisitor
|
| return true;
|
| }
|
|
|
| + bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) {
|
| + // `rewrite` below clears `node.usedBy`.
|
| + List<HInstruction> originalUsers = node.usedBy.toList();
|
| +
|
| + node.block.rewrite(node, receiver);
|
| +
|
| + // We have just rewritten:
|
| + //
|
| + // m = getInterceptor(a)
|
| + // m.foo$1(a, x)
|
| + // -->
|
| + // m = getInterceptor(a)
|
| + // a.foo$1(a, x)
|
| + //
|
| + // For the rewritten calls, 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)
|
| + //
|
| + JavaScriptBackend backend = compiler.backend;
|
| + for (HInstruction user in originalUsers) {
|
| + if (user is HInvokeDynamic) {
|
| + HInvokeDynamic invoke = user;
|
| + if (invoke.receiver == receiver &&
|
| + !backend.isInterceptedMixinSelector(invoke.selector)) {
|
| + HInstruction receiverArgument = invoke.inputs[1];
|
| + // TODO(15720): The test here should be
|
| + //
|
| + // invoke.receiver.nonCheck() == receiverArgument.nonCheck()
|
| + //
|
| + if (invoke.receiver == receiverArgument) { // recognize a.foo(a,...)
|
| + Constant constant = new DummyReceiverConstant(
|
| + receiverArgument.instructionType);
|
| + HConstant dummy = graph.addConstant(constant, compiler);
|
| + receiverArgument.usedBy.remove(invoke);
|
| + invoke.inputs[1] = dummy;
|
| + dummy.usedBy.add(invoke);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| bool visitOneShotInterceptor(HOneShotInterceptor node) {
|
| HInstruction constant = tryComputeConstantInterceptor(
|
| node.inputs[1], node.interceptedClasses);
|
|
|