comparison src/main/gov/nasa/jpf/vm/StackFrame.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children 3517702bd768
comparison
equal deleted inserted replaced
-1:000000000000 0:61d41facf527
1 /*
2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
4 * All rights reserved.
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0.
11 *
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.
17 */
18 package gov.nasa.jpf.vm;
19
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;
32
33 import java.io.PrintStream;
34 import java.io.PrintWriter;
35 import java.io.StringWriter;
36 import java.util.Iterator;
37
38
39 /**
40 * Describes callerSlots stack frame.
41 *
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
46 *
47 * slot[0] : 'this'
48 * .. .. local vars
49 * slot[stackBase-1] : last local var
50 * slot[stackBase] : first operand slot
51 * .. ^
52 * .. | operand stack range
53 * .. v
54 * slot[top] : highest used operand slot
55 *
56 */
57 public abstract class StackFrame implements Cloneable {
58
59 /**
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
63 */
64 public static final int ATTR_IS_FROZEN = 0x100;
65 static final int ATTR_IS_REFLECTION = 0x1000;
66 /**
67 * the previous StackFrame (usually the caller, null if first). To be set when
68 * the frame is pushed on the ThreadInfo callstack
69 */
70 protected StackFrame prev;
71
72 /**
73 * state management related attributes similar to ElementInfo. The lower 16 bits
74 * are stored/restored, the upper 16 bits are for transient use
75 */
76 protected int attributes;
77
78
79 protected int top; // top index of the operand stack (NOT size)
80 // this points to the last pushed value
81
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
84
85 protected int[] slots; // the combined local and operand slots
86 protected FixedBitSet isRef; // which slots contain references
87
88 protected Object frameAttr; // optional user attrs for the whole frame
89
90 /*
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
94 *
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
97 * in your clients
98 *
99 * these are set on demand
100 */
101 protected Object[] attrs = null; // the combined user-defined callerSlots (set on demand)
102
103 protected Instruction pc; // the next insn to execute (program counter)
104 protected MethodInfo mi; // which method is executed in this frame
105
106 static final int[] EMPTY_ARRAY = new int[0];
107 static final FixedBitSet EMPTY_BITSET = new BitSet64();
108
109 protected StackFrame (MethodInfo callee, int nLocals, int nOperands){
110 mi = callee;
111 pc = mi.getInstruction(0);
112
113 stackBase = nLocals;
114 top = nLocals-1;
115
116 int nSlots = nLocals + nOperands;
117 if (nSlots > 0){
118 slots = new int[nLocals + nOperands];
119 isRef = createReferenceMap(slots.length);
120 } else {
121 // NativeStackFrames don't use locals or operands, but we
122 // don't want to add tests to all our methods
123 slots = EMPTY_ARRAY;
124 isRef = EMPTY_BITSET;
125 }
126 }
127
128 public StackFrame (MethodInfo callee){
129 this( callee, callee.getMaxLocals(), callee.getMaxStack());
130 }
131
132
133
134 /**
135 * Creates an empty stack frame. Used by clone.
136 */
137 protected StackFrame () {
138 }
139
140 /**
141 * creates callerSlots dummy Stackframe for testing of operand/local operations
142 * NOTE - TESTING ONLY! this does not have a MethodInfo
143 */
144 protected StackFrame (int nLocals, int nOperands){
145 stackBase = nLocals;
146 slots = new int[nLocals + nOperands];
147 isRef = createReferenceMap(slots.length);
148 top = nLocals-1; // index, not size!
149 }
150
151 /**
152 * re-execute method from the beginning - use with care
153 */
154 public void reset() {
155 pc = mi.getInstruction(0);
156 }
157
158
159
160 protected FixedBitSet createReferenceMap (int nSlots){
161 if (nSlots <= 64){
162 return new BitSet64();
163 } else if (nSlots <= 256){
164 return new BitSet256();
165 } else if (nSlots <= 1024) {
166 return new BitSet1024();
167 } else {
168 return new BitSetN(nSlots);
169 }
170 }
171
172 public boolean isNative() {
173 return false;
174 }
175
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){
183 return frame;
184 }
185 }
186 }
187
188 return null;
189 }
190
191 /**
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
195 */
196 public int getCalleeThis (MethodInfo mi) {
197 return getCalleeThis(mi.getArgumentsSize());
198 }
199
200 /**
201 * return reference of called object in the context of the caller
202 * (i.e. we are in the caller frame)
203 */
204 public int getCalleeThis (int size) {
205 // top is the topmost index
206 int i = size-1;
207 if (top < i) {
208 return MJIEnv.NULL;
209 }
210
211 return slots[top-i];
212 }
213
214 public StackFrame getPrevious() {
215 return prev;
216 }
217
218 /**
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
221 */
222 public void setPrevious (StackFrame frame){
223 prev = frame;
224 }
225
226 public Object getLocalOrFieldValue (String id) {
227 // try locals first
228 LocalVarInfo lv = mi.getLocalVar(id, pc.getPosition());
229 if (lv != null){
230 return getLocalValueObject(lv);
231 }
232
233 // then fields
234 return getFieldValue(id);
235 }
236
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];
242
243 switch (sig.charAt(0)) {
244 case 'Z':
245 return Boolean.valueOf(v != 0);
246 case 'B':
247 return new Byte((byte) v);
248 case 'C':
249 return new Character((char) v);
250 case 'S':
251 return new Short((short) v);
252 case 'I':
253 return new Integer(v);
254 case 'J':
255 return new Long(Types.intsToLong(slots[slotIdx + 1], v)); // Java is big endian, Types expects low,high
256 case 'F':
257 return new Float(Float.intBitsToFloat(v));
258 case 'D':
259 return new Double(Double.longBitsToDouble(Types.intsToLong(slots[slotIdx + 1], v)));
260 default: // reference
261 if (v >= 0) {
262 return VM.getVM().getHeap().get(v);
263 }
264 }
265 }
266
267 return null;
268 }
269
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);
275 if (v != null) {
276 return v;
277 }
278 }
279
280 // check static fields (in method class and its superclasses)
281 return mi.getClassInfo().getStaticFieldValueObject(id);
282 }
283
284 public ClassInfo getClassInfo () {
285 return mi.getClassInfo();
286 }
287
288 public String getClassName () {
289 return mi.getClassInfo().getName();
290 }
291
292 public String getSourceFile () {
293 return mi.getClassInfo().getSourceFileName();
294 }
295
296 /**
297 * does any of the 'nTopSlots' hold callerSlots reference value of 'objRef'
298 * 'nTopSlots' is usually obtained from MethodInfo.getNumberOfCallerStackSlots()
299 */
300 public boolean includesReferenceOperand (int nTopSlots, int objRef){
301
302 for (int i=0, j=top-nTopSlots+1; i<nTopSlots && j>=0; i++, j++) {
303 if (isRef.get(j) && (slots[j] == objRef)){
304 return true;
305 }
306 }
307
308 return false;
309 }
310
311 /**
312 * does any of the operand slots hold callerSlots reference value of 'objRef'
313 */
314 public boolean includesReferenceOperand (int objRef){
315
316 for (int i=stackBase; i<=top; i++) {
317 if (isRef.get(i) && (slots[i] == objRef)){
318 return true;
319 }
320 }
321
322 return false;
323 }
324
325 /**
326 * is this StackFrame modifying the KernelState
327 * this is true unless this is callerSlots NativeStackFrame
328 */
329 public boolean modifiesState() {
330 return true;
331 }
332
333 public boolean isDirectCallFrame () {
334 return false;
335 }
336
337 public boolean isSynthetic() {
338 return false;
339 }
340
341 // gets and sets some derived information
342 public int getLine () {
343 return mi.getLineNumber(pc);
344 }
345
346
347 /**
348 * generic visitor for reference arguments
349 */
350 public void processRefArguments (MethodInfo miCallee, ReferenceProcessor visitor){
351 int nArgSlots = miCallee.getArgumentsSize();
352
353 for (int i=top-1; i>=top-nArgSlots; i--){
354 if (isRef.get(i)){
355 visitor.processReference(slots[i]);
356 }
357 }
358 }
359
360 public int getSlot(int idx){
361 return slots[idx];
362 }
363 public boolean isReferenceSlot(int idx){
364 return isRef.get(idx);
365 }
366
367
368 public void setOperand (int offset, int v, boolean isRefValue){
369 int i = top-offset;
370 slots[i] = v;
371 isRef.set(i, isRefValue);
372 }
373
374
375 //----------------------------- various attribute accessors
376
377 public boolean hasAttrs () {
378 return attrs != null;
379 }
380
381 public boolean hasFrameAttr(){
382 return frameAttr != null;
383 }
384
385 public boolean hasFrameAttr (Class<?> attrType){
386 return ObjectList.containsType(frameAttr, attrType);
387 }
388
389 public boolean hasFrameAttrValue (Object a){
390 return ObjectList.contains(frameAttr, a);
391 }
392
393 //--- the frame attr accessors
394
395 /**
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
398 */
399 public Object getFrameAttr(){
400 return frameAttr;
401 }
402
403 /**
404 * this replaces all of them - use only if you know there are no
405 * SystemAttributes in the list (which would cause an exception)
406 */
407 public void setFrameAttr (Object attr){
408 frameAttr = ObjectList.set(frameAttr, attr);
409 }
410
411 public void addFrameAttr (Object attr){
412 frameAttr = ObjectList.add(frameAttr, attr);
413 }
414
415 public void removeFrameAttr (Object attr){
416 frameAttr = ObjectList.remove(frameAttr, attr);
417 }
418
419 public void replaceFrameAttr (Object oldAttr, Object newAttr){
420 frameAttr = ObjectList.replace(frameAttr, oldAttr, newAttr);
421 }
422
423 /**
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
426 */
427 public <T> T getFrameAttr (Class<T> attrType) {
428 return ObjectList.getFirst(frameAttr, attrType);
429 }
430
431 public <T> T getAndResetFrameAttr (Class<T> attrType) {
432 T attr = ObjectList.getFirst(frameAttr, attrType);
433 if (attr != null){
434 frameAttr = ObjectList.remove(frameAttr, attr);
435 }
436 return attr;
437 }
438
439
440 public <T> T getNextFrameAttr (Class<T> attrType, Object prev) {
441 return ObjectList.getNext(frameAttr, attrType, prev);
442 }
443
444 public ObjectList.Iterator frameAttrIterator(){
445 return ObjectList.iterator(frameAttr);
446 }
447
448 public <T> ObjectList.TypedIterator<T> frameAttrIterator(Class<T> attrType){
449 return ObjectList.typedIterator(frameAttr, attrType);
450 }
451
452 //--- the top single-slot operand attrs
453
454 public boolean hasOperandAttr(){
455 if ((top >= stackBase) && (attrs != null)){
456 return (attrs[top] != null);
457 }
458 return false;
459 }
460 public boolean hasOperandAttr(Class<?> type){
461 if ((top >= stackBase) && (attrs != null)){
462 return ObjectList.containsType(attrs[top], type);
463 }
464 return false;
465 }
466
467 /**
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
470 */
471 public Object getOperandAttr () {
472 if ((top >= stackBase) && (attrs != null)){
473 return attrs[top];
474 }
475 return null;
476 }
477
478 /**
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()
483 */
484 public void setOperandAttr (Object a){
485 assert (top >= stackBase);
486 if (attrs == null) {
487 if (a == null) return;
488 attrs = new Object[slots.length];
489 }
490 attrs[top] = a;
491 }
492
493
494 /**
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
497 */
498 public <T> T getOperandAttr (Class<T> attrType){
499 assert (top >= stackBase);
500
501 if ((attrs != null)){
502 return ObjectList.getFirst( attrs[top], attrType);
503 }
504 return null;
505 }
506 public <T> T getNextOperandAttr (Class<T> attrType, Object prev){
507 assert (top >= stackBase);
508 if (attrs != null){
509 return ObjectList.getNext( attrs[top], attrType, prev);
510 }
511 return null;
512 }
513 public Iterator operandAttrIterator(){
514 assert (top >= stackBase);
515 Object a = (attrs != null) ? attrs[top] : null;
516 return ObjectList.iterator(a);
517 }
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);
522 }
523
524
525 public void addOperandAttr (Object a){
526 assert (top >= stackBase);
527 if (a != null){
528 if (attrs == null) {
529 attrs = new Object[slots.length];
530 }
531
532 attrs[top] = ObjectList.add(attrs[top], a);
533 }
534 }
535
536 public void removeOperandAttr (Object a){
537 assert (top >= stackBase) && (a != null);
538 if (attrs != null){
539 attrs[top] = ObjectList.remove(attrs[top], a);
540 }
541 }
542
543 public void replaceOperandAttr (Object oldAttr, Object newAttr){
544 assert (top >= stackBase) && (oldAttr != null) && (newAttr != null);
545 if (attrs != null){
546 attrs[top] = ObjectList.replace(attrs[top], oldAttr, newAttr);
547 }
548 }
549
550
551 //--- offset operand attrs
552
553 public boolean hasOperandAttr(int offset){
554 int i = top-offset;
555 assert (i >= stackBase);
556 if (attrs != null){
557 return (attrs[i] != null);
558 }
559 return false;
560 }
561 public boolean hasOperandAttr(int offset, Class<?> type){
562 int i = top-offset;
563 assert (i >= stackBase);
564 if (attrs != null){
565 return ObjectList.containsType(attrs[i], type);
566 }
567 return false;
568 }
569
570 /**
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
573 */
574 public Object getOperandAttr (int offset) {
575 int i = top-offset;
576 assert (i >= stackBase);
577
578 if (attrs != null) {
579 return attrs[i];
580 }
581 return null;
582 }
583
584 /**
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()
589 */
590 public void setOperandAttr (int offset, Object a){
591 int i = top-offset;
592 assert (i >= stackBase);
593
594 if (attrs == null) {
595 if (a == null) return;
596 attrs = new Object[slots.length];
597 }
598 attrs[i] = a;
599 }
600
601 /**
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
604 */
605 public <T> T getOperandAttr (int offset, Class<T> attrType){
606 int i = top-offset;
607 assert (i >= stackBase);
608 if (attrs != null){
609 return ObjectList.getFirst( attrs[i], attrType);
610 }
611 return null;
612 }
613 public <T> T getNextOperandAttr (int offset, Class<T> attrType, Object prev){
614 int i = top-offset;
615 assert (i >= stackBase);
616 if (attrs != null){
617 return ObjectList.getNext( attrs[i], attrType, prev);
618 }
619 return null;
620 }
621 public ObjectList.Iterator operandAttrIterator(int offset){
622 int i = top-offset;
623 assert (i >= stackBase);
624 Object a = (attrs != null) ? attrs[i] : null;
625 return ObjectList.iterator(a);
626 }
627 public <T> ObjectList.TypedIterator<T> operandAttrIterator(int offset, Class<T> attrType){
628 int i = top-offset;
629 assert (i >= stackBase);
630 Object a = (attrs != null) ? attrs[i] : null;
631 return ObjectList.typedIterator(a, attrType);
632 }
633
634
635 public void addOperandAttr (int offset, Object a){
636 int i = top-offset;
637 assert (i >= stackBase);
638
639 if (a != null){
640 if (attrs == null) {
641 attrs = new Object[slots.length];
642 }
643 attrs[i] = ObjectList.add(attrs[i],a);
644 }
645 }
646
647 public void removeOperandAttr (int offset, Object a){
648 int i = top-offset;
649 assert (i >= stackBase) && (a != null);
650 if (attrs != null){
651 attrs[i] = ObjectList.remove(attrs[i], a);
652 }
653 }
654
655 public void replaceOperandAttr (int offset, Object oldAttr, Object newAttr){
656 int i = top-offset;
657 assert (i >= stackBase) && (oldAttr != null) && (newAttr != null);
658 if (attrs != null){
659 attrs[i] = ObjectList.replace(attrs[i], oldAttr, newAttr);
660 }
661 }
662
663
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
667
668 public boolean hasLongOperandAttr(){
669 return hasOperandAttr(1);
670 }
671 public boolean hasLongOperandAttr(Class<?> type){
672 return hasOperandAttr(1, type);
673 }
674
675 /**
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
678 */
679 public Object getLongOperandAttr () {
680 return getOperandAttr(1);
681 }
682
683 /**
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()
688 */
689 public void setLongOperandAttr (Object a){
690 setOperandAttr(1, a);
691 }
692
693 /**
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
696 */
697 public <T> T getLongOperandAttr (Class<T> attrType) {
698 return getOperandAttr(1, attrType);
699 }
700 public <T> T getNextLongOperandAttr (Class<T> attrType, Object prev) {
701 return getNextOperandAttr(1, attrType, prev);
702 }
703 public ObjectList.Iterator longOperandAttrIterator(){
704 return operandAttrIterator(1);
705 }
706 public <T> ObjectList.TypedIterator<T> longOperandAttrIterator(Class<T> attrType){
707 return operandAttrIterator(1, attrType);
708 }
709
710 public void addLongOperandAttr (Object a){
711 addOperandAttr(1, a);
712 }
713
714 public void removeLongOperandAttr (Object a){
715 removeOperandAttr(1, a);
716 }
717
718 public void replaceLongOperandAttr (Object oldAttr, Object newAttr){
719 replaceOperandAttr(1, oldAttr, newAttr);
720 }
721
722
723 //--- local attrs
724 // single- or double-slot - you have to provide the var index anyways)
725
726 public boolean hasLocalAttr(int index){
727 assert index < stackBase;
728 if (attrs != null){
729 return (attrs[index] != null);
730 }
731 return false;
732 }
733 public boolean hasLocalAttr(int index, Class<?> type){
734 assert index < stackBase;
735 if (attrs != null){
736 return ObjectList.containsType(attrs[index], type);
737 }
738 return false;
739 }
740
741 /**
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
744 */
745 public Object getLocalAttr (int index){
746 assert index < stackBase;
747 if (attrs != null){
748 return attrs[index];
749 }
750 return null;
751 }
752
753 public Object getLongLocalAttr (int index){
754 return getLocalAttr( index);
755 }
756
757 /**
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()
762 */
763 public void setLocalAttr (int index, Object a) {
764 assert index < stackBase;
765 if (attrs == null){
766 if (a == null) return;
767 attrs = new Object[slots.length];
768 }
769 attrs[index] = a;
770 }
771
772 public void setLongLocalAttr (int index, Object a){
773 setLocalAttr( index, a);
774 }
775
776 public void addLongLocalAttr (int index, Object a){
777 addLocalAttr( index, a);
778 }
779
780 /**
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
783 */
784 public <T> T getLocalAttr (int index, Class<T> attrType){
785 assert index < stackBase;
786 if (attrs != null){
787 return ObjectList.getFirst( attrs[index], attrType);
788 }
789 return null;
790 }
791 public <T> T getNextLocalAttr (int index, Class<T> attrType, Object prev){
792 assert index < stackBase;
793 if (attrs != null){
794 return ObjectList.getNext( attrs[index], attrType, prev);
795 }
796 return null;
797 }
798 public ObjectList.Iterator localAttrIterator(int index){
799 assert index < stackBase;
800 Object a = (attrs != null) ? attrs[index] : null;
801 return ObjectList.iterator(a);
802 }
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);
807 }
808
809
810 public void addLocalAttr (int index, Object attr){
811 assert index < stackBase;
812 if (attrs == null){
813 if (attr == null) return;
814 attrs = new Object[slots.length];
815 }
816 attrs[index] = ObjectList.add(attrs[index], attr);
817 }
818
819 public void removeLocalAttr (int index, Object attr){
820 assert index < stackBase && attr != null;
821 if (attr != null){
822 attrs[index] = ObjectList.remove(attrs[index], attr);
823 }
824 }
825
826 public void replaceLocalAttr (int index, Object oldAttr, Object newAttr){
827 assert index < stackBase && oldAttr != null && newAttr != null;
828 if (attrs == null){
829 attrs[index] = ObjectList.replace(attrs[index], oldAttr, newAttr);
830 }
831 }
832
833 //--- various special attr accessors
834
835 /**
836 * helper to quickly find out if any of the locals slots holds
837 * an attribute of the provided type
838 *
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
842 */
843 public int getLocalAttrIndex (Class<?> attrType, int startIdx){
844 if (attrs != null){
845 for (int i=startIdx; i<stackBase; i++){
846 Object a = attrs[i];
847 if (ObjectList.containsType(a, attrType)){
848 return i;
849 }
850 }
851 }
852
853 return -1;
854 }
855
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
860
861 /**
862 * this retrieves the argument values from the caller, i.e. the previous stackframe
863 *
864 * references are returned as ElementInfos or null
865 * primitive values are returned as box objects (e.g. int -> Integer)
866 */
867 public Object[] getArgumentValues (ThreadInfo ti){
868 StackFrame callerFrame = getCallerFrame();
869 if (callerFrame != null){
870 return callerFrame.getCallArguments(ti);
871 } else {
872 // <2do> what about main(String[] args) ?
873 }
874
875 return null;
876 }
877
878 /**
879 * get the arguments of the executed call
880 * Note - this throws an exception if the StackFrame pc is not an InvokeInstruction
881 */
882 public Object[] getCallArguments (ThreadInfo ti){
883 if (pc == null || !(pc instanceof InvokeInstruction)){
884 throw new JPFException("stackframe not executing invoke: " + pc);
885 }
886
887 InvokeInstruction call = (InvokeInstruction) pc;
888 MethodInfo callee = call.getInvokedMethod();
889
890 byte[] argTypes = callee.getArgumentTypes();
891
892 return getArgumentsValues(ti, argTypes);
893 }
894
895 public Object[] getArgumentsValues (ThreadInfo ti, byte[] argTypes){
896 int n = argTypes.length;
897 Object[] args = new Object[n];
898
899 for (int i=n-1, off=0; i>=0; i--) {
900 switch (argTypes[i]) {
901 case Types.T_ARRAY:
902 //case Types.T_OBJECT:
903 case Types.T_REFERENCE:
904 int ref = peek(off);
905 if (ref != MJIEnv.NULL) {
906 args[i] = ti.getElementInfo(ref);
907 } else {
908 args[i] = null;
909 }
910 off++;
911 break;
912
913 case Types.T_LONG:
914 args[i] = new Long(peekLong(off));
915 off+=2;
916 break;
917 case Types.T_DOUBLE:
918 args[i] = new Double(Types.longToDouble(peekLong(off)));
919 off+=2;
920 break;
921
922 case Types.T_BOOLEAN:
923 args[i] = new Boolean(peek(off) != 0);
924 off++;
925 break;
926 case Types.T_BYTE:
927 args[i] = new Byte((byte)peek(off));
928 off++;
929 break;
930 case Types.T_CHAR:
931 args[i] = new Character((char)peek(off));
932 off++;
933 break;
934 case Types.T_SHORT:
935 args[i] = new Short((short)peek(off));
936 off++;
937 break;
938 case Types.T_INT:
939 args[i] = new Integer(peek(off));
940 off++;
941 break;
942 case Types.T_FLOAT:
943 args[i] = new Float(Types.intToFloat(peek(off)));
944 off++;
945 break;
946 default:
947 // error, unknown argument type
948 }
949 }
950 return args;
951 }
952
953 /**
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
956 *
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.
961 */
962 public Object[] getArgumentAttrs (MethodInfo miCallee) {
963 if (attrs != null) {
964 int nArgs = miCallee.getNumberOfArguments();
965 byte[] at = miCallee.getArgumentTypes();
966 Object[] a;
967
968 if (!miCallee.isStatic()) {
969 a = new Object[nArgs+1];
970 a[0] = getOperandAttr(miCallee.getArgumentsSize()-1);
971 } else {
972 a = new Object[nArgs];
973 }
974
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);
979 off +=2;
980 } else {
981 a[j] = getOperandAttr(off);
982 off++;
983 }
984 }
985
986 return a;
987
988 } else {
989 return null;
990 }
991 }
992
993 /**
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)
997 */
998 public boolean hasArgumentAttr (MethodInfo miCallee, Class<?> attrType){
999 if (attrs != null) {
1000 int nArgSlots = miCallee.getArgumentsSize();
1001
1002 for (int i=0; i<nArgSlots; i++){
1003 Object a = getOperandAttr(i);
1004 if (ObjectList.containsType(a, attrType)){
1005 return true;
1006 }
1007 }
1008 }
1009
1010 return false;
1011 }
1012
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) {
1021 return true;
1022 }
1023 }
1024 }
1025 }
1026
1027 return false;
1028 }
1029
1030
1031 // -- end attrs --
1032
1033 public void setLocalReferenceVariable (int index, int ref){
1034 if (slots[index] != MJIEnv.NULL){
1035 VM.getVM().getSystemState().activateGC();
1036 }
1037
1038 slots[index] = ref;
1039 isRef.set(index);
1040 }
1041
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();
1046 }
1047
1048 slots[index] = v;
1049 isRef.clear(index);
1050 }
1051
1052 public void setFloatLocalVariable (int index, float f){
1053 setLocalVariable( index, Float.floatToIntBits(f));
1054 }
1055
1056 public void setDoubleLocalVariable (int index, double f){
1057 setLongLocalVariable( index, Double.doubleToLongBits(f));
1058 }
1059
1060
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));
1065
1066 slots[index] = v;
1067 isRef.set(index,ref);
1068
1069 if (activateGc) {
1070 VM.getVM().getSystemState().activateGC();
1071 }
1072 }
1073
1074 public int getLocalVariable (int i) {
1075 return slots[i];
1076 }
1077
1078 public int getLocalVariable (String name) {
1079 int idx = getLocalVariableSlotIndex(name);
1080 if (idx >= 0) {
1081 return getLocalVariable(idx);
1082 } else {
1083 throw new JPFException("local variable not found: " + name);
1084 }
1085 }
1086
1087 public int getLocalVariableCount() {
1088 return stackBase;
1089 }
1090
1091 /**
1092 * <2do> - this should return only LocalVarInfo for the current pc
1093 */
1094 public LocalVarInfo[] getLocalVars () {
1095 return mi.getLocalVars();
1096 }
1097
1098
1099 public boolean isLocalVariableRef (int idx) {
1100 return isRef.get(idx);
1101 }
1102
1103 public String getLocalVariableType (String name) {
1104 LocalVarInfo lv = mi.getLocalVar(name, pc.getPosition()+pc.getLength());
1105 if (lv != null){
1106 return lv.getType();
1107 }
1108
1109 return null;
1110 }
1111
1112 public String getLocalVariableType (int idx){
1113 LocalVarInfo lv = mi.getLocalVar(idx, pc.getPosition()+pc.getLength());
1114 if (lv != null){
1115 return lv.getType();
1116 }
1117
1118 return null;
1119 }
1120
1121 public LocalVarInfo getLocalVarInfo (String name){
1122 return mi.getLocalVar(name, pc.getPosition()+pc.getLength());
1123 }
1124
1125 public LocalVarInfo getLocalVarInfo (int idx){
1126 return mi.getLocalVar(idx, pc.getPosition()+pc.getLength());
1127 }
1128
1129 public void setThis (int objRef){
1130 thisRef = objRef;
1131 }
1132
1133 public FixedBitSet getReferenceMap(){
1134 return isRef;
1135 }
1136
1137 //--- direct slot access - provided for machine-independent clients
1138
1139 public int[] getSlots () {
1140 return slots; // we should probably clone
1141 }
1142 public Object[] getSlotAttrs(){
1143 return attrs;
1144 }
1145 public Object getSlotAttr (int i){
1146 if (attrs != null){
1147 return attrs[i];
1148 }
1149 return null;
1150 }
1151 public <T> T getSlotAttr (int i, Class<T> attrType){
1152 if (attrs != null){
1153 return ObjectList.getFirst( attrs[i], attrType);
1154 }
1155 return null;
1156 }
1157 public void setSlotAttr (int i, Object a){
1158 if (attrs == null){
1159 attrs = new Object[slots.length];
1160 }
1161 attrs[i] = a;
1162 }
1163 public void addSlotAttr (int i, Object a){
1164 if (a != null){
1165 if (attrs == null) {
1166 attrs = new Object[slots.length];
1167 }
1168
1169 attrs[i] = ObjectList.add(attrs[i], a);
1170 }
1171 }
1172 public void replaceSlotAttr (int i, Object oldAttr, Object newAttr){
1173 if (attrs != null){
1174 attrs[i] = ObjectList.replace(attrs[i], oldAttr, newAttr);
1175 }
1176 }
1177
1178
1179
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]);
1183 }
1184 }
1185
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)
1189
1190 slots[index] = Types.hiLong(v);
1191 isRef.clear(index);
1192
1193 index++;
1194 slots[index] = Types.loLong(v);
1195 isRef.clear(index);
1196 }
1197
1198 public long getLongLocalVariable (int idx) {
1199 return Types.intsToLong(slots[idx + 1], slots[idx]);
1200 }
1201
1202 public double getDoubleLocalVariable (int idx) {
1203 return Types.intsToDouble(slots[idx + 1], slots[idx]);
1204 }
1205
1206 public float getFloatLocalVariable (int idx) {
1207 int bits = slots[idx];
1208 return Float.intBitsToFloat(bits);
1209 }
1210
1211 public double getDoubleLocalVariable (String name) {
1212 int idx = getLocalVariableSlotIndex(name);
1213 if (idx >= 0) {
1214 return getDoubleLocalVariable(idx);
1215 } else {
1216 throw new JPFException("long local variable not found: " + name);
1217 }
1218 }
1219
1220 public long getLongLocalVariable (String name) {
1221 int idx = getLocalVariableSlotIndex(name);
1222
1223 if (idx >= 0) {
1224 return getLongLocalVariable(idx);
1225 } else {
1226 throw new JPFException("long local variable not found: " + name);
1227 }
1228 }
1229
1230 public MethodInfo getMethodInfo () {
1231 return mi;
1232 }
1233
1234 public String getMethodName () {
1235 return mi.getName();
1236 }
1237
1238 public boolean isOperandRef (int offset) {
1239 return isRef.get(top-offset);
1240 }
1241
1242 public boolean isOperandRef () {
1243 return isRef.get(top);
1244 }
1245
1246 //--- direct pc modification
1247 // NOTE: this is dangerous, caller has to guarantee stack consistency
1248 public void setPC (Instruction newpc) {
1249 pc = newpc;
1250 }
1251
1252 public Instruction getPC () {
1253 return pc;
1254 }
1255
1256 public void advancePC() {
1257 int i = pc.getInstructionIndex() + 1;
1258 if (i < mi.getNumberOfInstructions()) {
1259 pc = mi.getInstruction(i);
1260 } else {
1261 pc = null;
1262 }
1263 }
1264
1265 public int getTopPos() {
1266 return top;
1267 }
1268
1269 ExceptionHandler getHandlerFor (ClassInfo ciException){
1270 return mi.getHandlerFor (ciException, pc);
1271 }
1272
1273 public boolean isFirewall (){
1274 return mi.isFirewall();
1275 }
1276
1277 public String getStackTraceInfo () {
1278 StringBuilder sb = new StringBuilder(128);
1279
1280 if(!mi.isJPFInternal()) {
1281 sb.append(mi.getStackTraceName());
1282
1283 if(pc != null) {
1284 sb.append('(');
1285 sb.append( pc.getFilePos());
1286 sb.append(')');
1287 }
1288 } else {
1289 sb.append(mi.getName());
1290
1291 if(mi.isMJI()) {
1292 sb.append("(Native)");
1293 } else {
1294 sb.append("(Synthetic)");
1295 }
1296 }
1297
1298 return sb.toString();
1299 }
1300
1301 /**
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)
1304 */
1305 public int getThis () {
1306 return thisRef;
1307 }
1308
1309 // stack operations
1310 public void clearOperandStack () {
1311 if (attrs != null){
1312 for (int i=stackBase; i<= top; i++){
1313 attrs[i] = null;
1314 }
1315 }
1316
1317 top = stackBase-1;
1318 }
1319
1320 // this is callerSlots deep copy
1321 @Override
1322 public StackFrame clone () {
1323 try {
1324 StackFrame sf = (StackFrame) super.clone();
1325
1326 sf.defreeze();
1327
1328 sf.slots = slots.clone();
1329 sf.isRef = isRef.clone();
1330
1331 if (attrs != null){
1332 sf.attrs = attrs.clone();
1333 }
1334
1335 // frameAttr is not cloned to allow search global use
1336
1337 return sf;
1338 } catch (CloneNotSupportedException cnsx) {
1339 throw new JPFException(cnsx);
1340 }
1341 }
1342
1343 //--- change management
1344
1345 protected void checkIsModifiable() {
1346 if ((attributes & ATTR_IS_FROZEN) != 0) {
1347 throw new JPFException("attempt to modify frozen stackframe: " + this);
1348 }
1349 }
1350
1351 public void freeze() {
1352 attributes |= ATTR_IS_FROZEN;
1353 }
1354
1355 public void defreeze() {
1356 attributes &= ~ATTR_IS_FROZEN;
1357 }
1358
1359 public boolean isFrozen() {
1360 return ((attributes & ATTR_IS_FROZEN) != 0);
1361 }
1362
1363
1364 public void setReflection(){
1365 attributes |= ATTR_IS_REFLECTION;
1366 }
1367
1368 public boolean isReflection(){
1369 return ((attributes & ATTR_IS_REFLECTION) != 0);
1370 }
1371
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()
1374
1375 public void dup () {
1376 // .. A =>
1377 // .. A A
1378 // ^
1379
1380 int t= top;
1381
1382 int td=t+1;
1383 slots[td] = slots[t];
1384 isRef.set(td, isRef.get(t));
1385
1386 if (attrs != null){
1387 attrs[td] = attrs[t];
1388 }
1389
1390 top = td;
1391 }
1392
1393 public void dup2 () {
1394 // .. A B =>
1395 // .. A B A B
1396 // ^
1397
1398 int ts, td;
1399 int t=top;
1400
1401 // duplicate A
1402 td = t+1; ts = t-1;
1403 slots[td] = slots[ts];
1404 isRef.set(td, isRef.get(ts));
1405 if (attrs != null){
1406 attrs[td] = attrs[ts];
1407 }
1408
1409 // duplicate B
1410 td++; ts=t;
1411 slots[td] = slots[ts];
1412 isRef.set(td, isRef.get(ts));
1413 if (attrs != null){
1414 attrs[td] = attrs[ts];
1415 }
1416
1417 top = td;
1418 }
1419
1420 public void dup2_x1 () {
1421 // .. A B C =>
1422 // .. B C A B C
1423 // ^
1424
1425 int b, c;
1426 boolean bRef, cRef;
1427 Object bAnn = null, cAnn = null;
1428 int ts, td;
1429 int t = top;
1430
1431 // duplicate C
1432 ts=t; td = t+2; // ts=top, td=top+2
1433 slots[td] = c = slots[ts];
1434 cRef = isRef.get(ts);
1435 isRef.set(td,cRef);
1436 if (attrs != null){
1437 attrs[td] = cAnn = attrs[ts];
1438 }
1439
1440 // duplicate B
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);
1445 if (attrs != null){
1446 attrs[td] = bAnn = attrs[ts];
1447 }
1448
1449 // shuffle A
1450 ts=t-2; td=t; // ts=top-2, td=top
1451 slots[td] = slots[ts];
1452 isRef.set(td, isRef.get(ts));
1453 if (attrs != null){
1454 attrs[td] = attrs[ts];
1455 }
1456
1457 // shuffle B
1458 td = ts; // td=top-2
1459 slots[td] = b;
1460 isRef.set(td, bRef);
1461 if (attrs != null){
1462 attrs[td] = bAnn;
1463 }
1464
1465 // shuffle C
1466 td++; // td=top-1
1467 slots[td] = c;
1468 isRef.set(td, cRef);
1469 if (attrs != null){
1470 attrs[td] = cAnn;
1471 }
1472
1473 top += 2;
1474 }
1475
1476 public void dup2_x2 () {
1477 // .. A B C D =>
1478 // .. C D A B C D
1479 // ^
1480
1481 int c, d;
1482 boolean cRef, dRef;
1483 Object cAnn = null, dAnn = null;
1484 int ts, td;
1485 int t = top;
1486
1487 // duplicate C
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);
1492 if (attrs != null){
1493 attrs[td] = cAnn = attrs[ts];
1494 }
1495
1496 // duplicate D
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);
1501 if (attrs != null){
1502 attrs[td] = dAnn = attrs[ts];
1503 }
1504
1505 // shuffle A
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));
1509 if (attrs != null){
1510 attrs[td] = attrs[ts];
1511 }
1512
1513 // shuffle B
1514 ts++; td = t; // ts = top-2
1515 slots[td] = slots[ts];
1516 isRef.set( td, isRef.get(ts));
1517 if (attrs != null){
1518 attrs[td] = attrs[ts];
1519 }
1520
1521 // shuffle D
1522 td = ts; // td = top-2
1523 slots[td] = d;
1524 isRef.set( td, dRef);
1525 if (attrs != null){
1526 attrs[td] = dAnn;
1527 }
1528
1529 // shuffle C
1530 td--; // td = top-3
1531 slots[td] = c;
1532 isRef.set(td, cRef);
1533 if (attrs != null){
1534 attrs[td] = cAnn;
1535 }
1536
1537 top += 2;
1538 }
1539
1540 public void dup_x1 () {
1541 // .. A B =>
1542 // .. B A B
1543 // ^
1544
1545 int b;
1546 boolean bRef;
1547 Object bAnn = null;
1548 int ts, td;
1549 int t = top;
1550
1551 // duplicate B
1552 ts = t; td = t+1;
1553 slots[td] = b = slots[ts];
1554 bRef = isRef.get(ts);
1555 isRef.set(td, bRef);
1556 if (attrs != null){
1557 attrs[td] = bAnn = attrs[ts];
1558 }
1559
1560 // shuffle A
1561 ts--; td = t; // ts=top-1, td = top
1562 slots[td] = slots[ts];
1563 isRef.set( td, isRef.get(ts));
1564 if (attrs != null){
1565 attrs[td] = attrs[ts];
1566 }
1567
1568 // shuffle B
1569 td = ts; // td=top-1
1570 slots[td] = b;
1571 isRef.set( td, bRef);
1572 if (attrs != null){
1573 attrs[td] = bAnn;
1574 }
1575
1576 top++;
1577 }
1578
1579 public void dup_x2 () {
1580 // .. A B C =>
1581 // .. C A B C
1582 // ^
1583
1584 int c;
1585 boolean cRef;
1586 Object cAnn = null;
1587 int ts, td;
1588 int t = top;
1589
1590 // duplicate C
1591 ts = t; td = t+1;
1592 slots[td] = c = slots[ts];
1593 cRef = isRef.get(ts);
1594 isRef.set( td, cRef);
1595 if (attrs != null){
1596 attrs[td] = cAnn = attrs[ts];
1597 }
1598
1599 // shuffle B
1600 td = ts; ts--; // td=top, ts=top-1
1601 slots[td] = slots[ts];
1602 isRef.set( td, isRef.get(ts));
1603 if (attrs != null){
1604 attrs[td] = attrs[ts];
1605 }
1606
1607 // shuffle A
1608 td=ts; ts--; // td=top-1, ts=top-2
1609 slots[td] = slots[ts];
1610 isRef.set( td, isRef.get(ts));
1611 if (attrs != null){
1612 attrs[td] = attrs[ts];
1613 }
1614
1615 // shuffle C
1616 td = ts; // td = top-2
1617 slots[td] = c;
1618 isRef.set(td, cRef);
1619 if (attrs != null){
1620 attrs[td] = cAnn;
1621 }
1622
1623 top++;
1624 }
1625
1626 /**
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
1629 * execution
1630 */
1631 public boolean originatesFrom (StackFrame other){
1632 if (other == this){
1633 return true;
1634 } else {
1635 return ((mi == other.mi) &&
1636 (prev == other.prev) &&
1637 (top == other.top) &&
1638 (getClass() == other.getClass()));
1639 }
1640 }
1641
1642
1643 // <2do> pcm - I assume this compares snapshots, not types. Otherwise it
1644 // would be pointless to equals stack/local values
1645 @Override
1646 public boolean equals (Object o) {
1647 if (o instanceof StackFrame){
1648 StackFrame other = (StackFrame)o;
1649
1650 if (prev != other.prev) {
1651 return false;
1652 }
1653 if (pc != other.pc) {
1654 return false;
1655 }
1656 if (mi != other.mi) {
1657 return false;
1658 }
1659 if (top != other.top){
1660 return false;
1661 }
1662
1663 int[] otherSlots = other.slots;
1664 FixedBitSet otherIsRef = other.isRef;
1665 for (int i=0; i<=top; i++){
1666 if ( slots[i] != otherSlots[i]){
1667 return false;
1668 }
1669 if ( isRef.get(i) != otherIsRef.get(i)){
1670 return false;
1671 }
1672 }
1673
1674 if (!Misc.compare(top,attrs,other.attrs)){
1675 return false;
1676 }
1677
1678 if (!ObjectList.equals(frameAttr, other.frameAttr)){
1679 return false;
1680 }
1681
1682 return true;
1683 }
1684
1685 return false;
1686 }
1687
1688 public boolean hasAnyRef () {
1689 return isRef.cardinality() > 0;
1690 }
1691
1692 public int mixinExecutionStateHash (int h) {
1693 h = OATHash.hashMixin( h, mi.getGlobalId());
1694
1695 if (pc != null){
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
1698 }
1699
1700 for (int i=0; i<top; i++) {
1701 h = OATHash.hashMixin(h, slots[i]);
1702 }
1703
1704 return h;
1705 }
1706
1707 protected void hash (HashData hd) {
1708 if (prev != null){
1709 hd.add(prev.objectHashCode());
1710 }
1711 hd.add(mi.getGlobalId());
1712
1713 if (pc != null){
1714 hd.add(pc.getInstructionIndex());
1715 }
1716
1717 for (int i=0; i<=top; i++){
1718 hd.add(slots[i]);
1719 }
1720
1721 isRef.hash(hd);
1722
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()
1725 if (attrs != null){
1726 for (int i=0; i<=top; i++){
1727 ObjectList.hash( attrs[i], hd);
1728 }
1729 }
1730
1731 if (frameAttr != null){
1732 ObjectList.hash(frameAttr, hd);
1733 }
1734 }
1735
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
1739 @Override
1740 public int hashCode () {
1741 HashData hd = new HashData();
1742 hash(hd);
1743 return hd.getValue();
1744 }
1745
1746 /**
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
1749 * Thread gc roots)
1750 */
1751 public void markThreadRoots (Heap heap, int tid) {
1752
1753 /**
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);
1758 }
1759 }
1760 **/
1761 for (int i = 0; i <= top; i++) {
1762 if (isRef.get(i)) {
1763 int objref = slots[i];
1764 if (objref != MJIEnv.NULL) {
1765 heap.markThreadRoot(objref, tid);
1766 }
1767 }
1768 }
1769 }
1770
1771 //--- debugging methods
1772
1773 public void printOperands (PrintStream pw){
1774 pw.print("operands = [");
1775 for (int i=stackBase; i<=top; i++){
1776 if (i>0){
1777 pw.print(',');
1778 }
1779 if (isOperandRef(i)){
1780 pw.print('^');
1781 }
1782 pw.print(slots[i]);
1783 Object a = getOperandAttr(top-i);
1784 if (a != null){
1785 pw.print(" {");
1786 pw.print(a);
1787 pw.print('}');
1788 }
1789 }
1790 pw.println(']');
1791 }
1792
1793 /**
1794 * this includes locals and pc
1795 */
1796 public void printStackContent () {
1797 PrintStream pw = System.out;
1798
1799 pw.print( "\tat ");
1800 pw.print( mi.getFullName());
1801
1802 if (pc != null) {
1803 pw.println( ":" + pc.getPosition());
1804 } else {
1805 pw.println();
1806 }
1807
1808 pw.print("\t slots: ");
1809 for (int i=0; i<=top; i++){
1810 if (i == stackBase){
1811 pw.println("\t ----------- operand stack");
1812 }
1813
1814 pw.print( "\t [");
1815 pw.print(i);
1816 pw.print("] ");
1817 if (isRef.get(i)) {
1818 pw.print( "@");
1819 }
1820 pw.print( slots[i]);
1821
1822 if (attrs != null){
1823 pw.print(" attr=");
1824 pw.print(attrs[i]);
1825 }
1826
1827 pw.println();
1828 }
1829 }
1830
1831 public void printStackTrace () {
1832 System.out.println( getStackTraceInfo());
1833 }
1834
1835 public void swap () {
1836 int t = top-1;
1837
1838 int v = slots[top];
1839 boolean isTopRef = isRef.get(top);
1840
1841 slots[top] = slots[t];
1842 isRef.set( top, isRef.get(t));
1843
1844 slots[t] = v;
1845 isRef.set( t, isTopRef);
1846
1847 if (attrs != null){
1848 Object a = attrs[top];
1849 attrs[top] = attrs[t];
1850 attrs[t] = a;
1851 }
1852 }
1853
1854 protected void printContentsOn(PrintWriter pw){
1855 pw.print("isFrozen=");
1856 pw.print(isFrozen());
1857 pw.print(",mi=");
1858 pw.print( mi != null ? mi.getUniqueName() : "null");
1859 pw.print(",top="); pw.print(top);
1860 pw.print(",slots=[");
1861
1862 for (int i = 0; i <= top; i++) {
1863 if (i == stackBase){
1864 pw.print("||");
1865 } else {
1866 if (i != 0) {
1867 pw.print(',');
1868 }
1869 }
1870
1871 if (isRef.get(i)){
1872 pw.print('@');
1873 }
1874 pw.print(slots[i]);
1875
1876 if (attrs != null && attrs[i] != null) {
1877 pw.print('(');
1878 pw.print(attrs[i]);
1879 pw.print(')');
1880 }
1881 }
1882
1883 pw.print("],pc=");
1884 pw.print(pc != null ? pc.getPosition() : "null");
1885
1886 pw.print(']');
1887
1888 }
1889
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){
1894 ps.print("||");
1895 } else {
1896 if (i != 0) {
1897 ps.print(',');
1898 }
1899 }
1900
1901 if (isRef.get(i)){
1902 PrintUtils.printReference(ps, slots[i]);
1903 } else {
1904 ps.print(slots[i]);
1905 }
1906 }
1907 }
1908
1909 public int getDepth(){
1910 int depth = 0;
1911
1912 for (StackFrame frame = prev; frame != null; frame = frame.prev){
1913 depth++;
1914 }
1915
1916 return depth;
1917 }
1918
1919 protected int objectHashCode() {
1920 return super.hashCode();
1921 }
1922
1923 @Override
1924 public String toString () {
1925 StringWriter sw = new StringWriter(128);
1926 PrintWriter pw = new PrintWriter(sw);
1927
1928 pw.print(getClass().getSimpleName() + '{');
1929 //pw.print(Integer.toHexString(objectHashCode()));
1930 printContentsOn(pw);
1931 pw.print('}');
1932
1933 return sw.toString();
1934 }
1935
1936 public float peekFloat() {
1937 return Float.intBitsToFloat(slots[top]);
1938 }
1939
1940 public float peekFloat (int offset){
1941 return Float.intBitsToFloat(slots[top-offset]);
1942 }
1943
1944 public double peekDouble() {
1945 int i = top;
1946 return Types.intsToDouble( slots[i], slots[i-1]);
1947 }
1948
1949 public double peekDouble (int offset){
1950 int i = top-offset;
1951 return Types.intsToDouble( slots[i], slots[i-1]);
1952 }
1953
1954 public long peekLong () {
1955 int i = top;
1956 return Types.intsToLong( slots[i], slots[i-1]);
1957 }
1958
1959 public long peekLong (int offset) {
1960 int i = top - offset;
1961 return Types.intsToLong( slots[i], slots[i-1]);
1962 }
1963
1964 public void pushLong (long v) {
1965 push( (int) (v>>32));
1966 push( (int) v);
1967 }
1968
1969 public void pushDouble (double v) {
1970 long l = Double.doubleToLongBits(v);
1971 push( (int) (l>>32));
1972 push( (int) l);
1973 }
1974
1975 public void pushFloat (float v) {
1976 push( Float.floatToIntBits(v));
1977 }
1978
1979 public double popDouble () {
1980 int i = top;
1981
1982 int lo = slots[i--];
1983 int hi = slots[i--];
1984
1985 if (attrs != null){
1986 i = top;
1987 attrs[i--] = null; // not really required
1988 attrs[i--] = null; // that's where the attribute should be
1989 }
1990
1991 top = i;
1992 return Types.intsToDouble(lo, hi);
1993 }
1994
1995 public long popLong () {
1996 int i = top;
1997
1998 int lo = slots[i--];
1999 int hi = slots[i--];
2000
2001 if (attrs != null){
2002 i = top;
2003 attrs[i--] = null; // not really required
2004 attrs[i--] = null; // that's where the attribute should be
2005 }
2006
2007 top = i;
2008 return Types.intsToLong(lo, hi);
2009 }
2010
2011 public int peek () {
2012 return slots[top];
2013 }
2014
2015 public int peek (int offset) {
2016 return slots[top-offset];
2017 }
2018
2019 public void removeArguments (MethodInfo mi) {
2020 int i = mi.getArgumentsSize();
2021
2022 if (i != 0) {
2023 pop(i);
2024 }
2025 }
2026
2027 public void pop (int n) {
2028 //assert (top >= stackBase) : "stack empty";
2029
2030 int t = top - n;
2031
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();
2036 break;
2037 }
2038 }
2039
2040 if (attrs != null){ // just to avoid memory leaks
2041 for (int i=top; i>t; i--){
2042 attrs[i] = null;
2043 }
2044 }
2045
2046 top = t;
2047 }
2048
2049 public float popFloat() {
2050 int v = slots[top];
2051
2052 if (attrs != null){ // just to avoid memory leaks
2053 attrs[top] = null;
2054 }
2055
2056 top--;
2057
2058 return Float.intBitsToFloat(v);
2059 }
2060
2061 public int pop () {
2062 //assert (top >= stackBase) : "stack empty";
2063
2064 int v = slots[top];
2065
2066 // <2do> get rid of this
2067 if (isRef.get(top)) {
2068 if (v != MJIEnv.NULL) {
2069 VM.getVM().getSystemState().activateGC();
2070 }
2071 }
2072
2073 if (attrs != null){ // just to avoid memory leaks
2074 attrs[top] = null;
2075 }
2076
2077 top--;
2078
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)
2082
2083 return v;
2084 }
2085
2086 public void pushLocal (int index) {
2087 top++;
2088 slots[top] = slots[index];
2089 isRef.set(top, isRef.get(index));
2090
2091 if (attrs != null){
2092 attrs[top] = attrs[index];
2093 }
2094 }
2095
2096 public void pushLongLocal (int index){
2097 int t = top;
2098
2099 slots[++t] = slots[index];
2100 isRef.clear(t);
2101 slots[++t] = slots[index+1];
2102 isRef.clear(t);
2103
2104 if (attrs != null){
2105 attrs[t-1] = attrs[index];
2106 attrs[t] = null;
2107 }
2108
2109 top = t;
2110 }
2111
2112 public void storeOperand (int index){
2113 slots[index] = slots[top];
2114 isRef.set( index, isRef.get(top));
2115
2116 if (attrs != null){
2117 attrs[index] = attrs[top];
2118 attrs[top] = null;
2119 }
2120
2121 top--;
2122 }
2123
2124 public void storeLongOperand (int index){
2125 int t = top-1;
2126 int i = index;
2127
2128 slots[i] = slots[t];
2129 isRef.clear(i);
2130
2131 slots[++i] = slots[t+1];
2132 isRef.clear(i);
2133
2134 if (attrs != null){
2135 attrs[index] = attrs[t]; // its in the lower word
2136 attrs[i] = null;
2137
2138 attrs[t] = null;
2139 attrs[t+1] = null;
2140 }
2141
2142 top -=2;
2143 }
2144
2145 public void push (int v){
2146 top++;
2147 slots[top] = v;
2148 isRef.clear(top);
2149
2150 //if (attrs != null){ // done on pop
2151 // attrs[top] = null;
2152 //}
2153 }
2154
2155 public void pushRef (int ref){
2156 top++;
2157 slots[top] = ref;
2158 isRef.set(top);
2159
2160 //if (attrs != null){ // done on pop
2161 // attrs[top] = null;
2162 //}
2163
2164 if (ref != MJIEnv.NULL) {
2165 VM.getVM().getSystemState().activateGC();
2166 }
2167 }
2168
2169 public void push (int v, boolean ref) {
2170 top++;
2171 slots[top] = v;
2172 isRef.set(top, ref);
2173
2174 //if (attrs != null){ // done on pop
2175 // attrs[top] = null;
2176 //}
2177
2178 if (ref && (v != MJIEnv.NULL)) {
2179 VM.getVM().getSystemState().activateGC();
2180 }
2181 }
2182
2183 // return the value of callerSlots variable given the name
2184 public int getLocalVariableSlotIndex (String name) {
2185 LocalVarInfo lv = mi.getLocalVar(name, pc.getPosition());
2186
2187 if (lv != null){
2188 return lv.getSlotIndex();
2189 }
2190
2191 return -1;
2192 }
2193
2194 //--- abstract argument & return passing that can have VM dependend implementation
2195
2196 public void setReferenceResult (int ref, Object attr){
2197 pushRef(ref);
2198 if (attr != null){
2199 setOperandAttr(attr);
2200 }
2201 }
2202
2203 public void setResult (int r, Object attr){
2204 push(r);
2205 if (attr != null){
2206 setOperandAttr(attr);
2207 }
2208 }
2209
2210 public void setResult (long r, Object attr){
2211 pushLong(r);
2212 if (attr != null){
2213 setLongOperandAttr(attr);
2214 }
2215 }
2216
2217 public int getResult(){
2218 return pop();
2219 }
2220
2221 public long getLongResult(){
2222 return popLong();
2223 }
2224
2225 public int getReferenceResult () {
2226 return pop();
2227 }
2228
2229 public Object getResultAttr () {
2230 return getOperandAttr();
2231 }
2232
2233 public Object getLongResultAttr () {
2234 return getLongOperandAttr();
2235 }
2236
2237 public float getFloatResult(){
2238 return Float.intBitsToFloat(getResult());
2239 }
2240 public double getDoubleResult(){
2241 return Double.longBitsToDouble(getLongResult());
2242 }
2243 public Object getFloatResultAttr(){
2244 return getResultAttr();
2245 }
2246 public Object getDoubleResultAttr(){
2247 return getLongResultAttr();
2248 }
2249
2250
2251 //--- VM independent exception handler setup
2252
2253 public void setExceptionReference (int exRef){
2254 pushRef(exRef);
2255 }
2256
2257 public int getExceptionReference (){
2258 return pop();
2259 }
2260
2261 public void setExceptionReferenceAttribute (Object attr){
2262 setOperandAttr(attr);
2263 }
2264
2265 public Object getExceptionReferenceAttribute (){
2266 return getOperandAttr();
2267 }
2268
2269
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);
2274
2275 public void setFloatArgumentLocal (int idx, float value, Object attr){
2276 setArgumentLocal( idx, Float.floatToIntBits(value), attr);
2277 }
2278 public void setDoubleArgumentLocal (int idx, double value, Object attr){
2279 setLongArgumentLocal( idx, Double.doubleToLongBits(value), attr);
2280 }
2281 }