Home | History | Annotate | Download | only in desugar
      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