Mercurial > hg > Members > kono > jpf-core
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 } |