下面列出了org.objectweb.asm.commons.Method#getName ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public void addSupportMethod() {
int access = Opcodes.ACC_PUBLIC;
Method m = new Method("isSupport", "(I)Z");
MethodVisitor mv = super.visitMethod(access,
m.getName(),
m.getDescriptor(),
null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 1);
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false);
int[] hashArray = new int[fixMtds.size()];
Label[] labelArray = new Label[fixMtds.size()];
Label l0 = new Label();
Label l1 = new Label();
for (int i = 0; i < fixMtds.size(); i++) {
hashArray[i] = AcesoProguardMap.instance().getClassData(visitedClassName).getMtdIndex(fixMtds.get(i));
labelArray[i] = l0;
}
mv.visitLookupSwitchInsn(l1, hashArray, labelArray);
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IRETURN);
mv.visitLabel(l1);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.IRETURN);
mv.visitMaxs(1, 2);
mv.visitEnd();
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private @Nullable Method hack(@Nullable Method method) {
if (method == null) {
return null;
}
Type[] argumentTypes = method.getArgumentTypes();
Type[] hackedArgumentTypes = new Type[argumentTypes.length];
for (int i = 0; i < argumentTypes.length; i++) {
hackedArgumentTypes[i] = hack(argumentTypes[i]);
}
return new Method(method.getName(), hack(method.getReturnType()), hackedArgumentTypes);
}
/***
* Inserts a trampoline to this class so that the updated methods can make calls to super
* class methods.
* <p/>
* Pseudo code for this trampoline:
* <code>
* Object access$super($classType instance, String name, object[] args) {
* switch(name) {
* case "firstMethod.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;":
* return super~instance.firstMethod((String)arg[0], arg[1]);
* case "secondMethod.(Ljava/lang/String;I)V":
* return super~instance.firstMethod((String)arg[0], arg[1]);
* <p>
* default:
* StringBuilder $local1 = new StringBuilder();
* $local1.append("Method not found ");
* $local1.append(name);
* $local1.append(" in " $classType $super implementation");
* throw new $package/InstantReloadException($local1.toString());
* }
* </code>
*/
private void createAccessSuper() {
int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC
| Opcodes.ACC_SYNTHETIC | Opcodes.ACC_VARARGS;
Method m = new Method("access$super", "(L" + visitedClassName
+ ";Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
MethodVisitor visitor = super.visitMethod(access,
m.getName(),
m.getDescriptor(),
null, null);
final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);
// Gather all methods from itself and its superclasses to generate a giant access$super
// implementation.
// This will work fine as long as we don't support adding methods to a class.
final Map<String, MethodReference> uniqueMethods =
new HashMap<String, MethodReference>();
if (parentNodes.isEmpty()) {
// if we cannot determine the parents for this class, let's blindly add all the
// method of the current class as a gateway to a possible parent version.
addAllNewMethods(uniqueMethods, classNode);
} else {
// otherwise, use the parent list.
for (ClassNode parentNode : parentNodes) {
addAllNewMethods(uniqueMethods, parentNode);
}
}
new StringSwitch() {
@Override
void visitString() {
mv.visitVarInsn(Opcodes.ALOAD, 1);
}
@Override
void visitCase(String methodName) {
MethodReference methodRef = uniqueMethods.get(methodName);
mv.visitVarInsn(Opcodes.ALOAD, 0);
Type[] args = Type.getArgumentTypes(methodRef.method.desc);
int argc = 0;
for (Type t : args) {
mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.push(argc);
mv.visitInsn(Opcodes.AALOAD);
ByteCodeUtils.unbox(mv, t);
argc++;
}
if (TRACING_ENABLED) {
trace(mv, "super selected ", methodRef.owner.name,
methodRef.method.name, methodRef.method.desc);
}
// Call super on the other object, yup this works cos we are on the right place to
// call from.
mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
methodRef.owner.name,
methodRef.method.name,
methodRef.method.desc, false);
Type ret = Type.getReturnType(methodRef.method.desc);
if (ret.getSort() == Type.VOID) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
mv.box(ret);
}
mv.visitInsn(Opcodes.ARETURN);
}
@Override
void visitDefault() {
writeMissingMessageWithHash(mv, visitedClassName);
}
}.visit(mv, uniqueMethods.keySet());
mv.visitMaxs(0, 0);
mv.visitEnd();
}
/***
* Inserts a trampoline to this class so that the updated methods can make calls to
* constructors.
* <p>
* <p/>
* Pseudo code for this trampoline:
* <code>
* ClassName(Object[] args, Marker unused) {
* String name = (String) args[0];
* if (name.equals(
* "java/lang/ClassName.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) {
* this((String)arg[1], arg[2]);
* return
* }
* if (name.equals("SuperClassName.(Ljava/lang/String;I)V")) {
* super((String)arg[1], (int)arg[2]);
* return;
* }
* ...
* StringBuilder $local1 = new StringBuilder();
* $local1.append("Method not found ");
* $local1.append(name);
* $local1.append(" in " $classType $super implementation");
* throw new $package/InstantReloadException($local1.toString());
* }
* </code>
*/
private void createDispatchingThis() {
// Gather all methods from itself and its superclasses to generate a giant constructor
// implementation.
// This will work fine as long as we don't support adding constructors to classes.
final Map<String, MethodNode> uniqueMethods = new HashMap<String, MethodNode>();
addAllNewConstructors(uniqueMethods, classNode, true /*keepPrivateConstructors*/);
for (ClassNode parentNode : parentNodes) {
addAllNewConstructors(uniqueMethods, parentNode, false /*keepPrivateConstructors*/);
}
int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
Method m = new Method(AsmUtils.CONSTRUCTOR,
ConstructorArgsRedirection.DISPATCHING_THIS_SIGNATURE);
MethodVisitor visitor = super.visitMethod(0, m.getName(), m.getDescriptor(), null, null);
final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);
mv.visitCode();
// Mark this code as redirection code
Label label = new Label();
mv.visitLineNumber(0, label);
// Get and store the constructor canonical name.
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.push(0);
mv.visitInsn(Opcodes.AALOAD);
mv.unbox(Type.getType("Ljava/lang/String;"));
final int constructorCanonicalName = mv.newLocal(Type.getType("Ljava/lang/String;"));
mv.storeLocal(constructorCanonicalName);
new StringSwitch() {
@Override
void visitString() {
mv.loadLocal(constructorCanonicalName);
}
@Override
void visitCase(String canonicalName) {
MethodNode methodNode = uniqueMethods.get(canonicalName);
String owner = canonicalName.split("\\.")[0];
// Parse method arguments and
mv.visitVarInsn(Opcodes.ALOAD, 0);
Type[] args = Type.getArgumentTypes(methodNode.desc);
int argc = 0;
for (Type t : args) {
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.push(argc + 1);
mv.visitInsn(Opcodes.AALOAD);
ByteCodeUtils.unbox(mv, t);
argc++;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, AsmUtils.CONSTRUCTOR,
methodNode.desc, false);
mv.visitInsn(Opcodes.RETURN);
}
@Override
void visitDefault() {
writeMissingMessageWithHash(mv, visitedClassName);
}
}.visit(mv, uniqueMethods.keySet());
mv.visitMaxs(1, 3);
mv.visitEnd();
}
private static void generateRun(ClassVisitor cv, Type testType, int iThread, List<Actor> actors, List<Object> objArgs, boolean waitsEnabled) {
int access = ACC_PUBLIC;
Method m = new Method("call", RESULT_ARRAY_TYPE, NO_ARGS);
GeneratorAdapter mv = new GeneratorAdapter(access, m,
// Try-catch blocks sorting is required
new TryCatchBlockSorter(cv.visitMethod(access, m.getName(), m.getDescriptor(), null, null),
access, m.getName(), m.getDescriptor(), null, null)
);
mv.visitCode();
// Create Result[] array and store it to a local variable
int resLocal = createResultArray(mv, actors.size());
// Call runner's onStart(iThread) method
mv.loadThis();
mv.getField(TEST_THREAD_EXECUTION_TYPE, "runner", RUNNER_TYPE);
mv.push(iThread);
mv.invokeVirtual(RUNNER_TYPE, RUNNER_ON_START_METHOD);
// Number of current operation (starts with 0)
int iLocal = mv.newLocal(Type.INT_TYPE);
mv.push(0);
mv.storeLocal(iLocal);
// Invoke actors
for (int i = 0; i < actors.size(); i++) {
Actor actor = actors.get(i);
// Add busy-wait before operation execution (for non-first operations only)
if (waitsEnabled && i > 0) {
mv.loadThis();
mv.getField(TEST_THREAD_EXECUTION_TYPE, "waits", INT_ARRAY_TYPE);
mv.push(i - 1);
mv.arrayLoad(Type.INT_TYPE);
mv.invokeStatic(UTILS_TYPE, UTILS_CONSUME_CPU);
}
// Start of try-catch block for exceptions which this actor should handle
Label start, end = null, handler = null, handlerEnd = null;
if (actor.handlesExceptions()) {
start = mv.newLabel();
end = mv.newLabel();
handler = mv.newLabel();
handlerEnd = mv.newLabel();
for (Class<? extends Throwable> ec : actor.handledExceptions)
mv.visitTryCatchBlock(start, end, handler, Type.getType(ec).getInternalName());
mv.visitLabel(start);
}
// Load result array and index to store the current result
mv.loadLocal(resLocal);
mv.push(i);
// Load test instance
mv.loadThis();
mv.getField(TEST_THREAD_EXECUTION_TYPE, "testInstance", OBJECT_TYPE);
mv.checkCast(testType);
// Load arguments for operation
for (int j = 0; j < actor.arguments.length; j++) {
pushArgumentOnStack(mv, objArgs, actor.arguments[j], actor.method.getParameterTypes()[j]);
}
// Invoke operation
Method actorMethod = Method.getMethod(actor.method);
mv.invokeVirtual(testType, actorMethod);
// Create result
mv.box(actorMethod.getReturnType()); // box if needed
if (actor.method.getReturnType() == void.class) {
mv.pop();
mv.invokeStatic(RESULT_TYPE, RESULT_CREATE_VOID_RESULT);
} else {
mv.invokeStatic(RESULT_TYPE, RESULT_CREATE_VALUE_RESULT);
}
// Store result to array
mv.arrayStore(RESULT_TYPE);
// End of try-catch block
if (actor.handlesExceptions()) {
mv.visitLabel(end);
mv.goTo(handlerEnd);
mv.visitLabel(handler);
storeExceptionResultFromThrowable(mv, resLocal, iLocal);
mv.visitLabel(handlerEnd);
}
// Increment number of current operation
mv.iinc(iLocal, 1);
}
// Call runner's onFinish(iThread) method
mv.loadThis();
mv.getField(TEST_THREAD_EXECUTION_TYPE, "runner", RUNNER_TYPE);
mv.push(iThread);
mv.invokeVirtual(RUNNER_TYPE, RUNNER_ON_FINISH_METHOD);
// Return results
mv.loadThis();
mv.loadLocal(resLocal);
mv.returnValue();
mv.visitMaxs(1, 1);
mv.visitEnd();
}