001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.cflow;
005:
006: import com.tc.asm.Opcodes;
007: import com.tc.asm.ClassWriter;
008: import com.tc.asm.MethodVisitor;
009: import com.tc.asm.Label;
010:
011: import com.tc.aspectwerkz.transform.TransformationConstants;
012: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
013: import com.tc.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
014:
015: /**
016: * Compiler for the JIT cflow Aspect
017: *
018: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
019: */
020: public class CflowCompiler implements Opcodes, TransformationConstants {
021:
022: public final static String JIT_CFLOW_CLASS = "com/tc/aspectwerkz/cflow/Cflow_";
023: private final static String ABSTRACT_CFLOW_CLASS = "com/tc/aspectwerkz/cflow/AbstractCflowSystemAspect";
024: private final static String INSTANCE_CFLOW_FIELD_NAME = "INSTANCE";
025: public static final String IN_CFLOW_METOD_NAME = "inCflow";
026: public static final String IN_CFLOW_METOD_SIGNATURE = "()Z";
027: public static final String CFLOW_ASPECTOF_METHOD_NAME = "aspectOf";
028:
029: /**
030: * Checks if a class name (ASM style) is a cflow name
031: *
032: * @param className
033: * @return
034: */
035: public static boolean isCflowClass(String className) {
036: return className.indexOf(JIT_CFLOW_CLASS) >= 0;
037: }
038:
039: /**
040: * The jit cflow aspect class name (with /)
041: */
042: private final String m_className;
043:
044: /**
045: * The jit cflow aspect class name (with /)
046: */
047: private final String m_classSignature;
048:
049: private ClassWriter m_cw;
050:
051: /**
052: * private ctor
053: *
054: * @param cflowId
055: */
056: private CflowCompiler(int cflowId) {
057: m_className = getCflowAspectClassName(cflowId);
058: m_classSignature = "L" + m_className + ";";
059: }
060:
061: /**
062: * compile the jit cflow aspect
063: *
064: * @return bytecode for the concrete jit cflow aspect
065: */
066: private byte[] compile() {
067: m_cw = AsmHelper.newClassWriter(true);
068:
069: // class extends AbstractCflowsystemAspect
070: m_cw.visit(AsmHelper.JAVA_VERSION, ACC_PUBLIC + ACC_SUPER
071: + ACC_SYNTHETIC, m_className, null,
072: ABSTRACT_CFLOW_CLASS, EMPTY_STRING_ARRAY);
073:
074: // static INSTANCE field
075: m_cw
076: .visitField(ACC_PRIVATE + ACC_STATIC,
077: INSTANCE_CFLOW_FIELD_NAME, m_classSignature,
078: null, null);
079:
080: // private ctor
081: MethodVisitor ctor = m_cw.visitMethod(ACC_PRIVATE,
082: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null,
083: EMPTY_STRING_ARRAY);
084: // invoke the constructor of abstract
085: ctor.visitVarInsn(ALOAD, 0);
086: ctor.visitMethodInsn(INVOKESPECIAL, ABSTRACT_CFLOW_CLASS,
087: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
088: ctor.visitInsn(RETURN);
089: ctor.visitMaxs(0, 0);
090:
091: // static isInCflow() delegators
092: MethodVisitor isInCflow = m_cw.visitMethod(ACC_PUBLIC
093: + ACC_STATIC, IS_IN_CFLOW_METOD_NAME,
094: IS_IN_CFLOW_METOD_SIGNATURE, null, EMPTY_STRING_ARRAY);
095: isInCflow.visitFieldInsn(GETSTATIC, m_className,
096: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
097: Label isNull = new Label();
098: isInCflow.visitJumpInsn(IFNULL, isNull);
099: isInCflow.visitFieldInsn(GETSTATIC, m_className,
100: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
101: isInCflow.visitMethodInsn(INVOKEVIRTUAL, ABSTRACT_CFLOW_CLASS,
102: IN_CFLOW_METOD_NAME, IN_CFLOW_METOD_SIGNATURE);
103: isInCflow.visitInsn(IRETURN);
104: isInCflow.visitLabel(isNull);
105: isInCflow.visitInsn(ICONST_0);
106: isInCflow.visitInsn(IRETURN);
107: isInCflow.visitMaxs(0, 0);
108:
109: // static aspectOf()
110: MethodVisitor aspectOf = m_cw.visitMethod(ACC_PUBLIC
111: + ACC_STATIC, CFLOW_ASPECTOF_METHOD_NAME, "()"
112: + m_classSignature, null, EMPTY_STRING_ARRAY);
113: aspectOf.visitFieldInsn(GETSTATIC, m_className,
114: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
115: Label isNotNull = new Label();
116: aspectOf.visitJumpInsn(IFNONNULL, isNotNull);
117: aspectOf.visitTypeInsn(NEW, m_className);
118: aspectOf.visitInsn(DUP);
119: aspectOf.visitMethodInsn(INVOKESPECIAL, m_className,
120: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
121: aspectOf.visitFieldInsn(PUTSTATIC, m_className,
122: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
123: aspectOf.visitLabel(isNotNull);
124: aspectOf.visitFieldInsn(GETSTATIC, m_className,
125: INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
126: aspectOf.visitInsn(ARETURN);
127: aspectOf.visitMaxs(0, 0);
128:
129: m_cw.visitEnd();
130:
131: return m_cw.toByteArray();
132: }
133:
134: /**
135: * The naming strategy for jit cflow aspect
136: *
137: * @param cflowID
138: * @return com.tc.aspectwerkz.cflow.Cflow_cflowID
139: */
140: public static String getCflowAspectClassName(int cflowID) {
141: return JIT_CFLOW_CLASS + cflowID;
142: }
143:
144: /**
145: * If necessary, compile a jit cflow aspect and attach it to the given classloader
146: *
147: * @param loader
148: * @param cflowID
149: * @return
150: */
151: public static Class compileCflowAspectAndAttachToClassLoader(
152: ClassLoader loader, int cflowID) {
153: // System.out.println("------------------> compileCflowAspectAndAttachToClassLoader: loader = " + loader);
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_JP_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: }
|