|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package jdk.jfr.internal; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
import java.io.PrintWriter; |
|
import java.util.List; |
|
|
|
import jdk.internal.org.objectweb.asm.ClassReader; |
|
import jdk.internal.org.objectweb.asm.MethodVisitor; |
|
import jdk.internal.org.objectweb.asm.Opcodes; |
|
import jdk.internal.org.objectweb.asm.Type; |
|
import jdk.internal.org.objectweb.asm.commons.Method; |
|
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; |
|
import jdk.jfr.ValueDescriptor; |
|
import jdk.jfr.internal.EventInstrumentation.FieldInfo; |
|
|
|
final class ASMToolkit { |
|
private static Type TYPE_STRING = Type.getType(String.class); |
|
private static Type Type_THREAD = Type.getType(Thread.class); |
|
private static Type TYPE_CLASS = Type.getType(Class.class); |
|
|
|
public static void invokeSpecial(MethodVisitor methodVisitor, String className, Method m) { |
|
methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, m.getName(), m.getDescriptor(), false); |
|
} |
|
|
|
public static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) { |
|
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false); |
|
} |
|
|
|
public static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) { |
|
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false); |
|
} |
|
|
|
|
|
public static Type toType(ValueDescriptor v) { |
|
String typeName = v.getTypeName(); |
|
|
|
switch (typeName) { |
|
case "byte": |
|
return Type.BYTE_TYPE; |
|
case "short": |
|
return Type.SHORT_TYPE; |
|
case "int": |
|
return Type.INT_TYPE; |
|
case "long": |
|
return Type.LONG_TYPE; |
|
case "double": |
|
return Type.DOUBLE_TYPE; |
|
case "float": |
|
return Type.FLOAT_TYPE; |
|
case "char": |
|
return Type.CHAR_TYPE; |
|
case "boolean": |
|
return Type.BOOLEAN_TYPE; |
|
case "java.lang.String": |
|
return TYPE_STRING; |
|
case "java.lang.Thread": |
|
return Type_THREAD; |
|
case "java.lang.Class": |
|
return TYPE_CLASS; |
|
} |
|
|
|
throw new Error("Not a valid type " + v.getTypeName()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getDescriptor(String typeName) { |
|
if ("int".equals(typeName)) { |
|
return "I"; |
|
} |
|
if ("long".equals(typeName)) { |
|
return "J"; |
|
} |
|
if ("boolean".equals(typeName)) { |
|
return "Z"; |
|
} |
|
if ("float".equals(typeName)) { |
|
return "F"; |
|
} |
|
if ("double".equals(typeName)) { |
|
return "D"; |
|
} |
|
if ("short".equals(typeName)) { |
|
return "S"; |
|
} |
|
if ("char".equals(typeName)) { |
|
return "C"; |
|
} |
|
if ("byte".equals(typeName)) { |
|
return "B"; |
|
} |
|
String internal = getInternalName(typeName); |
|
return Type.getObjectType(internal).getDescriptor(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String getInternalName(String className) { |
|
return className.replace(".", "/"); |
|
} |
|
|
|
public static Method makeWriteMethod(List<FieldInfo> fields) { |
|
StringBuilder sb = new StringBuilder(); |
|
sb.append("("); |
|
for (FieldInfo v : fields) { |
|
if (!v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD) && !v.fieldName.equals(EventInstrumentation.FIELD_STACK_TRACE)) { |
|
sb.append(v.fieldDescriptor); |
|
} |
|
} |
|
sb.append(")V"); |
|
return new Method("write", sb.toString()); |
|
} |
|
|
|
public static void logASM(String className, byte[] bytes) { |
|
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className); |
|
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, () -> { |
|
ClassReader cr = new ClassReader(bytes); |
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
|
PrintWriter w = new PrintWriter(baos); |
|
w.println("Bytecode:"); |
|
cr.accept(new TraceClassVisitor(w), 0); |
|
return baos.toString(); |
|
}); |
|
} |
|
|
|
} |