1 /* 2 * Copyright (c) 2013, 2019, 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.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 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.commons.RemappingMethodAdapter; 38 import jdk.internal.org.objectweb.asm.commons.SimpleRemapper; 39 import jdk.internal.org.objectweb.asm.tree.ClassNode; 40 import jdk.internal.org.objectweb.asm.tree.MethodNode; 41 import jdk.jfr.internal.LogLevel; 42 import jdk.jfr.internal.LogTag; 43 import jdk.jfr.internal.Logger; 44 45 /** 46 * This class will merge (some) methods from one class into another one. 47 * 48 * @author Staffan Larsen 49 */ 50 @Deprecated 51 final class JIMethodMergeAdapter extends ClassVisitor { 52 53 private final ClassNode cn; 54 private final List<Method> methodFilter; 55 private final Map<String, String> typeMap; 56 57 /** 58 * Methods in methodFilter that exist in cn will be merged into cv. If the method already exists, 59 * the original method will be deleted. 60 * 61 * @param cv 62 * @param cn - a ClassNode with Methods that will be merged into this class 63 * @param methodFilter - only methods in this list will be merged 64 * @param typeMappings - while merging, type references in the methods will be changed according to this map 65 */ 66 public JIMethodMergeAdapter(ClassVisitor cv, ClassNode cn, List<Method> methodFilter, JITypeMapping[] typeMappings) { 67 super(Opcodes.ASM5, cv); 68 this.cn = cn; 69 this.methodFilter = methodFilter; 70 71 this.typeMap = new HashMap<>(); 72 for (JITypeMapping tm : typeMappings) { 73 typeMap.put(tm.from().replace('.', '/'), tm.to().replace('.', '/')); 74 } 75 } 76 77 @Override 78 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 79 super.visit(version, access, name, signature, superName, interfaces); 80 typeMap.put(cn.name, name); 81 } 82 83 @Override 84 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 85 if(methodInFilter(name, desc)) { 86 // If the method is one that we will be replacing, delete the method 87 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Deleting " + name + desc); 88 return null; 89 } 90 return super.visitMethod(access, name, desc, signature, exceptions); 91 } 92 93 @Override 94 public void visitEnd() { 95 SimpleRemapper remapper = new SimpleRemapper(typeMap); 96 for (MethodNode mn : cn.methods) { 97 // Check if the method is in the list of methods to copy 98 if (methodInFilter(mn.name, mn.desc)) { 99 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Copying method: " + mn.name + mn.desc); 100 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, " with mapper: " + typeMap); 101 102 String[] exceptions = new String[mn.exceptions.size()]; 103 mn.exceptions.toArray(exceptions); 104 MethodVisitor mv = cv.visitMethod(mn.access, mn.name, mn.desc, mn.signature, exceptions); 105 mn.instructions.resetLabels(); 106 mn.accept(new RemappingMethodAdapter(mn.access, mn.desc, mv, remapper)); 107 } 108 } 109 super.visitEnd(); 110 } 111 112 private boolean methodInFilter(String name, String desc) { 113 for(Method m : methodFilter) { 114 if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) { 115 return true; 116 } 117 } 118 return false; 119 } 120 }