1 // Copyright 2018 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package com.google.devtools.build.android.desugar; 15 16 import static com.google.common.base.Preconditions.checkArgument; 17 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.base.Preconditions.checkState; 19 20 import org.objectweb.asm.ClassVisitor; 21 import org.objectweb.asm.MethodVisitor; 22 import org.objectweb.asm.Opcodes; 23 24 /** 25 * Rewriter of default and static interface methods defined in some core libraries. 26 * 27 * <p>This is conceptually similar to call site rewriting in {@link InterfaceDesugaring} but here 28 * we're doing it for certain bootclasspath methods and in particular for invokeinterface and 29 * invokevirtual, which are ignored in regular {@link InterfaceDesugaring}. 30 */ 31 public class CoreLibraryInvocationRewriter extends ClassVisitor { 32 33 private final CoreLibrarySupport support; 34 35 public CoreLibraryInvocationRewriter(ClassVisitor cv, CoreLibrarySupport support) { 36 super(Opcodes.ASM6, cv); 37 this.support = support; 38 } 39 40 @Override 41 public MethodVisitor visitMethod( 42 int access, String name, String desc, String signature, String[] exceptions) { 43 MethodVisitor result = super.visitMethod(access, name, desc, signature, exceptions); 44 return result != null ? new CoreLibraryMethodInvocationRewriter(result) : null; 45 } 46 47 private class CoreLibraryMethodInvocationRewriter extends MethodVisitor { 48 public CoreLibraryMethodInvocationRewriter(MethodVisitor mv) { 49 super(Opcodes.ASM6, mv); 50 } 51 52 @Override 53 public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 54 Class<?> coreInterface = 55 support.getCoreInterfaceRewritingTarget(opcode, owner, name, desc, itf); 56 57 if (coreInterface != null) { 58 String coreInterfaceName = coreInterface.getName().replace('.', '/'); 59 name = 60 InterfaceDesugaring.normalizeInterfaceMethodName( 61 name, name.startsWith("lambda$"), opcode == Opcodes.INVOKESTATIC); 62 if (opcode == Opcodes.INVOKESTATIC) { 63 checkState(owner.equals(coreInterfaceName)); 64 } else { 65 desc = InterfaceDesugaring.companionDefaultMethodDescriptor(coreInterfaceName, desc); 66 } 67 68 if (opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKESPECIAL) { 69 checkArgument(itf || opcode == Opcodes.INVOKESPECIAL, 70 "Expected interface to rewrite %s.%s : %s", owner, name, desc); 71 owner = coreInterface.isInterface() 72 ? InterfaceDesugaring.getCompanionClassName(coreInterfaceName) 73 : checkNotNull(support.getMoveTarget(coreInterfaceName, name)); 74 } else { 75 checkState(coreInterface.isInterface()); 76 owner = coreInterfaceName + "$$Dispatch"; 77 } 78 79 opcode = Opcodes.INVOKESTATIC; 80 itf = false; 81 } else { 82 String newOwner = support.getMoveTarget(owner, name); 83 if (newOwner != null) { 84 if (opcode != Opcodes.INVOKESTATIC) { 85 // assuming a static method 86 desc = InterfaceDesugaring.companionDefaultMethodDescriptor(owner, desc); 87 opcode = Opcodes.INVOKESTATIC; 88 } 89 owner = newOwner; 90 itf = false; // assuming a class 91 } 92 } 93 super.visitMethodInsn(opcode, owner, name, desc, itf); 94 } 95 } 96 } 97