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.compiler;
008:
009: import org.objectweb.asm.CodeVisitor;
010: import org.objectweb.asm.Type;
011:
012: import org.codehaus.aspectwerkz.transform.TransformationUtil;
013: import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
014:
015: import java.lang.reflect.Modifier;
016:
017: /**
018: * A compiler that compiles/generates a class that represents a specific join point, a class which invokes the advices
019: * and the target join point statically.
020: *
021: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
022: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
023: */
024: public class MethodCallJoinPointCompiler extends
025: AbstractJoinPointCompiler {
026:
027: /**
028: * Creates a new join point compiler instance.
029: *
030: * @param model
031: */
032: MethodCallJoinPointCompiler(final CompilationInfo.Model model) {
033: super (model);
034: }
035:
036: /**
037: * Creates join point specific fields.
038: */
039: protected void createJoinPointSpecificFields() {
040: String[] fieldNames = null;
041: // create the method argument fields
042: Type[] argumentTypes = Type
043: .getArgumentTypes(m_calleeMemberDesc);
044: fieldNames = new String[argumentTypes.length];
045: for (int i = 0; i < argumentTypes.length; i++) {
046: Type argumentType = argumentTypes[i];
047: String fieldName = ARGUMENT_FIELD + i;
048: fieldNames[i] = fieldName;
049: m_cw.visitField(ACC_PRIVATE, fieldName, argumentType
050: .getDescriptor(), null, null);
051: }
052: m_fieldNames = fieldNames;
053:
054: m_cw.visitField(ACC_PRIVATE + ACC_STATIC, SIGNATURE_FIELD_NAME,
055: METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE, null, null);
056: }
057:
058: /**
059: * Creates the signature for the join point.
060: * <p/>
061: * FIXME signature field should NOT be of type Signature but of the specific type (update all refs as well)
062: *
063: * @param cv
064: */
065: protected void createSignature(final CodeVisitor cv) {
066: cv.visitFieldInsn(GETSTATIC, m_joinPointClassName,
067: TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
068: cv.visitLdcInsn(new Integer(m_joinPointHash));
069:
070: cv.visitMethodInsn(INVOKESTATIC, SIGNATURE_FACTORY_CLASS,
071: NEW_METHOD_SIGNATURE_METHOD_NAME,
072: NEW_METHOD_SIGNATURE_METHOD_SIGNATURE);
073: cv.visitFieldInsn(PUTSTATIC, m_joinPointClassName,
074: SIGNATURE_FIELD_NAME,
075: METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE);
076:
077: }
078:
079: /**
080: * Optimized implementation that does not retrieve the parameters from the join point instance but is passed
081: * directly to the method from the input parameters in the 'invoke' method. Can only be used if no around advice
082: * exists.
083: *
084: * @param cv
085: * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
086: */
087: protected void createInlinedJoinPointInvocation(
088: final CodeVisitor cv, final boolean isOptimizedJoinPoint,
089: final int argStartIndex, final int joinPointIndex) {
090:
091: // load the target instance (arg0 else not available for static target)
092: if (!Modifier.isStatic(m_calleeMemberModifiers)) {
093: cv.visitVarInsn(ALOAD, 0);
094: }
095:
096: String joinPointName = null; // can be prefixed
097:
098: loadArgumentMemberFields(cv, argStartIndex);
099:
100: // call the package protected wrapper method if target method is not public
101: if (!Modifier.isPublic(m_calleeMemberModifiers)) {
102: joinPointName = TransformationUtil.getWrapperMethodName(
103: m_calleeMemberName, m_calleeMemberDesc,
104: m_calleeClassName, INVOKE_WRAPPER_METHOD_PREFIX);
105: } else {
106: joinPointName = m_calleeMemberName;
107: }
108: // FIXME - pbly broken if we are using a wrapper method - refactor this if / else
109: if (Modifier.isStatic(m_calleeMemberModifiers)) {
110: cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName,
111: joinPointName, m_calleeMemberDesc);
112: } else if (isInvokeInterface(m_calleeMemberModifiers)) {
113: // AW-253
114: cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName,
115: joinPointName, m_calleeMemberDesc);
116: } else {
117: cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName,
118: joinPointName, m_calleeMemberDesc);
119: }
120: }
121:
122: /**
123: * Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
124: * local join point instance.
125: *
126: * @param cv
127: */
128: protected void createJoinPointInvocation(final CodeVisitor cv) {
129:
130: // load the target instance member field unless calleeMember is static
131: if (!Modifier.isStatic(m_calleeMemberModifiers)) {
132: cv.visitVarInsn(ALOAD, 0);
133: cv.visitFieldInsn(GETFIELD, m_joinPointClassName,
134: CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
135: }
136:
137: String joinPointName;
138: loadArguments(cv);
139: if (!Modifier.isPublic(m_calleeMemberModifiers)) {
140: joinPointName = TransformationUtil.getWrapperMethodName(
141: m_calleeMemberName, m_calleeMemberDesc,
142: m_calleeClassName, INVOKE_WRAPPER_METHOD_PREFIX);
143: } else {
144: joinPointName = m_calleeMemberName;
145: }
146: // FIXME - pbly broken if we are using a wrapper method - refactor this if / else
147: if (Modifier.isStatic(m_calleeMemberModifiers)) {
148: cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName,
149: joinPointName, m_calleeMemberDesc);
150: } else if (isInvokeInterface(m_calleeMemberModifiers)) {
151: // AW-253
152: cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName,
153: joinPointName, m_calleeMemberDesc);
154: } else {
155: cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName,
156: joinPointName, m_calleeMemberDesc);
157: }
158: }
159:
160: /**
161: * Returns the join points return type.
162: *
163: * @return
164: */
165: protected Type getJoinPointReturnType() {
166: return Type.getReturnType(m_calleeMemberDesc);
167: }
168:
169: /**
170: * Returns the join points argument type(s).
171: *
172: * @return
173: */
174: protected Type[] getJoinPointArgumentTypes() {
175: return Type.getArgumentTypes(m_calleeMemberDesc);
176: }
177:
178: /**
179: * Creates the getRtti method
180: */
181: protected void createGetRttiMethod() {
182: CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC,
183: GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null,
184: null);
185:
186: // new MethodRttiImpl( .. )
187: cv.visitTypeInsn(NEW, METHOD_RTTI_IMPL_CLASS_NAME);
188: cv.visitInsn(DUP);
189: cv.visitFieldInsn(GETSTATIC, m_joinPointClassName,
190: SIGNATURE_FIELD_NAME,
191: METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE);
192: cv.visitVarInsn(ALOAD, 0);
193: cv.visitFieldInsn(GETFIELD, m_joinPointClassName,
194: CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
195: cv.visitVarInsn(ALOAD, 0);
196: cv.visitFieldInsn(GETFIELD, m_joinPointClassName,
197: CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
198: cv.visitMethodInsn(INVOKESPECIAL, METHOD_RTTI_IMPL_CLASS_NAME,
199: INIT_METHOD_NAME, METHOD_RTTI_IMPL_INIT_SIGNATURE);
200:
201: // set the arguments
202: cv.visitInsn(DUP);
203: createArgumentArrayAt(cv, 1);
204: cv.visitVarInsn(ALOAD, 1);
205: cv.visitMethodInsn(INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME,
206: SET_PARAMETER_VALUES_METHOD_NAME,
207: SET_PARAMETER_VALUES_METHOD_SIGNATURE);
208:
209: // set the Returned instance
210: if (m_returnType.getSort() != Type.VOID) {
211: cv.visitInsn(DUP);
212: if (AsmHelper.isPrimitive(m_returnType)) {
213: AsmHelper.prepareWrappingOfPrimitiveType(cv,
214: m_returnType);
215: cv.visitVarInsn(ALOAD, 0);
216: cv.visitFieldInsn(GETFIELD, m_joinPointClassName,
217: RETURN_VALUE_FIELD_NAME, m_returnType
218: .getDescriptor());
219: AsmHelper.wrapPrimitiveType(cv, m_returnType);
220: } else {
221: cv.visitVarInsn(ALOAD, 0);
222: cv.visitFieldInsn(GETFIELD, m_joinPointClassName,
223: RETURN_VALUE_FIELD_NAME, m_returnType
224: .getDescriptor());
225: }
226: cv.visitMethodInsn(INVOKEVIRTUAL,
227: METHOD_RTTI_IMPL_CLASS_NAME,
228: SET_RETURN_VALUE_METHOD_NAME,
229: SET_RETURN_VALUE_METHOD_SIGNATURE);
230: }
231:
232: cv.visitInsn(ARETURN);
233: cv.visitMaxs(0, 0);
234: }
235:
236: /**
237: * Creates the getSignature method.
238: */
239: protected void createGetSignatureMethod() {
240: CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC,
241: GET_SIGNATURE_METHOD_NAME,
242: GET_SIGNATURE_METHOD_SIGNATURE, null, null);
243:
244: cv.visitFieldInsn(GETSTATIC, m_joinPointClassName,
245: SIGNATURE_FIELD_NAME,
246: METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE);
247: cv.visitInsn(ARETURN);
248: cv.visitMaxs(0, 0);
249: }
250:
251: /**
252: * See AW-253
253: * For INVOKE INTERFACE, we are using a custom modifier to track it down in order to avoid to do the
254: * hierarchy resolution ourself here
255: */
256: private boolean isInvokeInterface(int modifier) {
257: return (modifier & MODIFIER_INVOKEINTERFACE) != 0;
258: }
259: }
|