1 /* 2 * Copyright (c) 2016, 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; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.PrintWriter; 30 import java.util.List; 31 32 import jdk.internal.org.objectweb.asm.ClassReader; 33 import jdk.internal.org.objectweb.asm.MethodVisitor; 34 import jdk.internal.org.objectweb.asm.Opcodes; 35 import jdk.internal.org.objectweb.asm.Type; 36 import jdk.internal.org.objectweb.asm.commons.Method; 37 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; 38 import jdk.jfr.ValueDescriptor; 39 import jdk.jfr.internal.EventInstrumentation.FieldInfo; 40 41 final class ASMToolkit { 42 private static Type TYPE_STRING = Type.getType(String.class); 43 private static Type Type_THREAD = Type.getType(Thread.class); 44 private static Type TYPE_CLASS = Type.getType(Class.class); 45 46 public static void invokeSpecial(MethodVisitor methodVisitor, String className, Method m) { 47 methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, m.getName(), m.getDescriptor(), false); 48 } 49 50 public static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) { 51 methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false); 52 } 53 54 public static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) { 55 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false); 56 } 57 58 59 public static Type toType(ValueDescriptor v) { 60 String typeName = v.getTypeName(); 61 62 switch (typeName) { 63 case "byte": 64 return Type.BYTE_TYPE; 65 case "short": 66 return Type.SHORT_TYPE; 67 case "int": 68 return Type.INT_TYPE; 69 case "long": 70 return Type.LONG_TYPE; 71 case "double": 72 return Type.DOUBLE_TYPE; 73 case "float": 74 return Type.FLOAT_TYPE; 75 case "char": 76 return Type.CHAR_TYPE; 77 case "boolean": 78 return Type.BOOLEAN_TYPE; 79 case "java.lang.String": 80 return TYPE_STRING; 81 case "java.lang.Thread": 82 return Type_THREAD; 83 case "java.lang.Class": 84 return TYPE_CLASS; 85 } 86 // Add support for SettingControl? 87 throw new Error("Not a valid type " + v.getTypeName()); 88 } 89 90 /** 91 * Converts "int" into "I" and "java.lang.String" into "Ljava/lang/String;" 92 * 93 * @param typeName 94 * type 95 * 96 * @return descriptor 97 */ 98 public static String getDescriptor(String typeName) { 99 if ("int".equals(typeName)) { 100 return "I"; 101 } 102 if ("long".equals(typeName)) { 103 return "J"; 104 } 105 if ("boolean".equals(typeName)) { 106 return "Z"; 107 } 108 if ("float".equals(typeName)) { 109 return "F"; 110 } 111 if ("double".equals(typeName)) { 112 return "D"; 113 } 114 if ("short".equals(typeName)) { 115 return "S"; 116 } 117 if ("char".equals(typeName)) { 118 return "C"; 119 } 120 if ("byte".equals(typeName)) { 121 return "B"; 122 } 123 String internal = getInternalName(typeName); 124 return Type.getObjectType(internal).getDescriptor(); 125 } 126 127 /** 128 * Converts java.lang.String into java/lang/String 129 * 130 * @param className 131 * 132 * @return internal name 133 */ 134 public static String getInternalName(String className) { 135 return className.replace(".", "/"); 136 } 137 138 public static Method makeWriteMethod(List<FieldInfo> fields) { 139 StringBuilder sb = new StringBuilder(); 140 sb.append("("); 141 for (FieldInfo v : fields) { 142 if (!v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD) && !v.fieldName.equals(EventInstrumentation.FIELD_STACK_TRACE)) { 143 sb.append(v.fieldDescriptor); 144 } 145 } 146 sb.append(")V"); 147 return new Method("write", sb.toString()); 148 } 149 150 public static void logASM(String className, byte[] bytes) { 151 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className); 152 Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, () -> { 153 ClassReader cr = new ClassReader(bytes); 154 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 155 PrintWriter w = new PrintWriter(baos); 156 w.println("Bytecode:"); 157 cr.accept(new TraceClassVisitor(w), 0); 158 return baos.toString(); 159 }); 160 } 161 162 }