Example usage for org.objectweb.asm.commons AdviceAdapter AdviceAdapter

List of usage examples for org.objectweb.asm.commons AdviceAdapter AdviceAdapter

Introduction

In this page you can find the example usage for org.objectweb.asm.commons AdviceAdapter AdviceAdapter.

Prototype

protected AdviceAdapter(final int api, final MethodVisitor methodVisitor, final int access, final String name,
        final String descriptor) 

Source Link

Document

Constructs a new AdviceAdapter .

Usage

From source file:co.cask.cdap.app.runtime.spark.SparkRunnerClassLoader.java

License:Apache License

/**
 * Rewrites the constructors who don't delegate to other constructor with the given {@link ConstructorRewriter}
 * and define the class.//w  ww  . jav a 2s  .  c  o m
 *
 * @param classType type of the class to be defined
 * @param byteCodeStream {@link InputStream} for reading the original bytecode of the class
 * @param rewriter a {@link ConstructorRewriter} for rewriting the constructor
 * @return a defined Class
 */
private Class<?> rewriteConstructorAndDefineClass(final Type classType, InputStream byteCodeStream,
        final ConstructorRewriter rewriter) throws IOException {
    ClassReader cr = new ClassReader(byteCodeStream);
    ClassWriter cw = new ClassWriter(0);

    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                String[] exceptions) {
            // Call super so that the method signature is registered with the ClassWriter (parent)
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

            // We only attempt to rewrite constructor
            if (!"<init>".equals(name)) {
                return mv;
            }

            return new AdviceAdapter(Opcodes.ASM5, mv, access, name, desc) {

                boolean calledThis;

                @Override
                public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
                    // See if in this constructor it is calling other constructor (this(..)).
                    calledThis = calledThis || (opcode == Opcodes.INVOKESPECIAL
                            && Type.getObjectType(owner).equals(classType) && name.equals("<init>")
                            && Type.getReturnType(desc).equals(Type.VOID_TYPE));
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                }

                @Override
                protected void onMethodExit(int opcode) {
                    if (calledThis) {
                        // For constructors that call this(), we don't need to generate a call to SparkContextCache
                        return;
                    }
                    // Add a call to SparkContextCache.setContext() for the normal method return path
                    if (opcode == RETURN) {
                        rewriter.onMethodExit(this);
                    }
                }
            };
        }
    }, ClassReader.EXPAND_FRAMES);

    byte[] byteCode = cw.toByteArray();
    return defineClass(classType.getClassName(), byteCode, 0, byteCode.length);
}

From source file:co.cask.cdap.internal.app.runtime.batch.distributed.MapReduceContainerHelper.java

License:Apache License

/**
 * Rewrites the TwillLauncher bytecode as described
 * in {@link #saveLauncher(Configuration, File, List)}.
 *
 * @param hConf the hadoop configuration
 * @param sourceByteCode the original bytecode of the TwillLauncher
 * @param output output stream for writing the modified bytecode.
 * @throws IOException/*from  www . j a va  2s  . c o  m*/
 */
private static void rewriteLauncher(Configuration hConf, InputStream sourceByteCode, OutputStream output)
        throws IOException {
    URI frameworkURI = getFrameworkURI(hConf);
    if (frameworkURI == null) {
        ByteStreams.copy(sourceByteCode, output);
        return;
    }

    // It is localized as archive, and due to TWILL-144, a suffix is added. We need to reverse the effect of it
    // by creating an extra symlink as the first line in the TwillLauncher.main() method.
    String ext = Paths.getExtension(frameworkURI.getPath());
    if (ext.isEmpty()) {
        ByteStreams.copy(sourceByteCode, output);
        return;
    }

    final String sourceName = frameworkURI.getFragment();
    final String targetName = sourceName + "." + ext;

    ClassReader cr = new ClassReader(sourceByteCode);
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            if (!name.equals("main")) {
                return mv;
            }
            Type[] argTypes = Type.getArgumentTypes(desc);
            if (argTypes.length != 1) {
                return mv;
            }
            Type argType = argTypes[0];
            if (argType.getSort() != Type.ARRAY
                    || !String.class.getName().equals(argType.getElementType().getClassName())) {
                return mv;
            }

            return new AdviceAdapter(Opcodes.ASM5, mv, access, name, desc) {
                @Override
                protected void onMethodEnter() {
                    visitLdcInsn(sourceName);
                    visitLdcInsn(targetName);
                    invokeStatic(Type.getType(MapReduceContainerSymLinker.class),
                            Methods.getMethod(void.class, "symlink", String.class, String.class));
                }
            };
        }
    }, ClassReader.EXPAND_FRAMES);

    output.write(cw.toByteArray());
}

From source file:com.axway.jmb.builders.Constructors.java

License:Open Source License

public static void buildDefault(ClassVisitor clazz, String superClassInternalFQName) {
    MethodVisitor mv = clazz.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    AdviceAdapter constructor = new AdviceAdapter(ASM5, mv, ACC_PUBLIC, "<init>", "()V") {
    };//from w ww .j  av a2s . c  om
    constructor.visitCode();
    constructor.visitMaxs(4, 1);

    callSuperConstructor(constructor, superClassInternalFQName);

    constructor.visitInsn(RETURN);
    constructor.visitEnd();
}

From source file:org.apache.aries.proxy.impl.common.AbstractWovenProxyAdapter.java

License:Apache License

/**
 * This method is called on each method implemented on this object (but not
 * for superclass methods) Each of these methods is visited in turn and the
 * code here generates the byte code for the calls to the InovcationListener
 * around the existing method/*ww  w.j  av  a  2s.  co  m*/
 */
public final MethodVisitor visitMethod(int access, String name, String desc, String signature,
        String[] exceptions) {
    LOGGER.debug(Constants.LOG_ENTRY, "visitMethod",
            new Object[] { access, name, desc, signature, exceptions });

    Method currentMethod = new Method(name, desc);

    getKnownMethods().add(currentMethod);

    MethodVisitor methodVisitorToReturn = null;

    // Only weave "real" instance methods. Not constructors, initializers or
    // compiler generated ones.
    if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_NATIVE | ACC_BRIDGE)) == 0
            && !!!name.equals("<init>") && !!!name.equals("<clinit>")) {

        // found a method we should weave

        //Create a field name and store it for later
        String methodStaticFieldName = "methodField" + getSanitizedUUIDString();
        transformedMethods.put(methodStaticFieldName,
                new TypeMethod(currentMethodDeclaringType, currentMethod));

        // Surround the MethodVisitor with our weaver so we can manipulate the code
        methodVisitorToReturn = getWeavingMethodVisitor(access, name, desc, signature, exceptions,
                currentMethod, methodStaticFieldName, currentMethodDeclaringType,
                currentMethodDeclaringTypeIsInterface);
    } else if (name.equals("<clinit>")) {
        //there is an existing clinit method, change the fields we use
        //to write our init code to static_init_UUID instead
        staticInitMethod = new Method("static_init_" + UU_ID, Type.VOID_TYPE, NO_ARGS);
        staticInitMethodFlags = staticInitMethodFlags | ACC_FINAL;
        methodVisitorToReturn = new AdviceAdapter(Opcodes.ASM5,
                cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc) {
            @Override
            protected void onMethodEnter() {
                //add into the <clinit> a call to our synthetic static_init_UUID
                invokeStatic(typeBeingWoven, staticInitMethod);
                super.onMethodEnter();
            }
        };
    } else {
        if (currentMethod.getArgumentTypes().length == 0 && name.equals("<init>"))
            hasNoArgsConstructor = true;
        //This isn't a method we want to weave, so just get the default visitor
        methodVisitorToReturn = cv.visitMethod(access, name, desc, signature, exceptions);
    }

    LOGGER.debug(Constants.LOG_EXIT, "visitMethod", methodVisitorToReturn);
    return methodVisitorToReturn;
}

From source file:org.eclipse.objectteams.otredyn.bytecode.asm.AddAfterClassLoadingHook.java

License:Open Source License

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    if (CLINIT_NAME.equals(name)) {
        // clinit already exists, add our statement to the front:
        this.needToAdd = false;
        final MethodVisitor clinit = cv.visitMethod(access, name, desc, null, null);
        return new AdviceAdapter(this.api, clinit, access, name, desc) {
            @Override/*  w w w .j  ava2  s .  c o  m*/
            protected void onMethodEnter() {
                createHookCall(clinit);
            }

            @Override
            public void visitMaxs(int maxStack, int maxLocals) {
                super.visitMaxs(Math.max(1, maxStack), maxLocals);
            }
        };
    }
    return null;
}

From source file:org.eclipse.objectteams.otredyn.bytecode.asm.AddGlobalTeamActivationAdapter.java

License:Open Source License

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    synchronized (AddGlobalTeamActivationAdapter.class) {
        if (!done && isMainMethod(name, desc, access)) {
            done = true;//from   w  w w .  j a  va  2 s .  co m
            final MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, null, null);
            return new AdviceAdapter(this.api, methodVisitor, access, name, desc) {
                @Override
                protected void onMethodEnter() {
                    List<String> teams = getTeamsFromConfigFile();
                    for (String aTeam : teams) {
                        Label start, end, typeHandler, ctorHandler, after;

                        String aTeamSlash = aTeam.replace('.', '/');

                        // new SomeTeam():
                        methodVisitor.visitLabel(start = new Label());
                        methodVisitor.visitTypeInsn(Opcodes.NEW, aTeamSlash);
                        //       .activate(Team.ALL_THREADS):
                        methodVisitor.visitInsn(Opcodes.DUP);
                        methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, aTeamSlash, "<init>", "()V",
                                false);
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, ClassNames.TEAM_SLASH, "ALL_THREADS",
                                "Ljava/lang/Thread;");
                        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, aTeamSlash, "activate",
                                "(Ljava/lang/Thread;)V", false);

                        methodVisitor.visitLabel(end = new Label());
                        methodVisitor.visitJumpInsn(Opcodes.GOTO, after = new Label());

                        // catch (ClassNotFoundException, NoClassDefFoundError):
                        //   System.err.println(...)
                        methodVisitor.visitLabel(typeHandler = new Label());
                        methodVisitor.visitInsn(Opcodes.POP); // discard the exception
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err",
                                "Ljava/io/PrintStream;");
                        methodVisitor.visitLdcInsn("Config error: Team class '" + aTeam + "' in config file '"
                                + TEAM_CONFIG_FILE + "' can not be found!");
                        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                                "(Ljava/lang/String;)V", false);
                        methodVisitor.visitJumpInsn(Opcodes.GOTO, after);
                        methodVisitor.visitTryCatchBlock(start, end, typeHandler,
                                "java/lang/ClassNotFoundException");
                        // dup to avoid stackmap errors (ASM bug at 1.8)
                        methodVisitor.visitLabel(typeHandler = new Label());
                        methodVisitor.visitInsn(Opcodes.POP); // discard the exception
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err",
                                "Ljava/io/PrintStream;");
                        methodVisitor.visitLdcInsn("Config error: Team class '" + aTeam + "' in config file '"
                                + TEAM_CONFIG_FILE + "' can not be found!");
                        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                                "(Ljava/lang/String;)V", false);
                        methodVisitor.visitJumpInsn(Opcodes.GOTO, after);
                        //
                        methodVisitor.visitTryCatchBlock(start, end, typeHandler,
                                "java/lang/NoClassDefFoundError");

                        // catch (NoSuchMethodError):
                        //   System.err.println(...)
                        methodVisitor.visitLabel(ctorHandler = new Label());
                        methodVisitor.visitInsn(Opcodes.POP); // discard the exception
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err",
                                "Ljava/io/PrintStream;");
                        methodVisitor.visitLdcInsn(
                                "Activation failed: Team class '" + aTeam + "' has no default constuctor!");
                        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                                "(Ljava/lang/String;)V", false);
                        methodVisitor.visitTryCatchBlock(start, end, ctorHandler,
                                "java/lang/NoSuchMethodError");

                        methodVisitor.visitLabel(after);
                    }
                }

                @Override
                public void visitMaxs(int maxStack, int maxLocals) {
                    super.visitMaxs(Math.max(maxStack, 3), maxLocals);
                }
            };
        }
        return null;
    }
}

From source file:org.eclipse.objectteams.otredyn.bytecode.asm.AddImplicitActivationAdapter.java

License:Open Source License

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    if (isCandidateForImplicitActivation(name, desc, access)) {
        final MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, null, null);
        final String enclTeamDesc = clazz.isRole()
                ? 'L' + clazz.getEnclosingClass().getName().replace('.', '/') + ';'
                : null;//from www .j av a 2  s  .c  o m
        final int nesting = clazz.nestingDepth() - 1;
        return new AdviceAdapter(this.api, methodVisitor, access, name, desc) {
            @Override
            protected void onMethodEnter() {
                if (clazz.isTeam()) {
                    methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                    methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                            IMPLICIT_ACTIVATE_METHOD_NAME, METHOD_DESC, true);
                }
                if (clazz.isRole()) {
                    // TODO(SH): respect nesting depth (this$n)
                    methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                    methodVisitor.visitFieldInsn(Opcodes.GETFIELD, clazz.getName().replace('.', '/'),
                            "this$" + nesting, enclTeamDesc);
                    methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                            IMPLICIT_ACTIVATE_METHOD_NAME, METHOD_DESC, true);
                }
            }

            @Override
            protected void onMethodExit(int opcode) {
                if (clazz.isTeam()) {
                    methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                    methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                            IMPLICIT_DEACTIVATE_METHOD_NAME, METHOD_DESC, true);
                }
                if (clazz.isRole()) {
                    // TODO(SH): respect nesting depth (this$n)
                    methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                    methodVisitor.visitFieldInsn(Opcodes.GETFIELD, clazz.getName().replace('.', '/'),
                            "this$" + nesting, enclTeamDesc);
                    methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                            IMPLICIT_DEACTIVATE_METHOD_NAME, METHOD_DESC, true);
                }
            }

            @Override
            public void endMethod() {
                if (clazz.isTeam() || clazz.isRole())
                    methodVisitor.visitMaxs(0, 0);
            }
        };
    }
    return null;
}

From source file:org.eclipse.objectteams.otredyn.bytecode.asm.AddThreadNotificationAdapter.java

License:Open Source License

@Override
public MethodVisitor visitMethod(int access, String methodName, String desc, String signature,
        String[] exceptions) {/*from w w  w .j  a  va2 s.  c o  m*/
    if (INIT.equals(methodName)) {
        // into each constructor ...
        final MethodVisitor methodVisitor = cv.visitMethod(access, methodName, desc, null, null);
        return new AdviceAdapter(this.api, methodVisitor, access, methodName, desc) {
            @Override
            public void invokeConstructor(Type type, Method method) {
                super.invokeConstructor(type, method);
                // ... that contains a super(..) call (rather than this(..)):
                if (type.getInternalName().equals(clazz.getInternalSuperClassName())) {
                    // insert:
                    // this._OT$creationThread = Thread.currentThread();
                    methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                    methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, ClassNames.THREAD_SLASH, CURRENT_THREAD,
                            CURRENT_THREAD_DESC, false);
                    methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, clazz.getInternalName(), CREATION_THREAD,
                            THREAD_DESC);
                }
            }
        };
    } else if (RUN.equals(methodName) && RUN_DESC.equals(desc)) {
        final MethodVisitor methodVisitor = cv.visitMethod(access, methodName, desc, null, null);
        return new AdviceAdapter(this.api, methodVisitor, access, methodName, desc) {

            Label start = new Label(); // start of method (scope of new local)
            Label end = new Label(); // end of method
            int isThreadStartIdx; // new local: boolean _OT$isThreadStart

            @Override
            protected void onMethodEnter() {
                methodVisitor.visitLabel(start);
                isThreadStartIdx = newLocal(Type.BOOLEAN_TYPE);
                methodVisitor.visitLocalVariable("_OT$isThreadStart", "Z", null, start, end, isThreadStartIdx);
                // TeamThreadManager.newThreadStarted(false, this._OT$creationThread)
                methodVisitor.visitInsn(Opcodes.ICONST_0);
                methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                methodVisitor.visitFieldInsn(Opcodes.GETFIELD, clazz.getInternalName(), CREATION_THREAD,
                        THREAD_DESC);
                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, ClassNames.TEAM_THREAD_MANAGER_SLASH,
                        NEW_THREAD_STARTED, NEW_THREAD_STARTED_DESC, false);
                methodVisitor.visitIntInsn(Opcodes.ISTORE, isThreadStartIdx);
                // this._OT$creationThread = null; // avoid leak
                methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                methodVisitor.visitInsn(Opcodes.ACONST_NULL);
                methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, clazz.getInternalName(), CREATION_THREAD,
                        THREAD_DESC);
            }

            @Override
            protected void onMethodExit(int opcode) {
                insertThreadEndedNotification();
            }

            @Override
            public void endMethod() {
                methodVisitor.visitLabel(end);

                // insert another threadEnded notification as a handler for Throwable
                Label handler = new Label();
                methodVisitor.visitLabel(handler);
                insertThreadEndedNotification();
                methodVisitor.visitInsn(Opcodes.ATHROW); // rethrow caught exception

                methodVisitor.visitTryCatchBlock(start, end, handler, ClassNames.THROWABLE_SLASH);
                methodVisitor.visitMaxs(0, 0);
            }

            void insertThreadEndedNotification() {
                Label skip = new Label();
                // insert:
                // if (_OT$isThreadStart) TeamThreadManager.threadEnded();
                methodVisitor.visitIntInsn(Opcodes.ILOAD, isThreadStartIdx);
                methodVisitor.visitJumpInsn(Opcodes.IFEQ, skip);
                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, ClassNames.TEAM_THREAD_MANAGER_SLASH,
                        THREAD_ENDED, THREAD_ENDED_DESC, false);
                methodVisitor.visitLabel(skip);
            }
        };
    }
    return null;
}

From source file:org.greencheek.gc.memusage.agent.MonitoringAspectGenerator.java

License:Apache License

/**
 * Visits a method of the class. This method <i>must</i> return a new
 * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is
 * called, i.e., it should not return a previously returned visitor.
 * //from   w  ww  .j av a 2  s .  c om
 * This is overriden to:
 * <ol>
 * <li>statically initialising the AtomicLong if a static initialiser method is present in the class</li>
 * <li>Add to the method on with the @RecordGCMemUsage was present, a piece of code that updates the atomic long</li>
 * </ol>
 *
 * @param access the method's access flags (see {@link Opcodes}). This
 *        parameter also indicates if the method is synthetic and/or
 *        deprecated.
 * @param name the method's name.
 * @param desc the method's descriptor (see {@link Type Type}).
 * @param signature the method's signature. May be <tt>null</tt> if the
 *        method parameters, return type and exceptions do not use generic
 *        types.
 * @param exceptions the internal names of the method's exception classes
 *        (see {@link Type#getInternalName() getInternalName}). May be
 *        <tt>null</tt>.
 * @return an object to visit the byte code of the method, or <tt>null</tt>
 *         if this class visitor is not interested in visiting the code of
 *         this method.
 */
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
        final String[] exceptions) {

    MethodVisitor r = super.visitMethod(access, name, desc, signature, exceptions);

    if ("<clinit>".equals(name)) {
        r = new AddStaticAtomicLongInitializer(Opcodes.ASM4, r, overrideMethodNames.values());
    }

    MethodInfo currentMethod = new MethodInfo(access, name, desc, signature, exceptions, null, null);
    if (overrideMethodNames.containsKey(currentMethod.toString())) {
        final MethodInfo info = overrideMethodNames.get(currentMethod.toString());

        r = new AdviceAdapter(Opcodes.ASM4, r, access, name, desc) {
            protected void onMethodEnter() {
                System.out.println("Aspecting: " + info.getAnnotatedClassName() + "." + info.toString());
                System.out.println("Increments: " + info.getFieldName());
                super.visitFieldInsn(GETSTATIC, info.getAnnotatedClassName(), info.getFieldName(),
                        "Ljava/util/concurrent/atomic/AtomicLong;");
                super.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/atomic/AtomicLong",
                        "incrementAndGet", "()J");
                super.visitInsn(POP2);
            }
        };
    }

    return r;

}

From source file:org.summer.aop.ltw.AspectWeaver.java

License:Open Source License

/**
 * Displaces the original method body to a corresponding private redirection method. However, if the visited class
 * has been mocked and the mock class overwrites this method, the original method body will be replaced entirely by
 * the corresponding mock method body./*from   ww w. ja  v  a2s  . c  o  m*/
 * <p/>
 * Note: As constructors are nothing else than methods, they are also taken into account.
 *
 * @param access     the original method access
 * @param name       the original method name
 * @param desc       the original method description
 * @param signature  the original method signature
 * @param exceptions the original exceptions
 * @return a method visitor that points to the private redirected method
 */
@Override
public MethodVisitor visitMethod(int access, final String name, final String desc, String signature,
        String[] exceptions) {
    // If this class should be replaced, skip all original methods
    if (replacingClassNode != null && !isVisitEndReached)
        return null;
    // If this class should be merged and this method isn't the static initializer, and a corresponding merging method is defined, merge their exceptions
    if (mergingClassNode != null && !name.equals("<clinit>")) {
        for (Object methodNode : mergingClassNode.methods) {
            MethodNode mn = (MethodNode) methodNode;
            if (mn.name.equals(name) && mn.desc.equals(desc)) {
                List<String> mergedExceptions = exceptions == null ? new ArrayList<String>()
                        : Arrays.asList(exceptions);
                for (Object e : mn.exceptions) {
                    String ex = (String) e;
                    if (!mergedExceptions.contains(ex))
                        mergedExceptions.add(ex);
                }
                exceptions = mergedExceptions.toArray(new String[mergedExceptions.size()]);
                break;
            }
        }
    }
    MethodVisitor mv;
    //Currently ALL constructors and methods will be transformed for retransformation purposes, because
    //the Java Instrumentation API doesn't yet allow the addition of new methods (or constructors).
    //If future Java versions cancel this restriction you can safely enable the following three lines in place of
    //the three lines after next!
    //    List<Aspect> matchingAspects = getMatchingAspects(access,name,desc,signature,exceptions);
    //    if(!isInterface && !matchingAspects.isEmpty())
    //    {
    if (!isInterface && !name.equals("<clinit>")) {
        List<Aspect> matchingAspects = getMatchingAspects(access, name, desc, signature, exceptions);
        if (name.equals("<init>")) {
            // Transform the constructor and add a constructor redirected method
            mv = new ConstructorSplitter(className, cv, access, ++constructorCounter, desc, signature,
                    exceptions, matchingAspects);
        } else {
            // Rename original non-constructor methods
            mv = cv.visitMethod(toPrivateAccess(access), AOPContext.toRedirectedMethodName(name, -1), desc,
                    signature, exceptions);
        }
        // Remember the intercepted original method details
        interceptedMethodInfos.add(new AspectWeaver.MethodInfo(access, name,
                name.equals("<init>") ? constructorCounter : -1, desc, signature, exceptions, matchingAspects));
        // If this class should be merged...
        if (mergingClassNode != null) {
            if (name.equals("<init>")) {
                visitedMergingClassMethods.add(name + desc);
                // Merge the original constructor body with ALL those defined in the merging class
                return new AdviceAdapter(ASM4, mv, access, "<init>", desc) {
                    @Override
                    protected void onMethodExit(int opcode) {
                        for (Object methodNode : mergingClassNode.methods) {
                            MethodNode mn = (MethodNode) methodNode;
                            if (mn.name.equals("<init>")) {
                                // Insert everything between the super call invocation and RETURN or ATHROW instruction
                                AbstractInsnNode insn = mn.instructions.getFirst();
                                while (!(insn instanceof MethodInsnNode)
                                        || !((MethodInsnNode) insn).owner.equals(mergingClassNode.superName)
                                        || ((MethodInsnNode) insn).getOpcode() != INVOKESPECIAL
                                        || !((MethodInsnNode) insn).name.equals("<init>")) {
                                    insn = insn.getNext();
                                }
                                insn = insn.getNext();
                                while (!(insn instanceof InsnNode) || (((InsnNode) insn).getOpcode() != RETURN
                                        && ((InsnNode) insn).getOpcode() != ATHROW)) {
                                    if (insn instanceof MethodInsnNode
                                            && ((MethodInsnNode) insn).owner.equals(mergingClassNode.name))
                                        ((MethodInsnNode) insn).owner = className;
                                    else if (insn instanceof FieldInsnNode
                                            && ((FieldInsnNode) insn).owner.equals(mergingClassNode.name))
                                        ((FieldInsnNode) insn).owner = className;
                                    insn.accept(this);
                                    insn = insn.getNext();
                                }
                                maxStack = Math.max(maxStack, mn.maxStack);
                                maxLocals = Math.max(maxLocals, mn.maxLocals);
                                for (Iterator<?> it = mn.localVariables.iterator(); it.hasNext();) {
                                    LocalVariableNode localVar = (LocalVariableNode) it.next();
                                    if (localVar.desc.equals("L" + mergingClassNode.name + ";"))
                                        localVar.desc = "L" + className + ";";
                                }
                            }
                        }
                    }

                    @Override
                    public void visitMaxs(int nStack, int nLocals) {
                        super.visitMaxs(Math.max(nStack, maxStack), Math.max(nLocals, maxLocals));
                    }

                    private int maxStack;
                    private int maxLocals;
                };
            } else {
                for (Object methodNode : mergingClassNode.methods) {
                    MethodNode mn = (MethodNode) methodNode;
                    if (mn.name.equals(name) && mn.desc.equals(desc)) {
                        visitedMergingClassMethods.add(name + desc);
                        if (shouldInsertRedirectionCondition) {
                            // Insert a redirection condition, which is based on the STATIC_IS_MERGING_REVERTED_FIELD boolean value.
                            // If the flag is false then call the original method and skip the merging one, otherwise do the opposite.
                            Type returnType = Type.getReturnType(desc);
                            boolean isVoid = returnType.getSort() == Type.VOID;
                            int returnOpcode = isVoid ? RETURN : returnType.getOpcode(IRETURN);
                            AbstractInsnNode first = mn.instructions.getFirst();
                            mn.instructions.insertBefore(first, new FieldInsnNode(GETSTATIC, className,
                                    AOPContext.STATIC_IS_MERGING_REVERTED_FIELD, "Z"));
                            LabelNode labelNode = new LabelNode();
                            mn.instructions.insertBefore(first, new JumpInsnNode(IFEQ, labelNode));
                            boolean isStatic = (access & ACC_STATIC) != 0;
                            int inc = 0;
                            if (!isStatic) {
                                mn.instructions.insertBefore(first, new VarInsnNode(ALOAD, 0));
                                mn.maxStack++;
                                inc = 1;
                            }
                            Type[] argTypes = Type.getArgumentTypes(desc);
                            for (int i = 0; i < argTypes.length; ++i) {
                                mn.instructions.insertBefore(first,
                                        new VarInsnNode(argTypes[i].getOpcode(ILOAD), inc + i));
                                if (argTypes[i].getInternalName().equals("J")
                                        || argTypes[i].getInternalName().equals("D"))
                                    ++inc;
                            }
                            mn.instructions.insertBefore(first,
                                    new MethodInsnNode(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, className,
                                            AOPContext.toMergedMethodName(name, -1), desc));
                            mn.instructions.insertBefore(first, new InsnNode(returnOpcode));
                            mn.instructions.insertBefore(first, labelNode);
                        }
                        // A corresponding merging method has been found, so let's replace the original method body
                        // with the merging method body
                        mn.accept(mv);
                        // Rename the original method if existent, otherwise return null
                        return shouldInsertRedirectionCondition
                                ? cv.visitMethod(access, AOPContext.toMergedMethodName(name, -1), desc,
                                        signature, exceptions)
                                : null;
                    }
                }
            }
        }
    } else {
        mv = cv.visitMethod(access, name, desc, signature, exceptions);
        if (mergingClassNode != null)
            visitedMergingClassMethods.add(name + desc);
        if (name.equals("<clinit>")) {
            isStaticBlockVisited = true;
            mv = new AdviceAdapter(ASM4, mv, access, name, desc) {
                @Override
                protected void onMethodEnter() {
                    initializeStaticAspectsField(this);
                    if (mergingClassNode != null)
                        initializeStaticIsMergingActiveField(this);
                }

                @Override
                protected void onMethodExit(int opcode) {
                    if (mergingClassNode != null) {
                        for (Object methodNode : mergingClassNode.methods) {
                            MethodNode mn = (MethodNode) methodNode;
                            if (mn.name.equals("<clinit>")) {
                                AbstractInsnNode insn = mn.instructions.getFirst();
                                while (!(insn instanceof InsnNode) || (((InsnNode) insn).getOpcode() != RETURN
                                        && ((InsnNode) insn).getOpcode() != ATHROW)) {
                                    if (insn instanceof MethodInsnNode
                                            && ((MethodInsnNode) insn).owner.equals(mergingClassNode.name))
                                        ((MethodInsnNode) insn).owner = className;
                                    else if (insn instanceof FieldInsnNode
                                            && ((FieldInsnNode) insn).owner.equals(mergingClassNode.name))
                                        ((FieldInsnNode) insn).owner = className;
                                    insn.accept(this);
                                    insn = insn.getNext();
                                }
                                maxStack = Math.max(maxStack, mn.maxStack);
                                maxLocals = Math.max(maxLocals, mn.maxLocals);
                                for (Iterator<?> it = mn.localVariables.iterator(); it.hasNext();) {
                                    LocalVariableNode localVar = (LocalVariableNode) it.next();
                                    if (localVar.desc.equals("L" + mergingClassNode.name + ";"))
                                        localVar.desc = "L" + className + ";";
                                }
                                break;
                            }
                        }
                    }
                }

                @Override
                public void visitMaxs(int nStack, int nLocals) {
                    if (mergingClassNode != null)
                        super.visitMaxs(Math.max(nStack, maxStack), Math.max(nLocals, maxLocals));
                    else
                        super.visitMaxs(nStack + 2, nLocals);
                }

                private int maxStack;
                private int maxLocals;
            };
        }
    }
    return mv;
}