001: //
002: //This file is part of the prose package.
003: //
004: //The contents of this file are subject to the Mozilla Public License
005: //Version 1.1 (the "License"); you may not use this file except in
006: //compliance with the License. You may obtain a copy of the License at
007: //http://www.mozilla.org/MPL/
008: //
009: //Software distributed under the License is distributed on an "AS IS" basis,
010: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: //for the specific language governing rights and limitations under the
012: //License.
013: //
014: //The Original Code is prose.
015: //
016: // Contributor(s):
017: // $Id$
018: // =====================================================================
019: //
020: //(history at end)
021: //
022:
023: package ch.ethz.inf.iks.jvmai.jvmdi;
024:
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027:
028: import ch.ethz.jvmai.CodeJoinPoint;
029: import ch.ethz.jvmai.JoinPointKinds;
030: import ch.ethz.jvmai.JoinPointStaticPart;
031: import ch.ethz.jvmai.ClassSpecific;
032: import ch.ethz.jvmai.Signature;
033:
034: /**
035: * HotSwap Join Points are join-points that can occur within the
036: * execution of a method. They can be arbitrary points within the
037: * bytecode of a method.
038: *
039: * @author Angela Nicoara
040: * @author Gerald Linhofer
041: * @version $Revision$
042: */
043: public class HotSwapJoinPointImpl implements CodeJoinPoint,
044: JoinPointStaticPart, ClassSpecific, JoinPointKinds {
045:
046: private Signature signature; // set
047: private Object aopTag;
048:
049: //
050: // Type codes for primitive types
051: //
052: protected static final int ARG_TYPE_VOID = -1;
053: // types that need two slots
054: protected static final int ARG_TYPE_OBJECT = 0;
055: protected static final int ARG_TYPE_INT = 1;
056: protected static final int ARG_TYPE_FLOAT = 2;
057: protected static final int ARG_TYPE_BYTE = 3;
058: protected static final int ARG_TYPE_CHAR = 4;
059: protected static final int ARG_TYPE_SHORT = 5;
060: protected static final int ARG_TYPE_BOOLEAN = 6;
061: // types that need two slots
062: protected static final int ARG_TYPE_LONG = 7;
063: protected static final int ARG_TYPE_DOUBLE = 8;
064:
065: // pre allocated arrays to use for args
066: protected Object[][] preAllocatedArgs = new Object[][] {
067: new Object[0], new Object[1], new Object[2], new Object[3],
068: new Object[4], new Object[5] };
069:
070: // pre allocated arrays to use for argTypeCodes
071: protected int[][] preAllocatedCodes = new int[][] { new int[0],
072: new int[1], new int[2], new int[3], new int[4], new int[5] };
073:
074: //
075: // Following private members are used to cache values that
076: // where fetched with a doGet...() method.
077: //
078: /**
079: * Method to which this join point belongs or
080: * <CODE>null</CODE> if not initialized.
081: */
082: protected Method method;
083: /**
084: * Object on which this join point is executed (the class for static methods)
085: * or <CODE>null</CODE> if not initialized.
086: */
087: protected Object target;
088: /**
089: * Bytecode index of the last executed instruction from {@link #method method}
090: * or <CODE>-1</CODE> if not initialized.
091: * For top level join points, this is a call to the advices callback function.
092: */
093: private int byteCodeIndex;
094: /**
095: * Method identifier to which this join point belongs.
096: * (this has nothing to do with JNI jmethodIDs)
097: */
098: protected int methodId;
099: //
100: // argument related fields are not private to allow subclasses
101: // to access them (MethodEntryJoinPoint.setArg()).
102: //
103: /**
104: * Contains the actual parameters of {@link #method method}
105: * if {@link #gotArgs gotArgs} is <CODE>true</CODE>.
106: */
107: protected Object[] args;
108: /**
109: * Contains the classes of the actual parameters of {@link #method method}
110: * if {@link #argTypesInitialized argTypesInitialized} is <CODE>true</CODE>.
111: */
112: protected Class[] argTypes;
113: /**
114: * Contains the type codes of the actual parameters of {@link #method method}
115: * if {@link #argTypesInitialized argTypesInitialized} is <CODE>true</CODE>.
116: */
117: protected int[] argTypeCodes;
118: /**
119: * <CODE>true</CODE> if {@link #args args} is valid.
120: */
121: protected boolean gotArgs;
122: /**
123: * <CODE>true</CODE> if {@link #argTypes argTypes} and
124: * {@link #argTypeCodes argTypeCodes} are valid.
125: */
126: protected boolean argTypesInitialized;
127: /**
128: * 'Height' for enclosing join point. For top level join points this is <CODE>0</CODE>.
129: */
130: protected int height;
131:
132: /**
133: * Constructs an uninitialized <CODE>HotSwapJoinPoint</CODE>
134: * instance. To use it {@link #init} must be called after construction.
135: */
136: public HotSwapJoinPointImpl() {
137: super ();
138:
139: method = null;
140: target = null;
141: args = preAllocatedArgs[0];
142: argTypeCodes = preAllocatedCodes[0];
143: gotArgs = false;
144: argTypesInitialized = false;
145: byteCodeIndex = -1;
146: height = 0;
147: this .signature = new HotSwapSignatureImpl(this );
148: }
149:
150: /**
151: * Constructs an uninitialized <CODE>HotSwapJoinPoint</CODE>
152: * instance. To use it {@link #init} must be called after construction.
153: */
154: public HotSwapJoinPointImpl(Object tag, int height) {
155: super ();
156:
157: method = null;
158: target = null;
159: args = preAllocatedArgs[0];
160: argTypeCodes = preAllocatedCodes[0];
161: gotArgs = false;
162: argTypesInitialized = false;
163: byteCodeIndex = -1;
164: aopTag = tag;
165: this .height = height;
166: this .signature = new HotSwapSignatureImpl(this );
167: }
168:
169: /**
170: * (Re)Initialize this join point.
171: *
172: * @param tag AOP tag associated with this join point
173: */
174: public void init(Object tag) {
175: aopTag = tag;
176: method = null;
177: target = null;
178: gotArgs = false;
179: argTypesInitialized = false;
180: byteCodeIndex = -1;
181: }
182:
183: /**
184: * Returns the method beeing executed
185: * when this joinpoint has been reached. For MethodEntry Join Points
186: * and method exit join points, methods captured statically and
187: * the method being currently executed coincide. Therefore, for such
188: * joinoints, the signature of the method returned by <code>getMethod</code>
189: * and the one returned by <code>getJoinPointStaticPart().getSignature()</code>
190: * are the same. This is not the case with
191: * Exception Throws, catche Field access & modifications join points.
192: *
193: * @return Method
194: * @throws IlligalIdException can not find the stack frame of the 'target'.
195: */
196: public Method getMethod() {
197: if (null == method)
198: method = doGetMethod(Thread.currentThread(), height);
199: return method;
200: }
201:
202: /**
203: * Returns the bytecode index of the last executed instruction from
204: * {@link #method method} or <CODE>-1</CODE> if not initialized.
205: * For top level join points, this is a call to the advices callback function.
206: *
207: * @return index
208: * @throws IlligalIdException can not find the stack frame of the 'target'.
209: */
210: public int getByteCodeIndex() {
211: if (0 > byteCodeIndex)
212: byteCodeIndex = doGetByteCodeIndex(Thread.currentThread(),
213: height);
214: return byteCodeIndex;
215: }
216:
217: /**
218: * Return the enclosing join-point. The enclosing join-point is join-point of the <em>calling frame</em>.
219: * For instance, if <em>a</em> calls <em>b</em> and <em>x</em> is the method entry join point in b,
220: * <em>x.getEnclosingJoinPoint</em> is the point in the execution of the same thread within
221: * <em>a</em>'s frame where the invocation to be is done.
222: * <p>
223: * If if <em>a</em> calls <em>b</em> and within <em>b</em> the join-point <em>y</em> is a field
224: * set join point, then <em>x.getEnclsingJoinPoint()</em> and <em>y.getEnclosingJoinPoint()</em>
225: * denote the same join point within a's frame.
226: *
227: * @return the enclosing JoinPoint.
228: * @throws IlligalIdException can not find the stack frame of the 'target'.
229: */
230: public CodeJoinPoint getEnclosingJoinPoint() {
231: HotSwapJoinPointImpl result = new HotSwapJoinPointImpl(
232: getThis(), height + 1);
233: return result;
234: }
235:
236: /**
237: * Returns a user-defined object. This object has been
238: * supplied during registration of this joinpoint.
239: * @return the user defined object.
240: */
241: public Object getAopTag() {
242: return aopTag;
243: }
244:
245: public String getKind() {
246: return CodeJoinPoint.KIND;
247: }
248:
249: /**
250: * Return the signature of this object
251: */
252: public Signature getSignature() {
253: return signature;
254: }
255:
256: public String toLongString() {
257: return getMethod().toString() + "@" + getByteCodeIndex();
258: }
259:
260: public String toShortString() {
261: return getMethod().toString() + "@" + getByteCodeIndex();
262: }
263:
264: /**
265: * Returns the arguments with that the target method was called.
266: *
267: * @return arguments the method was called with, primitive types
268: * are enclosed in there java types.
269: * @throws IlligalIdException can not find the stack frame of the 'target'.
270: */
271: public Object[] getArgs() {
272: if (gotArgs)
273: return args;
274: if (!argTypesInitialized)
275: initArgTypes();
276:
277: // dont try to get the values, if argument type is 'void'
278: if (0 == args.length)
279: return args;
280:
281: // get argument values
282: int firstSlot = Modifier.isStatic(getMethod().getModifiers()) ? 0
283: : 1;
284: doGetLocalVars(firstSlot, argTypeCodes, args, Thread
285: .currentThread(), height);
286:
287: gotArgs = true;
288: return args;
289: }
290:
291: /**
292: * Returns the object on that this join point is executed or the class for
293: * static methods.
294: *
295: * @return Object
296: * @throws IlligalIdException can not find the stack frame of the 'target'.
297: */
298: public Object getThis() {
299: if (null == target)
300: if (Modifier.isStatic(getMethod().getModifiers()))
301: target = getTargetClass();
302: else
303: // the first parameter passed to a member method is the 'this' pointer.
304: target = doGetLocalVar(0, ARG_TYPE_OBJECT, Thread
305: .currentThread(), height);
306: return target;
307: }
308:
309: /**
310: * Return the target object of this joinpoint.
311: */
312: public Object getTarget() {
313: return getThis();
314: }
315:
316: /**
317: * Returns this object. (just present for jaspect compliance).
318: */
319: public JoinPointStaticPart getStaticPart() {
320: return this ;
321: }
322:
323: /** This method provides information similar to the
324: * AspectJ original getKind. The problem with getKind
325: * is that it works with strings, which is inefficient.
326: * We cannot override getKind -- Java is not
327: * zero-variant on results (at least until 1.4.*).
328: *
329: * @return one of the JoinPointKinds.MASK_XXX integer values
330: */
331: public int getMask() {
332: return JoinPointKinds.MASK_CODE_JP;
333: }
334:
335: /**
336: * Return the Class of the target.
337: * <P><BOLD>
338: * Note: this returns the class of the method, which executed
339: * the join point, if the target is not a method subclasses
340: * have to overwrite this method.
341: * </BOLD>
342: * @return the class that declared the target object.
343: */
344: public Class getTargetClass() {
345: return getMethod().getDeclaringClass();
346: }
347:
348: /**
349: * Returns the type code ({@link #ARG_TYPE_OBJECT}, {@link #ARG_TYPE_INT},
350: * {@link #ARG_TYPE_FLOAT}, {@link #ARG_TYPE_BYTE}, {@link #ARG_TYPE_CHAR},
351: * {@link #ARG_TYPE_SHORT}, {@link #ARG_TYPE_BOOLEAN}, {@link #ARG_TYPE_LONG}
352: * or {@link #ARG_TYPE_DOUBLE} for a given class <CODE>argType</CODE>.
353: *
354: * @param argType
355: * @return code
356: */
357: protected int encodeArgType(Class argType) {
358: int retval;
359:
360: if (!argType.isPrimitive())
361: retval = ARG_TYPE_OBJECT;
362: else if (Integer.TYPE == argType)
363: retval = ARG_TYPE_INT;
364: else if (Long.TYPE == argType)
365: retval = ARG_TYPE_LONG;
366: else if (Boolean.TYPE == argType)
367: retval = ARG_TYPE_BOOLEAN;
368: else if (Float.TYPE == argType)
369: retval = ARG_TYPE_FLOAT;
370: else if (Double.TYPE == argType)
371: retval = ARG_TYPE_DOUBLE;
372: else if (Character.TYPE == argType)
373: retval = ARG_TYPE_CHAR;
374: else if (Byte.TYPE == argType)
375: retval = ARG_TYPE_BYTE;
376: else if (Short.TYPE == argType)
377: retval = ARG_TYPE_SHORT;
378: else if (Void.TYPE == argType)
379: retval = ARG_TYPE_VOID;
380: else {
381: throw new RuntimeException("Unknown primitive type <"
382: + argType.getName() + ">");
383: }
384: return retval;
385: }
386:
387: /**
388: * Internal method: initializes some member fields, required to get or
389: * set arguments.
390: */
391: protected void initArgTypes() {
392: // Get parameter types
393: argTypes = getMethod().getParameterTypes();
394: int argLength = argTypes.length;
395:
396: // Allocate or get arrays for the arguments
397: // and there type codes.
398: if (argTypeCodes.length != argLength)
399: if (5 > argLength) {
400: // use a preallocated array
401: args = preAllocatedArgs[argLength];
402: argTypeCodes = preAllocatedCodes[argLength];
403: } else {
404: // allocate a new array
405: args = new Object[argLength];
406: argTypeCodes = new int[argLength];
407: }
408: // fill argTypeCodes (get encoding for all argument types)
409: for (int i = 0; i < argLength; i++) {
410: argTypeCodes[i] = encodeArgType(argTypes[i]);
411: }
412: argTypesInitialized = true;
413: }
414:
415: /**
416: * Get some local values from the 'caller' (woven method that called the doOn...
417: * callback funtion of {@link ch.ethz.inf.iks.jvmai.jvmdi.AspectInterfaceImpl}).
418: * The values must must follow each other in the local variable table, so this may
419: * for example be used to get the arguments from the 'caller'.
420: * <p>
421: * Note: the class the callback funtion is belonging to is hard coded in the native
422: * part of this class.
423: *
424: * @param slot the first slot used for arguments (0 for static methods 1 otherwise).
425: * @param types array containing type codes for the parameters.
426: * @param vars array that will be filled with the values of the arguments
427: * @param current the current thread (must be the same thread that runs the caller).
428: * @throws IlligalIdException can not find or use the stack frame of the 'target'.
429: */
430: protected native void doGetLocalVars(int slot, int[] types,
431: Object[] vars, Thread current, int height);
432:
433: /**
434: * Get a local value from the 'caller' (woven method that called the doOn...
435: * callback funtion of {@link ch.ethz.inf.iks.jvmai.jvmdi.AspectInterfaceImpl}).
436: * <p>
437: * Note: the class the callback funtion is belonging to is hard coded in the native
438: * part of this class.
439: *
440: * @param slot index of the local variable.
441: * @param type code for the primitive type of the variable.
442: * @param current the current thread (must be the same thread that runs the caller).
443: * @return the value of the local variable.
444: * @throws IlligalIdException can not find the stack frame of the 'target'.
445: */
446: protected native Object doGetLocalVar(int slot, int type,
447: Thread current, int height);
448:
449: /**
450: * Change a local value of the 'caller' (woven method that called the doOn...
451: * callback funtion of {@link ch.ethz.inf.iks.jvmai.jvmdi.AspectInterfaceImpl}).
452: * <p>
453: * Note: the class the callback funtion is belonging to is hard coded in the native
454: * part of this class.
455: *
456: * @param slot index of the local variable.
457: * @param type code for the primitive type of the variable.
458: * @param var the new value of the local variable.
459: * @param current the current thread (must be the same thread that runs the caller).
460: * @throws IlligalIdException can not find the stack frame of the 'target'.
461: */
462: protected native void doSetLocalVar(int slot, int type, Object var,
463: Thread current, int height);
464:
465: /**
466: * Get the bytecode index of the last executed instruction from the method
467: * to that this joint point belongs.
468: *
469: * @param current the current thread (must be the same thread that runs the caller).
470: * @param height
471: * @return bytecode index
472: * @throws IlligalIdException can not find the stack frame of the 'target'.
473: */
474: private native int doGetByteCodeIndex(Thread current, int height);
475:
476: /**
477: * Get the reflected method object of the method excuting this join point.
478: *
479: * @param current the current thread (must be the same thread that runs the caller).
480: * @param height
481: * @return method
482: * @throws IlligalIdException can not find the stack frame of the 'target'.
483: */
484: private native Method doGetMethod(Thread current, int height);
485:
486: /// Returns the names (identifiers) of the local variables of a method from the stack.
487: protected native String[] doGetLocalVariableNames(int slot,
488: int count, Thread current, int height);
489: }
490:
491: //======================================================================
492: //
493: //$Log$
494: //
|