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: // The Initial Developer of the Original Code is Andrei Popovici. Portions
017: // created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
018: // All Rights Reserved.
019: //
020: // Contributor(s):
021: // $Id: JoinPointContext.java,v 1.1.1.1 2003/07/02 15:30:50 apopovic Exp $
022: // =====================================================================
023: //
024: // (history at end)
025: //
026:
027: package ch.ethz.inf.iks.jvmai.jvmdi;
028:
029: import java.lang.reflect.Modifier;
030: import java.lang.reflect.Method;
031:
032: /**
033: * Class JoinPointContext encapsulates local variable info. Because various
034: * types of join-points (Field Access, Field Modififcattion, Method Entry, Exit)
035: * have to have access to local variables, this functionality has been
036: * <em>delegated</em> to JoinPointContext (as opposed to being
037: * <em>inherited</em> from some root object.
038: *
039: * @version $Revision: 1.1.1.1 $
040: * @author Andrei Popovici
041: */
042: public class JoinPointContext {
043: private static int UNDEFINED_DEPTH = -1;
044:
045: protected Thread thread; // immutable
046: protected JoinPointLocation location; // immutable
047: protected int depth; // mutable
048: protected int height; // mutable
049:
050: private int state; // mutable
051: private static int SLOT_THIS_OBJ;
052: private static int STATE_GOT_NOTHING = 0x0;
053: private static int STATE_GOT_ARGS = 0x02;
054: private static int STATE_GOT_THIS = 0x01;
055: private static int STATE_GOT_INFO = 0x04;
056:
057: private Object this Object;
058: private Object[] argValues;
059: private Class[] argTypes;
060: private String[] argNames;
061: private int[] argSlots;
062:
063: protected JoinPointContext() {
064: this (Thread.currentThread(), UNDEFINED_DEPTH, 0);
065: }
066:
067: private JoinPointContext(Thread t, int dpth, int hght) {
068: this .location = new JoinPointLocation();
069: this .depth = dpth;
070: this .height = hght; // fix for JRE 1.4.0, where 'depth' is not correclty computed on jvmdi.
071: this .thread = t;
072: this .state = 0;
073: }
074:
075: protected JoinPointContext callerContext() {
076: JoinPointContext newContext = new JoinPointContext(thread,
077: depth - 1, height + 1);
078: doGetCallerLocationData(newContext.location, thread, depth - 1,
079: height + 1);
080: return newContext;
081: }
082:
083: protected void invalidate() {
084: state = 0;
085: location.executingMethod = null;
086: }
087:
088: protected boolean isValid() {
089: return location.executingMethod == null;
090: }
091:
092: protected Object[] getArgs() {
093: if ((state & STATE_GOT_ARGS) != 0)
094: return argValues;
095:
096: doGetLocalVariableInfo();
097:
098: for (int i = 0; i < argValues.length; i++)
099: argValues[i] = getLocalValue(argTypes[i], argSlots[i]);
100:
101: state |= STATE_GOT_ARGS;
102: return argValues;
103:
104: }
105:
106: protected Object getThis() {
107: if ((state & STATE_GOT_THIS) != 0)
108: return this Object;
109:
110: if ((location.executingMethod.getModifiers() & Modifier.STATIC) != 0)
111: this Object = null;
112: else
113: this Object = getLocalValue(java.lang.Object.class, 0);
114:
115: state |= STATE_GOT_THIS;
116: return this Object;
117: }
118:
119: protected String[] getParameterNames() {
120: doGetLocalVariableInfo();
121: return argNames;
122: }
123:
124: private Object[][] preAllocatedArgs = new Object[][] {
125: new Object[0], new Object[1], new Object[2], new Object[3],
126: new Object[4], new Object[5] };
127:
128: private int[][] preAllocatedSlots = new int[][] { new int[0],
129: new int[1], new int[2], new int[3], new int[4], new int[5] };
130:
131: private String[][] preAllocatedNames = new String[][] {
132: new String[0], new String[1], new String[2], new String[3],
133: new String[4], new String[5] };
134:
135: private void doGetLocalVariableInfo() {
136: if ((state & STATE_GOT_INFO) != 0)
137: return;
138:
139: // allocate or reuse parameters
140: argTypes = location.executingMethod.getParameterTypes();
141: if (argTypes.length < 5) {
142: argValues = preAllocatedArgs[argTypes.length];
143: argSlots = preAllocatedSlots[argTypes.length];
144: argNames = preAllocatedNames[argTypes.length];
145: } else {
146: argValues = new Object[argTypes.length];
147: argSlots = new int[argTypes.length];
148: argNames = new String[argTypes.length];
149: }
150:
151: try {
152:
153: // call the Vm to obtain the parameters
154: doGetLocalVariables(thread, location.executingMethod,
155: location.executingMethod.getDeclaringClass(),
156: argNames, argSlots);
157: } catch (AbsentInformationException e) {
158: // no debugger info, we compute the offsets ourselves
159: int slot = 0;
160: if ((location.executingMethod.getModifiers() & Modifier.STATIC) == 0)
161: slot++;
162:
163: for (int i = 0; i < argTypes.length; i++) {
164: argNames[i] = null;
165: argSlots[i] = slot;
166: if (Double.class.isAssignableFrom(argTypes[i])
167: || Long.class.isAssignableFrom(argTypes[i]))
168: slot += 2;
169: else
170: slot += 1;
171: }
172: }
173: state |= STATE_GOT_INFO;
174: }
175:
176: /*
177: * Set the local value in thread t, frameNumber frames up from frameId,
178: * located in the frame at slot index, to the value v.
179: *
180: * @throws StackFrameException if the frame is opaque (e.g., native)
181: * @throws InternalValueException if the frameId does not exist in
182: * this vm or the slot index is out of range
183: * @throws ProseVmException for a type mismatch
184: */
185: protected void setLocalValue(Object v, int index)
186: throws ClassCastException {
187: doGetLocalVariableInfo();
188: Class cls = argTypes[index];
189: Thread crtThread = thread;
190: if (cls.isAssignableFrom(Boolean.TYPE)) {
191: setLocalBoolean(crtThread, depth, height, argSlots[index],
192: ((Boolean) v).booleanValue());
193: return;
194: }
195: if (cls.isAssignableFrom(Byte.TYPE)) {
196: setLocalInt(crtThread, depth, height, argSlots[index],
197: ((Byte) v).byteValue());
198: return;
199: }
200:
201: if (cls.isAssignableFrom(Character.TYPE)) {
202: setLocalInt(crtThread, depth, height, argSlots[index],
203: ((Character) v).charValue());
204: return;
205: }
206:
207: if (cls.isAssignableFrom(Short.TYPE)) {
208: setLocalInt(crtThread, depth, height, argSlots[index],
209: ((Short) v).shortValue());
210: return;
211: }
212:
213: if (cls.isAssignableFrom(Integer.TYPE)) {
214: setLocalInt(crtThread, depth, height, argSlots[index],
215: ((Integer) v).intValue());
216: return;
217: }
218:
219: if (cls.isAssignableFrom(Long.TYPE)) {
220: setLocalLong(crtThread, depth, height, argSlots[index],
221: ((Long) v).longValue());
222: return;
223: }
224: if (cls.isAssignableFrom(Double.TYPE)) {
225: setLocalDouble(crtThread, depth, height, argSlots[index],
226: ((Double) v).doubleValue());
227: return;
228: }
229:
230: if (cls.isAssignableFrom(Float.TYPE)) {
231: setLocalFloat(crtThread, depth, height, argSlots[index],
232: ((Float) v).floatValue());
233: return;
234: }
235:
236: setLocalObject(crtThread, depth, height, argSlots[index], v);
237: }
238:
239: /*
240: * @throws StackFrameException if the frame is opaque (e.g., native)
241: * @throws InternalValueException if the frameId does not exist in
242: * this vm or the slot index is out of range
243: * @throws ProseVmException for a type mismatch, if the signature
244: * does not correspond to the variable in the slot.
245: */
246:
247: protected Object getLocalValue(Class cls, int slot) {
248: Thread crtThread = thread;
249:
250: if (cls.isAssignableFrom(Boolean.TYPE)) {
251: return getLocalBoolean(crtThread, depth, height, slot) ? Boolean.TRUE
252: : Boolean.FALSE;
253: }
254:
255: if (cls.isAssignableFrom(Byte.TYPE))
256: return new Byte((byte) getLocalInt(crtThread, depth,
257: height, slot));
258:
259: if (cls.isAssignableFrom(Character.TYPE))
260: return new Character((char) getLocalInt(crtThread, depth,
261: height, slot));
262:
263: if (cls.isAssignableFrom(Short.TYPE))
264: return new Short((short) getLocalInt(crtThread, depth,
265: height, slot));
266:
267: if (cls.isAssignableFrom(Integer.TYPE))
268: return new Integer((int) getLocalInt(crtThread, depth,
269: height, slot));
270:
271: if (cls.isAssignableFrom(Long.TYPE))
272: return new Long((int) getLocalLong(crtThread, depth,
273: height, slot));
274:
275: if (cls.isAssignableFrom(Double.TYPE))
276: return new Double((int) getLocalDouble(crtThread, depth,
277: height, slot));
278:
279: if (cls.isAssignableFrom(Float.TYPE))
280: return new Float(getLocalFloat(crtThread, depth, height,
281: slot));
282:
283: return getLocalObject(crtThread, depth, height, slot);
284:
285: }
286:
287: private static native void doGetLocalVariables(Thread t,
288: Method meth, Class cls, String[] aNames, int[] aSlots);
289:
290: /** FOR all 'getLocalXXX':Return the value in the stack of the
291: * thread <code>t</code>, located at slot <code>slot</code> in the
292: * stackframe <code>height</code> stackframes away (up) from the
293: * currently executing join point and <code>depth</code> stackframes
294: * down from the top of the stack.
295: */
296: private static native Object getLocalObject(Thread t, int depth,
297: int height, int slot);
298:
299: private static native int getLocalInt(Thread t, int depth,
300: int height, int slot);
301:
302: private static native byte getLocalByte(Thread t, int depth,
303: int height, int slot);
304:
305: private static native char getLocalChar(Thread t, int depth,
306: int height, int slot);
307:
308: private static native short getLocalShort(Thread t, int depth,
309: int height, int slot);
310:
311: private static native long getLocalLong(Thread t, int depth,
312: int height, int slot);
313:
314: private static native boolean getLocalBoolean(Thread t, int depth,
315: int height, int slot);
316:
317: private static native double getLocalDouble(Thread t, int depth,
318: int height, int slot);
319:
320: private static native float getLocalFloat(Thread t, int depth,
321: int height, int slot);
322:
323: private static native void setLocalObject(Thread t, int depth,
324: int height, int slot, Object value);
325:
326: private static native void setLocalInt(Thread t, int depth,
327: int height, int slot, int value);
328:
329: private static native void setLocalLong(Thread t, int depth,
330: int height, int slot, long value);
331:
332: private static native void setLocalBoolean(Thread t, int depth,
333: int height, int slot, boolean value);
334:
335: /** Set the value in the stack of the thread <code>t</code>, located at slot <code>slot</code>
336: * in the stackframe <code>frameNum</code> stackframes away (up) from the <code>baseFrame</code>.
337: */
338: private static native void setLocalDouble(Thread t, int depth,
339: int height, int slot, double value);
340:
341: /** Set the value in the stack of the thread <code>t</code>, located at slot <code>slot</code>
342: * in the stackframe <code>frameNum</code> stackframes away (up) from the <code>baseFrame</code>.
343: */
344: private static native void setLocalFloat(Thread t, int depth,
345: int height, int slot, float value);
346:
347: private native void doGetCallerLocationData(JoinPointLocation jpl,
348: Thread t, int depth, int height);
349:
350: }
351:
352: //======================================================================
353: //
354: // $Log: JoinPointContext.java,v $
355: // Revision 1.1.1.1 2003/07/02 15:30:50 apopovic
356: // Imported from ETH Zurich
357: //
358: // Revision 1.6 2003/05/06 15:51:16 popovici
359: // Mozilla-ification
360: //
361: // Revision 1.5 2003/05/05 17:46:26 popovici
362: // Refactorization step (runes->prose) cleanup
363: //
364: // Revision 1.4 2003/04/30 14:46:33 popovici
365: // 2 Bugs: when reading Floats from the stack, we used to get a local int instead of a local float.
366: // Second: when writing to the stack, we used to write in the wrong slot
367: //
368: // Revision 1.3 2003/03/13 12:46:30 popovici
369: // Bug fix in the extraction of slot offsets. The non-native solution
370: // (computing offsets) was inverting static and non-static cases
371: //
372: // Revision 1.2 2003/03/04 16:09:36 popovici
373: // Documentation improvements
374: //
375: // Revision 1.1 2003/03/04 11:26:41 popovici
376: // Important refactorization step (march):
377: // - removal of 'JoinPointEvents'; JoinPoints now have the same function as events
378: // - reimplementation of the JVMAIDebuggerAspectInterface (better performance, coding conventions, removal of ProseVM
379: // structures
380: //
|