001: //
002: // Copyright (C) 2005 United States Government as represented by the
003: // Administrator of the National Aeronautics and Space Administration
004: // (NASA). All Rights Reserved.
005: //
006: // This software is distributed under the NASA Open Source Agreement
007: // (NOSA), version 1.3. The NOSA has been approved by the Open Source
008: // Initiative. See the file NOSA-1.3-JPF at the top of the distribution
009: // directory tree for the complete NOSA document.
010: //
011: // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
012: // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
013: // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
014: // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
015: // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
016: // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
017: // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
018: //
019: package gov.nasa.jpf.jvm;
020:
021: import gov.nasa.jpf.JPFException;
022: import gov.nasa.jpf.jvm.bytecode.Instruction;
023: import gov.nasa.jpf.util.Debug;
024: import gov.nasa.jpf.util.HashData;
025:
026: import java.util.Random;
027:
028: import org.apache.bcel.Constants;
029:
030: /**
031: * Describes a stack frame.
032: *
033: * implementation is based on the fact that each Java method has a fixed size
034: * operand stack (overrun actually checked by a real VM), and the heuristics that
035: * (a) stack / local operations are frequent
036: * (b) stack / local sizes are typically small (both < 10)
037: * hence a BitSet is not too useful
038: */
039: public class StackFrame implements Constants {
040: /**
041: * Used for random choices.
042: */
043: private static Random random = new Random();
044:
045: /** top index of the operand stack (NOT size) */
046: int top;
047:
048: /** since the 'this' local slot apparently can change during execution, we need to keep
049: * track of it elsewhere
050: */
051: int this Ref = -1;
052:
053: /** the operand stack (untyped, except of ref/no-ref) */
054: int[] operands;
055: boolean[] isOperandRef;
056:
057: /** This array can be used to store attributes (e.g. variable names) for
058: * operands. We don't do anything with this except of preserving it (across
059: * dups etc.), so it's pretty much up to the VM listeners what's stored
060: */
061: Object[] operandAttr;
062:
063: /**
064: * Local variables.
065: */
066: int[] locals;
067: boolean[] isLocalRef;
068:
069: /**
070: * Program counter.
071: */
072: private Instruction pc;
073:
074: /**
075: * Method being executed.
076: */
077: private MethodInfo mi;
078:
079: /**
080: * this is set to true if this method was directly called by the VM, i.e. there is
081: * no corresponding INVOKE instruction
082: */
083: private boolean isDirectCall;
084:
085: /**
086: * Creates a new stack frame for a given method.
087: * 'isDirect' specifies if this method was called directly by the VM, i.e. there is
088: * no corresponding INVOKE insn in the underlying stack frame (for instance, that's
089: * important to know for handling return values and computing the next pc)
090: * 'caller' is the calling stack frame (if any)
091: */
092: public StackFrame(MethodInfo m, boolean isDirect, StackFrame caller) {
093: mi = m;
094: pc = mi.getInstruction(0);
095:
096: int nOperands = mi.getMaxStack();
097: operands = new int[nOperands];
098: isOperandRef = new boolean[nOperands];
099: operandAttr = new Object[nOperands];
100: top = -1; // index, not size!
101:
102: int nargs = mi.getArgumentsSize();
103: int nlocals = (pc == null) ? nargs : mi.getMaxLocals();
104: locals = new int[nlocals];
105: isLocalRef = new boolean[nlocals];
106:
107: isDirectCall = isDirect;
108:
109: // copy the args, if any
110: if (nargs > 0 && (caller != null)) {
111: int[] a = caller.operands;
112: boolean[] r = caller.isOperandRef;
113:
114: for (int i = 0, j = caller.top - nargs + 1; i < nargs; i++, j++) {
115: locals[i] = a[j];
116: isLocalRef[i] = r[j];
117: }
118:
119: if (!mi.isStatic()) { // according to the spec, this is guaranteed upon entry
120: this Ref = locals[0];
121: }
122: }
123: }
124:
125: public StackFrame(MethodInfo m, boolean isDirect, int objRef) {
126: this (m, isDirect, null);
127:
128: // maybe we should check here if this is an instance method
129:
130: this Ref = objRef;
131:
132: locals[0] = this Ref;
133: isLocalRef[0] = true;
134: }
135:
136: /**
137: * Creates an empty stack frame. Used by clone.
138: */
139: private StackFrame() {
140: }
141:
142: public boolean isDirectCall() {
143: return isDirectCall;
144: }
145:
146: /**
147: * return the object reference for an instance method to be called (we are still in the
148: * caller's frame). This only makes sense after all params have been pushed, before the
149: * INVOKEx insn is executed
150: */
151: public int getCalleeThis(MethodInfo mi) {
152: return getCalleeThis(mi.getArgumentsSize());
153: }
154:
155: /**
156: * return reference of called object in the context of the caller
157: * (i.e. we are in the caller frame)
158: */
159: public int getCalleeThis(int size) {
160: // top is the topmost index
161: int i = size - 1;
162: if (top < i) {
163: return -1;
164: }
165:
166: return operands[top - i];
167: }
168:
169: public ClassInfo getClassInfo() {
170: return mi.getClassInfo();
171: }
172:
173: // gets and sets some derived information
174: public int getLine() {
175: return mi.getLineNumber(pc);
176: }
177:
178: public void setOperandAttr(Object o) {
179: operandAttr[top] = o;
180: }
181:
182: public Object getOperandAttr() {
183: if (top >= 0) {
184: return operandAttr[top];
185: } else {
186: return null;
187: }
188: }
189:
190: public Object getOperandAttr(int offset) {
191: if (top >= offset) {
192: return operandAttr[top - offset];
193: } else {
194: return null;
195: }
196: }
197:
198: public void setLocalVariable(int index, int v, boolean ref) {
199: boolean activateGc = (isLocalRef[index] && (locals[index] != -1));
200:
201: locals[index] = v;
202: isLocalRef[index] = ref;
203:
204: if (ref) {
205: if (v != -1)
206: activateGc = true;
207: }
208:
209: if (activateGc) {
210: JVM.getVM().getSystemState().activateGC();
211: }
212: }
213:
214: public int getLocalVariable(int i) {
215: return locals[i];
216: }
217:
218: public int getLocalVariable(String name) {
219: return getLocalVariable(getLocalVariableOffset(name));
220: }
221:
222: public String[] getLocalVariableNames() {
223: return mi.getLocalVariableNames();
224: }
225:
226: public boolean isLocalVariableRef(int idx) {
227: return isLocalRef[idx];
228: }
229:
230: public String getLocalVariableType(String name) {
231: String[] lNames = mi.getLocalVariableNames();
232: String[] lTypes = mi.getLocalVariableTypes();
233:
234: if ((lNames != null) && (lTypes != null)) {
235: for (int i = 0, l = lNames.length; i < l; i++) {
236: if (name.equals(lNames[i])) {
237: return lTypes[i];
238: }
239: }
240: }
241:
242: throw new JPFException("Local variable " + name + " not found");
243: }
244:
245: public int[] getLocalVariables() {
246: return locals;
247: }
248:
249: public void setLongLocalVariable(int index, long v) {
250:
251: // local slots shouldn't change type, and 'long' can't be a reference,
252: // hence no isLocalRef update or gc request
253:
254: locals[index + 1] = Types.loLong(v);
255: locals[index] = Types.hiLong(v);
256: }
257:
258: public long getLongLocalVariable(int i) {
259: return Types.intsToLong(locals[i + 1], locals[i]);
260: }
261:
262: public long getLongLocalVariable(String name) {
263: return getLongLocalVariable(getLocalVariableOffset(name));
264: }
265:
266: public MethodInfo getMethodInfo() {
267: return mi;
268: }
269:
270: public String getMethodName() {
271: return mi.getName();
272: }
273:
274: public boolean isOperandRef(int idx) {
275: return isOperandRef[top - idx];
276: }
277:
278: public boolean isOperandRef() {
279: return isOperandRef[top];
280: }
281:
282: public void setPC(Instruction newpc) {
283: pc = newpc;
284: }
285:
286: public Instruction getPC() {
287: return pc;
288: }
289:
290: public String getStackTrace() {
291: StringBuffer sb = new StringBuffer(128);
292: sb.append("\tat ");
293: sb.append(mi.getClassInfo().getName());
294: sb.append(".");
295: sb.append(mi.getName());
296:
297: if (pc != null) {
298: sb.append("(");
299: sb.append(mi.getClassInfo().getSourceFileName());
300: sb.append(":");
301: sb.append(getLine());
302: sb.append(")");
303: } else {
304: sb.append("(Native Method)");
305: }
306: //sb.append('\n');
307:
308: return sb.toString();
309: }
310:
311: /**
312: * if this is an instance method, return the reference of the corresponding object
313: * (note this only has to be in slot 0 upon entry)
314: */
315: public int getThis() {
316: return this Ref;
317: }
318:
319: // stack operations
320: public void clearOperandStack() {
321: top = -1;
322: }
323:
324: // functions to handle exceptions
325: // creates a clone of the stack frame
326: public Object clone() {
327: StackFrame sf = new StackFrame();
328:
329: sf.operands = new int[operands.length];
330: System.arraycopy(operands, 0, sf.operands, 0, top + 1);
331:
332: sf.isOperandRef = new boolean[operands.length];
333: System.arraycopy(isOperandRef, 0, sf.isOperandRef, 0, top + 1);
334:
335: sf.operandAttr = new Object[operands.length];
336: System.arraycopy(operandAttr, 0, sf.operandAttr, 0, top + 1);
337:
338: sf.top = top;
339:
340: sf.locals = new int[locals.length];
341: System.arraycopy(locals, 0, sf.locals, 0, locals.length);
342:
343: sf.isLocalRef = new boolean[locals.length];
344: System
345: .arraycopy(isLocalRef, 0, sf.isLocalRef, 0,
346: locals.length);
347:
348: sf.pc = pc;
349: sf.mi = mi;
350:
351: sf.isDirectCall = isDirectCall;
352: sf.this Ref = this Ref;
353:
354: return sf;
355: }
356:
357: // all the dupses don't have any GC side effect (everything is already
358: // on the stack), so skip the GC requests associated with push()/pop()
359:
360: public void dup() {
361: // .. A => .. A.A
362: int t = top;
363: top++;
364:
365: operands[top] = operands[t];
366: isOperandRef[top] = isOperandRef[t];
367: operandAttr[top] = operandAttr[t];
368: }
369:
370: public void dup2() {
371: // .. A B => .. A B.A B
372: int td = top + 1;
373: int ts = top - 1;
374: operands[td] = operands[ts];
375: isOperandRef[td] = isOperandRef[ts];
376: operandAttr[td] = operandAttr[ts];
377:
378: td++;
379: ts++;
380: operands[td] = operands[ts];
381: isOperandRef[td] = isOperandRef[ts];
382: operandAttr[td] = operandAttr[ts];
383:
384: top = td;
385: }
386:
387: public void dup2_x1() {
388: // .. A B C => .. B C A.B C
389:
390: int b, c;
391: boolean bRef, cRef;
392: Object bAnn, cAnn;
393: int ts, td;
394:
395: // duplicate B
396: ts = top - 1;
397: td = top + 1;
398: operands[td] = b = operands[ts];
399: isOperandRef[td] = bRef = isOperandRef[ts];
400: operandAttr[td] = bAnn = operandAttr[ts];
401:
402: // duplicate C
403: ts = top;
404: td++;
405: operands[td] = c = operands[ts];
406: isOperandRef[td] = cRef = isOperandRef[ts];
407: operandAttr[td] = cAnn = operandAttr[ts];
408:
409: // shuffle A
410: ts = top - 2;
411: td = top;
412: operands[td] = operands[ts];
413: isOperandRef[td] = isOperandRef[ts];
414: operandAttr[td] = operandAttr[ts];
415:
416: // shuffle B
417: td = ts;
418: operands[td] = b;
419: isOperandRef[td] = bRef;
420: operandAttr[td] = bAnn;
421:
422: // shuffle C
423: td++;
424: operands[td] = c;
425: isOperandRef[td] = cRef;
426: operandAttr[td] = cAnn;
427:
428: top += 2;
429: }
430:
431: public void dup2_x2() {
432: // .. A B C D => .. C D A B.C D
433:
434: int c, d;
435: boolean cRef, dRef;
436: Object cAnn, dAnn;
437: int ts, td;
438:
439: // duplicate C
440: ts = top - 1;
441: td = top + 1;
442: operands[td] = c = operands[ts];
443: isOperandRef[td] = cRef = isOperandRef[ts];
444: operandAttr[td] = cAnn = operandAttr[ts];
445:
446: // duplicate D
447: ts = top;
448: td++;
449: operands[td] = d = operands[ts];
450: isOperandRef[td] = dRef = isOperandRef[ts];
451: operandAttr[td] = dAnn = operandAttr[ts];
452:
453: // shuffle A
454: ts = top - 3;
455: td = top - 1;
456: operands[td] = operands[ts];
457: isOperandRef[td] = isOperandRef[ts];
458: operandAttr[td] = operandAttr[ts];
459:
460: // shuffle B
461: ts++;
462: td = top;
463: operands[td] = operands[ts];
464: isOperandRef[td] = isOperandRef[ts];
465: operandAttr[td] = operandAttr[ts];
466:
467: // shuffle C
468: td = ts;
469: operands[td] = c;
470: isOperandRef[td] = cRef;
471: operandAttr[td] = cAnn;
472:
473: // shuffle C
474: td++;
475: operands[td] = d;
476: isOperandRef[td] = dRef;
477: operandAttr[td] = dAnn;
478:
479: top += 2;
480: }
481:
482: public void dup_x1() {
483: // .. A B => .. B A.B
484:
485: int b;
486: boolean bRef;
487: Object bAnn;
488: int ts, td;
489:
490: // duplicate B
491: ts = top;
492: td = top + 1;
493: operands[td] = b = operands[ts];
494: isOperandRef[td] = bRef = isOperandRef[ts];
495: operandAttr[td] = bAnn = operandAttr[ts];
496:
497: // shuffle A
498: ts = top - 1;
499: td = top;
500: operands[td] = operands[ts];
501: isOperandRef[td] = isOperandRef[ts];
502: operandAttr[td] = operandAttr[ts];
503:
504: // shuffle B
505: td = ts;
506: operands[td] = b;
507: isOperandRef[td] = bRef;
508: operandAttr[td] = bAnn;
509:
510: top++;
511: }
512:
513: public void dup_x2() {
514: // .. A B C => .. C A B.C
515:
516: int c;
517: boolean cRef;
518: Object cAnn;
519: int ts, td;
520:
521: // duplicate C
522: ts = top;
523: td = top + 1;
524: operands[td] = c = operands[ts];
525: isOperandRef[td] = cRef = isOperandRef[ts];
526: operandAttr[td] = cAnn = operandAttr[ts];
527:
528: // shuffle B
529: ts = top - 1;
530: td = top;
531: operands[td] = operands[ts];
532: isOperandRef[td] = isOperandRef[ts];
533: operandAttr[td] = operandAttr[ts];
534:
535: // shuffle A
536: td = ts;
537: ts--;
538: operands[td] = operands[ts];
539: isOperandRef[td] = isOperandRef[ts];
540: operandAttr[td] = operandAttr[ts];
541:
542: // shuffle C
543: td = ts;
544: operands[td] = c;
545: isOperandRef[td] = cRef;
546: operandAttr[td] = cAnn;
547:
548: top++;
549: }
550:
551: // <2do> pcm - I assume this compares snapshots, not types. Otherwise it
552: // would be pointless to compare stack/local values
553: public boolean equals(Object object) {
554: // casts to stack frame
555: StackFrame sf = (StackFrame) object;
556:
557: // compares the program counter REFERENCES
558: // the code is statically read into the vm so the same
559: // chunk of code means the same reference
560: if (pc != sf.pc) {
561: return false;
562: }
563:
564: if (mi != sf.mi) {
565: return false;
566: }
567:
568: // compare the locals
569: int[] l = sf.locals;
570: boolean[] lr = sf.isLocalRef;
571: int nlocals = locals.length;
572:
573: if (nlocals != l.length) {
574: return false;
575: }
576: for (int idx = 0; idx < nlocals; idx++) {
577: if ((locals[idx] != l[idx]) || (isLocalRef[idx] != lr[idx])) {
578: return false;
579: }
580: }
581:
582: // compare the operand stacks
583: int[] o = sf.operands;
584: boolean[] or = sf.isOperandRef;
585:
586: if (top != sf.top) {
587: return false;
588: }
589: for (int idx = 0; idx <= top; idx++) {
590: if ((operands[idx] != o[idx])
591: || (isOperandRef[idx] != or[idx])) {
592: return false;
593: }
594: }
595:
596: return true;
597: }
598:
599: public boolean hasAnyRef() {
600: for (int i = 0; i <= top; i++) {
601: if (isOperandRef[i]) {
602: return true;
603: }
604: }
605:
606: for (int i = 0, l = locals.length; i < l; i++) {
607: if (isLocalRef[i]) {
608: return true;
609: }
610: }
611:
612: return false;
613: }
614:
615: public void hash(HashData hd) {
616: for (int i = 0, l = locals.length; i < l; i++) {
617: hd.add(locals[i]);
618: }
619:
620: for (int i = 0; i <= top; i++) {
621: hd.add(operands[i]);
622: }
623: }
624:
625: // computes an hash code for the hash table
626: // the default hash code is different for each object
627: // we need to redifine it to make the hash table work
628: public int hashCode() {
629: HashData hd = new HashData();
630:
631: hash(hd);
632:
633: return hd.getValue();
634: }
635:
636: public void log(int id) {
637: Debug.print(Debug.MESSAGE, " SF#" + id + " S(");
638:
639: for (int i = 0; i <= top; i++) {
640: Debug.print(Debug.MESSAGE, " ");
641:
642: if (isOperandRef[i]) {
643: Debug.print(Debug.MESSAGE, "#");
644: }
645:
646: Debug.print(Debug.MESSAGE, operands[i] + "");
647: }
648:
649: Debug.print(Debug.MESSAGE, " ) L(");
650:
651: for (int i = 0; i < locals.length; i++) {
652: int j = locals[i];
653: Debug.print(Debug.MESSAGE, " ");
654:
655: if (isLocalRef[i]) {
656: Debug.print(Debug.MESSAGE, "#");
657: }
658:
659: Debug.print(Debug.MESSAGE, j + "");
660: }
661:
662: Debug.print(Debug.MESSAGE, " ) ");
663:
664: if (mi == null) {
665: Debug.print(Debug.MESSAGE, "null");
666: } else {
667: Debug.print(Debug.MESSAGE, mi.getCompleteName());
668: }
669:
670: Debug.print(Debug.MESSAGE, ":");
671:
672: if (pc == null) {
673: Debug.println(Debug.MESSAGE, "null");
674: } else {
675: Debug.println(Debug.MESSAGE, pc.getPosition() + " " + pc);
676: }
677: }
678:
679: /**
680: * mark all objects reachable from local or operand stack positions containing
681: * references. Done during phase1 marking of threads (the stack is one of the
682: * Thread gc roots)
683: * @aspects: gc
684: */
685: public void markThreadRoots(int tid) {
686: DynamicArea heap = DynamicArea.getHeap();
687: int objRef;
688:
689: for (int i = 0; i <= top; i++) {
690: if (isOperandRef[i]) {
691: heap.markThreadRoot(operands[i], tid);
692: }
693: }
694:
695: for (int i = 0, l = locals.length; i < l; i++) {
696: if (isLocalRef[i]) {
697: heap.markThreadRoot(locals[i], tid);
698: }
699: }
700: }
701:
702: public void printStackContent() {
703: Debug.print(Debug.ERROR, "\tat ");
704: Debug.print(Debug.ERROR, mi.getCompleteName());
705:
706: if (pc != null) {
707: Debug.println(Debug.ERROR, ":" + pc.getPosition());
708: } else {
709: Debug.println(Debug.ERROR);
710: }
711:
712: Debug.println(Debug.ERROR, "\t Operand stack is:");
713:
714: for (int i = 0; i <= top; i++) {
715: Debug.print(Debug.ERROR, "\t ");
716:
717: if (isOperandRef[i]) {
718: Debug.print(Debug.ERROR, "#");
719: }
720:
721: Debug.println(Debug.ERROR, operands[i]);
722: }
723:
724: Debug.println(Debug.ERROR, "\t Local variables are:");
725:
726: for (int i = 0, l = locals.length; i < l; i++) {
727: Debug.print(Debug.ERROR, "\t ");
728:
729: if (isLocalRef[i]) {
730: Debug.print(Debug.ERROR, "#");
731: }
732:
733: Debug.println(Debug.ERROR, "" + locals[i]);
734: }
735: }
736:
737: public void printStackTrace() {
738: Debug.println(Debug.ERROR, getStackTrace());
739: }
740:
741: public void swap() {
742: int t = top - 1;
743: int v = operands[top];
744: boolean isRef = isOperandRef[top];
745: Object a = operandAttr[top];
746:
747: operands[top] = operands[t];
748: isOperandRef[top] = isOperandRef[t];
749: operandAttr[top] = operandAttr[t];
750:
751: operands[t] = v;
752: isOperandRef[t] = isRef;
753: operandAttr[t] = a;
754: }
755:
756: public String toString() {
757: StringBuffer sb = new StringBuffer();
758:
759: sb.append("StackFrame(");
760: sb.append("top=");
761: sb.append(top);
762: sb.append("operands=");
763: sb.append('[');
764:
765: for (int i = 0; i <= top; i++) {
766: if (i != 0) {
767: sb.append(',');
768: }
769:
770: sb.append(operands[i]);
771: if (operandAttr[i] != null) {
772: sb.append('(');
773: sb.append(operandAttr[i]);
774: sb.append(')');
775: }
776: }
777:
778: sb.append(']');
779: sb.append(',');
780: sb.append("locals=");
781: sb.append('[');
782:
783: for (int i = 0; i < locals.length; i++) {
784: if (i != 0) {
785: sb.append(',');
786: }
787:
788: sb.append(locals[i]);
789: }
790:
791: sb.append(']');
792: sb.append(',');
793: sb.append("pc=");
794: sb.append(pc.getPosition());
795: sb.append(',');
796: sb.append("oRefs=");
797:
798: for (int i = 0; i <= top; i++) {
799: sb.append(isOperandRef[i] ? 'R' : '-');
800: }
801:
802: sb.append(',');
803: sb.append("lRefs=");
804:
805: for (int i = 0; i < locals.length; i++) {
806: sb.append(isLocalRef[i] ? 'R' : '-');
807: }
808:
809: sb.append(')');
810:
811: return sb.toString();
812: }
813:
814: long longPeek() {
815: return Types.intsToLong(operands[top], operands[top - 1]);
816: }
817:
818: long longPeek(int n) {
819: int i = top - n;
820: return Types.intsToLong(operands[i], operands[i - 1]);
821: }
822:
823: long longPop() {
824: int lo = pop();
825: int hi = pop();
826:
827: return Types.intsToLong(lo, hi);
828: }
829:
830: void longPush(long v) {
831: push(Types.hiLong(v), false);
832: push(Types.loLong(v), false);
833: }
834:
835: int peek() {
836: return operands[top];
837: }
838:
839: int peek(int n) {
840: return operands[top - n];
841: }
842:
843: void pop(int n) {
844: int t = top - n;
845: for (int i = top; i > t; i--) {
846: if (isOperandRef[i] && (operands[i] != -1)) {
847: JVM.getVM().getSystemState().activateGC();
848: break;
849: }
850: }
851:
852: top = t;
853: }
854:
855: int pop() {
856: int v = operands[top];
857:
858: if (isOperandRef[top]) {
859: if (v != -1) {
860: JVM.getVM().getSystemState().activateGC();
861: }
862: }
863: top--;
864:
865: // note that we don't reset the operands or oRefs values, so that
866: // we can still access them after the insn doing the pop got executed
867: // (e.g. useful for listeners)
868:
869: return v;
870: }
871:
872: void push(int v, boolean ref) {
873: top++;
874: operands[top] = v;
875: isOperandRef[top] = ref;
876: operandAttr[top] = null;
877:
878: if (ref && (v != -1)) {
879: JVM.getVM().getSystemState().activateGC();
880: }
881: }
882:
883: // return the value of a variable given the name
884: private int getLocalVariableOffset(String name) {
885: String[] lNames = mi.getLocalVariableNames();
886: String[] lTypes = mi.getLocalVariableTypes();
887:
888: int offset = 0;
889:
890: for (int i = 0, l = lNames.length; i < l; i++) {
891: if (name.equals(lNames[i])) {
892: return offset;
893: } else {
894: offset += Types.getTypeSize(lTypes[i]);
895: }
896: }
897:
898: throw new JPFException("Local variable " + name + " not found");
899: }
900:
901: }
|