/************************************************************************************** * Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. * * http://aspectwerkz.codehaus.org * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the LGPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package org.codehaus.aspectwerkz.cflow; import org.objectweb.asm.Opcodes; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Label; import org.codehaus.aspectwerkz.transform.TransformationConstants; import org.codehaus.aspectwerkz.transform.inlining.AsmHelper; import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler; /** * Compiler for the JIT cflow Aspect * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ public class CflowCompiler implements Opcodes, TransformationConstants { public final static String JIT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/Cflow_"; private final static String ABSTRACT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/AbstractCflowSystemAspect"; private final static String INSTANCE_CFLOW_FIELD_NAME = "INSTANCE"; public static final String IN_CFLOW_METOD_NAME = "inCflow"; public static final String IN_CFLOW_METOD_SIGNATURE = "()Z"; public static final String CFLOW_ASPECTOF_METHOD_NAME = "aspectOf"; /** * Checks if a class name (ASM style) is a cflow name * * @param className * @return */ public static boolean isCflowClass(String className) { return className.indexOf(JIT_CFLOW_CLASS) >= 0; } /** * The jit cflow aspect class name (with /) */ private final String m_className; /** * The jit cflow aspect class name (with /) */ private final String m_classSignature; private ClassWriter m_cw; /** * private ctor * @param cflowId */ private CflowCompiler(int cflowId) { m_className = getCflowAspectClassName(cflowId); m_classSignature = "L"+m_className+";"; } /** * compile the jit cflow aspect * @return bytecode for the concrete jit cflow aspect */ private byte[] compile() { m_cw = AsmHelper.newClassWriter(true); // class extends AbstractCflowsystemAspect m_cw.visit( AsmHelper.JAVA_VERSION, ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC, m_className, null, ABSTRACT_CFLOW_CLASS, EMPTY_STRING_ARRAY ); // static INSTANCE field m_cw.visitField( ACC_PRIVATE + ACC_STATIC, INSTANCE_CFLOW_FIELD_NAME, m_classSignature, null, null ); // private ctor MethodVisitor ctor = m_cw.visitMethod( ACC_PRIVATE, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, EMPTY_STRING_ARRAY ); // invoke the constructor of abstract ctor.visitVarInsn(ALOAD, 0); ctor.visitMethodInsn(INVOKESPECIAL, ABSTRACT_CFLOW_CLASS, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE); ctor.visitInsn(RETURN); ctor.visitMaxs(0, 0); // static isInCflow() delegators MethodVisitor isInCflow = m_cw.visitMethod( ACC_PUBLIC + ACC_STATIC, IS_IN_CFLOW_METOD_NAME, IS_IN_CFLOW_METOD_SIGNATURE, null, EMPTY_STRING_ARRAY ); isInCflow.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature); Label isNull = new Label(); isInCflow.visitJumpInsn(IFNULL, isNull); isInCflow.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature); isInCflow.visitMethodInsn(INVOKEVIRTUAL, ABSTRACT_CFLOW_CLASS, IN_CFLOW_METOD_NAME, IN_CFLOW_METOD_SIGNATURE); isInCflow.visitInsn(IRETURN); isInCflow.visitLabel(isNull); isInCflow.visitInsn(ICONST_0); isInCflow.visitInsn(IRETURN); isInCflow.visitMaxs(0, 0); // static aspectOf() MethodVisitor aspectOf = m_cw.visitMethod( ACC_PUBLIC + ACC_STATIC, CFLOW_ASPECTOF_METHOD_NAME, "()"+m_classSignature, null, EMPTY_STRING_ARRAY ); aspectOf.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature); Label isNotNull = new Label(); aspectOf.visitJumpInsn(IFNONNULL, isNotNull); aspectOf.visitTypeInsn(NEW, m_className); aspectOf.visitInsn(DUP); aspectOf.visitMethodInsn(INVOKESPECIAL, m_className, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE); aspectOf.visitFieldInsn(PUTSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature); aspectOf.visitLabel(isNotNull); aspectOf.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature); aspectOf.visitInsn(ARETURN); aspectOf.visitMaxs(0, 0); m_cw.visitEnd(); return m_cw.toByteArray(); } /** * The naming strategy for jit cflow aspect * @param cflowID * @return org.codehaus.aspectwerkz.cflow.Cflow_cflowID */ public static String getCflowAspectClassName(int cflowID) { return JIT_CFLOW_CLASS + cflowID; } /** * If necessary, compile a jit cflow aspect and attach it to the given classloader * * @param loader * @param cflowID * @return */ public static Class compileCflowAspectAndAttachToClassLoader(ClassLoader loader, int cflowID) { //TODO we need a Class.forName check first to avoid unecessary compilation // else it will fail in defineClass and fallback on Class.forName ie uneeded compilation // -> price to pay between compilation + exception in the worse case vs Class.forName each time CompiledCflowAspect cflowAspect = compileCflowAspect(cflowID); if (AbstractJoinPointCompiler.DUMP_JIT_CLASSES) { try { AsmHelper.dumpClass("_dump", getCflowAspectClassName(cflowID), cflowAspect.bytecode); } catch (Throwable t) {;} } Class cflowAspectClass = AsmHelper.defineClass( loader, cflowAspect.bytecode, getCflowAspectClassName(cflowID) ); return cflowAspectClass; } /** * Compile a jit cflow aspect * * @param cflowID * @return */ public static CompiledCflowAspect compileCflowAspect(int cflowID) { CompiledCflowAspect cflowAspect = new CompiledCflowAspect(); CflowCompiler compiler = new CflowCompiler(cflowID); cflowAspect.bytecode = compiler.compile(); cflowAspect.className = compiler.m_className; return cflowAspect; } /** * Information about a compiled Cflow Aspect */ public static class CompiledCflowAspect { public byte[] bytecode; public String className;// ASM style public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof CompiledCflowAspect)) return false; final CompiledCflowAspect compiledCflowAspect = (CompiledCflowAspect) o; if (!className.equals(compiledCflowAspect.className)) return false; return true; } public int hashCode() { return className.hashCode(); } } }