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.transform.inlining.compiler;
005:
006: import java.util.Map;
007: import java.util.Iterator;
008: import java.util.WeakHashMap;
009: import java.util.HashSet;
010: import java.util.Set;
011:
012: import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
013: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
014: import com.tc.aspectwerkz.reflect.ClassInfo;
015: import com.tc.aspectwerkz.reflect.MethodInfo;
016: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
017: import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
018: import com.tc.aspectwerkz.expression.PointcutType;
019: import com.tc.aspectwerkz.expression.ExpressionContext;
020: import com.tc.aspectwerkz.expression.ExpressionInfo;
021:
022: /**
023: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
024: */
025: public class CompilerHelper {
026:
027: /**
028: * Stores the compilation infos - mapped to the last compiled join point class based on this compilation info.
029: */
030: private static final Map COMPILATION_INFO_REPOSITORY = new WeakHashMap();
031:
032: /**
033: * Compiles and loades a join point class, one specific class for each distinct join point.
034: *
035: * @param model the model for the compilation
036: * @param loader the class loader that the compiled join point should live in
037: * @return the compiled join point class
038: */
039: public static Class compileJoinPointAndAttachToClassLoader(
040: final CompilationInfo.Model model, final ClassLoader loader) {
041: return attachToClassLoader(model.getJoinPointClassName(),
042: loader, compileJoinPoint(model));
043: }
044:
045: /**
046: * Loads a join point class, one specific class for each distinct join point.
047: *
048: * @param joinpointClassName
049: * @param loader the class loader that the compiled join point should live in
050: * @param bytecode of the joinpoint
051: * @return the compiled join point class
052: */
053: public static Class attachToClassLoader(
054: final String joinpointClassName, final ClassLoader loader,
055: final byte[] bytecode) {
056: return AsmHelper.defineClass(loader, bytecode,
057: joinpointClassName);
058: }
059:
060: /**
061: * Adds or updates a compilation info. The class key is always the first compiled join point class.
062: *
063: * @param clazz
064: * @param compilationInfo
065: */
066: public static void addCompilationInfo(final Class clazz,
067: final CompilationInfo compilationInfo) {
068: COMPILATION_INFO_REPOSITORY.put(clazz, compilationInfo);
069: }
070:
071: /**
072: * Compiles a join point class, one specific class for each distinct join point.
073: *
074: * @param model the model for the compilation
075: * @return the compiled join point bytecode
076: */
077: public static byte[] compileJoinPoint(
078: final CompilationInfo.Model model) {
079: switch (model.getEmittedJoinPoint().getJoinPointType()) {
080: case JoinPointType.METHOD_EXECUTION_INT:
081: return new MethodExecutionJoinPointCompiler(model)
082: .compile();
083: case JoinPointType.METHOD_CALL_INT:
084: return new MethodCallJoinPointCompiler(model).compile();
085: case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
086: return new ConstructorExecutionJoinPointCompiler(model)
087: .compile();
088: case JoinPointType.CONSTRUCTOR_CALL_INT:
089: return new ConstructorCallJoinPointCompiler(model)
090: .compile();
091: case JoinPointType.FIELD_SET_INT:
092: return new FieldSetJoinPointCompiler(model).compile();
093: case JoinPointType.FIELD_GET_INT:
094: return new FieldGetJoinPointCompiler(model).compile();
095: case JoinPointType.HANDLER_INT:
096: return new HandlerJoinPointCompiler(model).compile();
097: case JoinPointType.STATIC_INITIALIZATION_INT:
098: return new StaticInitializationJoinPointCompiler(model)
099: .compile();
100: default:
101: throw new UnsupportedOperationException(
102: "join point type is not supported: "
103: + model.getEmittedJoinPoint()
104: .getJoinPointType());
105: }
106: }
107:
108: /**
109: * Redefines the originally compiled join point.
110: *
111: * @param compilationInfo the model for the compilation
112: * @return the compiled join point bytecode
113: */
114: public static byte[] redefineJoinPoint(
115: final CompilationInfo compilationInfo) {
116: switch (compilationInfo.getInitialModel().getEmittedJoinPoint()
117: .getJoinPointType()) {
118: case JoinPointType.METHOD_EXECUTION_INT:
119: return new MethodExecutionJoinPointRedefiner(
120: compilationInfo).compile();
121: case JoinPointType.METHOD_CALL_INT:
122: return new MethodCallJoinPointRedefiner(compilationInfo)
123: .compile();
124: case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
125: return new ConstructorExecutionJoinPointRedefiner(
126: compilationInfo).compile();
127: case JoinPointType.CONSTRUCTOR_CALL_INT:
128: return new ConstructorCallJoinPointRedefiner(
129: compilationInfo).compile();
130: case JoinPointType.FIELD_SET_INT:
131: return new FieldSetJoinPointRedefiner(compilationInfo)
132: .compile();
133: case JoinPointType.FIELD_GET_INT:
134: return new FieldGetJoinPointRedefiner(compilationInfo)
135: .compile();
136: case JoinPointType.HANDLER_INT:
137: return new HandlerJoinPointRedefiner(compilationInfo)
138: .compile();
139: default:
140: throw new UnsupportedOperationException(
141: "join point type is not supported: "
142: + compilationInfo.getInitialModel()
143: .getEmittedJoinPoint()
144: .getJoinPointType());
145: }
146: }
147:
148: /**
149: * Returns a list with all the join point compilers that matches a specific pointcut expression.
150: * <p/>
151: * To be used for redefinition of the join point compilers only. This since the compilers must have been created
152: * in advance to exist in the repository (which is done when the target class is loaded).
153: *
154: * @param expression the pointcut expression
155: * @return a set with the matching emitted join point
156: */
157: public static Set getJoinPointsMatching(
158: final ExpressionInfo expression) {
159: final Set matchingJoinPointInfos = new HashSet();
160: for (Iterator it = COMPILATION_INFO_REPOSITORY.entrySet()
161: .iterator(); it.hasNext();) {
162: final Map.Entry entry = (Map.Entry) it.next();
163:
164: final Class clazz = (Class) entry.getKey();
165: final CompilationInfo compilationInfo = (CompilationInfo) entry
166: .getValue();
167: final EmittedJoinPoint joinPoint = (EmittedJoinPoint) compilationInfo
168: .getInitialModel().getEmittedJoinPoint();
169: final ClassLoader loader = clazz.getClassLoader();
170:
171: final ClassInfo calleeClassInfo = AsmClassInfo
172: .getClassInfo(joinPoint.getCalleeClassName(),
173: loader);
174: final ClassInfo callerClassInfo = AsmClassInfo
175: .getClassInfo(joinPoint.getCallerClassName(),
176: loader);
177: final MethodInfo callerMethodInfo = getCallerMethodInfo(
178: callerClassInfo, joinPoint);
179:
180: ExpressionContext ctx = null;
181: switch (joinPoint.getJoinPointType()) {
182: case JoinPointType.METHOD_EXECUTION_INT:
183: ctx = new ExpressionContext(PointcutType.EXECUTION,
184: calleeClassInfo.getMethod(joinPoint
185: .getJoinPointHash()), callerMethodInfo);
186: break;
187: case JoinPointType.METHOD_CALL_INT:
188: ctx = new ExpressionContext(PointcutType.CALL,
189: calleeClassInfo.getMethod(joinPoint
190: .getJoinPointHash()), callerMethodInfo);
191: break;
192: case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
193: ctx = new ExpressionContext(PointcutType.EXECUTION,
194: calleeClassInfo.getConstructor(joinPoint
195: .getJoinPointHash()), callerMethodInfo);
196: break;
197: case JoinPointType.CONSTRUCTOR_CALL_INT:
198: ctx = new ExpressionContext(PointcutType.CALL,
199: calleeClassInfo.getConstructor(joinPoint
200: .getJoinPointHash()), callerMethodInfo);
201: break;
202: case JoinPointType.FIELD_SET_INT:
203: ctx = new ExpressionContext(PointcutType.SET,
204: calleeClassInfo.getField(joinPoint
205: .getJoinPointHash()), callerMethodInfo);
206: break;
207: case JoinPointType.FIELD_GET_INT:
208: ctx = new ExpressionContext(PointcutType.GET,
209: calleeClassInfo.getField(joinPoint
210: .getJoinPointHash()), callerMethodInfo);
211: break;
212: case JoinPointType.HANDLER_INT:
213: ctx = new ExpressionContext(PointcutType.HANDLER,
214: AsmClassInfo.getClassInfo(joinPoint
215: .getCalleeClassName(), loader),
216: callerMethodInfo);
217: break;
218: case JoinPointType.STATIC_INITIALIZATION_INT:
219: ctx = new ExpressionContext(
220: PointcutType.STATIC_INITIALIZATION,
221: calleeClassInfo.staticInitializer(),
222: calleeClassInfo);
223: }
224: if (expression.getExpression().match(ctx)) {
225: matchingJoinPointInfos.add(new MatchingJoinPointInfo(
226: clazz, compilationInfo, ctx));
227: }
228: }
229: return matchingJoinPointInfos;
230: }
231:
232: /**
233: * Returns the emitted join point structure for a specific JIT generated join point class.
234: *
235: * @param clazz the join point class
236: * @return the emitted join point structure
237: */
238: public static EmittedJoinPoint getEmittedJoinPoint(final Class clazz) {
239: return (EmittedJoinPoint) COMPILATION_INFO_REPOSITORY
240: .get(clazz);
241: }
242:
243: /**
244: * Grabs the caller method info.
245: *
246: * @param callerClassInfo
247: * @param emittedJoinPoint
248: * @return
249: */
250: private static MethodInfo getCallerMethodInfo(
251: final ClassInfo callerClassInfo,
252: final EmittedJoinPoint emittedJoinPoint) {
253: MethodInfo callerMethodInfo = null;
254: MethodInfo[] callerMethods = callerClassInfo.getMethods();
255: for (int i = 0; i < callerMethods.length; i++) {
256: MethodInfo method = callerMethods[i];
257: if (method.getName().equals(
258: emittedJoinPoint.getCallerMethodName())
259: && method.getSignature().equals(
260: emittedJoinPoint.getCallerMethodDesc())) {
261: callerMethodInfo = method;
262: break;
263: }
264: }
265: return callerMethodInfo;
266: }
267: }
|