KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > tree > analysis > Frame


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package oracle.toplink.libraries.asm.tree.analysis;
32
33 import java.util.ArrayList JavaDoc;
34 import java.util.List JavaDoc;
35
36 import oracle.toplink.libraries.asm.Constants;
37 import oracle.toplink.libraries.asm.Type;
38 import oracle.toplink.libraries.asm.tree.AbstractInsnNode;
39 import oracle.toplink.libraries.asm.tree.IincInsnNode;
40 import oracle.toplink.libraries.asm.tree.MethodInsnNode;
41 import oracle.toplink.libraries.asm.tree.MultiANewArrayInsnNode;
42 import oracle.toplink.libraries.asm.tree.VarInsnNode;
43
44 /**
45  * A symbolic execution stack frame. A stack frame contains a set of local
46  * variable slots, and an operand stack. Warning: long and double values are
47  * represented by <i>two</i> slots in local variables, and by <i>one</i> slot
48  * in the operand stack.
49  *
50  * @author Eric Bruneton
51  */

52
53 public class Frame {
54   
55   /**
56    * The local variables of this frame.
57    */

58   
59   private Value[] locals;
60   
61   /**
62    * The operand stack of this frame.
63    */

64   
65   private Value[] stack;
66
67   /**
68    * The number of elements in the operand stack.
69    */

70   
71   private int top;
72   
73   /**
74    * Constructs a new frame with the given size.
75    *
76    * @param nLocals the maximum number of local variables of the frame.
77    * @param nStack the maximum stack size of the frame.
78    */

79   
80   public Frame (final int nLocals, final int nStack) {
81     this.locals = new Value[nLocals];
82     this.stack = new Value[nStack];
83   }
84   
85   /**
86    * Constructs a new frame that is identical to the given frame.
87    *
88    * @param src a frame.
89    */

90   
91   public Frame (final Frame src) {
92     this(src.locals.length, src.stack.length);
93     init(src);
94   }
95   
96   /**
97    * Copies the state of the given frame into this frame.
98    *
99    * @param src a frame.
100    * @return this frame.
101    */

102   
103   public Frame init (final Frame src) {
104     System.arraycopy(src.locals, 0, locals, 0, locals.length);
105     System.arraycopy(src.stack, 0, stack, 0, src.top);
106     top = src.top;
107     return this;
108   }
109   
110   /**
111    * Returns the maximum number of local variables of this frame.
112    *
113    * @return the maximum number of local variables of this frame.
114    */

115   
116   public int getLocals () {
117     return locals.length;
118   }
119   
120   /**
121    * Returns the value of the given local variable.
122    *
123    * @param i a local variable index.
124    * @return the value of the given local variable.
125    * @throws AnalyzerException if the variable does not exist.
126    */

127   
128   public Value getLocal (final int i) throws AnalyzerException {
129     if (i >= locals.length) {
130       throw new AnalyzerException("Trying to access an inexistant local variable");
131     }
132     return locals[i];
133   }
134   
135   /**
136    * Sets the value of the given local variable.
137    *
138    * @param i a local variable index.
139    * @param value the new value of this local variable.
140    * @throws AnalyzerException if the variable does not exist.
141    */

142   
143   public void setLocal (final int i, final Value value) throws AnalyzerException {
144     if (i >= locals.length) {
145       throw new AnalyzerException("Trying to access an inexistant local variable");
146     }
147     locals[i] = value;
148   }
149
150   /**
151    * Returns the number of values in the operand stack of this frame. Long and
152    * double values are treated as single values.
153    *
154    * @return the number of values in the operand stack of this frame.
155    */

156   
157   public int getStackSize () {
158     return top;
159   }
160   
161   /**
162    * Returns the value of the given operand stack slot.
163    *
164    * @param i the index of an operand stack slot.
165    * @return the value of the given operand stack slot.
166    * @throws AnalyzerException if the operand stack slot does not exist.
167    */

168   
169   public Value getStack (final int i) throws AnalyzerException {
170     if (i >= top) {
171       throw new AnalyzerException("Trying to access an inexistant stack element");
172     }
173     return stack[i];
174   }
175   
176   /**
177    * Clears the operand stack of this frame.
178    */

179   
180   public void clearStack () {
181     top = 0;
182   }
183
184   /**
185    * Pops a value from the operand stack of this frame.
186    *
187    * @return the value that has been popped from the stack.
188    * @throws AnalyzerException if the operand stack is empty.
189    */

190   
191   public Value pop () throws AnalyzerException {
192     if (top == 0) {
193       throw new AnalyzerException("Cannot pop operand off an empty stack.");
194     }
195     return stack[--top];
196   }
197   
198   /**
199    * Pushes a value into the operand stack of this frame.
200    *
201    * @param value the value that must be pushed into the stack.
202    * @throws AnalyzerException if the operand stack is full.
203    */

204   
205   public void push (final Value value) throws AnalyzerException {
206     if (top >= stack.length) {
207       throw new AnalyzerException("Insufficient maximum stack size.");
208     }
209     stack[top++] = value;
210   }
211   
212   public void execute (
213     final AbstractInsnNode insn,
214     final Interpreter interpreter) throws AnalyzerException
215   {
216     Value value1, value2, value3, value4;
217     List JavaDoc values;
218     int var;
219     
220     switch (insn.getOpcode()) {
221       case Constants.NOP:
222         break;
223       case Constants.ACONST_NULL:
224       case Constants.ICONST_M1:
225       case Constants.ICONST_0:
226       case Constants.ICONST_1:
227       case Constants.ICONST_2:
228       case Constants.ICONST_3:
229       case Constants.ICONST_4:
230       case Constants.ICONST_5:
231       case Constants.LCONST_0:
232       case Constants.LCONST_1:
233       case Constants.FCONST_0:
234       case Constants.FCONST_1:
235       case Constants.FCONST_2:
236       case Constants.DCONST_0:
237       case Constants.DCONST_1:
238       case Constants.BIPUSH:
239       case Constants.SIPUSH:
240       case Constants.LDC:
241         push(interpreter.newOperation(insn));
242         break;
243       case Constants.ILOAD:
244       case Constants.LLOAD:
245       case Constants.FLOAD:
246       case Constants.DLOAD:
247       case Constants.ALOAD:
248         push(interpreter.copyOperation(insn, getLocal(((VarInsnNode)insn).var)));
249         break;
250       case Constants.IALOAD:
251       case Constants.LALOAD:
252       case Constants.FALOAD:
253       case Constants.DALOAD:
254       case Constants.AALOAD:
255       case Constants.BALOAD:
256       case Constants.CALOAD:
257       case Constants.SALOAD:
258         value2 = pop();
259         value1 = pop();
260         push(interpreter.binaryOperation(insn, value1, value2));
261         break;
262       case Constants.ISTORE:
263       case Constants.LSTORE:
264       case Constants.FSTORE:
265       case Constants.DSTORE:
266       case Constants.ASTORE:
267         value1 = interpreter.copyOperation(insn, pop());
268         var = ((VarInsnNode)insn).var;
269         setLocal(var, value1);
270         if (value1.getSize() == 2) {
271           setLocal(var + 1, interpreter.newValue(null));
272         }
273         if (var > 0 && getLocal(var - 1).getSize() == 2) {
274           setLocal(var - 1, interpreter.newValue(null));
275         }
276         break;
277       case Constants.IASTORE:
278       case Constants.LASTORE:
279       case Constants.FASTORE:
280       case Constants.DASTORE:
281       case Constants.AASTORE:
282       case Constants.BASTORE:
283       case Constants.CASTORE:
284       case Constants.SASTORE:
285         value3 = pop();
286         value2 = pop();
287         value1 = pop();
288         interpreter.ternaryOperation(insn, value1, value2, value3);
289         break;
290       case Constants.POP:
291         if (pop().getSize() == 2) {
292           throw new AnalyzerException("Illegal use of POP");
293         }
294         break;
295       case Constants.POP2:
296         if (pop().getSize() == 1) {
297           if (pop().getSize() != 1) {
298             throw new AnalyzerException("Illegal use of POP2");
299           }
300         }
301         break;
302       case Constants.DUP:
303         value1 = pop();
304         if (value1.getSize() != 1) {
305           throw new AnalyzerException("Illegal use of DUP");
306         }
307         push(interpreter.copyOperation(insn, value1));
308         push(interpreter.copyOperation(insn, value1));
309         break;
310       case Constants.DUP_X1:
311         value1 = pop();
312         value2 = pop();
313         if (value1.getSize() != 1 || value2.getSize() != 1) {
314           throw new AnalyzerException("Illegal use of DUP_X1");
315         }
316         push(interpreter.copyOperation(insn, value1));
317         push(interpreter.copyOperation(insn, value2));
318         push(interpreter.copyOperation(insn, value1));
319         break;
320       case Constants.DUP_X2:
321         value1 = pop();
322         if (value1.getSize() == 1) {
323           value2 = pop();
324           if (value2.getSize() == 1) {
325             value3 = pop();
326             if (value3.getSize() == 1) {
327               push(interpreter.copyOperation(insn, value1));
328               push(interpreter.copyOperation(insn, value3));
329               push(interpreter.copyOperation(insn, value2));
330               push(interpreter.copyOperation(insn, value1));
331               break;
332             }
333           } else {
334             push(interpreter.copyOperation(insn, value1));
335             push(interpreter.copyOperation(insn, value2));
336             push(interpreter.copyOperation(insn, value1));
337             break;
338           }
339         }
340         throw new AnalyzerException("Illegal use of DUP_X2");
341       case Constants.DUP2:
342         value1 = pop();
343         if (value1.getSize() == 1) {
344           value2 = pop();
345           if (value2.getSize() == 1) {
346             push(interpreter.copyOperation(insn, value2));
347             push(interpreter.copyOperation(insn, value1));
348             push(interpreter.copyOperation(insn, value2));
349             push(interpreter.copyOperation(insn, value1));
350             break;
351           }
352         } else {
353           push(interpreter.copyOperation(insn, value1));
354           push(interpreter.copyOperation(insn, value1));
355           break;
356         }
357         throw new AnalyzerException("Illegal use of DUP2");
358       case Constants.DUP2_X1:
359         value1 = pop();
360         if (value1.getSize() == 1) {
361           value2 = pop();
362           if (value2.getSize() == 1) {
363             value3 = pop();
364             if (value3.getSize() == 1) {
365               push(interpreter.copyOperation(insn, value2));
366               push(interpreter.copyOperation(insn, value1));
367               push(interpreter.copyOperation(insn, value3));
368               push(interpreter.copyOperation(insn, value2));
369               push(interpreter.copyOperation(insn, value1));
370               break;
371             }
372           }
373         } else {
374           value2 = pop();
375           if (value2.getSize() == 1) {
376             push(interpreter.copyOperation(insn, value1));
377             push(interpreter.copyOperation(insn, value2));
378             push(interpreter.copyOperation(insn, value1));
379             break;
380           }
381         }
382         throw new AnalyzerException("Illegal use of DUP2_X1");
383       case Constants.DUP2_X2:
384         value1 = pop();
385         if (value1.getSize() == 1) {
386           value2 = pop();
387           if (value2.getSize() == 1) {
388             value3 = pop();
389             if (value3.getSize() == 1) {
390               value4 = pop();
391               if (value4.getSize() == 1) {
392                 push(interpreter.copyOperation(insn, value2));
393                 push(interpreter.copyOperation(insn, value1));
394                 push(interpreter.copyOperation(insn, value4));
395                 push(interpreter.copyOperation(insn, value3));
396                 push(interpreter.copyOperation(insn, value2));
397                 push(interpreter.copyOperation(insn, value1));
398                 break;
399               }
400             } else {
401               push(interpreter.copyOperation(insn, value2));
402               push(interpreter.copyOperation(insn, value1));
403               push(interpreter.copyOperation(insn, value3));
404               push(interpreter.copyOperation(insn, value2));
405               push(interpreter.copyOperation(insn, value1));
406               break;
407             }
408           }
409         } else {
410           value2 = pop();
411           if (value2.getSize() == 1) {
412             value3 = pop();
413             if (value3.getSize() == 1) {
414               push(interpreter.copyOperation(insn, value1));
415               push(interpreter.copyOperation(insn, value3));
416               push(interpreter.copyOperation(insn, value2));
417               push(interpreter.copyOperation(insn, value1));
418               break;
419             }
420           } else {
421             push(interpreter.copyOperation(insn, value1));
422             push(interpreter.copyOperation(insn, value2));
423             push(interpreter.copyOperation(insn, value1));
424             break;
425           }
426         }
427         throw new AnalyzerException("Illegal use of DUP2_X2");
428       case Constants.SWAP:
429         value2 = pop();
430         value1 = pop();
431         if (value1.getSize() != 1 || value2.getSize() != 1) {
432           throw new AnalyzerException("Illegal use of SWAP");
433         }
434         push(interpreter.copyOperation(insn, value2));
435         push(interpreter.copyOperation(insn, value1));
436         break;
437       case Constants.IADD:
438       case Constants.LADD:
439       case Constants.FADD:
440       case Constants.DADD:
441       case Constants.ISUB:
442       case Constants.LSUB:
443       case Constants.FSUB:
444       case Constants.DSUB:
445       case Constants.IMUL:
446       case Constants.LMUL:
447       case Constants.FMUL:
448       case Constants.DMUL:
449       case Constants.IDIV:
450       case Constants.LDIV:
451       case Constants.FDIV:
452       case Constants.DDIV:
453       case Constants.IREM:
454       case Constants.LREM:
455       case Constants.FREM:
456       case Constants.DREM:
457         value2 = pop();
458         value1 = pop();
459         push(interpreter.binaryOperation(insn, value1, value2));
460         break;
461       case Constants.INEG:
462       case Constants.LNEG:
463       case Constants.FNEG:
464       case Constants.DNEG:
465         push(interpreter.unaryOperation(insn, pop()));
466         break;
467       case Constants.ISHL:
468       case Constants.LSHL:
469       case Constants.ISHR:
470       case Constants.LSHR:
471       case Constants.IUSHR:
472       case Constants.LUSHR:
473       case Constants.IAND:
474       case Constants.LAND:
475       case Constants.IOR:
476       case Constants.LOR:
477       case Constants.IXOR:
478       case Constants.LXOR:
479         value2 = pop();
480         value1 = pop();
481         push(interpreter.binaryOperation(insn, value1, value2));
482         break;
483       case Constants.IINC:
484         var = ((IincInsnNode)insn).var;
485         setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
486         break;
487       case Constants.I2L:
488       case Constants.I2F:
489       case Constants.I2D:
490       case Constants.L2I:
491       case Constants.L2F:
492       case Constants.L2D:
493       case Constants.F2I:
494       case Constants.F2L:
495       case Constants.F2D:
496       case Constants.D2I:
497       case Constants.D2L:
498       case Constants.D2F:
499       case Constants.I2B:
500       case Constants.I2C:
501       case Constants.I2S:
502         push(interpreter.unaryOperation(insn, pop()));
503         break;
504       case Constants.LCMP:
505       case Constants.FCMPL:
506       case Constants.FCMPG:
507       case Constants.DCMPL:
508       case Constants.DCMPG:
509         value2 = pop();
510         value1 = pop();
511         push(interpreter.binaryOperation(insn, value1, value2));
512         break;
513       case Constants.IFEQ:
514       case Constants.IFNE:
515       case Constants.IFLT:
516       case Constants.IFGE:
517       case Constants.IFGT:
518       case Constants.IFLE:
519         interpreter.unaryOperation(insn, pop());
520         break;
521       case Constants.IF_ICMPEQ:
522       case Constants.IF_ICMPNE:
523       case Constants.IF_ICMPLT:
524       case Constants.IF_ICMPGE:
525       case Constants.IF_ICMPGT:
526       case Constants.IF_ICMPLE:
527       case Constants.IF_ACMPEQ:
528       case Constants.IF_ACMPNE:
529         value2 = pop();
530         value1 = pop();
531         interpreter.binaryOperation(insn, value1, value2);
532         break;
533       case Constants.GOTO:
534         break;
535       case Constants.JSR:
536         push(interpreter.newOperation(insn));
537         break;
538       case Constants.RET:
539         break;
540       case Constants.TABLESWITCH:
541       case Constants.LOOKUPSWITCH:
542       case Constants.IRETURN:
543       case Constants.LRETURN:
544       case Constants.FRETURN:
545       case Constants.DRETURN:
546       case Constants.ARETURN:
547         interpreter.unaryOperation(insn, pop());
548         break;
549       case Constants.RETURN:
550         break;
551       case Constants.GETSTATIC:
552         push(interpreter.newOperation(insn));
553         break;
554       case Constants.PUTSTATIC:
555         interpreter.unaryOperation(insn, pop());
556         break;
557       case Constants.GETFIELD:
558         push(interpreter.unaryOperation(insn, pop()));
559         break;
560       case Constants.PUTFIELD:
561         value2 = pop();
562         value1 = pop();
563         interpreter.binaryOperation(insn, value1, value2);
564         break;
565       case Constants.INVOKEVIRTUAL:
566       case Constants.INVOKESPECIAL:
567       case Constants.INVOKESTATIC:
568       case Constants.INVOKEINTERFACE:
569         values = new ArrayList JavaDoc();
570         String JavaDoc desc = ((MethodInsnNode)insn).desc;
571         for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
572           values.add(0, pop());
573         }
574         if (insn.getOpcode() != Constants.INVOKESTATIC) {
575           values.add(0, pop());
576         }
577         if (Type.getReturnType(desc) == Type.VOID_TYPE) {
578           interpreter.naryOperation(insn, values);
579         } else {
580           push(interpreter.naryOperation(insn, values));
581         }
582         break;
583       case Constants.NEW:
584         push(interpreter.newOperation(insn));
585         break;
586       case Constants.NEWARRAY:
587       case Constants.ANEWARRAY:
588       case Constants.ARRAYLENGTH:
589         push(interpreter.unaryOperation(insn, pop()));
590         break;
591       case Constants.ATHROW:
592         interpreter.unaryOperation(insn, pop());
593         break;
594       case Constants.CHECKCAST:
595       case Constants.INSTANCEOF:
596         push(interpreter.unaryOperation(insn, pop()));
597         break;
598       case Constants.MONITORENTER:
599       case Constants.MONITOREXIT:
600         interpreter.unaryOperation(insn, pop());
601         break;
602       case Constants.MULTIANEWARRAY:
603         values = new ArrayList JavaDoc();
604         for (int i = ((MultiANewArrayInsnNode)insn).dims; i > 0; --i) {
605           values.add(0, pop());
606         }
607         push(interpreter.naryOperation(insn, values));
608         break;
609       case Constants.IFNULL:
610       case Constants.IFNONNULL:
611         interpreter.unaryOperation(insn, pop());
612         break;
613       default:
614         throw new RuntimeException JavaDoc("Illegal opcode");
615     }
616   }
617
618   /**
619    * Merges this frame with the given frame.
620    *
621    * @param frame a frame.
622    * @param interpreter the interpreter used to merge values.
623    * @return <tt>true</tt> if this frame has been changed as a result of the
624    * merge operation, or <tt>false</tt> otherwise.
625    * @throws AnalyzerException if the frames have incompatible sizes.
626    */

627   
628   public boolean merge (final Frame frame, final Interpreter interpreter)
629     throws AnalyzerException
630   {
631     if (top != frame.top) {
632       throw new AnalyzerException("Incompatible stack heights");
633     }
634     boolean changes = false;
635     for (int i = 0; i < locals.length; ++i) {
636       Value v = interpreter.merge(locals[i], frame.locals[i]);
637       if (v != locals[i]) {
638         locals[i] = v;
639         changes |= true;
640       }
641     }
642     for (int i = 0; i < top; ++i) {
643       Value v = interpreter.merge(stack[i], frame.stack[i]);
644       if (v != stack[i]) {
645         stack[i] = v;
646         changes |= true;
647       }
648     }
649     return changes;
650   }
651   
652   /**
653    * Merges this frame with the given frame (case of a RET instruction).
654
655    * @param frame a frame
656    * @param access the local variables that have been accessed by the
657    * subroutine to which the RET instruction corresponds.
658    * @return <tt>true</tt> if this frame has been changed as a result of the
659    * merge operation, or <tt>false</tt> otherwise.
660    */

661   
662   public boolean merge (final Frame frame, final boolean[] access) {
663     boolean changes = false;
664     for (int i = 0; i < locals.length; ++i) {
665       if (!access[i] && !locals[i].equals(frame.locals[i])) {
666         locals[i] = frame.locals[i];
667         changes = true;
668       }
669     }
670     return changes;
671   }
672   
673   /**
674    * Returns a string representation of this frame.
675    *
676    * @return a string representation of this frame.
677    */

678   
679   public String JavaDoc toString () {
680     StringBuffer JavaDoc b = new StringBuffer JavaDoc();
681     for (int i = 0; i < locals.length; ++i) {
682       b.append(locals[i]);
683     }
684     b.append(' ');
685     for (int i = 0; i < top; ++i) {
686       b.append(stack[i].toString());
687     }
688     return b.toString();
689   }
690 }
691
Popular Tags