1 /*
   2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.jfr.internal.instrument;
  27 
  28 import java.util.ArrayList;
  29 import java.util.List;
  30 
  31 import jdk.internal.org.objectweb.asm.Label;
  32 import jdk.internal.org.objectweb.asm.MethodVisitor;
  33 import jdk.internal.org.objectweb.asm.Opcodes;
  34 import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
  35 import jdk.internal.org.objectweb.asm.commons.Remapper;
  36 import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
  37 import jdk.internal.org.objectweb.asm.tree.MethodNode;
  38 import jdk.jfr.internal.LogLevel;
  39 import jdk.jfr.internal.LogTag;
  40 import jdk.jfr.internal.Logger;
  41 
  42 /**
  43  * Class responsible for finding the call to inline and inlining it.
  44  *
  45  * This code is heavily influenced by section 3.2.6 "Inline Method" in
  46  * "Using ASM framework to implement common bytecode transformation patterns",
  47  * E. Kuleshov, AOSD.07, March 2007, Vancouver, Canada.
  48  * http://asm.ow2.org/index.html
  49  */
  50 @Deprecated
  51 final class JIMethodCallInliner extends LocalVariablesSorter {
  52 
  53     private final String oldClass;
  54     private final String newClass;
  55     private final MethodNode inlineTarget;
  56     private final List<CatchBlock> blocks = new ArrayList<>();
  57     private boolean inlining;
  58 
  59     /**
  60      * inlineTarget defines the method to inline and also contains the actual
  61      * code to inline.
  62      *
  63      * @param access
  64      * @param desc
  65      * @param mv
  66      * @param inlineTarget
  67      * @param oldClass
  68      * @param newClass
  69      * @param logger
  70      */
  71     public JIMethodCallInliner(int access, String desc, MethodVisitor mv,
  72             MethodNode inlineTarget, String oldClass, String newClass) {
  73         super(Opcodes.ASM7, access, desc, mv);
  74         this.oldClass = oldClass;
  75         this.newClass = newClass;
  76         this.inlineTarget = inlineTarget;
  77 
  78         Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "MethodCallInliner: targetMethod=" + newClass + "."
  79                 + inlineTarget.name + inlineTarget.desc);
  80     }
  81 
  82     @Override
  83     public void visitMethodInsn(int opcode, String owner, String name,
  84             String desc, boolean itf) {
  85         // Now we are looking at method call in the source method
  86         if (!shouldBeInlined(owner, name, desc)) {
  87             // If this method call should not be inlined, just keep it
  88             mv.visitMethodInsn(opcode, owner, name, desc, itf);
  89             return;
  90         }
  91         // If the call should be inlined, we create a MethodInliningAdapter
  92         // The MIA will walk the instructions in the inlineTarget and add them
  93         // to the current method, doing the necessary name remappings.
  94         Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inlining call to " + name + desc);
  95         Remapper remapper = new SimpleRemapper(oldClass, newClass);
  96         Label end = new Label();
  97         inlining = true;
  98         inlineTarget.instructions.resetLabels();
  99         JIMethodInliningAdapter mia = new JIMethodInliningAdapter(this, end,
 100                 opcode == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0, desc,
 101                 remapper);
 102         inlineTarget.accept(mia);
 103         inlining = false;
 104         super.visitLabel(end);
 105     }
 106 
 107     /**
 108      * Determine if the method should be inlined or not.
 109      */
 110     private boolean shouldBeInlined(String owner, String name, String desc) {
 111         return inlineTarget.desc.equals(desc) && inlineTarget.name.equals(name)
 112                 && owner.equals(newClass.replace('.', '/'));
 113     }
 114 
 115     @Override
 116     public void visitTryCatchBlock(Label start, Label end, Label handler,
 117             String type) {
 118         if (!inlining) {
 119             // try-catch blocks are saved here and replayed at the end
 120             // of the method (in visitMaxs)
 121             blocks.add(new CatchBlock(start, end, handler, type));
 122         } else {
 123             super.visitTryCatchBlock(start, end, handler, type);
 124         }
 125     }
 126 
 127     @Override
 128     public void visitMaxs(int stack, int locals) {
 129         for (CatchBlock b : blocks) {
 130             super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
 131         }
 132         super.visitMaxs(stack, locals);
 133     }
 134 
 135     static final class CatchBlock {
 136 
 137         final Label start;
 138         final Label end;
 139         final Label handler;
 140         final String type;
 141 
 142         CatchBlock(Label start, Label end, Label handler, String type) {
 143             this.start = start;
 144             this.end = end;
 145             this.handler = handler;
 146             this.type = type;
 147         }
 148     }
 149 }