2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.JPFException;
21 import gov.nasa.jpf.util.BitSetN;
22 import gov.nasa.jpf.util.BitSet1024;
23 import gov.nasa.jpf.util.BitSet256;
24 import gov.nasa.jpf.util.BitSet64;
25 import gov.nasa.jpf.util.FixedBitSet;
26 import gov.nasa.jpf.util.HashData;
27 import gov.nasa.jpf.util.Misc;
28 import gov.nasa.jpf.util.OATHash;
29 import gov.nasa.jpf.util.ObjectList;
30 import gov.nasa.jpf.util.PrintUtils;
31 import gov.nasa.jpf.vm.bytecode.InvokeInstruction;
33 import java.io.PrintStream;
34 import java.io.PrintWriter;
35 import java.io.StringWriter;
36 import java.util.Iterator;
40 * Describes callerSlots stack frame.
42 * Java methods always have bounded local and operand stack sizes, computed
43 * at compile time, stored in the classfile, and checked at runtime by the
44 * bytecode verifier. Consequently, we combine locals and operands in one
45 * data structure with the following layout
49 * slot[stackBase-1] : last local var
50 * slot[stackBase] : first operand slot
52 * .. | operand stack range
54 * slot[top] : highest used operand slot
57 public abstract class StackFrame implements Cloneable {
60 * this StackFrame is not allowed to be modified anymore because it has been state stored.
61 * Set during state storage and checked upon each modification, causing exceptions on attempts
62 * to modify callerSlots frozen instance. The flag is reset in clones
64 public static final int ATTR_IS_FROZEN = 0x100;
65 static final int ATTR_IS_REFLECTION = 0x1000;
67 * the previous StackFrame (usually the caller, null if first). To be set when
68 * the frame is pushed on the ThreadInfo callstack
70 protected StackFrame prev;
73 * state management related attributes similar to ElementInfo. The lower 16 bits
74 * are stored/restored, the upper 16 bits are for transient use
76 protected int attributes;
79 protected int top; // top index of the operand stack (NOT size)
80 // this points to the last pushed value
82 protected int thisRef = MJIEnv.NULL; // slots[0] can change, but we have to keep 'this'
83 protected int stackBase; // index where the operand stack begins
85 protected int[] slots; // the combined local and operand slots
86 protected FixedBitSet isRef; // which slots contain references
88 protected Object frameAttr; // optional user attrs for the whole frame
91 * This array can be used to store attributes (e.g. variable names) for
92 * operands. We don't do anything with this except of preserving it (across
93 * dups etc.), so it's pretty much up to the VM listeners/peers what's stored
95 * NOTE: attribute values are not restored upon backtracking per default, but
96 * attribute references are. If you need restoration of values, use copy-on-write
99 * these are set on demand
101 protected Object[] attrs = null; // the combined user-defined callerSlots (set on demand)
103 protected Instruction pc; // the next insn to execute (program counter)
104 protected MethodInfo mi; // which method is executed in this frame
106 static final int[] EMPTY_ARRAY = new int[0];
107 static final FixedBitSet EMPTY_BITSET = new BitSet64();
109 protected StackFrame (MethodInfo callee, int nLocals, int nOperands){
111 pc = mi.getInstruction(0);
116 int nSlots = nLocals + nOperands;
118 slots = new int[nLocals + nOperands];
119 isRef = createReferenceMap(slots.length);
121 // NativeStackFrames don't use locals or operands, but we
122 // don't want to add tests to all our methods
124 isRef = EMPTY_BITSET;
128 public StackFrame (MethodInfo callee){
129 this( callee, callee.getMaxLocals(), callee.getMaxStack());
135 * Creates an empty stack frame. Used by clone.
137 protected StackFrame () {
141 * creates callerSlots dummy Stackframe for testing of operand/local operations
142 * NOTE - TESTING ONLY! this does not have a MethodInfo
144 protected StackFrame (int nLocals, int nOperands){
146 slots = new int[nLocals + nOperands];
147 isRef = createReferenceMap(slots.length);
148 top = nLocals-1; // index, not size!
152 * re-execute method from the beginning - use with care
154 public void reset() {
155 pc = mi.getInstruction(0);
160 protected FixedBitSet createReferenceMap (int nSlots){
162 return new BitSet64();
163 } else if (nSlots <= 256){
164 return new BitSet256();
165 } else if (nSlots <= 1024) {
166 return new BitSet1024();
168 return new BitSetN(nSlots);
172 public boolean isNative() {
176 public StackFrame getCallerFrame (){
177 MethodInfo callee = mi;
178 for (StackFrame frame = getPrevious(); frame != null; frame = frame.getPrevious()){
179 Instruction insn = frame.getPC();
180 if (insn instanceof InvokeInstruction){
181 InvokeInstruction call = (InvokeInstruction)insn;
182 if (call.getInvokedMethod() == callee){
192 * return the object reference for an instance method to be called (we are still in the
193 * caller's frame). This only makes sense after all params have been pushed, before the
194 * INVOKEx insn is executed
196 public int getCalleeThis (MethodInfo mi) {
197 return getCalleeThis(mi.getArgumentsSize());
201 * return reference of called object in the context of the caller
202 * (i.e. we are in the caller frame)
204 public int getCalleeThis (int size) {
205 // top is the topmost index
214 public StackFrame getPrevious() {
219 * to be set (by ThreadInfo) when the frame is pushed. Can also be used
220 * for non-local gotos, but be warned - that's tricky
222 public void setPrevious (StackFrame frame){
226 public Object getLocalOrFieldValue (String id) {
228 LocalVarInfo lv = mi.getLocalVar(id, pc.getPosition());
230 return getLocalValueObject(lv);
234 return getFieldValue(id);
237 public Object getLocalValueObject (LocalVarInfo lv) {
238 if (lv != null) { // might not have been compiled with debug info
239 String sig = lv.getSignature();
240 int slotIdx = lv.getSlotIndex();
241 int v = slots[slotIdx];
243 switch (sig.charAt(0)) {
245 return Boolean.valueOf(v != 0);
247 return new Byte((byte) v);
249 return new Character((char) v);
251 return new Short((short) v);
253 return new Integer(v);
255 return new Long(Types.intsToLong(slots[slotIdx + 1], v)); // Java is big endian, Types expects low,high
257 return new Float(Float.intBitsToFloat(v));
259 return new Double(Double.longBitsToDouble(Types.intsToLong(slots[slotIdx + 1], v)));
260 default: // reference
262 return VM.getVM().getHeap().get(v);
270 public Object getFieldValue (String id) {
271 // try instance fields first
272 if (thisRef != MJIEnv.NULL) { // it's an instance method
273 ElementInfo ei = VM.getVM().getHeap().get(thisRef);
274 Object v = ei.getFieldValueObject(id);
280 // check static fields (in method class and its superclasses)
281 return mi.getClassInfo().getStaticFieldValueObject(id);
284 public ClassInfo getClassInfo () {
285 return mi.getClassInfo();
288 public String getClassName () {
289 return mi.getClassInfo().getName();
292 public String getSourceFile () {
293 return mi.getClassInfo().getSourceFileName();
297 * does any of the 'nTopSlots' hold callerSlots reference value of 'objRef'
298 * 'nTopSlots' is usually obtained from MethodInfo.getNumberOfCallerStackSlots()
300 public boolean includesReferenceOperand (int nTopSlots, int objRef){
302 for (int i=0, j=top-nTopSlots+1; i<nTopSlots && j>=0; i++, j++) {
303 if (isRef.get(j) && (slots[j] == objRef)){
312 * does any of the operand slots hold callerSlots reference value of 'objRef'
314 public boolean includesReferenceOperand (int objRef){
316 for (int i=stackBase; i<=top; i++) {
317 if (isRef.get(i) && (slots[i] == objRef)){
326 * is this StackFrame modifying the KernelState
327 * this is true unless this is callerSlots NativeStackFrame
329 public boolean modifiesState() {
333 public boolean isDirectCallFrame () {
337 public boolean isSynthetic() {
341 // gets and sets some derived information
342 public int getLine () {
343 return mi.getLineNumber(pc);
348 * generic visitor for reference arguments
350 public void processRefArguments (MethodInfo miCallee, ReferenceProcessor visitor){
351 int nArgSlots = miCallee.getArgumentsSize();
353 for (int i=top-1; i>=top-nArgSlots; i--){
355 visitor.processReference(slots[i]);
360 public int getSlot(int idx){
363 public boolean isReferenceSlot(int idx){
364 return isRef.get(idx);
368 public void setOperand (int offset, int v, boolean isRefValue){
371 isRef.set(i, isRefValue);
375 //----------------------------- various attribute accessors
377 public boolean hasAttrs () {
378 return attrs != null;
381 public boolean hasFrameAttr(){
382 return frameAttr != null;
385 public boolean hasFrameAttr (Class<?> attrType){
386 return ObjectList.containsType(frameAttr, attrType);
389 public boolean hasFrameAttrValue (Object a){
390 return ObjectList.contains(frameAttr, a);
393 //--- the frame attr accessors
396 * this returns all of them - use either if you know there will be only
397 * one attribute at callerSlots time, or check/process result with ObjectList
399 public Object getFrameAttr(){
404 * this replaces all of them - use only if you know there are no
405 * SystemAttributes in the list (which would cause an exception)
407 public void setFrameAttr (Object attr){
408 frameAttr = ObjectList.set(frameAttr, attr);
411 public void addFrameAttr (Object attr){
412 frameAttr = ObjectList.add(frameAttr, attr);
415 public void removeFrameAttr (Object attr){
416 frameAttr = ObjectList.remove(frameAttr, attr);
419 public void replaceFrameAttr (Object oldAttr, Object newAttr){
420 frameAttr = ObjectList.replace(frameAttr, oldAttr, newAttr);
424 * this only returns the first attr of this type, there can be more
425 * if you don't use client private types or the provided type is too general
427 public <T> T getFrameAttr (Class<T> attrType) {
428 return ObjectList.getFirst(frameAttr, attrType);
431 public <T> T getAndResetFrameAttr (Class<T> attrType) {
432 T attr = ObjectList.getFirst(frameAttr, attrType);
434 frameAttr = ObjectList.remove(frameAttr, attr);
440 public <T> T getNextFrameAttr (Class<T> attrType, Object prev) {
441 return ObjectList.getNext(frameAttr, attrType, prev);
444 public ObjectList.Iterator frameAttrIterator(){
445 return ObjectList.iterator(frameAttr);
448 public <T> ObjectList.TypedIterator<T> frameAttrIterator(Class<T> attrType){
449 return ObjectList.typedIterator(frameAttr, attrType);
452 //--- the top single-slot operand attrs
454 public boolean hasOperandAttr(){
455 if ((top >= stackBase) && (attrs != null)){
456 return (attrs[top] != null);
460 public boolean hasOperandAttr(Class<?> type){
461 if ((top >= stackBase) && (attrs != null)){
462 return ObjectList.containsType(attrs[top], type);
468 * this returns all of them - use either if you know there will be only
469 * one attribute at callerSlots time, or check/process result with ObjectList
471 public Object getOperandAttr () {
472 if ((top >= stackBase) && (attrs != null)){
479 * this replaces all of them - use only if you know
480 * - there will be only one attribute at callerSlots time
481 * - you obtained the value you set by callerSlots previous getXAttr()
482 * - you constructed callerSlots multi value list with ObjectList.createList()
484 public void setOperandAttr (Object a){
485 assert (top >= stackBase);
487 if (a == null) return;
488 attrs = new Object[slots.length];
495 * this only returns the first attr of this type, there can be more
496 * if you don't use client private types or the provided type is too general
498 public <T> T getOperandAttr (Class<T> attrType){
499 assert (top >= stackBase);
501 if ((attrs != null)){
502 return ObjectList.getFirst(attrs[top], attrType);
506 public <T> T getNextOperandAttr (Class<T> attrType, Object prev){
507 assert (top >= stackBase);
509 return ObjectList.getNext( attrs[top], attrType, prev);
513 public Iterator operandAttrIterator(){
514 assert (top >= stackBase);
515 Object a = (attrs != null) ? attrs[top] : null;
516 return ObjectList.iterator(a);
518 public <T> Iterator<T> operandAttrIterator(Class<T> attrType){
519 assert (top >= stackBase);
520 Object a = (attrs != null) ? attrs[top] : null;
521 return ObjectList.typedIterator(a, attrType);
525 public void addOperandAttr (Object a){
526 assert (top >= stackBase);
529 attrs = new Object[slots.length];
532 attrs[top] = ObjectList.add(attrs[top], a);
536 public void removeOperandAttr (Object a){
537 assert (top >= stackBase) && (a != null);
539 attrs[top] = ObjectList.remove(attrs[top], a);
543 public void replaceOperandAttr (Object oldAttr, Object newAttr){
544 assert (top >= stackBase) && (oldAttr != null) && (newAttr != null);
546 attrs[top] = ObjectList.replace(attrs[top], oldAttr, newAttr);
551 //--- offset operand attrs
553 public boolean hasOperandAttr(int offset){
555 assert (i >= stackBase);
557 return (attrs[i] != null);
561 public boolean hasOperandAttr(int offset, Class<?> type){
563 assert (i >= stackBase);
565 return ObjectList.containsType(attrs[i], type);
571 * this returns all of them - use either if you know there will be only
572 * one attribute at callerSlots time, or check/process result with ObjectList
574 public Object getOperandAttr (int offset) {
576 assert (i >= stackBase);
585 * this replaces all of them - use only if you know
586 * - there will be only one attribute at callerSlots time
587 * - you obtained the value you set by callerSlots previous getXAttr()
588 * - you constructed callerSlots multi value list with ObjectList.createList()
590 public void setOperandAttr (int offset, Object a){
592 assert (i >= stackBase);
595 if (a == null) return;
596 attrs = new Object[slots.length];
602 * this only returns the first attr of this type, there can be more
603 * if you don't use client private types or the provided type is too general
605 public <T> T getOperandAttr (int offset, Class<T> attrType){
607 assert (i >= stackBase) : this;
609 return ObjectList.getFirst(attrs[i], attrType);
613 public <T> T getNextOperandAttr (int offset, Class<T> attrType, Object prev){
615 assert (i >= stackBase);
617 return ObjectList.getNext( attrs[i], attrType, prev);
621 public ObjectList.Iterator operandAttrIterator(int offset){
623 assert (i >= stackBase);
624 Object a = (attrs != null) ? attrs[i] : null;
625 return ObjectList.iterator(a);
627 public <T> ObjectList.TypedIterator<T> operandAttrIterator(int offset, Class<T> attrType){
629 assert (i >= stackBase);
630 Object a = (attrs != null) ? attrs[i] : null;
631 return ObjectList.typedIterator(a, attrType);
635 public void addOperandAttr (int offset, Object a){
637 assert (i >= stackBase);
641 attrs = new Object[slots.length];
643 attrs[i] = ObjectList.add(attrs[i],a);
647 public void removeOperandAttr (int offset, Object a){
649 assert (i >= stackBase) && (a != null);
651 attrs[i] = ObjectList.remove(attrs[i], a);
655 public void replaceOperandAttr (int offset, Object oldAttr, Object newAttr){
657 assert (i >= stackBase) && (oldAttr != null) && (newAttr != null);
659 attrs[i] = ObjectList.replace(attrs[i], oldAttr, newAttr);
664 //--- top double-slot operand attrs
665 // we store attributes for double slot values at the local var index,
666 // which is the lower one. The ..LongOperand.. APIs are handling this offset
668 public boolean hasLongOperandAttr(){
669 return hasOperandAttr(1);
671 public boolean hasLongOperandAttr(Class<?> type){
672 return hasOperandAttr(1, type);
676 * this returns all of them - use either if you know there will be only
677 * one attribute at callerSlots time, or check/process result with ObjectList
679 public Object getLongOperandAttr () {
680 return getOperandAttr(1);
684 * this replaces all of them - use only if you know
685 * - there will be only one attribute at callerSlots time
686 * - you obtained the value you set by callerSlots previous getXAttr()
687 * - you constructed callerSlots multi value list with ObjectList.createList()
689 public void setLongOperandAttr (Object a){
690 setOperandAttr(1, a);
694 * this only returns the first attr of this type, there can be more
695 * if you don't use client private types or the provided type is too general
697 public <T> T getLongOperandAttr (Class<T> attrType) {
698 return getOperandAttr(1, attrType);
700 public <T> T getNextLongOperandAttr (Class<T> attrType, Object prev) {
701 return getNextOperandAttr(1, attrType, prev);
703 public ObjectList.Iterator longOperandAttrIterator(){
704 return operandAttrIterator(1);
706 public <T> ObjectList.TypedIterator<T> longOperandAttrIterator(Class<T> attrType){
707 return operandAttrIterator(1, attrType);
710 public void addLongOperandAttr (Object a){
711 addOperandAttr(1, a);
714 public void removeLongOperandAttr (Object a){
715 removeOperandAttr(1, a);
718 public void replaceLongOperandAttr (Object oldAttr, Object newAttr){
719 replaceOperandAttr(1, oldAttr, newAttr);
724 // single- or double-slot - you have to provide the var index anyways)
726 public boolean hasLocalAttr(int index){
727 assert index < stackBase;
729 return (attrs[index] != null);
733 public boolean hasLocalAttr(int index, Class<?> type){
734 assert index < stackBase;
736 return ObjectList.containsType(attrs[index], type);
742 * this returns all of them - use either if you know there will be only
743 * one attribute at callerSlots time, or check/process result with ObjectList
745 public Object getLocalAttr (int index){
746 assert index < stackBase;
753 public Object getLongLocalAttr (int index){
754 return getLocalAttr( index);
758 * this replaces all of them - use only if you know
759 * - there will be only one attribute at callerSlots time
760 * - you obtained the value you set by callerSlots previous getXAttr()
761 * - you constructed callerSlots multi value list with ObjectList.createList()
763 public void setLocalAttr (int index, Object a) {
764 assert index < stackBase;
766 if (a == null) return;
767 attrs = new Object[slots.length];
772 public void setLongLocalAttr (int index, Object a){
773 setLocalAttr( index, a);
776 public void addLongLocalAttr (int index, Object a){
777 addLocalAttr( index, a);
781 * this only returns the first attr of this type, there can be more
782 * if you don't use client private types or the provided type is too general
784 public <T> T getLocalAttr (int index, Class<T> attrType){
785 assert index < stackBase;
787 return ObjectList.getFirst( attrs[index], attrType);
791 public <T> T getNextLocalAttr (int index, Class<T> attrType, Object prev){
792 assert index < stackBase;
794 return ObjectList.getNext( attrs[index], attrType, prev);
798 public ObjectList.Iterator localAttrIterator(int index){
799 assert index < stackBase;
800 Object a = (attrs != null) ? attrs[index] : null;
801 return ObjectList.iterator(a);
803 public <T> ObjectList.TypedIterator<T> localAttrIterator(int index, Class<T> attrType){
804 assert index < stackBase;
805 Object a = (attrs != null) ? attrs[index] : null;
806 return ObjectList.typedIterator(a, attrType);
810 public void addLocalAttr (int index, Object attr){
811 assert index < stackBase;
813 if (attr == null) return;
814 attrs = new Object[slots.length];
816 attrs[index] = ObjectList.add(attrs[index], attr);
819 public void removeLocalAttr (int index, Object attr){
820 assert index < stackBase && attr != null;
822 attrs[index] = ObjectList.remove(attrs[index], attr);
826 public void replaceLocalAttr (int index, Object oldAttr, Object newAttr){
827 assert index < stackBase && oldAttr != null && newAttr != null;
829 attrs[index] = ObjectList.replace(attrs[index], oldAttr, newAttr);
833 //--- various special attr accessors
836 * helper to quickly find out if any of the locals slots holds
837 * an attribute of the provided type
839 * @param attrType type of attribute to look for
840 * @param startIdx local index to start from
841 * @return index of local slot with attribute, -1 if none found
843 public int getLocalAttrIndex (Class<?> attrType, int startIdx){
845 for (int i=startIdx; i<stackBase; i++){
847 if (ObjectList.containsType(a, attrType)){
856 // <2do> this is machine dependent since it uses the operand stack. Only here because there
857 // is no suitable place to factor this out between xStackFrame, xNativeStackFrame and xDirectCallStackFrame
858 // (another example of missing multiple inheritance)
859 // Needs to be overridden for Dalvik
862 * this retrieves the argument values from the caller, i.e. the previous stackframe
864 * references are returned as ElementInfos or null
865 * primitive values are returned as box objects (e.g. int -> Integer)
867 public Object[] getArgumentValues (ThreadInfo ti){
868 StackFrame callerFrame = getCallerFrame();
869 if (callerFrame != null){
870 return callerFrame.getCallArguments(ti);
872 // <2do> what about main(String[] args) ?
879 * get the arguments of the executed call
880 * Note - this throws an exception if the StackFrame pc is not an InvokeInstruction
882 public Object[] getCallArguments (ThreadInfo ti){
883 if (pc == null || !(pc instanceof InvokeInstruction)){
884 throw new JPFException("stackframe not executing invoke: " + pc);
887 InvokeInstruction call = (InvokeInstruction) pc;
888 MethodInfo callee = call.getInvokedMethod();
890 byte[] argTypes = callee.getArgumentTypes();
892 return getArgumentsValues(ti, argTypes);
895 public Object[] getArgumentsValues (ThreadInfo ti, byte[] argTypes){
896 int n = argTypes.length;
897 Object[] args = new Object[n];
899 for (int i=n-1, off=0; i>=0; i--) {
900 switch (argTypes[i]) {
902 //case Types.T_OBJECT:
903 case Types.T_REFERENCE:
905 if (ref != MJIEnv.NULL) {
906 args[i] = ti.getElementInfo(ref);
914 args[i] = new Long(peekLong(off));
918 args[i] = new Double(Types.longToDouble(peekLong(off)));
922 case Types.T_BOOLEAN:
923 args[i] = new Boolean(peek(off) != 0);
927 args[i] = new Byte((byte)peek(off));
931 args[i] = new Character((char)peek(off));
935 args[i] = new Short((short)peek(off));
939 args[i] = new Integer(peek(off));
943 args[i] = new Float(Types.intToFloat(peek(off)));
947 // error, unknown argument type
954 * return an array of all argument attrs, which in turn can be lists. If
955 * you have to retrieve values, use the ObjectList APIs
957 * this is here (and not in ThreadInfo) because we might call it
958 * on callerSlots cached/cloned StackFrame (caller stack might be already
959 * modified, e.g. for callerSlots native method).
960 * to be used from listeners.
962 public Object[] getArgumentAttrs (MethodInfo miCallee) {
964 int nArgs = miCallee.getNumberOfArguments();
965 byte[] at = miCallee.getArgumentTypes();
968 if (!miCallee.isStatic()) {
969 a = new Object[nArgs+1];
970 a[0] = getOperandAttr(miCallee.getArgumentsSize()-1);
972 a = new Object[nArgs];
975 for (int i=nArgs-1, off=0, j=a.length-1; i>=0; i--, j--) {
976 byte argType = at[i];
977 if (argType == Types.T_LONG || argType == Types.T_DOUBLE) {
978 a[j] = getOperandAttr(off+1);
981 a[j] = getOperandAttr(off);
994 * check if there is any argument attr of the provided type on the operand stack
995 * this is far more efficient than retrieving attribute values (we don't
996 * care for argument types)
998 public boolean hasArgumentAttr (MethodInfo miCallee, Class<?> attrType){
1000 int nArgSlots = miCallee.getArgumentsSize();
1002 for (int i=0; i<nArgSlots; i++){
1003 Object a = getOperandAttr(i);
1004 if (ObjectList.containsType(a, attrType)){
1013 public boolean hasArgumentObjectAttr (ThreadInfo ti, MethodInfo miCallee, Class<?> type){
1014 int nArgSlots = miCallee.getArgumentsSize();
1015 for (int i=0; i<nArgSlots; i++){
1016 if (isOperandRef(i)){
1017 int objRef = peek(i);
1018 if (objRef != MJIEnv.NULL){
1019 ElementInfo ei = ti.getElementInfo(objRef);
1020 if (ei.getObjectAttr(type) != null) {
1033 public void setLocalReferenceVariable (int index, int ref){
1034 if (slots[index] != MJIEnv.NULL){
1035 VM.getVM().getSystemState().activateGC();
1042 public void setLocalVariable (int index, int v){
1043 // Hmm, should we treat this an error?
1044 if (isRef.get(index) && slots[index] != MJIEnv.NULL){
1045 VM.getVM().getSystemState().activateGC();
1052 public void setFloatLocalVariable (int index, float f){
1053 setLocalVariable( index, Float.floatToIntBits(f));
1056 public void setDoubleLocalVariable (int index, double f){
1057 setLongLocalVariable( index, Double.doubleToLongBits(f));
1061 // <2do> replace with non-ref version
1062 public void setLocalVariable (int index, int v, boolean ref) {
1063 // <2do> activateGc should be replaced by local refChanged
1064 boolean activateGc = ref || (isRef.get(index) && (slots[index] != MJIEnv.NULL));
1067 isRef.set(index,ref);
1070 VM.getVM().getSystemState().activateGC();
1074 public int getLocalVariable (int i) {
1078 public int getLocalVariable (String name) {
1079 int idx = getLocalVariableSlotIndex(name);
1081 return getLocalVariable(idx);
1083 throw new JPFException("local variable not found: " + name);
1087 public int getLocalVariableCount() {
1092 * <2do> - this should return only LocalVarInfo for the current pc
1094 public LocalVarInfo[] getLocalVars () {
1095 return mi.getLocalVars();
1099 public boolean isLocalVariableRef (int idx) {
1100 return isRef.get(idx);
1103 public String getLocalVariableType (String name) {
1104 LocalVarInfo lv = mi.getLocalVar(name, pc.getPosition()+pc.getLength());
1106 return lv.getType();
1112 public String getLocalVariableType (int idx){
1113 LocalVarInfo lv = mi.getLocalVar(idx, pc.getPosition()+pc.getLength());
1115 return lv.getType();
1121 public LocalVarInfo getLocalVarInfo (String name){
1122 return mi.getLocalVar(name, pc.getPosition()+pc.getLength());
1125 public LocalVarInfo getLocalVarInfo (int idx){
1126 return mi.getLocalVar(idx, pc.getPosition()+pc.getLength());
1129 public void setThis (int objRef){
1133 public FixedBitSet getReferenceMap(){
1137 //--- direct slot access - provided for machine-independent clients
1139 public int[] getSlots () {
1140 return slots; // we should probably clone
1142 public Object[] getSlotAttrs(){
1145 public Object getSlotAttr (int i){
1151 public <T> T getSlotAttr (int i, Class<T> attrType){
1153 return ObjectList.getFirst( attrs[i], attrType);
1157 public void setSlotAttr (int i, Object a){
1159 attrs = new Object[slots.length];
1163 public void addSlotAttr (int i, Object a){
1165 if (attrs == null) {
1166 attrs = new Object[slots.length];
1169 attrs[i] = ObjectList.add(attrs[i], a);
1172 public void replaceSlotAttr (int i, Object oldAttr, Object newAttr){
1174 attrs[i] = ObjectList.replace(attrs[i], oldAttr, newAttr);
1180 public void visitReferenceSlots (ReferenceProcessor visitor){
1181 for (int i=isRef.nextSetBit(0); i>=0 && i<=top; i=isRef.nextSetBit(i+1)){
1182 visitor.processReference(slots[i]);
1186 public void setLongLocalVariable (int index, long v) {
1187 // WATCH OUT: apparently, slots can change type, so we have to
1188 // reset the reference flag (happened in JavaSeq)
1190 slots[index] = Types.hiLong(v);
1194 slots[index] = Types.loLong(v);
1198 public long getLongLocalVariable (int idx) {
1199 return Types.intsToLong(slots[idx + 1], slots[idx]);
1202 public double getDoubleLocalVariable (int idx) {
1203 return Types.intsToDouble(slots[idx + 1], slots[idx]);
1206 public float getFloatLocalVariable (int idx) {
1207 int bits = slots[idx];
1208 return Float.intBitsToFloat(bits);
1211 public double getDoubleLocalVariable (String name) {
1212 int idx = getLocalVariableSlotIndex(name);
1214 return getDoubleLocalVariable(idx);
1216 throw new JPFException("long local variable not found: " + name);
1220 public long getLongLocalVariable (String name) {
1221 int idx = getLocalVariableSlotIndex(name);
1224 return getLongLocalVariable(idx);
1226 throw new JPFException("long local variable not found: " + name);
1230 public MethodInfo getMethodInfo () {
1234 public String getMethodName () {
1235 return mi.getName();
1238 public boolean isOperandRef (int offset) {
1239 return isRef.get(top-offset);
1242 public boolean isOperandRef () {
1243 return isRef.get(top);
1246 //--- direct pc modification
1247 // NOTE: this is dangerous, caller has to guarantee stack consistency
1248 public void setPC (Instruction newpc) {
1252 public Instruction getPC () {
1256 public void advancePC() {
1257 int i = pc.getInstructionIndex() + 1;
1258 if (i < mi.getNumberOfInstructions()) {
1259 pc = mi.getInstruction(i);
1265 public int getTopPos() {
1269 ExceptionHandler getHandlerFor (ClassInfo ciException){
1270 return mi.getHandlerFor (ciException, pc);
1273 public boolean isFirewall (){
1274 return mi.isFirewall();
1277 public String getStackTraceInfo () {
1278 StringBuilder sb = new StringBuilder(128);
1280 if(!mi.isJPFInternal()) {
1281 sb.append(mi.getStackTraceName());
1285 sb.append( pc.getFilePos());
1289 sb.append(mi.getName());
1292 sb.append("(Native)");
1294 sb.append("(Synthetic)");
1298 return sb.toString();
1302 * if this is an instance method, return the reference of the corresponding object
1303 * (note this only has to be in slot 0 upon entry)
1305 public int getThis () {
1310 public void clearOperandStack () {
1312 for (int i=stackBase; i<= top; i++){
1320 // this is callerSlots deep copy
1322 public StackFrame clone () {
1324 StackFrame sf = (StackFrame) super.clone();
1328 sf.slots = slots.clone();
1329 sf.isRef = isRef.clone();
1332 sf.attrs = attrs.clone();
1335 // frameAttr is not cloned to allow search global use
1338 } catch (CloneNotSupportedException cnsx) {
1339 throw new JPFException(cnsx);
1343 //--- change management
1345 protected void checkIsModifiable() {
1346 if ((attributes & ATTR_IS_FROZEN) != 0) {
1347 throw new JPFException("attempt to modify frozen stackframe: " + this);
1351 public void freeze() {
1352 attributes |= ATTR_IS_FROZEN;
1355 public void defreeze() {
1356 attributes &= ~ATTR_IS_FROZEN;
1359 public boolean isFrozen() {
1360 return ((attributes & ATTR_IS_FROZEN) != 0);
1364 public void setReflection(){
1365 attributes |= ATTR_IS_REFLECTION;
1368 public boolean isReflection(){
1369 return ((attributes & ATTR_IS_REFLECTION) != 0);
1372 // all the dupses don't have any GC side effect (everything is already
1373 // on the stack), so skip the GC requests associated with push()/pop()
1375 public void dup () {
1383 slots[td] = slots[t];
1384 isRef.set(td, isRef.get(t));
1387 attrs[td] = attrs[t];
1393 public void dup2 () {
1403 slots[td] = slots[ts];
1404 isRef.set(td, isRef.get(ts));
1406 attrs[td] = attrs[ts];
1411 slots[td] = slots[ts];
1412 isRef.set(td, isRef.get(ts));
1414 attrs[td] = attrs[ts];
1420 public void dup2_x1 () {
1427 Object bAnn = null, cAnn = null;
1432 ts=t; td = t+2; // ts=top, td=top+2
1433 slots[td] = c = slots[ts];
1434 cRef = isRef.get(ts);
1437 attrs[td] = cAnn = attrs[ts];
1441 ts--; td--; // ts=top-1, td=top+1
1442 slots[td] = b = slots[ts];
1443 bRef = isRef.get(ts);
1444 isRef.set(td, bRef);
1446 attrs[td] = bAnn = attrs[ts];
1450 ts=t-2; td=t; // ts=top-2, td=top
1451 slots[td] = slots[ts];
1452 isRef.set(td, isRef.get(ts));
1454 attrs[td] = attrs[ts];
1458 td = ts; // td=top-2
1460 isRef.set(td, bRef);
1468 isRef.set(td, cRef);
1476 public void dup2_x2 () {
1483 Object cAnn = null, dAnn = null;
1488 ts = t-1; td = t+1; // ts=top-1, td=top+1
1489 slots[td] = c = slots[ts];
1490 cRef = isRef.get(ts);
1491 isRef.set(td, cRef);
1493 attrs[td] = cAnn = attrs[ts];
1497 ts=t; td++; // ts=top, td=top+2
1498 slots[td] = d = slots[ts];
1499 dRef = isRef.get(ts);
1500 isRef.set(td, dRef);
1502 attrs[td] = dAnn = attrs[ts];
1506 ts = t-3; td = t-1; // ts=top-3, td=top-1
1507 slots[td] = slots[ts];
1508 isRef.set( td, isRef.get(ts));
1510 attrs[td] = attrs[ts];
1514 ts++; td = t; // ts = top-2
1515 slots[td] = slots[ts];
1516 isRef.set( td, isRef.get(ts));
1518 attrs[td] = attrs[ts];
1522 td = ts; // td = top-2
1524 isRef.set( td, dRef);
1532 isRef.set(td, cRef);
1540 public void dup_x1 () {
1553 slots[td] = b = slots[ts];
1554 bRef = isRef.get(ts);
1555 isRef.set(td, bRef);
1557 attrs[td] = bAnn = attrs[ts];
1561 ts--; td = t; // ts=top-1, td = top
1562 slots[td] = slots[ts];
1563 isRef.set( td, isRef.get(ts));
1565 attrs[td] = attrs[ts];
1569 td = ts; // td=top-1
1571 isRef.set( td, bRef);
1579 public void dup_x2 () {
1592 slots[td] = c = slots[ts];
1593 cRef = isRef.get(ts);
1594 isRef.set( td, cRef);
1596 attrs[td] = cAnn = attrs[ts];
1600 td = ts; ts--; // td=top, ts=top-1
1601 slots[td] = slots[ts];
1602 isRef.set( td, isRef.get(ts));
1604 attrs[td] = attrs[ts];
1608 td=ts; ts--; // td=top-1, ts=top-2
1609 slots[td] = slots[ts];
1610 isRef.set( td, isRef.get(ts));
1612 attrs[td] = attrs[ts];
1616 td = ts; // td = top-2
1618 isRef.set(td, cRef);
1627 * to be used to check if a StackFrame got cloned due to its execution
1628 * changing attributes and/or slots, but otherwise represents the same
1631 public boolean originatesFrom (StackFrame other){
1635 return ((mi == other.mi) &&
1636 (prev == other.prev) &&
1637 (top == other.top) &&
1638 (getClass() == other.getClass()));
1643 // <2do> pcm - I assume this compares snapshots, not types. Otherwise it
1644 // would be pointless to equals stack/local values
1646 public boolean equals (Object o) {
1647 if (o instanceof StackFrame){
1648 StackFrame other = (StackFrame)o;
1650 if (prev != other.prev) {
1653 if (pc != other.pc) {
1656 if (mi != other.mi) {
1659 if (top != other.top){
1663 int[] otherSlots = other.slots;
1664 FixedBitSet otherIsRef = other.isRef;
1665 for (int i=0; i<=top; i++){
1666 if ( slots[i] != otherSlots[i]){
1669 if ( isRef.get(i) != otherIsRef.get(i)){
1674 if (!Misc.compare(top,attrs,other.attrs)){
1678 if (!ObjectList.equals(frameAttr, other.frameAttr)){
1688 public boolean hasAnyRef () {
1689 return isRef.cardinality() > 0;
1692 public int mixinExecutionStateHash (int h) {
1693 h = OATHash.hashMixin( h, mi.getGlobalId());
1696 h = OATHash.hashMixin(h, pc.getInstructionIndex());
1697 // we don't need the bytecode since there can only be one insn with this index in this method
1700 for (int i=0; i<top; i++) {
1701 h = OATHash.hashMixin(h, slots[i]);
1707 protected void hash (HashData hd) {
1709 hd.add(prev.objectHashCode());
1711 hd.add(mi.getGlobalId());
1714 hd.add(pc.getInstructionIndex());
1717 for (int i=0; i<=top; i++){
1723 // it's debatable if we add the attributes to the state, but whatever it
1724 // is, it should be kept consistent with the Fields.hash()
1726 for (int i=0; i<=top; i++){
1727 ObjectList.hash( attrs[i], hd);
1731 if (frameAttr != null){
1732 ObjectList.hash(frameAttr, hd);
1736 // computes an hash code for the hash table
1737 // the default hash code is different for each object
1738 // we need to redifine it to make the hash table work
1740 public int hashCode () {
1741 HashData hd = new HashData();
1743 return hd.getValue();
1747 * mark all objects reachable from local or operand stack positions containing
1748 * references. Done during phase1 marking of threads (the stack is one of the
1751 public void markThreadRoots (Heap heap, int tid) {
1754 for (int i = isRef.nextSetBit(0); i>=0 && i<=top; i = isRef.nextSetBit(i + 1)) {
1755 int objref = slots[i];
1756 if (objref != MJIEnv.NULL) {
1757 heap.markThreadRoot(objref, tid);
1761 for (int i = 0; i <= top; i++) {
1763 int objref = slots[i];
1764 if (objref != MJIEnv.NULL) {
1765 heap.markThreadRoot(objref, tid);
1771 //--- debugging methods
1773 public void printOperands (PrintStream pw){
1774 pw.print("operands = [");
1775 for (int i=stackBase; i<=top; i++){
1779 if (isOperandRef(i)){
1783 Object a = getOperandAttr(top-i);
1794 * this includes locals and pc
1796 public void printStackContent () {
1797 PrintStream pw = System.out;
1800 pw.print( mi.getFullName());
1803 pw.println( ":" + pc.getPosition());
1808 pw.print("\t slots: ");
1809 for (int i=0; i<=top; i++){
1810 if (i == stackBase){
1811 pw.println("\t ----------- operand stack");
1820 pw.print( slots[i]);
1831 public void printStackTrace () {
1832 System.out.println( getStackTraceInfo());
1835 public void swap () {
1839 boolean isTopRef = isRef.get(top);
1841 slots[top] = slots[t];
1842 isRef.set( top, isRef.get(t));
1845 isRef.set( t, isTopRef);
1848 Object a = attrs[top];
1849 attrs[top] = attrs[t];
1854 protected void printContentsOn(PrintWriter pw){
1855 pw.print("isFrozen=");
1856 pw.print(isFrozen());
1858 pw.print( mi != null ? mi.getUniqueName() : "null");
1859 pw.print(",top="); pw.print(top);
1860 pw.print(",slots=[");
1862 for (int i = 0; i <= top; i++) {
1863 if (i == stackBase){
1876 if (attrs != null && attrs[i] != null) {
1884 pw.print(pc != null ? pc.getPosition() : "null");
1890 // <2do> there are way too many different print/debug methods here
1891 public void printSlots (PrintStream ps){
1892 for (int i = 0; i <= top; i++) {
1893 if (i == stackBase){
1902 PrintUtils.printReference(ps, slots[i]);
1909 public int getDepth(){
1912 for (StackFrame frame = prev; frame != null; frame = frame.prev){
1919 protected int objectHashCode() {
1920 return super.hashCode();
1924 public String toString () {
1925 StringWriter sw = new StringWriter(128);
1926 PrintWriter pw = new PrintWriter(sw);
1928 pw.print(getClass().getSimpleName() + '{');
1929 //pw.print(Integer.toHexString(objectHashCode()));
1930 printContentsOn(pw);
1933 return sw.toString();
1936 public float peekFloat() {
1937 return Float.intBitsToFloat(slots[top]);
1940 public float peekFloat (int offset){
1941 return Float.intBitsToFloat(slots[top-offset]);
1944 public double peekDouble() {
1946 return Types.intsToDouble( slots[i], slots[i-1]);
1949 public double peekDouble (int offset){
1951 return Types.intsToDouble( slots[i], slots[i-1]);
1954 public long peekLong () {
1956 return Types.intsToLong( slots[i], slots[i-1]);
1959 public long peekLong (int offset) {
1960 int i = top - offset;
1961 return Types.intsToLong( slots[i], slots[i-1]);
1964 public void pushLong (long v) {
1965 push( (int) (v>>32));
1969 public void pushDouble (double v) {
1970 long l = Double.doubleToLongBits(v);
1971 push( (int) (l>>32));
1975 public void pushFloat (float v) {
1976 push( Float.floatToIntBits(v));
1979 public double popDouble () {
1982 int lo = slots[i--];
1983 int hi = slots[i--];
1987 attrs[i--] = null; // not really required
1988 attrs[i--] = null; // that's where the attribute should be
1992 return Types.intsToDouble(lo, hi);
1995 public long popLong () {
1998 int lo = slots[i--];
1999 int hi = slots[i--];
2003 attrs[i--] = null; // not really required
2004 attrs[i--] = null; // that's where the attribute should be
2008 return Types.intsToLong(lo, hi);
2011 public int peek () {
2015 public int peek (int offset) {
2016 return slots[top-offset];
2019 public void removeArguments (MethodInfo mi) {
2020 int i = mi.getArgumentsSize();
2027 public void pop (int n) {
2028 //assert (top >= stackBase) : "stack empty";
2032 // <2do> get rid of this !
2033 for (int i=top; i>t; i--) {
2034 if (isRef.get(i) && (slots[i] != MJIEnv.NULL)) {
2035 VM.getVM().getSystemState().activateGC();
2040 if (attrs != null){ // just to avoid memory leaks
2041 for (int i=top; i>t; i--){
2049 public float popFloat() {
2052 if (attrs != null){ // just to avoid memory leaks
2058 return Float.intBitsToFloat(v);
2062 //assert (top >= stackBase) : "stack empty";
2066 // <2do> get rid of this
2067 if (isRef.get(top)) {
2068 if (v != MJIEnv.NULL) {
2069 VM.getVM().getSystemState().activateGC();
2073 if (attrs != null){ // just to avoid memory leaks
2079 // note that we don't reset the operands or oRefs values, so that
2080 // we can still access them after the insn doing the pop got executed
2081 // (e.g. useful for listeners)
2086 public void pushLocal (int index) {
2088 slots[top] = slots[index];
2089 isRef.set(top, isRef.get(index));
2092 attrs[top] = attrs[index];
2096 public void pushLongLocal (int index){
2099 slots[++t] = slots[index];
2101 slots[++t] = slots[index+1];
2105 attrs[t-1] = attrs[index];
2112 public void storeOperand (int index){
2113 slots[index] = slots[top];
2114 isRef.set( index, isRef.get(top));
2117 attrs[index] = attrs[top];
2124 public void storeLongOperand (int index){
2128 slots[i] = slots[t];
2131 slots[++i] = slots[t+1];
2135 attrs[index] = attrs[t]; // its in the lower word
2145 public void push (int v){
2150 //if (attrs != null){ // done on pop
2151 // attrs[top] = null;
2155 public void pushRef (int ref){
2160 //if (attrs != null){ // done on pop
2161 // attrs[top] = null;
2164 if (ref != MJIEnv.NULL) {
2165 VM.getVM().getSystemState().activateGC();
2169 public void push (int v, boolean ref) {
2172 isRef.set(top, ref);
2174 //if (attrs != null){ // done on pop
2175 // attrs[top] = null;
2178 if (ref && (v != MJIEnv.NULL)) {
2179 VM.getVM().getSystemState().activateGC();
2183 // return the value of callerSlots variable given the name
2184 public int getLocalVariableSlotIndex (String name) {
2185 LocalVarInfo lv = mi.getLocalVar(name, pc.getPosition());
2188 return lv.getSlotIndex();
2194 //--- abstract argument & return passing that can have VM dependend implementation
2196 public void setReferenceResult (int ref, Object attr){
2199 setOperandAttr(attr);
2203 public void setResult (int r, Object attr){
2206 setOperandAttr(attr);
2210 public void setResult (long r, Object attr){
2213 setLongOperandAttr(attr);
2217 public int getResult(){
2221 public long getLongResult(){
2225 public int getReferenceResult () {
2229 public Object getResultAttr () {
2230 return getOperandAttr();
2233 public Object getLongResultAttr () {
2234 return getLongOperandAttr();
2237 public float getFloatResult(){
2238 return Float.intBitsToFloat(getResult());
2240 public double getDoubleResult(){
2241 return Double.longBitsToDouble(getLongResult());
2243 public Object getFloatResultAttr(){
2244 return getResultAttr();
2246 public Object getDoubleResultAttr(){
2247 return getLongResultAttr();
2251 //--- VM independent exception handler setup
2253 public void setExceptionReference (int exRef){
2257 public int getExceptionReference (){
2261 public void setExceptionReferenceAttribute (Object attr){
2262 setOperandAttr(attr);
2265 public Object getExceptionReferenceAttribute (){
2266 return getOperandAttr();
2270 // those set the local vars that are normally initialized from call arguments
2271 public abstract void setArgumentLocal (int idx, int value, Object attr);
2272 public abstract void setLongArgumentLocal (int idx, long value, Object attr);
2273 public abstract void setReferenceArgumentLocal (int idx, int ref, Object attr);
2275 public void setFloatArgumentLocal (int idx, float value, Object attr){
2276 setArgumentLocal( idx, Float.floatToIntBits(value), attr);
2278 public void setDoubleArgumentLocal (int idx, double value, Object attr){
2279 setLongArgumentLocal( idx, Double.doubleToLongBits(value), attr);