List of usage examples for org.objectweb.asm.commons AdviceAdapter AdviceAdapter
protected AdviceAdapter(final int api, final MethodVisitor methodVisitor, final int access, final String name, final String descriptor)
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; }