001: /**************************************************************************************
002: * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.cflow;
008:
009: import org.objectweb.asm.Constants;
010: import org.objectweb.asm.ClassWriter;
011: import org.objectweb.asm.CodeVisitor;
012: import org.objectweb.asm.Label;
013: import org.codehaus.aspectwerkz.transform.TransformationConstants;
014: import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
015: import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
016:
017: /**
018: * Compiler for the JIT cflow Aspect
019: *
020: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
021: */
022: public class CflowCompiler implements Constants,
023: TransformationConstants {
024:
025: public final static String JIT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/Cflow_";
026: private final static String ABSTRACT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/AbstractCflowSystemAspect";
027: private final static String INSTANCE_CFLOW_FIELD_NAME = "INSTANCE";
028: private final static String[] EMPTY_STRING_ARRAY = new String[0];
029: public static final String IN_CFLOW_METOD_NAME = "inCflow";
030: public static final String IN_CFLOW_METOD_SIGNATURE = "()Z";
031: public static final String CFLOW_ASPECTOF_METHOD_NAME = "aspectOf";
032:
033: /**
034: * Checks if a class name (ASM style) is a cflow name
035: *
036: * @param className
037: * @return
038: */
039: public static boolean isCflowClass(String className) {
040: return className.indexOf(JIT_CFLOW_CLASS) >= 0;
041: }
042:
043: /**
044: * The jit cflow aspect class name (with /)
045: */
046: private final String m_className;
047:
048: /**
049: * The jit cflow aspect class name (with /)
050: */
051: private final String m_classSignature;
052:
053: private ClassWriter m_cw;
054:
055: /**
056: * private ctor
057: * @param cflowId
058: */
059: private CflowCompiler(int cflowId) {
060: m_className = getCflowAspectClassName(cflowId);
061: m_classSignature = "L" + m_className + ";";
062: }
063:
064: /**
065: * compile the jit cflow aspect
066: * @return bytecode for the concrete jit cflow aspect
067: */
068: private byte[] compile() {
069: m_cw = AsmHelper.newClassWriter(true);
070:
071: // class extends AbstractCflowsystemAspect
072: m_cw.visit(AsmHelper.JAVA_VERSION, ACC_PUBLIC + ACC_SUPER
073: + ACC_SYNTHETIC, m_className, ABSTRACT_CFLOW_CLASS,
074: EMPTY_STRING_ARRAY, null);
075:
076: // static INSTANCE field
077: m_cw
078: .visitField(ACC_PRIVATE + ACC_STATIC,
079: INSTANCE_CFLOW_FIELD_NAME, m_classSignature,
080: null, null);
081:
082: // private ctor
083: CodeVisitor ctor = m_cw.visitMethod(ACC_PRIVATE,
084: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE,
085: EMPTY_STRING_ARRAY, null);
086: // invoke the constructor of abstract
087: ctor.visitVarInsn(ALOAD, 0);
088: ctor.visitMethodInsn(INVOKESPECIAL, ABSTRACT_CFLOW_CLASS,
089: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
090: ctor.visitInsn(RETURN);
091: ctor.visitMaxs(0, 0);
092:
093: // static isInCflow() delegators
094: CodeVisitor isInCflow = m_cw.visitMethod(ACC_PUBLIC
095: + ACC_STATIC, IS_IN_CFLOW_METOD_NAME,
096: IS_IN_CFLOW_METOD_SIGNATURE, EMPTY_STRING_ARRAY, null);
097: isInCflow.visitFieldInsn(GETSTATIC, m_className,
098: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
099: Label isNull = new Label();
100: isInCflow.visitJumpInsn(IFNULL, isNull);
101: isInCflow.visitFieldInsn(GETSTATIC, m_className,
102: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
103: isInCflow.visitMethodInsn(INVOKEVIRTUAL, ABSTRACT_CFLOW_CLASS,
104: IN_CFLOW_METOD_NAME, IN_CFLOW_METOD_SIGNATURE);
105: isInCflow.visitInsn(IRETURN);
106: isInCflow.visitLabel(isNull);
107: isInCflow.visitInsn(ICONST_0);
108: isInCflow.visitInsn(IRETURN);
109: isInCflow.visitMaxs(0, 0);
110:
111: // static aspectOf()
112: CodeVisitor aspectOf = m_cw.visitMethod(
113: ACC_PUBLIC + ACC_STATIC, CFLOW_ASPECTOF_METHOD_NAME,
114: "()" + m_classSignature, EMPTY_STRING_ARRAY, null);
115: aspectOf.visitFieldInsn(GETSTATIC, m_className,
116: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
117: Label isNotNull = new Label();
118: aspectOf.visitJumpInsn(IFNONNULL, isNotNull);
119: aspectOf.visitTypeInsn(NEW, m_className);
120: aspectOf.visitInsn(DUP);
121: aspectOf.visitMethodInsn(INVOKESPECIAL, m_className,
122: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
123: aspectOf.visitFieldInsn(PUTSTATIC, m_className,
124: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
125: aspectOf.visitLabel(isNotNull);
126: aspectOf.visitFieldInsn(GETSTATIC, m_className,
127: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
128: aspectOf.visitInsn(ARETURN);
129: aspectOf.visitMaxs(0, 0);
130:
131: m_cw.visitEnd();
132:
133: return m_cw.toByteArray();
134: }
135:
136: /**
137: * The naming strategy for jit cflow aspect
138: * @param cflowID
139: * @return org.codehaus.aspectwerkz.cflow.Cflow_cflowID
140: */
141: public static String getCflowAspectClassName(int cflowID) {
142: return JIT_CFLOW_CLASS + cflowID;
143: }
144:
145: /**
146: * If necessary, compile a jit cflow aspect and attach it to the given classloader
147: *
148: * @param loader
149: * @param cflowID
150: * @return
151: */
152: public static Class compileCflowAspectAndAttachToClassLoader(
153: ClassLoader loader, int cflowID) {
154: //TODO we need a Class.forName check first to avoid unecessary compilation
155: // else it will fail in defineClass and fallback on Class.forName ie uneeded compilation
156: // -> price to pay between compilation + exception in the worse case vs Class.forName each time
157: CompiledCflowAspect cflowAspect = compileCflowAspect(cflowID);
158:
159: if (AbstractJoinPointCompiler.DUMP_JIT_CLASSES) {
160: try {
161: AsmHelper.dumpClass("_dump",
162: getCflowAspectClassName(cflowID),
163: cflowAspect.bytecode);
164: } catch (Throwable t) {
165: ;
166: }
167: }
168:
169: Class cflowAspectClass = AsmHelper.defineClass(loader,
170: cflowAspect.bytecode, getCflowAspectClassName(cflowID));
171: return cflowAspectClass;
172: }
173:
174: /**
175: * Compile a jit cflow aspect
176: *
177: * @param cflowID
178: * @return
179: */
180: public static CompiledCflowAspect compileCflowAspect(int cflowID) {
181: CompiledCflowAspect cflowAspect = new CompiledCflowAspect();
182: CflowCompiler compiler = new CflowCompiler(cflowID);
183: cflowAspect.bytecode = compiler.compile();
184: cflowAspect.className = compiler.m_className;
185: return cflowAspect;
186: }
187:
188: /**
189: * Information about a compiled Cflow Aspect
190: */
191: public static class CompiledCflowAspect {
192: public byte[] bytecode;
193: public String className;// ASM style
194:
195: public boolean equals(Object o) {
196: if (this == o)
197: return true;
198: if (!(o instanceof CompiledCflowAspect))
199: return false;
200:
201: final CompiledCflowAspect compiledCflowAspect = (CompiledCflowAspect) o;
202:
203: if (!className.equals(compiledCflowAspect.className))
204: return false;
205:
206: return true;
207: }
208:
209: public int hashCode() {
210: return className.hashCode();
211: }
212: }
213: }
|