From a01493b751fa1a31e1cef929b36ee030402909fa Mon Sep 17 00:00:00 2001 From: kmb Date: Mon, 23 Oct 2017 21:35:37 +0200 Subject: Record dependencies when directly calling moved interface methods. RELNOTES: None. PiperOrigin-RevId: 173154512 --- .../testdata/b68049457/StaticInterfaceMethod.java | 21 ++++++++++++++++++++ .../b68049457/StaticInterfaceMethodCaller.java | 21 ++++++++++++++++++++ .../android/desugar/DefaultMethodClassFixer.java | 20 +++++++++---------- .../build/android/desugar/InterfaceDesugaring.java | 23 +++++++++++++++++++--- 4 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethod.java create mode 100644 src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethodCaller.java (limited to 'src') diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethod.java new file mode 100644 index 0000000000..7815a73657 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethod.java @@ -0,0 +1,21 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.b68049457; + +/** Interface declaring a static method for regression test for b/68049457. */ +public interface StaticInterfaceMethod { + static String never() { + throw new IllegalStateException("can't get here"); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethodCaller.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethodCaller.java new file mode 100644 index 0000000000..f961d96750 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/b68049457/StaticInterfaceMethodCaller.java @@ -0,0 +1,21 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.b68049457; + +/** Class calling static interface method for regression test for b/68049457. */ +public class StaticInterfaceMethodCaller { + public String callIt() { + return StaticInterfaceMethod.never(); + } +} diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java b/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java index 2d89e8b2b1..cf904a49dd 100644 --- a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java +++ b/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java @@ -385,7 +385,7 @@ public class DefaultMethodClassFixer extends ClassVisitor { */ private class DefaultMethodStubber extends ClassVisitor { - private String interfaceName; + private String stubbedInterfaceName; public DefaultMethodStubber() { super(Opcodes.ASM5); @@ -400,8 +400,8 @@ public class DefaultMethodClassFixer extends ClassVisitor { String superName, String[] interfaces) { checkArgument(BitFlags.isSet(access, Opcodes.ACC_INTERFACE)); - checkState(interfaceName == null); - interfaceName = name; + checkState(stubbedInterfaceName == null); + stubbedInterfaceName = name; } @Override @@ -414,7 +414,7 @@ public class DefaultMethodClassFixer extends ClassVisitor { // methods redefined in interfaces extending another. recordIfInstanceMethod(access, name, desc); depsCollector.assumeCompanionClass( - internalName, InterfaceDesugaring.getCompanionClassName(interfaceName)); + internalName, InterfaceDesugaring.getCompanionClassName(stubbedInterfaceName)); // Add this method to the class we're desugaring and stub in a body to call the default // implementation in the interface's companion class. ijar omits these methods when setting @@ -433,9 +433,9 @@ public class DefaultMethodClassFixer extends ClassVisitor { } stubMethod.visitMethodInsn( Opcodes.INVOKESTATIC, - InterfaceDesugaring.getCompanionClassName(interfaceName), + InterfaceDesugaring.getCompanionClassName(stubbedInterfaceName), name, - InterfaceDesugaring.companionDefaultMethodDescriptor(interfaceName, desc), + InterfaceDesugaring.companionDefaultMethodDescriptor(stubbedInterfaceName, desc), /*itf*/ false); stubMethod.visitInsn(neededType.getReturnType().getOpcode(Opcodes.IRETURN)); @@ -444,15 +444,15 @@ public class DefaultMethodClassFixer extends ClassVisitor { return null; } else if (shouldStubAsBridgeDefaultMethod(access, name, desc)) { recordIfInstanceMethod(access, name, desc); - depsCollector.assumeCompanionClass( - internalName, InterfaceDesugaring.getCompanionClassName(interfaceName)); // For bridges we just copy their bodies instead of going through the companion class. // Meanwhile, we also need to desugar the copied method bodies, so that any calls to // interface methods are correctly handled. return new InterfaceDesugaring.InterfaceInvocationRewriter( DefaultMethodClassFixer.this.visitMethod(access, name, desc, (String) null, exceptions), - interfaceName, - bootclasspath); + stubbedInterfaceName, + bootclasspath, + depsCollector, + internalName); } else { return null; // we don't care about the actual code in these methods } diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java index 9371d60f51..d7e3886641 100644 --- a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java +++ b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java @@ -160,6 +160,7 @@ class InterfaceDesugaring extends ClassVisitor { @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { + String codeOwner = internalName; MethodVisitor result; if (isInterface() && isStaticInitializer(name)) { result = @@ -180,6 +181,8 @@ class InterfaceDesugaring extends ClassVisitor { name = normalizeInterfaceMethodName( name, isLambdaBody, BitFlags.isSet(access, Opcodes.ACC_STATIC)); + codeOwner = getCompanionClassName(internalName); + if (BitFlags.isSet(access, Opcodes.ACC_STATIC)) { // Completely move static interface methods, which requires rewriting call sites result = @@ -226,7 +229,7 @@ class InterfaceDesugaring extends ClassVisitor { } return result != null ? new InterfaceInvocationRewriter( - result, isInterface() ? internalName : null, bootclasspath) + result, isInterface() ? internalName : null, bootclasspath, depsCollector, codeOwner) : null; } @@ -330,12 +333,21 @@ class InterfaceDesugaring extends ClassVisitor { @Nullable private final String interfaceName; private final ClassReaderFactory bootclasspath; + private final DependencyCollector depsCollector; + /** Internal name that'll be used to record any dependencies on interface methods. */ + private final String declaringClass; public InterfaceInvocationRewriter( - MethodVisitor dest, @Nullable String knownInterfaceName, ClassReaderFactory bootclasspath) { + MethodVisitor dest, + @Nullable String knownInterfaceName, + ClassReaderFactory bootclasspath, + DependencyCollector depsCollector, + String declaringClass) { super(Opcodes.ASM5, dest); this.interfaceName = knownInterfaceName; this.bootclasspath = bootclasspath; + this.depsCollector = depsCollector; + this.declaringClass = declaringClass; } @Override @@ -361,6 +373,10 @@ class InterfaceDesugaring extends ClassVisitor { } // Reflect that InterfaceDesugaring moves and renames the lambda body method owner += DependencyCollector.INTERFACE_COMPANION_SUFFIX; + itf = false; + // Record dependency on companion class + depsCollector.assumeCompanionClass(declaringClass, owner); + String expectedLambdaMethodName = LambdaDesugaring.uniqueInPackage(owner, name); checkState( name.equals(expectedLambdaMethodName), @@ -368,7 +384,6 @@ class InterfaceDesugaring extends ClassVisitor { owner, name, expectedLambdaMethodName); - itf = false; } else if ((opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKESPECIAL)) { checkArgument(!owner.endsWith(DependencyCollector.INTERFACE_COMPANION_SUFFIX), "shouldn't consider %s an interface", owner); @@ -379,6 +394,8 @@ class InterfaceDesugaring extends ClassVisitor { } owner += DependencyCollector.INTERFACE_COMPANION_SUFFIX; itf = false; + // Record dependency on companion class + depsCollector.assumeCompanionClass(declaringClass, owner); } } super.visitMethodInsn(opcode, owner, name, desc, itf); -- cgit v1.2.3