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.lang.reflect.Method; 29 import java.lang.reflect.Modifier; 30 import java.util.List; 31 32 import jdk.internal.org.objectweb.asm.ClassReader; 33 import jdk.internal.org.objectweb.asm.ClassVisitor; 34 import jdk.internal.org.objectweb.asm.MethodVisitor; 35 import jdk.internal.org.objectweb.asm.Opcodes; 36 import jdk.internal.org.objectweb.asm.Type; 37 import jdk.internal.org.objectweb.asm.tree.ClassNode; 38 import jdk.internal.org.objectweb.asm.tree.MethodNode; 39 import jdk.jfr.internal.LogLevel; 40 import jdk.jfr.internal.LogTag; 41 import jdk.jfr.internal.Logger; 42 43 @Deprecated 44 final class JIInliner extends ClassVisitor { 45 private final String targetClassName; 46 private final String instrumentationClassName; 47 private final ClassNode targetClassNode; 48 private final List<Method> instrumentationMethods; 49 50 /** 51 * A ClassVisitor which will check all methods of the class it visits against the instrumentationMethods 52 * list. If a method is on that list, the method will be further processed for inlining into that 53 * method. 54 */ 55 JIInliner(int api, ClassVisitor cv, String targetClassName, String instrumentationClassName, 56 ClassReader targetClassReader, 57 List<Method> instrumentationMethods) { 58 super(api, cv); 59 this.targetClassName = targetClassName; 60 this.instrumentationClassName = instrumentationClassName; 61 this.instrumentationMethods = instrumentationMethods; 62 63 ClassNode cn = new ClassNode(Opcodes.ASM5); 64 targetClassReader.accept(cn, ClassReader.EXPAND_FRAMES); 65 this.targetClassNode = cn; 66 } 67 68 @Override 69 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 70 MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 71 72 if (isInstrumentationMethod(name, desc)) { 73 MethodNode methodToInline = findTargetMethodNode(name, desc); 74 if (methodToInline == null) { 75 throw new IllegalArgumentException("Could not find the method to instrument in the target class"); 76 } 77 if (Modifier.isNative(methodToInline.access)) { 78 throw new IllegalArgumentException("Cannot instrument native methods: " + targetClassNode.name + "." + methodToInline.name + methodToInline.desc); 79 } 80 81 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inliner processing method " + name + desc); 82 83 JIMethodCallInliner mci = new JIMethodCallInliner(access, 84 desc, 85 mv, 86 methodToInline, 87 targetClassName, 88 instrumentationClassName); 89 return mci; 90 } 91 92 return mv; 93 } 94 95 private boolean isInstrumentationMethod(String name, String desc) { 96 for(Method m : instrumentationMethods) { 97 if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) { 98 return true; 99 } 100 } 101 return false; 102 } 103 104 private MethodNode findTargetMethodNode(String name, String desc) { 105 for (MethodNode mn : targetClassNode.methods) { 106 if (mn.desc.equals(desc) && mn.name.equals(name)) { 107 return mn; 108 } 109 } 110 throw new IllegalArgumentException("could not find MethodNode for " 111 + name + desc); 112 } 113 }