List of usage examples for org.objectweb.asm Opcodes ACC_STATIC
int ACC_STATIC
To view the source code for org.objectweb.asm Opcodes ACC_STATIC.
Click Source Link
From source file:com.alibaba.hotswap.processor.clinit.ClinitVisitor.java
License:Open Source License
/** * Generate <code><clinit></code> method with default body *//*from ww w . j a va 2 s . co m*/ private void generateDefaultClinit() { MethodVisitor clinit = cv.visitMethod(Opcodes.ACC_STATIC, HotswapConstants.CLINIT, "()V", null, null); if (clinit != null) { clinit.visitCode(); clinit.visitInsn(Opcodes.RETURN); clinit.visitMaxs(0, 0); clinit.visitEnd(); } }
From source file:com.alibaba.hotswap.processor.field.holder.FieldHolderVisitor.java
License:Open Source License
private void addStaticFieldHolder() { FieldVisitor fv = cv.visitField(//from w ww. j a v a2 s . c o m Opcodes.ACC_TRANSIENT + Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, HotswapConstants.STATIC_FIELD_HOLDER, "Ljava/util/concurrent/ConcurrentHashMap;", null, null); if (fv != null) { fv.visitEnd(); } }
From source file:com.android.build.gradle.internal.incremental.ConstructorBuilder.java
License:Apache License
/** * Splits the constructor in two methods, the "set up" and the "body" parts (see above). *//* w ww. j a va 2 s . c om*/ @NonNull private static Constructor split(@NonNull String owner, @NonNull MethodNode method, @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine, @NonNull List<LocalVariable> variables, int localsAtLoadThis) { String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]); // Do not add the local array yet, as we treat it as a new variable. String newDesc = method.desc.replace(")V", ")Ljava/lang/Object;"); newDesc = newDesc.replace("(", "([L" + owner + ";"); Type[] argumentTypes = Type.getArgumentTypes(newDesc); // Store the non hotswappable part of the constructor List<AbstractInsnNode> fixed = Lists.newLinkedList(); AbstractInsnNode insn = method.instructions.getFirst(); while (insn != loadThis) { fixed.add(insn); insn = insn.getNext(); } fixed.add(loadThis); MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null, exceptions); GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc); int newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.loadLocal(newArgument); ByteCodeUtils.restoreVariables(mv, variables.subList(0, localsAtLoadThis)); // Now insert the original method insn = loadThis.getNext(); while (insn != delegation) { insn.accept(mv); insn = insn.getNext(); } LabelNode labelBefore = new LabelNode(); labelBefore.accept(mv); // Create the args array with the local variables and the values to send to the delegated constructor Type[] returnTypes = Type.getArgumentTypes(delegation.desc); // The extra elements for the local variables and the qualified name of the constructor. mv.push(returnTypes.length + 2); mv.newArray(Type.getType(Object.class)); int args = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.storeLocal(args); for (int i = returnTypes.length - 1; i >= 0; i--) { Type type = returnTypes[i]; mv.loadLocal(args); mv.swap(type, Type.getType(Object.class)); mv.push(i + 2); mv.swap(type, Type.INT_TYPE); mv.box(type); mv.arrayStore(Type.getType(Object.class)); } // Store the qualified name of the constructor in the second element of the array. mv.loadLocal(args); mv.push(1); mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called. mv.arrayStore(Type.getType(Object.class)); // Create the locals array and place it in the first element of the return array mv.loadLocal(args); mv.push(0); mv.push(argumentTypes.length + 1); mv.newArray(Type.getType(Object.class)); ByteCodeUtils.loadVariableArray(mv, ByteCodeUtils.toLocalVariables(Arrays.asList(argumentTypes)), 0); mv.dup(); mv.push(argumentTypes.length); ByteCodeUtils.newVariableArray(mv, variables); mv.arrayStore(Type.getType(Object.class)); mv.arrayStore(Type.getType(Object.class)); mv.loadLocal(args); mv.returnValue(); // Move the first variable up to be an argument initArgs.desc = initArgs.desc.replace(")", "[Ljava/lang/Object;)"); newDesc = method.desc.replace("(", "(L" + owner + ";"); MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null, exceptions); mv = new GeneratorAdapter(body, body.access, body.name, body.desc); newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;")); LabelNode labelAfter = new LabelNode(); labelAfter.accept(body); Set<LabelNode> bodyLabels = new HashSet<LabelNode>(); mv.loadLocal(newArgument); ByteCodeUtils.restoreVariables(mv, variables); insn = delegation.getNext(); while (insn != null) { if (insn instanceof LabelNode) { bodyLabels.add((LabelNode) insn); } insn.accept(mv); insn = insn.getNext(); } // manually transfer the exception table from the existing constructor to the new // "init$body" method. The labels were transferred just above so we can reuse them. //noinspection unchecked for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) { tryCatch.accept(mv); } //noinspection unchecked for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) { boolean startsInBody = bodyLabels.contains(variable.start); boolean endsInBody = bodyLabels.contains(variable.end); if (!startsInBody && !endsInBody) { if (variable.index != 0) { // '#0' on init$args is not 'this' variable.accept(initArgs); } } else if (startsInBody && endsInBody) { variable.accept(body); } else if (!startsInBody && endsInBody) { // The variable spans from the args to the end of the method, create two: if (variable.index != 0) { // '#0' on init$args is not 'this' LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature, variable.start, labelBefore, variable.index); var0.accept(initArgs); } LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature, labelAfter, variable.end, variable.index); var1.accept(body); } else { throw new IllegalStateException("Local variable starts after it ends."); } } // Move the first variable up to be an argument body.desc = body.desc.replace(")", "[Ljava/lang/Object;)"); return new Constructor(owner, fixed, loadThis, loadThisLine, initArgs, delegation, body, variables, localsAtLoadThis); }
From source file:com.android.build.gradle.internal.incremental.ConstructorDelegationDetector.java
License:Apache License
/** * Splits the constructor in two methods, the "set up" and the "body" parts (see above). */// ww w .java 2 s . c o m @NonNull private static Constructor split(@NonNull String owner, @NonNull MethodNode method, @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine) { String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]); String newDesc = method.desc.replaceAll("\\((.*)\\)V", "([Ljava/lang/Object;$1)Ljava/lang/Object;"); MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null, exceptions); AbstractInsnNode insn = loadThis.getNext(); while (insn != delegation) { insn.accept(initArgs); insn = insn.getNext(); } LabelNode labelBefore = new LabelNode(); labelBefore.accept(initArgs); GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc); // Copy the arguments back to the argument array // The init_args part cannot access the "this" object and can have side effects on the // local variables. Because of this we use the first argument (which we want to keep // so all the other arguments remain unchanged) as a reference to the array where to // return the values of the modified local variables. Type[] types = Type.getArgumentTypes(initArgs.desc); int stack = 1; // Skip the first one which is a reference to the local array. for (int i = 1; i < types.length; i++) { Type type = types[i]; // This is not this, but the array of local arguments final values. mv.visitVarInsn(Opcodes.ALOAD, 0); mv.push(i); mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), stack); mv.box(type); mv.arrayStore(Type.getType(Object.class)); stack += type.getSize(); } // Create the args array with the values to send to the delegated constructor Type[] returnTypes = Type.getArgumentTypes(delegation.desc); // The extra element for the qualified name of the constructor. mv.push(returnTypes.length + 1); mv.newArray(Type.getType(Object.class)); int args = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.storeLocal(args); for (int i = returnTypes.length - 1; i >= 0; i--) { Type type = returnTypes[i]; mv.loadLocal(args); mv.swap(type, Type.getType(Object.class)); mv.push(i + 1); mv.swap(type, Type.INT_TYPE); mv.box(type); mv.arrayStore(Type.getType(Object.class)); } // Store the qualified name of the constructor in the first element of the array. mv.loadLocal(args); mv.push(0); mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called. mv.arrayStore(Type.getType(Object.class)); mv.loadLocal(args); mv.returnValue(); newDesc = method.desc.replace("(", "(L" + owner + ";"); MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null, exceptions); LabelNode labelAfter = new LabelNode(); labelAfter.accept(body); Set<LabelNode> bodyLabels = new HashSet<LabelNode>(); insn = delegation.getNext(); while (insn != null) { if (insn instanceof LabelNode) { bodyLabels.add((LabelNode) insn); } insn.accept(body); insn = insn.getNext(); } // manually transfer the exception table from the existing constructor to the new // "init$body" method. The labels were transferred just above so we can reuse them. //noinspection unchecked for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) { tryCatch.accept(body); } //noinspection unchecked for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) { boolean startsInBody = bodyLabels.contains(variable.start); boolean endsInBody = bodyLabels.contains(variable.end); if (!startsInBody && !endsInBody) { if (variable.index != 0) { // '#0' on init$args is not 'this' variable.accept(initArgs); } } else if (startsInBody && endsInBody) { variable.accept(body); } else if (!startsInBody && endsInBody) { // The variable spans from the args to the end of the method, create two: if (variable.index != 0) { // '#0' on init$args is not 'this' LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature, variable.start, labelBefore, variable.index); var0.accept(initArgs); } LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature, labelAfter, variable.end, variable.index); var1.accept(body); } else { throw new IllegalStateException("Local variable starts after it ends."); } } return new Constructor(loadThis, loadThisLine, initArgs, delegation, body); }
From source file:com.android.build.gradle.internal.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * Turns this class into an override class that can be loaded by our custom class loader: *<ul>//www. java 2 s . c o m * <li>Make the class name be OriginalName$override</li> * <li>Ensure the class derives from java.lang.Object, no other inheritance</li> * <li>Ensure the class has a public parameterless constructor that is a noop.</li> *</ul> */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name + OVERRIDE_SUFFIX, signature, "java/lang/Object", new String[] { CHANGE_TYPE.getInternalName() }); if (DEBUG) { System.out.println(">>>>>>>> Processing " + name + "<<<<<<<<<<<<<"); } visitedClassName = name; visitedSuperName = superName; instanceToStaticDescPrefix = "(L" + visitedClassName + ";"; // Create empty constructor MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "$obsolete", "Z", null, null); }
From source file:com.android.build.gradle.internal.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * Generates new delegates for all 'patchable' methods in the visited class. Delegates * are static methods that do the same thing the visited code does, but from outside the class. * For instance methods, the instance is passed as the first argument. Note that: * <ul>/* w w w . j a v a2 s . c o m*/ * <li>We ignore the class constructor as we don't support it right now</li> * <li>We skip abstract methods.</li> * <li>For constructors split the method body into super arguments and the rest of * the method body, see {@link ConstructorBuilder}</li> * </ul> */ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (instantRunDisabled || !isAccessCompatibleWithInstantRun(access)) { // Nothing to generate. return null; } if (name.equals(ByteCodeUtils.CLASS_INITIALIZER)) { // we skip the class init as it can reset static fields which we don't support right now return null; } boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; String newDesc = computeOverrideMethodDesc(desc, isStatic); if (DEBUG) { System.out.println(">>> Visiting method " + visitedClassName + ":" + name + ":" + desc); if (exceptions != null) { for (String exception : exceptions) { System.out.println("> Exception thrown : " + exception); } } } if (DEBUG) { System.out.println("New Desc is " + newDesc + ":" + isStatic); } // Do not carry on any access flags from the original method. For example synchronized // on the original method would translate into a static synchronized method here. access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; MethodNode method = getMethodByNameInClass(name, desc, classNode); if (name.equals(ByteCodeUtils.CONSTRUCTOR)) { Constructor constructor = ConstructorBuilder.build(visitedClassName, method); MethodVisitor mv = createMethodAdapter(access, constructor.args.name, constructor.args.desc, constructor.args.desc, constructor.args.signature, exceptions, isStatic, true /* isConstructor */); constructor.args.accept(mv); mv = createMethodAdapter(access, constructor.body.name, constructor.body.desc, newDesc, constructor.body.signature, exceptions, isStatic, true /* isConstructor */); constructor.body.accept(mv); // Remember our created methods so we can generated the access$dispatch for them. addedMethods.add(constructor.args); addedMethods.add(constructor.body); return null; } else { String newName = isStatic ? computeOverrideMethodName(name, desc) : name; return createMethodAdapter(access, newName, newDesc, newDesc, signature, exceptions, isStatic, false /* isConstructor */); } }
From source file:com.android.build.gradle.internal.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * To each class, add the dispatch method called by the original code that acts as a trampoline to * invoke the changed methods.// w w w . jav a 2 s . c o m * <p> * Pseudo code: * <code> * Object access$dispatch(String name, object[] args) { * if (name.equals( * "firstMethod.(L$type;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) { * return firstMethod(($type)arg[0], (String)arg[1], arg[2]); * } * if (name.equals("secondMethod.(L$type;Ljava/lang/String;I;)V")) { * secondMethod(($type)arg[0], (String)arg[1], (int)arg[2]); * return; * } * ... * StringBuilder $local1 = new StringBuilder(); * $local1.append("Method not found "); * $local1.append(name); * $local1.append(" in " + visitedClassName + * "$dispatch implementation, restart the application"); * throw new $package/InstantReloadException($local1.toString()); * } * </code> */ private void addDispatchMethod() { int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS; Method m = new Method("access$dispatch", "(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); if (TRACING_ENABLED) { mv.push("Redirecting "); mv.loadArg(0); trace(mv, 2); } List<MethodNode> allMethods = new ArrayList<>(); // if we are disabled, do not generate any dispatch, the method will throw an exception // if invoked which should never happen. if (!instantRunDisabled) { //noinspection unchecked allMethods.addAll(classNode.methods); allMethods.addAll(addedMethods); } final Map<String, MethodNode> methods = new HashMap<>(); for (MethodNode methodNode : allMethods) { if (methodNode.name.equals("<clinit>") || methodNode.name.equals("<init>")) { continue; } if (!isAccessCompatibleWithInstantRun(methodNode.access)) { continue; } methods.put(methodNode.name + "." + methodNode.desc, methodNode); } new StringSwitch() { @Override void visitString() { mv.visitVarInsn(Opcodes.ALOAD, 1); } @Override void visitCase(String methodName) { MethodNode methodNode = methods.get(methodName); String name = methodNode.name; boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; String newDesc = computeOverrideMethodDesc(methodNode.desc, isStatic); if (TRACING_ENABLED) { trace(mv, "M: " + name + " P:" + newDesc); } Type[] args = Type.getArgumentTypes(newDesc); int argc = 0; for (Type t : args) { mv.visitVarInsn(Opcodes.ALOAD, 2); mv.push(argc); mv.visitInsn(Opcodes.AALOAD); ByteCodeUtils.unbox(mv, t); argc++; } mv.visitMethodInsn(Opcodes.INVOKESTATIC, visitedClassName + "$override", isStatic ? computeOverrideMethodName(name, methodNode.desc) : name, newDesc, false); Type ret = Type.getReturnType(methodNode.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, methods.keySet()); mv.visitMaxs(0, 0); mv.visitEnd(); super.visitEnd(); }
From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java
License:Apache License
/** * Ensures that the class contains a $change field used for referencing the IncrementalChange * dispatcher./*from www . jav a 2 s . com*/ * * <p>Also updates package_private visibility to public so we can call into this class from * outside the package. */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { visitedClassName = name; visitedSuperName = superName; super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, "$change", getRuntimeTypeName(CHANGE_TYPE), null, null); access = transformClassAccessForInstantRun(access); super.visit(version, access, name, signature, superName, interfaces); }
From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java
License:Apache License
/** * Insert Constructor specific logic({@link ConstructorRedirection} and * {@link ConstructorBuilder}) for constructor redirecting or * normal method redirecting ({@link MethodRedirection}) for other methods. *//*from w w w .ja v a 2s .c o m*/ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { access = transformAccessForInstantRun(access); MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions); MethodNode method = checkNotNull(getMethodByNameInClass(name, desc, classNode), "Method found by visitor but not in the pre-parsed class node."); // does the method use blacklisted APIs. boolean hasIncompatibleChange = InstantRunMethodVerifier .verifyMethod(method) != InstantRunVerifierStatus.COMPATIBLE; if (hasIncompatibleChange || disableRedirectionForClass || !isAccessCompatibleWithInstantRun(access) || name.equals(ByteCodeUtils.CLASS_INITIALIZER)) { return defaultVisitor; } else { ArrayList<Type> args = new ArrayList<>(Arrays.asList(Type.getArgumentTypes(desc))); boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; if (!isStatic) { args.add(0, Type.getType(Object.class)); } // Install the Jsr/Ret inliner adapter, we have had reports of code still using the // Jsr/Ret deprecated byte codes. // see https://code.google.com/p/android/issues/detail?id=220019 JSRInlinerAdapter jsrInlinerAdapter = new JSRInlinerAdapter(defaultVisitor, access, name, desc, signature, exceptions); ISMethodVisitor mv = new ISMethodVisitor(jsrInlinerAdapter, access, name, desc); if (name.equals(ByteCodeUtils.CONSTRUCTOR)) { Constructor constructor = ConstructorBuilder.build(visitedClassName, method); LabelNode start = new LabelNode(); method.instructions.insert(constructor.loadThis, start); if (constructor.lineForLoad != -1) { // Record the line number from the start of LOAD_0 for uninitialized 'this'. // This allows a breakpoint to be set at the line with this(...) or super(...) // call in the constructor. method.instructions.insert(constructor.loadThis, new LineNumberNode(constructor.lineForLoad, start)); } mv.addRedirection(new ConstructorRedirection(start, constructor, args)); } else { mv.addRedirection(new MethodRedirection(new LabelNode(mv.getStartLabel()), name + "." + desc, args, Type.getReturnType(desc))); } method.accept(mv); return null; } }
From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java
License:Apache License
/*** * Inserts a trampoline to this class so that the updated methods can make calls to super * class methods.//www. j a v a 2 s .c o m * <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]); * * 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<>(); 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(classNode, classNode, uniqueMethods); } else { // otherwise, use the parent list. for (ClassNode parentNode : parentNodes) { addAllNewMethods(classNode, parentNode, uniqueMethods); } } 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); } String parentName = findParentClassForMethod(methodRef); logger.verbose("Generating access$super for %1$s recev %2$s", methodRef.method.name, parentName); // Call super on the other object, yup this works cos we are on the right place to // call from. mv.visitMethodInsn(Opcodes.INVOKESPECIAL, parentName, 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(); }