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.transform.inlining.weaver;
008:
009: import org.objectweb.asm.ClassAdapter;
010: import org.objectweb.asm.ClassVisitor;
011: import org.objectweb.asm.CodeVisitor;
012: import org.objectweb.asm.Attribute;
013: import org.objectweb.asm.CodeAdapter;
014: import org.codehaus.aspectwerkz.transform.Context;
015: import org.codehaus.aspectwerkz.transform.TransformationConstants;
016: import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
017: import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
018:
019: import java.util.Iterator;
020:
021: /**
022: * A ClassAdapter that take care of all weaved class and add the glue between the class and its JIT dependencies.
023: * <p/>
024: * Adds a 'private static final Class aw$clazz' field a 'private static void ___AW_$_AW_$initJoinPoints()' method
025: * and patches the 'clinit' method.
026: * <p/>
027: * If the class has been made advisable, we also add a ___AW_$_AW_$emittedJoinPoints fields that gets populated.
028: *
029: *
030: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
031: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
032: * @TODO: for multi weaving, we could go on in adding several AW initJoinPoints_xxWeaveCount method, but then cannot be
033: * done with RW
034: */
035: public class JoinPointInitVisitor extends ClassAdapter implements
036: TransformationConstants {
037:
038: private final ContextImpl m_ctx;
039: private boolean m_hasClinitMethod = false;
040: private boolean m_hasInitJoinPointsMethod = false;
041: private boolean m_hasClassField = false;
042: private boolean m_hasEmittedJoinPointsField = false;
043:
044: /**
045: * Creates a new instance.
046: *
047: * @param cv
048: * @param ctx
049: */
050: public JoinPointInitVisitor(final ClassVisitor cv, final Context ctx) {
051: super (cv);
052: m_ctx = (ContextImpl) ctx;
053: }
054:
055: /**
056: * Visits the methods. If the AW joinPointsInit method is found, remember that, it means we are in a multi-weaving
057: * scheme. Patch the 'clinit' method if already present.
058: *
059: * @TODO: multi-weaving will lead to several invocation of AW initJoinPoints and several assigment of __AW_Clazz in the patched clinit which slows down a bit the load time
060: * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String[],
061: * org.objectweb.asm.Attribute)
062: */
063: public CodeVisitor visitMethod(final int access, final String name,
064: final String desc, final String[] exceptions,
065: final Attribute attrs) {
066:
067: if (CLINIT_METHOD_NAME.equals(name)) {
068: m_hasClinitMethod = true;
069: // at the beginning of the existing <clinit> method
070: // ___AWClazz = Class.forName("TargetClassName");
071: // ___AW_$_AW_$initJoinPoints();
072: CodeVisitor ca = new InsertBeforeClinitCodeAdapter(cv
073: .visitMethod(access, name, desc, exceptions, attrs));
074: ca.visitMaxs(0, 0);
075: return ca;
076:
077: } else if (INIT_JOIN_POINTS_METHOD_NAME.equals(name)) {
078: m_hasInitJoinPointsMethod = true;
079: // add the gathered JIT dependencies for multi-weaving support
080: CodeVisitor ca = new InsertBeforeInitJoinPointsCodeAdapter(
081: cv.visitMethod(access, name, desc, exceptions,
082: attrs));
083: ca.visitMaxs(0, 0);
084: return ca;
085: } else {
086: return super .visitMethod(access, name, desc, exceptions,
087: attrs);
088: }
089: }
090:
091: /**
092: * Remember if we have already the static class field for multi-weaving scheme.
093: *
094: * @param access
095: * @param name
096: * @param desc
097: * @param value
098: * @param attrs
099: */
100: public void visitField(int access, String name, String desc,
101: Object value, Attribute attrs) {
102: if (TARGET_CLASS_FIELD_NAME.equals(name)) {
103: m_hasClassField = true;
104: } else if (EMITTED_JOINPOINTS_FIELD_NAME.equals(name)) {
105: m_hasEmittedJoinPointsField = true;
106: }
107: super .visitField(access, name, desc, value, attrs);
108: }
109:
110: /**
111: * Finalize the visit. Add static class field if needed, add initJoinPoints method if needed, add <clinit>if
112: * needed.
113: */
114: public void visitEnd() {
115: if (!m_ctx.isAdvised()) {
116: super .visitEnd();
117: return;
118: }
119:
120: if (!m_hasClassField) {
121: // create field
122: // private final static Class aw$clazz = Class.forName("TargetClassName");
123: cv.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC
124: + ACC_SYNTHETIC, TARGET_CLASS_FIELD_NAME,
125: CLASS_CLASS_SIGNATURE, null, null);
126: }
127:
128: if (!m_hasEmittedJoinPointsField && m_ctx.isMadeAdvisable()) {
129: // create field
130: // private final static Class aw$emittedJoinPoints that will host a Trove int Object map
131: cv.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC
132: + ACC_SYNTHETIC, EMITTED_JOINPOINTS_FIELD_NAME,
133: "Lgnu/trove/TIntObjectHashMap;", null, null);
134: }
135:
136: if (!m_hasClinitMethod) {
137: CodeVisitor ca = new InsertBeforeClinitCodeAdapter(cv
138: .visitMethod(ACC_STATIC, CLINIT_METHOD_NAME,
139: NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE,
140: null, null));
141: ca.visitInsn(RETURN);
142: ca.visitMaxs(0, 0);
143: }
144:
145: if (!m_hasInitJoinPointsMethod) {
146: CodeVisitor mv = new InsertBeforeInitJoinPointsCodeAdapter(
147: cv.visitMethod(ACC_PRIVATE + ACC_FINAL + ACC_STATIC
148: + ACC_SYNTHETIC,
149: INIT_JOIN_POINTS_METHOD_NAME,
150: NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE,
151: null, null));
152: mv.visitInsn(RETURN);
153: mv.visitMaxs(0, 0);
154: }
155:
156: cv.visitEnd();
157: }
158:
159: /**
160: * Handles the method body of the <clinit>method.
161: *
162: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
163: */
164: public class InsertBeforeClinitCodeAdapter extends CodeAdapter {
165:
166: public InsertBeforeClinitCodeAdapter(CodeVisitor ca) {
167: super (ca);
168: if (!m_hasClassField) {
169: cv.visitLdcInsn(m_ctx.getClassName().replace('/', '.'));
170: cv
171: .visitMethodInsn(INVOKESTATIC, CLASS_CLASS,
172: FOR_NAME_METHOD_NAME,
173: FOR_NAME_METHOD_SIGNATURE);
174: cv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(),
175: TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
176: }
177: if (!m_hasEmittedJoinPointsField && m_ctx.isMadeAdvisable()) {
178: // aw$emittedJoinPoints = new TIntObjectHashMap()
179: cv.visitTypeInsn(NEW, "gnu/trove/TIntObjectHashMap");
180: cv.visitInsn(DUP);
181: cv.visitMethodInsn(INVOKESPECIAL,
182: "gnu/trove/TIntObjectHashMap", "<init>", "()V");
183: cv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(),
184: EMITTED_JOINPOINTS_FIELD_NAME,
185: "Lgnu/trove/TIntObjectHashMap;");
186: }
187: if (!m_hasClassField) {
188: cv.visitMethodInsn(INVOKESTATIC, m_ctx.getClassName(),
189: INIT_JOIN_POINTS_METHOD_NAME,
190: NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE);
191: }
192: }
193: }
194:
195: /**
196: * Handles the method body of the AW initJoinPoints method.
197: *
198: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
199: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
200: */
201: public class InsertBeforeInitJoinPointsCodeAdapter extends
202: CodeAdapter {
203:
204: public InsertBeforeInitJoinPointsCodeAdapter(CodeVisitor ca) {
205: super (ca);
206:
207: // loop over emitted jp and insert call to "JoinPointManager.loadJoinPoint(...)"
208: // add calls to aw$emittedJoinPoints.put(.. new EmittedJoinPoint) if needed.
209: for (Iterator iterator = m_ctx.getEmittedJoinPoints()
210: .iterator(); iterator.hasNext();) {
211:
212: EmittedJoinPoint jp = (EmittedJoinPoint) iterator
213: .next();
214: cv.visitLdcInsn(new Integer(jp.getJoinPointType()));
215:
216: cv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(),
217: TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
218: cv.visitLdcInsn(jp.getCallerMethodName());
219: cv.visitLdcInsn(jp.getCallerMethodDesc());
220: cv.visitLdcInsn(new Integer(jp
221: .getCallerMethodModifiers()));
222:
223: cv.visitLdcInsn(jp.getCalleeClassName());
224: cv.visitLdcInsn(jp.getCalleeMemberName());
225: cv.visitLdcInsn(jp.getCalleeMemberDesc());
226: cv.visitLdcInsn(new Integer(jp
227: .getCalleeMemberModifiers()));
228:
229: cv.visitLdcInsn(new Integer(jp.getJoinPointHash()));
230: cv.visitLdcInsn(jp.getJoinPointClassName());
231: cv.visitMethodInsn(INVOKESTATIC,
232: JOIN_POINT_MANAGER_CLASS_NAME,
233: LOAD_JOIN_POINT_METHOD_NAME,
234: LOAD_JOIN_POINT_METHOD_SIGNATURE);
235:
236: if (m_ctx.isMadeAdvisable()) {
237: // trove map
238: cv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(),
239: EMITTED_JOINPOINTS_FIELD_NAME,
240: "Lgnu/trove/TIntObjectHashMap;");
241: // trove map key
242: cv.visitLdcInsn(new Integer(jp
243: .getJoinPointClassName().hashCode()));
244:
245: cv
246: .visitTypeInsn(NEW,
247: "org/codehaus/aspectwerkz/transform/inlining/EmittedJoinPoint");
248: cv.visitInsn(DUP);
249:
250: cv.visitLdcInsn(new Integer(jp.getJoinPointType()));
251:
252: cv.visitLdcInsn(m_ctx.getClassName());
253: cv.visitLdcInsn(jp.getCallerMethodName());
254: cv.visitLdcInsn(jp.getCallerMethodDesc());
255: cv.visitLdcInsn(new Integer(jp
256: .getCallerMethodModifiers()));
257:
258: cv.visitLdcInsn(jp.getCalleeClassName());
259: cv.visitLdcInsn(jp.getCalleeMemberName());
260: cv.visitLdcInsn(jp.getCalleeMemberDesc());
261: cv.visitLdcInsn(new Integer(jp
262: .getCalleeMemberModifiers()));
263:
264: cv.visitLdcInsn(new Integer(jp.getJoinPointHash()));
265: cv.visitLdcInsn(jp.getJoinPointClassName());
266:
267: cv
268: .visitMethodInsn(
269: INVOKESPECIAL,
270: "org/codehaus/aspectwerkz/transform/inlining/EmittedJoinPoint",
271: "<init>",
272: "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
273: cv.visitMethodInsn(INVOKEVIRTUAL,
274: "gnu/trove/TIntObjectHashMap", "put",
275: "(ILjava/lang/Object;)Ljava/lang/Object;");
276: }
277: }
278: }
279: }
280:
281: }
|