下面列出了org.objectweb.asm.ClassVisitor#visitMethod ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static void implementProxy(ClassVisitor classVisitor, Class<?> iFace, String generatedName) {
MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC,
"proxy",
methodDescriptor(iFace),
null,
null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(Opcodes.ALOAD, LOCALS_INDEX_THIS);
methodVisitor.visitInsn(Opcodes.ARETURN);
methodVisitor.visitMaxs(-1, -1);
methodVisitor.visitEnd();
implementBridgeMethod(classVisitor, generatedName, "proxy", iFace);
}
/**
* Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
* version.
*
* @param access access flags of the adapted method.
* @param method the adapted method.
* @param signature the signature of the adapted method (may be {@literal null}).
* @param exceptions the exceptions thrown by the adapted method (may be {@literal null}).
* @param classVisitor the class visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(
final int access,
final Method method,
final String signature,
final Type[] exceptions,
final ClassVisitor classVisitor) {
this(
access,
method,
classVisitor.visitMethod(
access,
method.getName(),
method.getDescriptor(),
signature,
exceptions == null ? null : getInternalNames(exceptions)));
}
@Test
public void testInstrumentationLegacyClassOtherType() throws Exception {
ClassVisitor classVisitor = TypeConstantAdjustment.INSTANCE.wrap(mock(TypeDescription.class),
this.classVisitor,
mock(Implementation.Context.class),
mock(TypePool.class),
new FieldList.Empty<FieldDescription.InDefinedShape>(),
new MethodList.Empty<MethodDescription>(),
IGNORED,
IGNORED);
classVisitor.visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
MethodVisitor methodVisitor = classVisitor.visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
assertThat(methodVisitor, not(this.methodVisitor));
methodVisitor.visitLdcInsn(FOO);
verify(this.classVisitor).visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verify(this.classVisitor).visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verifyNoMoreInteractions(this.classVisitor);
verify(this.methodVisitor).visitLdcInsn(FOO);
verifyNoMoreInteractions(this.methodVisitor);
}
/**
* Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
* version.
*
* @param access access flags of the adapted method.
* @param method the adapted method.
* @param signature the signature of the adapted method (may be <tt>null</tt>).
* @param exceptions the exceptions thrown by the adapted method (may be <tt>null</tt>).
* @param classVisitor the class visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(
final int access,
final Method method,
final String signature,
final Type[] exceptions,
final ClassVisitor classVisitor) {
this(
access,
method,
classVisitor.visitMethod(
access,
method.getName(),
method.getDescriptor(),
signature,
getInternalNames(exceptions)));
}
private static void implementProxyInstance(ClassVisitor classVisitor, Class<?> iFace, String generatedName) {
MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC,
"proxyInstance",
methodDescriptor(iFace, iFace),
null,
null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(Opcodes.ALOAD, LOCALS_INDEX_THIS);
methodVisitor.visitInsn(Opcodes.ARETURN);
methodVisitor.visitMaxs(-1, -1);
methodVisitor.visitEnd();
implementBridgeMethod(classVisitor, generatedName, "proxyInstance", iFace, iFace);
}
private static void enhanceForNewInstanceInner(ClassVisitor cw, String classNm, String enclosingClassNm) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()LLjava/lang/Object;", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, classNm);
mv.visitInsn(DUP);
mv.visitTypeInsn(NEW, enclosingClassNm);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, enclosingClassNm, "<init>", "()V");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKEVIRTUAL, classNm, "getClass", "()Ljava/lang/Class;");
mv.visitInsn(POP);
mv.visitMethodInsn(INVOKESPECIAL, classNm, "<init>", "(L" + enclosingClassNm + ";)V");
mv.visitInsn(ARETURN);
mv.visitMaxs(4, 1);
mv.visitEnd();
}
/**
* Generate the getter method for each arguments. These getters are not
* available from consumer code, but instead are called by the injector to
* retrieve each argument in turn for passing to the method invocation being
* modified.
*
* @param ref Class ref being generated
* @param desc Argument descriptor
* @param args Parsed argument list from descriptor
* @param writer Class writer
*/
private void generateGetters(ArgsClassInfo info, ClassVisitor writer) {
byte argIndex = 0;
for (Type arg : info.args) {
String name = ArgsClassGenerator.GETTER_PREFIX + argIndex;
String sig = "()" + arg.getDescriptor();
MethodVisitorEx get = new MethodVisitorEx(writer.visitMethod(Opcodes.ACC_PUBLIC, name, sig, null, null));
get.visitCode();
// Read the value from the values field
get.visitVarInsn(Opcodes.ALOAD, 0);
get.visitFieldInsn(Opcodes.GETFIELD, info.getName(), ArgsClassGenerator.VALUES_FIELD, ArgsClassGenerator.OBJECT_ARRAY);
get.visitConstant(argIndex);
get.visitInsn(Opcodes.AALOAD);
// Unbox (if primitive) or cast down the value
ArgsClassGenerator.unbox(get, arg);
// Return the value
get.visitInsn(arg.getOpcode(Opcodes.IRETURN));
get.visitMaxs(2, 1);
get.visitEnd();
argIndex++;
}
}
/**
* Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
* version.
*
* @param access access flags of the adapted method.
* @param method the adapted method.
* @param signature the signature of the adapted method (may be {@literal null}).
* @param exceptions the exceptions thrown by the adapted method (may be {@literal null}).
* @param classVisitor the class visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(
final int access,
final Method method,
final String signature,
final Type[] exceptions,
final ClassVisitor classVisitor) {
this(
access,
method,
classVisitor.visitMethod(
access,
method.getName(),
method.getDescriptor(),
signature,
getInternalNames(exceptions)));
}
/** Emits a bridge method for a field with a {@link Opcodes.PUTSTATIC} access. */
@Override
public MethodVisitor visitPutStatic(FieldKey fieldKey, ClassVisitor cv) {
MethodKey bridgeMethodKey = fieldKey.bridgeOfStaticWrite();
MethodVisitor mv =
cv.visitMethod(
ACC_SYNTHETIC | ACC_STATIC,
bridgeMethodKey.name(),
bridgeMethodKey.descriptor(),
/* signature= */ null,
/* exceptions= */ null);
mv.visitCode();
Type fieldType = fieldKey.getFieldType();
mv.visitVarInsn(fieldType.getOpcode(Opcodes.ILOAD), 0);
mv.visitInsn(
LangModelHelper.getTypeSizeAlignedDupOpcode(ImmutableList.of(fieldKey.getFieldType())));
mv.visitFieldInsn(
Opcodes.PUTSTATIC, fieldKey.ownerName(), fieldKey.name(), fieldKey.descriptor());
mv.visitInsn(fieldType.getOpcode(Opcodes.IRETURN));
int fieldTypeSize = fieldType.getSize();
mv.visitMaxs(fieldTypeSize, fieldTypeSize);
mv.visitEnd();
return mv;
}
public final MethodVisitor accept(ClassVisitor cv) {
return cv.visitMethod(
memberAccess(),
methodKey().name(),
methodKey().descriptor(),
signature(),
exceptionArray());
}
/**
* Makes the given class visitor visit this method.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
String[] exceptions = new String[this.exceptions.size()];
this.exceptions.toArray(exceptions);
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
if (mv != null) {
accept(mv);
}
}
private static void enhanceForConstructor(ClassVisitor cw, String accessClassNm, String clazzNm) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Class;)V", "(L" + clazzNm + ";)V", null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, INVOKEDYNAMIC_CLASS_ACCESS_NM, "<init>", "(Ljava/lang/Class;)V");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
private static void implementConstructor(ClassVisitor classVisitor,
Class<? extends ProxyChannelRingBuffer> parentType,
String generatedName,
int primitiveMessageSize,
int referenceMessageSize) {
MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC,
"<init>",
methodDescriptor(void.class,
int.class,
WaitStrategy.class),
null,
null);
methodVisitor.visitCode();
LocalsHelper locals = LocalsHelper.forInstanceMethod();
int localIndexOfCapacity = locals.newLocal(int.class);
int localIndexOfWaitStrategy = locals.newLocal(WaitStrategy.class);
methodVisitor.visitVarInsn(Opcodes.ALOAD, LOCALS_INDEX_THIS);
methodVisitor.visitVarInsn(Opcodes.ILOAD, localIndexOfCapacity);
methodVisitor.visitLdcInsn(primitiveMessageSize);
methodVisitor.visitLdcInsn(referenceMessageSize);
methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
Type.getInternalName(parentType),
"<init>",
methodDescriptor(void.class,
int.class,
int.class,
int.class),
false);
methodVisitor.visitVarInsn(Opcodes.ALOAD, LOCALS_INDEX_THIS);
methodVisitor.visitVarInsn(Opcodes.ALOAD, localIndexOfWaitStrategy);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, generatedName, "waitStrategy", Type.getDescriptor(WaitStrategy.class));
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(-1, -1);
methodVisitor.visitEnd();
}
/**
* Generate the varargs <tt>set</tt> method body. The <tt>set</tt> method
* performs a <tt>CHECKCAST</tt> on all incoming arguments, and also ensures
* that primitive types are not assigned <tt>null</tt> by the consumer code.
*
* @param ref Class ref being generated
* @param desc Argument descriptor
* @param args Parsed argument list from descriptor
* @param writer Class writer
*/
private void generateMultiSetter(ArgsClassInfo info, ClassVisitor writer) {
MethodVisitorEx set = new MethodVisitorEx(writer.visitMethod(Opcodes.ACC_PUBLIC,
ArgsClassGenerator.SETALL, ArgsClassGenerator.SETALL_DESC, null, null));
set.visitCode();
Label lengthOk = new Label(), nullPrimitive = new Label();
int maxStack = 6;
// Compare the length of the varargs array to the expected argument count
set.visitVarInsn(Opcodes.ALOAD, 1);
set.visitInsn(Opcodes.ARRAYLENGTH);
set.visitInsn(Opcodes.DUP);
set.visitConstant((byte)info.args.length);
// If the lengths are the same, proceed with assignment
set.visitJumpInsn(Opcodes.IF_ICMPEQ, lengthOk);
// Otherwise prepare and throw an ArgumentCountException
set.visitTypeInsn(Opcodes.NEW, ArgsClassGenerator.ACE);
set.visitInsn(Opcodes.DUP);
set.visitInsn(Opcodes.DUP2_X1);
set.visitInsn(Opcodes.POP2);
set.visitConstant((byte)info.args.length);
set.visitLdcInsn(info.getSignature());
set.visitMethodInsn(Opcodes.INVOKESPECIAL, ArgsClassGenerator.ACE, Constants.CTOR, ArgsClassGenerator.ACE_CTOR_DESC, false);
set.visitInsn(Opcodes.ATHROW);
set.visitLabel(lengthOk);
set.visitInsn(Opcodes.POP); // Pop the remaining length value
// Put the values array on the stack to begin with
set.visitVarInsn(Opcodes.ALOAD, 0);
set.visitFieldInsn(Opcodes.GETFIELD, info.getName(), ArgsClassGenerator.VALUES_FIELD, ArgsClassGenerator.OBJECT_ARRAY);
for (byte index = 0; index < info.args.length; index++) {
// Dup the member array reference and target index
set.visitInsn(Opcodes.DUP);
set.visitConstant(index);
// Read the value from the varargs array
set.visitVarInsn(Opcodes.ALOAD, 1);
set.visitConstant(index);
set.visitInsn(Opcodes.AALOAD);
// Check the argument type
String boxingType = Bytecode.getBoxingType(info.args[index]);
set.visitTypeInsn(Opcodes.CHECKCAST, boxingType != null ? boxingType : info.args[index].getInternalName());
// For primitives, check the value is not null
if (boxingType != null) {
set.visitInsn(Opcodes.DUP);
set.visitJumpInsn(Opcodes.IFNULL, nullPrimitive);
maxStack = 7;
}
// Everything succeeded, assign the value
set.visitInsn(Opcodes.AASTORE);
}
set.visitInsn(Opcodes.RETURN);
set.visitLabel(nullPrimitive);
ArgsClassGenerator.throwNPE(set, "Argument with primitive type cannot be set to NULL");
set.visitInsn(Opcodes.RETURN);
set.visitMaxs(maxStack, 2);
set.visitEnd();
}
/**
* 生成格式如下的代码,其中ServiceInit_xxx由注解生成器生成。
* <pre>
* package com.sankuai.waimai.router.generated;
*
* public class ServiceLoaderInit {
*
* public static void init() {
* ServiceInit_xxx1.init();
* ServiceInit_xxx2.init();
* }
* }
* </pre>
*/
private void generateServiceInitClass(String directory, Set<String> classes) {
if (classes.isEmpty()) {
WMRouterLogger.info(GENERATE_INIT + "skipped, no service found");
return;
}
try {
WMRouterLogger.info(GENERATE_INIT + "start...");
long ms = System.currentTimeMillis();
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, writer) {
};
String className = Const.SERVICE_LOADER_INIT.replace('.', '/');
cv.visit(50, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
Const.INIT_METHOD, "()V", null, null);
mv.visitCode();
for (String clazz : classes) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazz.replace('.', '/'),
"init",
"()V",
false);
}
mv.visitMaxs(0, 0);
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
cv.visitEnd();
File dest = new File(directory, className + SdkConstants.DOT_CLASS);
dest.getParentFile().mkdirs();
new FileOutputStream(dest).write(writer.toByteArray());
WMRouterLogger.info(GENERATE_INIT + "cost %s ms", System.currentTimeMillis() - ms);
} catch (IOException e) {
WMRouterLogger.fatal(e);
}
}
public MethodVisitor visitMethod(ClassVisitor visitor, int access, String[] exceptions) {
return visitor.visitMethod(access, s_name, s_desc, null, exceptions);
}
static void addLogError(ClassVisitor cw) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_VARARGS, "$$error", "(Ljava/lang/String;[Ljava/lang/Object;)V",
null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(433, l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
mv.visitLdcInsn("SessionAgent: [ERROR] %s");
mv.visitInsn(ICONST_1);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
mv.visitInsn(DUP);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format",
"(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false);
mv.visitInsn(AASTORE);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format",
"(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(434, l1);
mv.visitVarInsn(ALOAD, 1);
Label l2 = new Label();
mv.visitJumpInsn(IFNULL, l2);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ARRAYLENGTH);
mv.visitInsn(ICONST_1);
mv.visitJumpInsn(IF_ICMPLE, l2);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ARRAYLENGTH);
mv.visitInsn(ICONST_1);
mv.visitInsn(ISUB);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(INSTANCEOF, "java/lang/Throwable");
mv.visitJumpInsn(IFEQ, l2);
Label l3 = new Label();
mv.visitLabel(l3);
mv.visitLineNumber(435, l3);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ARRAYLENGTH);
mv.visitInsn(ICONST_1);
mv.visitInsn(ISUB);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "(Ljava/io/PrintStream;)V", false);
mv.visitLabel(l2);
mv.visitLineNumber(437, l2);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
Label l4 = new Label();
mv.visitLabel(l4);
mv.visitLocalVariable("format", "Ljava/lang/String;", null, l0, l4, 0);
mv.visitLocalVariable("args", "[Ljava/lang/Object;", null, l0, l4, 1);
mv.visitMaxs(7, 2);
mv.visitEnd();
}
private MethodVisitor declareMethod(Method method, ClassVisitor writer) {
String name = method.getName();
String descriptor = Type.getMethodDescriptor(method);
return writer.visitMethod(ACC_PUBLIC, name, descriptor, null, null);
}
private MethodVisitor createMethod(ClassVisitor cw) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", createMethodDescriptor(), null, null);
generateAnnotations(mv);
mv.visitCode();
return mv;
}
private static void enhanceForGetValuePrimitive(ClassVisitor cw, String accessClassNm, String clazzNm, Field[] fields, Type type) {
String methodName;
final String typeNm = type.getDescriptor();
final int instruction;
switch (type.getSort()) {
case Type.BOOLEAN:
methodName = "getBooleanValue";
instruction = IRETURN;
break;
case Type.BYTE:
methodName = "getByteValue";
instruction = IRETURN;
break;
case Type.CHAR:
methodName = "getCharValue";
instruction = IRETURN;
break;
case Type.SHORT:
methodName = "getShortValue";
instruction = IRETURN;
break;
case Type.INT:
methodName = "getIntValue";
instruction = IRETURN;
break;
case Type.FLOAT:
methodName = "getFloatValue";
instruction = FRETURN;
break;
case Type.LONG:
methodName = "getLongValue";
instruction = LRETURN;
break;
case Type.DOUBLE:
methodName = "getDoubleValue";
instruction = DRETURN;
break;
default:
methodName = "getValue";
instruction = ARETURN;
break;
}
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "(Ljava/lang/Object;Ljava/lang/String;)" + typeNm, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, accessClassNm, "fieldNames", "[Ljava/lang/String;");
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "binarySearch", "([Ljava/lang/Object;Ljava/lang/Object;)I");
mv.visitVarInsn(ISTORE, 3);
mv.visitVarInsn(ILOAD, 3);
final int maxStack;
if (fields.length > 0) {
maxStack = 5;
Label[] labels = constructLabels(fields);
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields[i];
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, clazzNm);
mv.visitFieldInsn(GETFIELD, clazzNm, field.getName(), typeNm);
mv.visitInsn(instruction);
}
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
} else {
maxStack = 6;
}
enhanceForThrowingException(mv, IllegalArgumentException.class, "Field was not found", "Ljava/lang/Object;", ALOAD, 2);
mv.visitMaxs(maxStack, 4);
mv.visitEnd();
}