KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > OpcodeStack


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2004 Dave Brosius <dbrosius@users.sourceforge.net>
4  * Copyright (C) 2003-2006 University of Maryland
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */

20  
21 package edu.umd.cs.findbugs;
22
23 import java.util.ArrayList JavaDoc;
24 import java.util.BitSet JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Stack JavaDoc;
29
30 import org.apache.bcel.Repository;
31 import org.apache.bcel.classfile.Code;
32 import org.apache.bcel.classfile.CodeException;
33 import org.apache.bcel.classfile.Constant;
34 import org.apache.bcel.classfile.ConstantClass;
35 import org.apache.bcel.classfile.ConstantDouble;
36 import org.apache.bcel.classfile.ConstantFloat;
37 import org.apache.bcel.classfile.ConstantInteger;
38 import org.apache.bcel.classfile.ConstantLong;
39 import org.apache.bcel.classfile.ConstantString;
40 import org.apache.bcel.classfile.ConstantUtf8;
41 import org.apache.bcel.classfile.JavaClass;
42 import org.apache.bcel.classfile.LocalVariable;
43 import org.apache.bcel.classfile.LocalVariableTable;
44 import org.apache.bcel.classfile.Method;
45 import org.apache.bcel.generic.BasicType;
46 import org.apache.bcel.generic.Type;
47
48 import edu.umd.cs.findbugs.ba.AnalysisContext;
49 import edu.umd.cs.findbugs.ba.AnalysisFeatures;
50 import edu.umd.cs.findbugs.ba.XFactory;
51 import edu.umd.cs.findbugs.ba.XField;
52 import edu.umd.cs.findbugs.visitclass.Constants2;
53 import edu.umd.cs.findbugs.visitclass.DismantleBytecode;
54 import edu.umd.cs.findbugs.visitclass.LVTHelper;
55 import edu.umd.cs.findbugs.visitclass.PreorderVisitor;
56
57 /**
58  * tracks the types and numbers of objects that are currently on the operand stack
59  * throughout the execution of method. To use, a detector should instantiate one for
60  * each method, and call <p>stack.sawOpcode(this,seen);</p> at the bottom of their sawOpcode method.
61  * at any point you can then inspect the stack and see what the types of objects are on
62  * the stack, including constant values if they were pushed. The types described are of
63  * course, only the static types.
64  * There are some outstanding opcodes that have yet to be implemented, I couldn't
65  * find any code that actually generated these, so i didn't put them in because
66  * I couldn't test them:
67  * <ul>
68  * <li>dup2_x2</li>
69  * <li>jsr_w</li>
70  * <li>wide</li>
71  * </ul>
72  */

73 public class OpcodeStack implements Constants2
74 {
75     private static final boolean DEBUG
76         = SystemProperties.getBoolean("ocstack.debug");
77     private List JavaDoc<Item> stack;
78     private List JavaDoc<Item> lvValues;
79     private List JavaDoc<Integer JavaDoc> lastUpdate;
80
81         
82
83     private boolean seenTransferOfControl = false;
84
85     private boolean useIterativeAnalysis
86     = AnalysisContext.currentAnalysisContext().getBoolProperty(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS);
87         
88     
89     public static class Item
90     {
91         public static final int SIGNED_BYTE = 1;
92         public static final int RANDOM_INT = 2;
93         public static final int LOW_8_BITS_CLEAR = 3;
94         public static final int HASHCODE_INT = 4;
95         public static final int INTEGER_SUM = 5;
96         public static final int AVERAGE_COMPUTED_USING_DIVISION = 6;
97         public static final int FLOAT_MATH = 7;
98         public static final int RANDOM_INT_REMAINDER = 8;
99         public static final int HASHCODE_INT_REMAINDER = 9;
100         public static final int FILE_SEPARATOR_STRING = 10;
101         
102         private static final int IS_INITIAL_PARAMETER_FLAG=1;
103         private static final int COULD_BE_ZERO_FLAG = 2;
104         private static final int IS_NULL_FLAG = 4;
105         
106         public static final Object JavaDoc UNKNOWN = null;
107         private int specialKind;
108         private String JavaDoc signature;
109         private Object JavaDoc constValue = UNKNOWN;
110         private XField xfield;
111         private int flags;
112         // private boolean isNull = false;
113
private int registerNumber = -1;
114         // private boolean isInitialParameter = false;
115
// private boolean couldBeZero = false;
116
private Object JavaDoc userValue = null;
117         private int fieldLoadedFromRegister = -1;
118
119         
120         public int getSize() {
121             if (signature.equals("J") || signature.equals("D")) return 2;
122             return 1;
123         }
124
125         private static boolean equals(Object JavaDoc o1, Object JavaDoc o2) {
126             if (o1 == o2) return true;
127             if (o1 == null || o2 == null) return false;
128             return o1.equals(o2);
129             }
130
131         @Override JavaDoc
132         public int hashCode() {
133             int r = 42 + specialKind;
134             if (signature != null)
135                 r+= signature.hashCode();
136             r *= 31;
137             if (constValue != null)
138                 r+= constValue.hashCode();
139             r *= 31;
140             if (xfield != null)
141                 r+= xfield.hashCode();
142             r *= 31;
143             r += flags;
144             r *= 31;
145             r += registerNumber;
146             return r;
147             
148             }
149         @Override JavaDoc
150         public boolean equals(Object JavaDoc o) {
151             if (!(o instanceof Item)) return false;
152             Item that = (Item) o;
153
154             return equals(this.signature, that.signature)
155                 && equals(this.constValue, that.constValue)
156                 && equals(this.xfield, that.xfield)
157                 && this.specialKind == that.specialKind
158                 && this.registerNumber == that.registerNumber
159                 && this.flags == that.flags
160                 && this.userValue == that.userValue
161                 && this.fieldLoadedFromRegister == that.fieldLoadedFromRegister;
162                 
163             }
164
165         @Override JavaDoc
166         public String JavaDoc toString() {
167             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("< ");
168             buf.append(signature);
169             switch(specialKind) {
170             case SIGNED_BYTE:
171                 buf.append(", byte_array_load");
172                 break;
173             case RANDOM_INT:
174                 buf.append(", random_int");
175                 break;
176             case LOW_8_BITS_CLEAR:
177                 buf.append(", low8clear");
178                 break;
179             case HASHCODE_INT:
180                 buf.append(", hashcode_int");
181                 break;
182             case INTEGER_SUM:
183                 buf.append(", int_sum");
184                 break;
185             case AVERAGE_COMPUTED_USING_DIVISION:
186                 buf.append(", averageComputingUsingDivision");
187                 break;
188             case FLOAT_MATH:
189                 buf.append(", floatMath");
190                 break;
191             case HASHCODE_INT_REMAINDER:
192                 buf.append(", hashcode_int_rem");
193                 break;
194             case RANDOM_INT_REMAINDER:
195                 buf.append(", random_int_rem");
196                 break;
197             case FILE_SEPARATOR_STRING:
198                 buf.append(", file_separator_string");
199                 break;
200             case 0 :
201                 break;
202             default:
203                     buf.append(", #" + specialKind);
204                 break;
205
206             }
207             if (constValue != UNKNOWN) {
208                 buf.append(", ");
209                 buf.append(constValue);
210                 }
211             if (xfield!= UNKNOWN) {
212                 buf.append(", ");
213                 if (fieldLoadedFromRegister != -1)
214                     buf.append(fieldLoadedFromRegister).append(':');
215                 buf.append(xfield);
216                 }
217             if (isInitialParameter()) {
218                 buf.append(", IP");
219                 }
220             if (isNull()) {
221                 buf.append(", isNull");
222                 }
223                 
224             if (registerNumber != -1) {
225                 buf.append(", r");
226                 buf.append(registerNumber);
227                 }
228             if (isCouldBeZero()) buf.append(", cbz");
229             buf.append(" >");
230             return buf.toString();
231             }
232                 
233         
234         public static Item merge(Item i1, Item i2) {
235             if (i1 == null) return i2;
236             if (i2 == null) return i1;
237             if (i1.equals(i2)) return i1;
238             Item m = new Item();
239             m.flags = i1.flags & i2.flags;
240             m.setCouldBeZero(i1.isCouldBeZero() || i2.isCouldBeZero());
241             if (equals(i1.signature,i2.signature))
242                 m.signature = i1.signature;
243             if (equals(i1.constValue,i2.constValue))
244                 m.constValue = i1.constValue;
245             if (equals(i1.xfield,i2.xfield)) {
246                 m.xfield = i1.xfield;
247             }
248                 if (i1.registerNumber == i2.registerNumber)
249                 m.registerNumber = i1.registerNumber;
250             if (i1.fieldLoadedFromRegister == i2.fieldLoadedFromRegister)
251                 m.fieldLoadedFromRegister = i1.fieldLoadedFromRegister;
252         
253             if (i1.specialKind == i2.specialKind)
254                 m.specialKind = i1.specialKind;
255             else if (i1.specialKind == FLOAT_MATH || i2.specialKind == FLOAT_MATH)
256                 m.specialKind = FLOAT_MATH;
257             if (DEBUG) System.out.println("Merge " + i1 + " and " + i2 + " gives " + m);
258             return m;
259         }
260         public Item(String JavaDoc signature, int constValue) {
261             this(signature, (Object JavaDoc)(Integer JavaDoc)constValue);
262         }
263
264         public Item(String JavaDoc signature) {
265             this(signature, UNKNOWN);
266         }
267         public Item(Item it) {
268             this.signature = it.signature;
269             this.constValue = it.constValue;
270             this.xfield = it.xfield;
271             this.registerNumber = it.registerNumber;
272             this.userValue = it.userValue;
273             this.flags = it.flags;
274             this.specialKind = it.specialKind;
275         }
276         public Item(Item it, int reg) {
277             this(it);
278             this.registerNumber = reg;
279         }
280         public Item(String JavaDoc signature, FieldAnnotation f) {
281             this.signature = signature;
282             if (f != null)
283                 xfield = XFactory.createXField(f);
284             fieldLoadedFromRegister = -1;
285         }
286         public Item(String JavaDoc signature, FieldAnnotation f, int fieldLoadedFromRegister) {
287             this.signature = signature;
288             if (f != null)
289                 xfield = XFactory.createXField(f);
290             this.fieldLoadedFromRegister = fieldLoadedFromRegister;
291         }
292         
293         public int getFieldLoadedFromRegister() {
294             return fieldLoadedFromRegister;
295         }
296
297         public Item(String JavaDoc signature, Object JavaDoc constantValue) {
298             this.signature = signature;
299             constValue = constantValue;
300             if (constantValue instanceof Integer JavaDoc) {
301                 int value = (Integer JavaDoc) constantValue;
302                 if (value != 0 && (value & 0xff) == 0)
303                     specialKind = LOW_8_BITS_CLEAR;
304                 if (value == 0) setCouldBeZero(true);
305  
306             }
307             else if (constantValue instanceof Long JavaDoc) {
308                 long value = (Long JavaDoc) constantValue;
309                 if (value != 0 && (value & 0xff) == 0)
310                     specialKind = LOW_8_BITS_CLEAR;
311                 if (value == 0) setCouldBeZero(true);
312             }
313             
314         }
315         
316         public Item() {
317             signature = "Ljava/lang/Object;";
318             constValue = null;
319             setNull(true);
320         }
321                         
322         public JavaClass getJavaClass() throws ClassNotFoundException JavaDoc {
323             String JavaDoc baseSig;
324             
325             if (isPrimitive())
326                 return null;
327                 
328             if (isArray()) {
329                 baseSig = getElementSignature();
330             } else {
331                 baseSig = signature;
332             }
333             
334             if (baseSig.length() == 0)
335                 return null;
336             baseSig = baseSig.substring(1, baseSig.length() - 1);
337             baseSig = baseSig.replace('/', '.');
338             return Repository.lookupClass(baseSig);
339         }
340                 
341         public boolean isArray() {
342             return signature.startsWith("[");
343         }
344                 
345         public String JavaDoc getElementSignature() {
346             if (!isArray())
347                 return signature;
348             else {
349                 int pos = 0;
350                 int len = signature.length();
351                 while (pos < len) {
352                     if (signature.charAt(pos) != '[')
353                         break;
354                     pos++;
355                 }
356                 return signature.substring(pos);
357             }
358         }
359         
360         public boolean isPrimitive() {
361             return !signature.startsWith("L");
362         }
363         
364         public int getRegisterNumber() {
365             return registerNumber;
366         }
367         public String JavaDoc getSignature() {
368             return signature;
369         }
370         
371         public Object JavaDoc getConstant() {
372             return constValue;
373         }
374
375         /** Use getXField instead */
376         @Deprecated JavaDoc
377         public FieldAnnotation getFieldAnnotation() {
378             return FieldAnnotation.fromXField(xfield);
379         }
380         public XField getXField() {
381             return xfield;
382         }
383         /**
384          * @param specialKind The specialKind to set.
385          */

386         public void setSpecialKind(int specialKind) {
387             this.specialKind = specialKind;
388         }
389
390         /**
391          * @return Returns the specialKind.
392          */

393         public int getSpecialKind() {
394             return specialKind;
395         }
396         
397         /**
398          * attaches a detector specified value to this item
399          *
400          * @param value the custom value to set
401          */

402         public void setUserValue(Object JavaDoc value) {
403             userValue = value;
404         }
405         
406         public boolean couldBeZero() {
407             return isCouldBeZero();
408         }
409         public boolean mustBeZero() {
410             Object JavaDoc value = getConstant();
411             return value instanceof Number JavaDoc && ((Number JavaDoc)value).intValue() == 0;
412         }
413         /**
414          * gets the detector specified value for this item
415          *
416          * @return the custom value
417          */

418         public Object JavaDoc getUserValue() {
419             return userValue;
420         }
421
422         public boolean valueCouldBeNegative() {
423             return (getSpecialKind() == Item.RANDOM_INT
424                     || getSpecialKind() == Item.SIGNED_BYTE
425                     || getSpecialKind() == Item.HASHCODE_INT
426                     || getSpecialKind() == Item.RANDOM_INT_REMAINDER || getSpecialKind() == Item.HASHCODE_INT_REMAINDER);
427             
428         }
429
430         /**
431          * @param isInitialParameter The isInitialParameter to set.
432          */

433         private void setInitialParameter(boolean isInitialParameter) {
434             setFlag(isInitialParameter, IS_INITIAL_PARAMETER_FLAG);
435         }
436
437         /**
438          * @return Returns the isInitialParameter.
439          */

440         public boolean isInitialParameter() {
441             return (flags & IS_INITIAL_PARAMETER_FLAG) != 0;
442         }
443
444         /**
445          * @param couldBeZero The couldBeZero to set.
446          */

447         private void setCouldBeZero(boolean couldBeZero) {
448             setFlag(couldBeZero, COULD_BE_ZERO_FLAG);
449         }
450
451         /**
452          * @return Returns the couldBeZero.
453          */

454         private boolean isCouldBeZero() {
455             return (flags & COULD_BE_ZERO_FLAG) != 0;
456         }
457
458         /**
459          * @param isNull The isNull to set.
460          */

461         private void setNull(boolean isNull) {
462             setFlag(isNull, IS_NULL_FLAG);
463         }
464
465         private void setFlag(boolean value, int flagBit) {
466             if (value)
467                 flags |= flagBit;
468             else
469                 flags &= ~flagBit;
470         }
471         /**
472          * @return Returns the isNull.
473          */

474         public boolean isNull() {
475             return (flags & IS_NULL_FLAG) != 0;
476         }
477     }
478
479     @Override JavaDoc
480     public String JavaDoc toString() {
481         return stack.toString() + "::" + lvValues.toString();
482     }
483     
484     public OpcodeStack()
485     {
486         stack = new ArrayList JavaDoc<Item>();
487         lvValues = new ArrayList JavaDoc<Item>();
488         lastUpdate = new ArrayList JavaDoc<Integer JavaDoc>();
489     }
490
491     boolean needToMerge = true;
492     boolean reachOnlyByBranch = false;
493     public static String JavaDoc getExceptionSig(DismantleBytecode dbc, CodeException e) {
494         if (e.getCatchType() == 0) return "Ljava/lang/Throwable;";
495         Constant c = dbc.getConstantPool().getConstant(e.getCatchType());
496         if (c instanceof ConstantClass)
497             return "L"+((ConstantClass)c).getBytes(dbc.getConstantPool())+";";
498         return "Ljava/lang/Throwable;";
499     }
500     public void mergeJumps(DismantleBytecode dbc) {
501         
502         if (!needToMerge) return;
503         needToMerge = false;
504         boolean stackUpdated = false;
505         if (convertJumpToOneZeroState == 3 || convertJumpToZeroOneState == 3) {
506             pop();
507             Item top = new Item("I");
508             top.setCouldBeZero(true);
509             push(top);
510             convertJumpToOneZeroState = convertJumpToZeroOneState = 0;
511             stackUpdated = true;
512         }
513         
514         
515         List JavaDoc<Item> jumpEntry = jumpEntries.get(dbc.getPC());
516         if (jumpEntry != null) {
517             if (DEBUG) {
518                 System.out.println("XXXXXXX " + reachOnlyByBranch);
519                 System.out.println("merging lvValues at jump target " + dbc.getPC() + " -> " + Integer.toString(System.identityHashCode(jumpEntry),16) + " " + jumpEntry);
520                 System.out.println(" current lvValues " + lvValues);
521             }
522             List JavaDoc<Item> jumpStackEntry = jumpStackEntries.get(dbc.getPC());
523             if (reachOnlyByBranch) {
524                 lvValues = new ArrayList JavaDoc<Item>(jumpEntry);
525                 if (!stackUpdated) {
526                     if (jumpStackEntry != null) stack = new ArrayList JavaDoc<Item>(jumpStackEntry);
527                     else stack.clear();
528                     }
529         
530             }
531             else {
532                 mergeLists(lvValues, jumpEntry, false);
533                 if (!stackUpdated && jumpStackEntry != null) mergeLists(stack, jumpStackEntry, false);
534             }
535             if (DEBUG)
536                 System.out.println(" merged lvValues " + lvValues);
537         }
538         else if (reachOnlyByBranch && !stackUpdated) {
539             stack.clear();
540        
541             boolean foundException = false;
542             for(CodeException e : dbc.getCode().getExceptionTable()) {
543                 if (e.getHandlerPC() == dbc.getPC()) {
544                     push(new Item(getExceptionSig(dbc, e)));
545                     foundException = true;
546                 }
547             }
548             if (!foundException)
549                 push(new Item("Ljava/lang/Throwable;"));
550         }
551         reachOnlyByBranch = false;
552     }
553
554     int convertJumpToOneZeroState = 0;
555     int convertJumpToZeroOneState = 0;
556     
557     private void setLastUpdate(int reg, int pc) {
558         while (lastUpdate.size() <= reg) lastUpdate.add(0);
559         lastUpdate.set(reg, pc);
560     }
561     
562     public int getLastUpdate(int reg) {
563         if (lastUpdate.size() <= reg) return 0;
564         return lastUpdate.get(reg);
565     }
566     
567     public int getNumLastUpdates() {
568         return lastUpdate.size();
569     }
570     public void sawOpcode(DismantleBytecode dbc, int seen) {
571         int register;
572         String JavaDoc signature;
573         Item it, it2, it3;
574         Constant cons;
575         if (dbc.isRegisterStore())
576             setLastUpdate(dbc.getRegisterOperand(), dbc.getPC());
577         mergeJumps(dbc);
578         needToMerge = true;
579         switch (seen) {
580         case ICONST_1:
581             convertJumpToOneZeroState = 1;
582             break;
583         case GOTO:
584             if (convertJumpToOneZeroState == 1 && dbc.getBranchOffset() == 4)
585                 convertJumpToOneZeroState = 2;
586             else
587                 convertJumpToOneZeroState = 0;
588             break;
589         case ICONST_0:
590             if (convertJumpToOneZeroState == 2)
591                 convertJumpToOneZeroState = 3;
592             else convertJumpToOneZeroState = 0;
593             break;
594             default:convertJumpToOneZeroState = 0;
595                 
596         }
597         switch (seen) {
598         case ICONST_0:
599             convertJumpToZeroOneState = 1;
600             break;
601         case GOTO:
602             if (convertJumpToZeroOneState == 1 && dbc.getBranchOffset() == 4)
603                 convertJumpToZeroOneState = 2;
604             else
605                 convertJumpToZeroOneState = 0;
606             break;
607         case ICONST_1:
608             if (convertJumpToZeroOneState == 2)
609                 convertJumpToZeroOneState = 3;
610             else convertJumpToZeroOneState = 0;
611             break;
612         default:convertJumpToZeroOneState = 0;
613         }
614
615         try
616         {
617             switch (seen) {
618                 case ALOAD:
619                     pushByLocalObjectLoad(dbc, dbc.getRegisterOperand());
620                 break;
621                 
622                 case ALOAD_0:
623                 case ALOAD_1:
624                 case ALOAD_2:
625                 case ALOAD_3:
626                     pushByLocalObjectLoad(dbc, seen - ALOAD_0);
627                 break;
628                 
629                 case DLOAD:
630                     pushByLocalLoad("D", dbc.getRegisterOperand());
631                 break;
632                 
633                 case DLOAD_0:
634                 case DLOAD_1:
635                 case DLOAD_2:
636                 case DLOAD_3:
637                     pushByLocalLoad("D", seen - DLOAD_0);
638                 break;
639
640                 case FLOAD:
641                     pushByLocalLoad("F", dbc.getRegisterOperand());
642                 break;
643                 
644                 case FLOAD_0:
645                 case FLOAD_1:
646                 case FLOAD_2:
647                 case FLOAD_3:
648                     pushByLocalLoad("F", seen - FLOAD_0);
649                 break;
650
651                 case ILOAD:
652                     pushByLocalLoad("I", dbc.getRegisterOperand());
653                 break;
654                 
655                 case ILOAD_0:
656                 case ILOAD_1:
657                 case ILOAD_2:
658                 case ILOAD_3:
659                     pushByLocalLoad("I", seen - ILOAD_0);
660                 break;
661
662                 case LLOAD:
663                     pushByLocalLoad("J", dbc.getRegisterOperand());
664                 break;
665                 
666                 case LLOAD_0:
667                 case LLOAD_1:
668                 case LLOAD_2:
669                 case LLOAD_3:
670                     pushByLocalLoad("J", seen - LLOAD_0);
671                 break;
672                 
673                 
674                 case GETSTATIC:
675                     {
676                     FieldAnnotation field = FieldAnnotation.fromReferencedField(dbc);
677                     Item i = new Item(dbc.getSigConstantOperand(), field, Integer.MAX_VALUE);
678                     if (field.getFieldName().equals("separator") && field.getClassName().equals("java.io.File")) {
679                         i.setSpecialKind(Item.FILE_SEPARATOR_STRING);
680                     }
681                     
682                     push(i);
683                     break;
684                     }
685                 
686                 case LDC:
687                 case LDC_W:
688                 case LDC2_W:
689                     cons = dbc.getConstantRefOperand();
690                     pushByConstant(dbc, cons);
691                 break;
692                 
693                 case INSTANCEOF:
694                     pop();
695                     push(new Item("I"));
696                 break;
697                 case IFEQ:
698                 case IFNE:
699                 case IFLT:
700                 case IFLE:
701                 case IFGT:
702                 case IFGE:
703                 case IFNONNULL:
704                 case IFNULL:
705                 seenTransferOfControl = true;
706                 {
707                     Item top = pop();
708                     
709                     // if we see a test comparing a special negative value with 0,
710
// reset all other such values on the opcode stack
711
if (top.valueCouldBeNegative()
712                             && (seen == IFLT || seen == IFLE || seen == IFGT || seen == IFGE)) {
713                         int specialKind = top.getSpecialKind();
714                         for(Item item : stack) if (item != null && item.getSpecialKind() == specialKind) item.setSpecialKind(0);
715                         for(Item item : lvValues) if (item != null && item.getSpecialKind() == specialKind) item.setSpecialKind(0);
716                                     
717                     }
718                 }
719                 addJumpValue(dbc.getBranchTarget());
720                 
721             break;
722                 case LOOKUPSWITCH:
723                     
724                 case TABLESWITCH:
725                     seenTransferOfControl = true;
726                     pop();
727                     addJumpValue(dbc.getBranchTarget());
728                     int pc = dbc.getBranchTarget() - dbc.getBranchOffset();
729                     for(int offset : dbc.getSwitchOffsets())
730                         addJumpValue(offset+pc);
731                 
732                 break;
733                 case ARETURN:
734                 case DRETURN:
735                 case FRETURN:
736             
737                 case IRETURN:
738                 case LRETURN:
739                 
740                     seenTransferOfControl = true;
741                     reachOnlyByBranch = true;
742                     pop();
743                 break;
744                 case MONITORENTER:
745                 case MONITOREXIT:
746                 case POP:
747                 case PUTSTATIC:
748                     pop();
749                 break;
750                 
751                 case IF_ACMPEQ:
752                 case IF_ACMPNE:
753                 case IF_ICMPEQ:
754                 case IF_ICMPNE:
755                 case IF_ICMPLT:
756                 case IF_ICMPLE:
757                 case IF_ICMPGT:
758                 case IF_ICMPGE:
759                     
760                     seenTransferOfControl = true;
761                     pop(2);
762                     addJumpValue(dbc.getBranchTarget());
763                     break;
764                     
765                     
766                 case POP2:
767                     it = pop();
768                     if (it.getSize() == 1) pop();
769                     break;
770                 case PUTFIELD:
771                     pop(2);
772                 break;
773                 
774                 case IALOAD:
775                 case SALOAD:
776                     pop(2);
777                     push(new Item("I"));
778                 break;
779                 
780                 case DUP:
781                     handleDup();
782                 break;
783                 
784                 case DUP2:
785                     handleDup2();
786                 break;
787                 
788                 case DUP_X1:
789                 handleDupX1();
790                 break;
791                 
792                 case DUP_X2:
793
794                     handleDupX2();
795                 break;
796
797                 case DUP2_X1:
798                         handleDup2X1();
799                 break;
800
801                                 
802                 case IINC:
803                     register = dbc.getRegisterOperand();
804                     it = getLVValue( register );
805                     it2 = new Item("I", dbc.getIntConstant());
806                     pushByIntMath( IADD, it2, it);
807                     pushByLocalStore(register);
808                 break;
809
810                 case ATHROW:
811                     pop();
812                     seenTransferOfControl = true;
813                     reachOnlyByBranch = true;
814                     break;
815
816                 case CHECKCAST:
817                 {
818                     String JavaDoc castTo = dbc.getClassConstantOperand();
819                     
820                     if (castTo.charAt(0) != '[') castTo = "L" + castTo + ";";
821                     it = new Item(pop());
822                     it.signature = castTo;
823                     push(it);
824                     
825                     break;
826                     
827                         
828                 }
829                 case NOP:
830                     break;
831                 case RET:
832                 case RETURN:
833                     seenTransferOfControl = true;
834                     reachOnlyByBranch = true;
835                     break;
836                 
837                 case GOTO:
838                 case GOTO_W: //It is assumed that no stack items are present when
839
seenTransferOfControl = true;
840                     reachOnlyByBranch = true;
841                     addJumpValue(dbc.getBranchTarget());
842                     stack.clear();
843                     
844                 break;
845                     
846                 
847                 case SWAP:
848                     handleSwap();
849                 break;
850                 
851                 case ICONST_M1:
852                 case ICONST_0:
853                 case ICONST_1:
854                 case ICONST_2:
855                 case ICONST_3:
856                 case ICONST_4:
857                 case ICONST_5:
858                     push(new Item("I", (seen-ICONST_0)));
859                 break;
860                 
861                 case LCONST_0:
862                 case LCONST_1:
863                     push(new Item("J", (long)(seen-LCONST_0)));
864                 break;
865                 
866                 case DCONST_0:
867                 case DCONST_1:
868                     push(new Item("D", (double)(seen-DCONST_0)));
869                 break;
870
871                 case FCONST_0:
872                 case FCONST_1:
873                 case FCONST_2:
874                     push(new Item("F", (float)(seen-FCONST_0)));
875                 break;
876
877                 case ACONST_NULL:
878                     push(new Item());
879                 break;
880                                                 
881                 case ASTORE:
882                 case DSTORE:
883                 case FSTORE:
884                 case ISTORE:
885                 case LSTORE:
886                     pushByLocalStore(dbc.getRegisterOperand());
887                 break;
888                 
889                 case ASTORE_0:
890                 case ASTORE_1:
891                 case ASTORE_2:
892                 case ASTORE_3:
893                     pushByLocalStore(seen - ASTORE_0);
894                 break;
895
896                 case DSTORE_0:
897                 case DSTORE_1:
898                 case DSTORE_2:
899                 case DSTORE_3:
900                     pushByLocalStore(seen - DSTORE_0);
901                 break;
902
903
904                 case FSTORE_0:
905                 case FSTORE_1:
906                 case FSTORE_2:
907                 case FSTORE_3:
908                     pushByLocalStore(seen - FSTORE_0);
909                 break;
910
911                 case ISTORE_0:
912                 case ISTORE_1:
913                 case ISTORE_2:
914                 case ISTORE_3:
915                     pushByLocalStore(seen - ISTORE_0);
916                 break;
917                 
918                 case LSTORE_0:
919                 case LSTORE_1:
920                 case LSTORE_2:
921                 case LSTORE_3:
922                     pushByLocalStore(seen - LSTORE_0);
923                 break;
924
925                 case GETFIELD:
926                     {
927                         Item item = pop();
928                         int reg = item.getRegisterNumber();
929                     push(new Item(dbc.getSigConstantOperand(),
930                         FieldAnnotation.fromReferencedField(dbc), reg));
931                     }
932                 break;
933                 
934                 case ARRAYLENGTH:
935                     pop();
936                     push(new Item("I"));
937                 break;
938                 
939                 case BALOAD:
940                 {
941                     pop(2);
942                     Item v = new Item("I");
943                     v.setSpecialKind(Item.SIGNED_BYTE);
944                     push(v);
945                     break;
946                 }
947                 case CALOAD:
948                     pop(2);
949                     push(new Item("I"));
950                 break;
951                 
952                 case DALOAD:
953                     pop(2);
954                     push(new Item("D"));
955                 break;
956                 
957                 case FALOAD:
958                     pop(2);
959                     push(new Item("F"));
960                 break;
961                 
962                 case LALOAD:
963                     pop(2);
964                     push(new Item("J"));
965                 break;
966                 
967                 case AASTORE:
968                 case BASTORE:
969                 case CASTORE:
970                 case DASTORE:
971                 case FASTORE:
972                 case IASTORE:
973                 case LASTORE:
974                 case SASTORE:
975                     pop(3);
976                 break;
977                 
978                 case BIPUSH:
979                 case SIPUSH:
980                     push(new Item("I", (Integer JavaDoc)dbc.getIntConstant()));
981                 break;
982                 
983                 case IADD:
984                 case ISUB:
985                 case IMUL:
986                 case IDIV:
987                 case IAND:
988                 case IOR:
989                 case IXOR:
990                 case ISHL:
991                 case ISHR:
992                 case IREM:
993                 case IUSHR:
994                     it = pop();
995                     it2 = pop();
996                     pushByIntMath(seen, it2, it);
997                 break;
998                 
999                 case INEG:
1000                    it = pop();
1001                    if (it.getConstant() != null) {
1002                        push(new Item("I", ( Integer JavaDoc)(-(Integer JavaDoc) it.getConstant())));
1003                    } else {
1004                        push(new Item("I"));
1005                    }
1006                break;
1007                
1008                case LNEG:
1009                    it = pop();
1010                    if (it.getConstant() != null) {
1011                        push(new Item("J", ( Long JavaDoc)(-(Long JavaDoc) it.getConstant())));
1012                    } else {
1013                        push(new Item("J"));
1014                    }
1015                break;
1016
1017                case DNEG:
1018                    it = pop();
1019                    if (it.getConstant() != null) {
1020                        push(new Item("D", ( Double JavaDoc)(-(Double JavaDoc) it.getConstant())));
1021                    } else {
1022                        push(new Item("D"));
1023                    }
1024                break;
1025
1026                case LADD:
1027                case LSUB:
1028                case LMUL:
1029                case LDIV:
1030                case LAND:
1031                case LOR:
1032                case LXOR:
1033                case LSHL:
1034                case LSHR:
1035                case LREM:
1036                case LUSHR:
1037                    
1038                    it = pop();
1039                    it2 = pop();
1040                    pushByLongMath(seen, it2, it);
1041                break;
1042            
1043                case LCMP:
1044                handleLcmp();
1045                break;
1046                    
1047                case FCMPG:
1048                case FCMPL: handleFcmp(seen);
1049                break;
1050
1051                case DCMPG:
1052                case DCMPL:
1053                    handleDcmp(seen);
1054                break;
1055                
1056                case FADD:
1057                case FSUB:
1058                case FMUL:
1059                case FDIV:
1060                    it = pop();
1061                    it2 = pop();
1062                    pushByFloatMath(seen, it, it2);
1063                break;
1064
1065                case DADD:
1066                case DSUB:
1067                case DMUL:
1068                case DDIV:
1069                case DREM:
1070                    it = pop();
1071                    it2 = pop();
1072                    pushByDoubleMath(seen, it, it2);
1073                break;
1074                
1075                case I2B:
1076                    it = pop();
1077                    if (it.getConstant() != null) {
1078                        it =new Item("I", (byte)constantToInt(it));
1079                    } else {
1080                        it = new Item("I");
1081                    }
1082                    it.setSpecialKind(Item.SIGNED_BYTE);
1083                    push(it);
1084                break;
1085
1086                case I2C:
1087                    it = pop();
1088                    if (it.getConstant() != null) {
1089                        push(new Item("I", (char)constantToInt(it)));
1090                    } else {
1091                        push(new Item("I"));
1092                    }
1093                break;
1094                
1095                case I2L:
1096                case D2L:{
1097                    it = pop();
1098                    Item newValue;
1099                    if (it.getConstant() != null) {
1100                        newValue = new Item("J", constantToLong(it));
1101                    } else {
1102                        newValue = new Item("J");
1103                    }
1104                    newValue.setSpecialKind(it.getSpecialKind());
1105                    push(newValue);
1106                }
1107                break;
1108
1109                case I2S:
1110                    it = pop();
1111                    if (it.getConstant() != null) {
1112                        push(new Item("I", (short)constantToInt(it)));
1113                    } else {
1114                        push(new Item("I"));
1115                    }
1116                break;
1117
1118                case L2I:
1119                case D2I:
1120                case F2I:
1121                    it = pop();
1122                    if (it.getConstant() != null) {
1123                        push(new Item("I",constantToInt(it)));
1124                    } else {
1125                        push(new Item("I"));
1126                    }
1127                break;
1128                
1129                case L2F:
1130                case D2F:
1131                case I2F:
1132                    it = pop();
1133                    if (it.getConstant() != null) {
1134                        push(new Item("F", (Float JavaDoc)(constantToFloat(it))));
1135                    } else {
1136                        push(new Item("F"));
1137                    }
1138                break;
1139
1140                case F2D:
1141                case I2D:
1142                case L2D:
1143                    it = pop();
1144                    if (it.getConstant() != null) {
1145                        push(new Item("D", constantToDouble(it)));
1146                    } else {
1147                        push(new Item("D"));
1148                    }
1149                break;
1150                
1151                case NEW:
1152                    pushBySignature("L" + dbc.getClassConstantOperand() + ";");
1153                break;
1154                
1155                case NEWARRAY:
1156                    pop();
1157                    signature = "[" + BasicType.getType((byte)dbc.getIntConstant()).getSignature();
1158                    pushBySignature(signature);
1159                break;
1160
1161                // According to the VM Spec 4.4.1, anewarray and multianewarray
1162
// can refer to normal class/interface types (encoded in
1163
// "internal form"), or array classes (encoded as signatures
1164
// beginning with "[").
1165

1166                case ANEWARRAY:
1167                    pop();
1168                    signature = dbc.getClassConstantOperand();
1169                    if (!signature.startsWith("[")) {
1170                        signature = "[L" + signature + ";";
1171                    }
1172                    pushBySignature(signature);
1173                break;
1174                
1175                case MULTIANEWARRAY:
1176                    int dims = dbc.getIntConstant();
1177                    while ((dims--) > 0) {
1178                        pop();
1179                    }
1180                    signature = dbc.getClassConstantOperand();
1181                    if (!signature.startsWith("[")) {
1182                        dims = dbc.getIntConstant();
1183                        signature = "";
1184                        while ((dims--) > 0)
1185                            signature += "[";
1186                        signature += "L" + signature + ";";
1187                    }
1188                    pushBySignature(signature);
1189                break;
1190                    
1191                case AALOAD:
1192                    pop();
1193                    it = pop();
1194                    pushBySignature(it.getElementSignature());
1195                break;
1196                                
1197                case JSR:
1198                    push(new Item("")); //?
1199
break;
1200                
1201                case INVOKEINTERFACE:
1202                case INVOKESPECIAL:
1203                case INVOKESTATIC:
1204                case INVOKEVIRTUAL:
1205                    processMethodCall(dbc, seen);
1206                break;
1207                    
1208                default:
1209                    throw new UnsupportedOperationException JavaDoc("OpCode " + OPCODE_NAMES[seen] + " not supported " );
1210            }
1211        }
1212
1213        catch (RuntimeException JavaDoc e) {
1214            //If an error occurs, we clear the stack and locals. one of two things will occur.
1215
//Either the client will expect more stack items than really exist, and so they're condition check will fail,
1216
//or the stack will resync with the code. But hopefully not false positives
1217
// TODO: log this
1218
if (DEBUG)
1219                e.printStackTrace();
1220            clear();
1221        }
1222        finally {
1223            if (exceptionHandlers.get(dbc.getNextPC()))
1224                push(new Item());
1225            if (DEBUG) {
1226                System.out.println(dbc.getNextPC() + "pc : " + OPCODE_NAMES[seen] + " stack depth: " + getStackDepth());
1227                System.out.println(this);
1228            }
1229        }
1230    }
1231
1232    /**
1233     * @param it
1234     * @return
1235     */

1236    private int constantToInt(Item it) {
1237        return ((Number JavaDoc)it.getConstant()).intValue();
1238    }
1239
1240    /**
1241     * @param it
1242     * @return
1243     */

1244    private float constantToFloat(Item it) {
1245        return ((Number JavaDoc)it.getConstant()).floatValue();
1246    }
1247
1248    /**
1249     * @param it
1250     * @return
1251     */

1252    private double constantToDouble(Item it) {
1253        return ((Number JavaDoc)it.getConstant()).doubleValue();
1254    }
1255
1256    /**
1257     * @param it
1258     * @return
1259     */

1260    private long constantToLong(Item it) {
1261        return ((Number JavaDoc)it.getConstant()).longValue();
1262    }
1263
1264    /**
1265     * @param opcode TODO
1266     *
1267     */

1268    private void handleDcmp(int opcode) {
1269        Item it;
1270        Item it2;
1271
1272        it = pop();
1273
1274        it2 = pop();
1275        if ((it.getConstant() != null) && it2.getConstant() != null) {
1276            double d = (Double JavaDoc) it.getConstant();
1277            double d2 = (Double JavaDoc) it.getConstant();
1278            if (Double.isNaN(d) || Double.isNaN(d2)) {
1279                if (opcode == DCMPG)
1280                    push(new Item("I", (Integer JavaDoc)(1)));
1281                else
1282                    push(new Item("I", (Integer JavaDoc)(-1)));
1283            }
1284            if (d2 < d)
1285                push(new Item("I", (Integer JavaDoc) (-1) ));
1286            else if (d2 > d)
1287                push(new Item("I", (Integer JavaDoc)1));
1288            else
1289                push(new Item("I", (Integer JavaDoc)0));
1290        } else {
1291            push(new Item("I"));
1292        }
1293
1294    }
1295
1296    /**
1297     * @param opcode TODO
1298     *
1299     */

1300    private void handleFcmp(int opcode) {
1301        Item it;
1302        Item it2;
1303            it = pop();
1304            it2 = pop();
1305            if ((it.getConstant() != null) && it2.getConstant() != null) {
1306                float f = (Float JavaDoc) it.getConstant();
1307                float f2 = (Float JavaDoc) it.getConstant();
1308                if (Float.isNaN(f) || Float.isNaN(f2)) {
1309                    if (opcode == FCMPG)
1310                        push(new Item("I", (Integer JavaDoc)(1)));
1311                    else
1312                        push(new Item("I", (Integer JavaDoc)(-1)));
1313                }
1314                if (f2 < f)
1315                    push(new Item("I", (Integer JavaDoc)(-1)));
1316                else if (f2 > f)
1317                    push(new Item("I", (Integer JavaDoc)(1)));
1318                else
1319                    push(new Item("I", (Integer JavaDoc)(0)));
1320            } else {
1321                push(new Item("I"));
1322            }
1323    }
1324
1325    /**
1326     *
1327     */

1328    private void handleLcmp() {
1329        Item it;
1330        Item it2;
1331
1332            it = pop();
1333            it2 = pop();
1334            if ((it.getConstant() != null) && it2.getConstant() != null) {
1335                long l = (Long JavaDoc) it.getConstant();
1336                long l2 = (Long JavaDoc) it.getConstant();
1337                if (l2 < l)
1338                    push(new Item("I", (Integer JavaDoc)(-1)));
1339                else if (l2 > l)
1340                    push(new Item("I", (Integer JavaDoc)(1)));
1341                else
1342                    push(new Item("I", (Integer JavaDoc)(0)));
1343            } else {
1344                push(new Item("I"));
1345            }
1346
1347    }
1348
1349    /**
1350     *
1351     */

1352    private void handleSwap() {
1353        Item i1 = pop();
1354        Item i2 = pop();
1355        push(i1);
1356        push(i2);
1357    }
1358
1359    /**
1360     *
1361     */

1362    private void handleDup() {
1363        Item it;
1364        it = pop();
1365        push(it);
1366        push(it);
1367    }
1368
1369    /**
1370     *
1371     */

1372    private void handleDupX1() {
1373        Item it;
1374        Item it2;
1375            it = pop();
1376            it2 = pop();
1377            push(it);
1378            push(it2);
1379            push(it);
1380    }
1381
1382    /**
1383     *
1384     */

1385    private void handleDup2() {
1386        Item it, it2;
1387        it = pop();
1388        if (it.getSize() == 2) {
1389            push(it);
1390            push(it);
1391        }
1392        else {
1393            it2 = pop();
1394            push(it2);
1395            push(it);
1396            push(it2);
1397            push(it);
1398        }
1399    }
1400
1401    /**
1402     *
1403     */

1404    private void handleDup2X1() {
1405        String JavaDoc signature;
1406        Item it;
1407        Item it2;
1408        Item it3;
1409
1410        it = pop();
1411
1412    it2 = pop();
1413    signature = it.getSignature();
1414    if (signature.equals("J") || signature.equals("D")) {
1415        push(it);
1416        push(it2);
1417        push(it);
1418    } else {
1419        it3 = pop();
1420        push(it2);
1421        push(it);
1422        push(it3);
1423        push(it2);
1424        push(it);
1425    }
1426    }
1427
1428    /**
1429     *
1430     */

1431    private void handleDupX2() {
1432        String JavaDoc signature;
1433        Item it;
1434        Item it2;
1435        Item it3;
1436        it = pop();
1437        it2 = pop();
1438        signature = it2.getSignature();
1439        if (signature.equals("J") || signature.equals("D")) {
1440            push(it);
1441            push(it2);
1442            push(it);
1443        } else {
1444            it3 = pop();
1445            push(it);
1446            push(it3);
1447            push(it2);
1448            push(it);
1449        }
1450    }
1451
1452    private void processMethodCall(DismantleBytecode dbc, int seen) {
1453        String JavaDoc clsName = dbc.getClassConstantOperand();
1454        String JavaDoc methodName = dbc.getNameConstantOperand();
1455        String JavaDoc signature = dbc.getSigConstantOperand();
1456        String JavaDoc appenderValue = null;
1457        Item sbItem = null;
1458        
1459        //TODO: stack merging for trinaries kills the constant.. would be nice to maintain.
1460
if ("java/lang/StringBuffer".equals(clsName)
1461        || "java/lang/StringBuilder".equals(clsName)) {
1462            if ("<init>".equals(methodName)) {
1463                if ("(Ljava/lang/String;)V".equals(signature)) {
1464                    Item i = getStackItem(0);
1465                    appenderValue = (String JavaDoc)i.getConstant();
1466                } else if ("()V".equals(signature)) {
1467                    appenderValue = "";
1468                }
1469            } else if ("toString".equals(methodName)) {
1470                Item i = getStackItem(0);
1471                appenderValue = (String JavaDoc)i.getConstant();
1472            } else if ("append".equals(methodName) && signature.indexOf("II)") == -1) {
1473                sbItem = getStackItem(1);
1474                Item i = getStackItem(0);
1475                Object JavaDoc sbVal = sbItem.getConstant();
1476                Object JavaDoc sVal = i.getConstant();
1477                if ((sbVal != null) && (sVal != null)) {
1478                    appenderValue = sbVal + sVal.toString();
1479                } else if (sbItem.registerNumber >= 0) {
1480                    OpcodeStack.Item item = getLVValue(sbItem.registerNumber);
1481                    if (item != null)
1482                        item.constValue = null;
1483                }
1484            }
1485        }
1486        
1487        pushByInvoke(dbc, seen != INVOKESTATIC);
1488        
1489        if (appenderValue != null) {
1490            Item i = this.getStackItem(0);
1491            i.constValue = appenderValue;
1492            if (sbItem != null) {
1493                 i.registerNumber = sbItem.registerNumber;
1494                 i.xfield = sbItem.xfield;
1495                 i.userValue = sbItem.userValue;
1496                 if (sbItem.registerNumber >= 0)
1497                     setLVValue(sbItem.registerNumber, i );
1498            }
1499            return;
1500        }
1501        
1502        if ((clsName.equals("java/util/Random") || clsName.equals("java/security/SecureRandom")) && methodName.equals("nextInt") && signature.equals("()I")) {
1503            Item i = pop();
1504            i.setSpecialKind(Item.RANDOM_INT);
1505            push(i);
1506        }
1507        else if (seen == INVOKEVIRTUAL && methodName.equals("hashCode") && signature.equals("()I")
1508                || seen == INVOKESTATIC && clsName.equals("java/lang/System") && methodName.equals("identityHashCode") && signature.equals("(Ljava/lang/Object;)I")) {
1509            Item i = pop();
1510            i.setSpecialKind(Item.HASHCODE_INT);
1511            push(i);
1512        }
1513 
1514    }
1515    
1516    private void mergeLists(List JavaDoc<Item> mergeInto, List JavaDoc<Item> mergeFrom, boolean errorIfSizesDoNotMatch) {
1517        // merge stacks
1518
int intoSize = mergeInto.size();
1519        int fromSize = mergeFrom.size();
1520        if (errorIfSizesDoNotMatch && intoSize != fromSize) {
1521            if (DEBUG) {
1522                System.out.println("Bad merging items");
1523                System.out.println("current items: " + mergeInto);
1524                System.out.println("jump items: " + mergeFrom);
1525            }
1526        } else {
1527            if (DEBUG) {
1528                System.out.println("Merging items");
1529                System.out.println("current items: " + mergeInto);
1530                System.out.println("jump items: " + mergeFrom);
1531            }
1532
1533            for (int i = 0; i < Math.min(intoSize, fromSize); i++)
1534                mergeInto.set(i, Item.merge(mergeInto.get(i), mergeFrom.get(i)));
1535            if (DEBUG) {
1536                System.out.println("merged items: " + mergeInto);
1537            }
1538        }
1539    }
1540    
1541    public void clear() {
1542        stack.clear();
1543        lvValues.clear();
1544    }
1545    BitSet JavaDoc exceptionHandlers = new BitSet JavaDoc();
1546    private Map JavaDoc<Integer JavaDoc, List JavaDoc<Item>> jumpEntries = new HashMap JavaDoc<Integer JavaDoc, List JavaDoc<Item>>();
1547    private Map JavaDoc<Integer JavaDoc, List JavaDoc<Item>> jumpStackEntries = new HashMap JavaDoc<Integer JavaDoc, List JavaDoc<Item>>();
1548    
1549    private void addJumpValue(int target) {
1550        if (DEBUG)
1551            System.out.println("Set jump entry at " + methodName + ":" + target + "pc to " + stack + " : " + lvValues );
1552        
1553        List JavaDoc<Item> atTarget = jumpEntries.get(target);
1554        if (atTarget == null) {
1555            if (DEBUG)
1556                System.out.println("Was null");
1557            
1558            jumpEntries.put(target, new ArrayList JavaDoc<Item>(lvValues));
1559            if (false) {
1560            System.out.println("jump entires are now...");
1561            for (Integer JavaDoc pc : jumpEntries.keySet()) {
1562                List JavaDoc<Item> list = jumpEntries.get(pc);
1563                System.out.println(pc + "pc -> " + Integer.toString(System.identityHashCode(list),16) + " " + list);
1564            }}
1565            if (stack.size() > 0)
1566                jumpStackEntries.put(target, new ArrayList JavaDoc<Item>(stack));
1567            return;
1568        }
1569        mergeLists(atTarget, lvValues, false);
1570        List JavaDoc<Item> stackAtTarget = jumpStackEntries.get(target);
1571        if (stack.size() > 0 && stackAtTarget != null)
1572            mergeLists(stackAtTarget, stack, false);
1573        if (DEBUG)
1574                System.out.println("merge target for " + methodName + ":" + target + "pc is " + atTarget);
1575    }
1576    private String JavaDoc methodName;
1577    public int resetForMethodEntry(final DismantleBytecode v) {
1578        methodName = v.getMethodName();
1579        jumpEntries.clear();
1580        jumpStackEntries.clear();
1581        lastUpdate.clear();
1582        convertJumpToOneZeroState = convertJumpToZeroOneState = 0;
1583        reachOnlyByBranch = false;
1584        int result= resetForMethodEntry0(v);
1585        Code code = v.getMethod().getCode();
1586        if (code == null) return result;
1587    
1588        if (useIterativeAnalysis) {
1589            // FIXME: Be clever
1590
if (DEBUG)
1591                System.out.println(" --- Iterative analysis");
1592            DismantleBytecode branchAnalysis = new DismantleBytecode() {
1593                @Override JavaDoc
1594                public void sawOpcode(int seen) {
1595                    OpcodeStack.this.sawOpcode(this, seen);
1596                }
1597
1598                // perhaps we don't need this
1599
// @Override
1600
// public void sawBranchTo(int pc) {
1601
// addJumpValue(pc);
1602
// }
1603
};
1604            branchAnalysis.setupVisitorForClass(v.getThisClass());
1605            branchAnalysis.doVisitMethod(v.getMethod());
1606            if (!jumpEntries.isEmpty())
1607                branchAnalysis.doVisitMethod(v.getMethod());
1608            if (DEBUG && !jumpEntries.isEmpty()) {
1609                System.out.println("Found dataflow for jumps in " + v.getMethodName());
1610                for (Integer JavaDoc pc : jumpEntries.keySet()) {
1611                    List JavaDoc<Item> list = jumpEntries.get(pc);
1612                    System.out.println(pc + " -> " + Integer.toString(System.identityHashCode(list),16) + " " + list);
1613                }
1614            }
1615            resetForMethodEntry0(v);
1616            if (DEBUG)
1617                System.out.println(" --- End of Iterative analysis");
1618            
1619        }
1620    
1621        return result;
1622    
1623        }
1624
1625    
1626    private int resetForMethodEntry0(PreorderVisitor v) {
1627        if (DEBUG) System.out.println(" --- ");
1628        stack.clear();
1629        lvValues.clear();
1630        reachOnlyByBranch = false;
1631        seenTransferOfControl = false;
1632        String JavaDoc className = v.getClassName();
1633    
1634        String JavaDoc signature = v.getMethodSig();
1635        exceptionHandlers.clear();
1636        Method m = v.getMethod();
1637        Code code = m.getCode();
1638        if (code != null)
1639     {
1640            CodeException[] exceptionTable = code.getExceptionTable();
1641            if (exceptionTable != null)
1642                for(CodeException ex : exceptionTable)
1643                    exceptionHandlers.set(ex.getHandlerPC());
1644        }
1645        if (DEBUG) System.out.println(" --- " + className
1646                + " " + m.getName() + " " + signature);
1647        Type[] argTypes = Type.getArgumentTypes(signature);
1648        int reg = 0;
1649        if (!m.isStatic()) {
1650            Item it = new Item("L" + className+";");
1651            it.setInitialParameter(true);
1652            it.registerNumber = reg;
1653            setLVValue( reg, it);
1654            reg += it.getSize();
1655            }
1656         for (Type argType : argTypes) {
1657             Item it = new Item(argType.getSignature());
1658             it.registerNumber = reg;
1659             it.setInitialParameter(true);
1660             setLVValue(reg, it);
1661             reg += it.getSize();
1662         }
1663        return reg;
1664    }
1665        
1666    public int getStackDepth() {
1667        return stack.size();
1668    }
1669 
1670    public Item getStackItem(int stackOffset) {
1671        if (stackOffset < 0 || stackOffset >= stack.size()) {
1672            // assert false : "Can't get stack offset " + stackOffset + " from " + stack.toString();
1673
return new Item("Lfindbugs/OpcodeStackError;");
1674            
1675        }
1676        int tos = stack.size() - 1;
1677        int pos = tos - stackOffset;
1678        try {
1679        return stack.get(pos);
1680        } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
1681            throw new ArrayIndexOutOfBoundsException JavaDoc(
1682                "Requested item at offset " + stackOffset + " in a stack of size " + stack.size()
1683                +", made request for position " + pos);
1684        }
1685    }
1686    
1687     private Item pop() {
1688        return stack.remove(stack.size()-1);
1689    }
1690    
1691    private void pop(int count)
1692    {
1693        while ((count--) > 0)
1694            pop();
1695    }
1696    
1697    private void push(Item i) {
1698        stack.add(i);
1699    }
1700    
1701    private void pushByConstant(DismantleBytecode dbc, Constant c) {
1702        
1703        if (c instanceof ConstantClass)
1704            push(new Item("Ljava/lang/Class;", ((ConstantClass)c).getConstantValue(dbc.getConstantPool())));
1705        else if (c instanceof ConstantInteger)
1706            push(new Item("I", (Integer JavaDoc)(((ConstantInteger) c).getBytes())));
1707        else if (c instanceof ConstantString) {
1708            int s = ((ConstantString) c).getStringIndex();
1709            push(new Item("Ljava/lang/String;", getStringFromIndex(dbc, s)));
1710        }
1711        else if (c instanceof ConstantFloat)
1712            push(new Item("F", (Float JavaDoc)(((ConstantFloat) c).getBytes())));
1713        else if (c instanceof ConstantDouble)
1714            push(new Item("D", (Double JavaDoc)(((ConstantDouble) c).getBytes())));
1715        else if (c instanceof ConstantLong)
1716            push(new Item("J", (Long JavaDoc)(((ConstantLong) c).getBytes())));
1717        else
1718            throw new UnsupportedOperationException JavaDoc("Constant type not expected" );
1719    }
1720    
1721    private void pushByLocalObjectLoad(DismantleBytecode dbc, int register) {
1722        Method m = dbc.getMethod();
1723        LocalVariableTable lvt = m.getLocalVariableTable();
1724        if (lvt != null) {
1725            LocalVariable lv = LVTHelper.getLocalVariableAtPC(lvt, register, dbc.getPC());
1726            if (lv != null) {
1727                String JavaDoc signature = lv.getSignature();
1728                pushByLocalLoad(signature, register);
1729                return;
1730            }
1731        }
1732        pushByLocalLoad("", register);
1733    }
1734    
1735    private void pushByIntMath(int seen, Item lhs, Item rhs) {
1736         if (DEBUG) System.out.println("pushByIntMath: " + rhs.getConstant() + " " + lhs.getConstant() );
1737        Item newValue = new Item("I");
1738        try {
1739    
1740        if ((rhs.getConstant() != null) && lhs.getConstant() != null) {
1741            Integer JavaDoc lhsValue = (Integer JavaDoc) lhs.getConstant();
1742            Integer JavaDoc rhsValue = (Integer JavaDoc) rhs.getConstant();
1743            if (seen == IADD)
1744                newValue = new Item("I",lhsValue + rhsValue);
1745            else if (seen == ISUB)
1746                newValue = new Item("I",lhsValue - rhsValue);
1747            else if (seen == IMUL)
1748                newValue = new Item("I", lhsValue * rhsValue);
1749            else if (seen == IDIV)
1750                newValue = new Item("I", lhsValue / rhsValue);
1751            else if (seen == IAND) {
1752                newValue = new Item("I", lhsValue & rhsValue);
1753                if ((rhsValue&0xff) == 0 && rhsValue != 0 || (lhsValue&0xff) == 0 && lhsValue != 0 )
1754                    newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1755            
1756            } else if (seen == IOR)
1757                newValue = new Item("I",lhsValue | rhsValue);
1758            else if (seen == IXOR)
1759                newValue = new Item("I",lhsValue ^ rhsValue);
1760            else if (seen == ISHL) {
1761                newValue = new Item("I",lhsValue << rhsValue);
1762                if (rhsValue >= 8) newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1763            }
1764            else if (seen == ISHR)
1765                newValue = new Item("I",lhsValue >> rhsValue);
1766            else if (seen == IREM)
1767                newValue = new Item("I", lhsValue % rhsValue);
1768            else if (seen == IUSHR)
1769                newValue = new Item("I", lhsValue >>> rhsValue);
1770        } else if (rhs.getConstant() != null && seen == ISHL && (Integer JavaDoc) rhs.getConstant() >= 8)
1771            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1772        else if (lhs.getConstant() != null && seen == IAND && ((Integer JavaDoc) lhs.getConstant() & 0xff) == 0)
1773            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1774        else if (rhs.getConstant() != null && seen == IAND && ((Integer JavaDoc) rhs.getConstant() & 0xff) == 0)
1775            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1776        } catch (RuntimeException JavaDoc e) {
1777            // ignore it
1778
}
1779        if (lhs.specialKind == Item.INTEGER_SUM && rhs.getConstant() != null ) {
1780            int rhsValue = (Integer JavaDoc) rhs.getConstant();
1781            if (seen == IDIV && rhsValue ==2 || seen == ISHR && rhsValue == 1)
1782                newValue.specialKind = Item.AVERAGE_COMPUTED_USING_DIVISION;
1783        }
1784        if (seen == IADD && newValue.specialKind == 0 && lhs.getConstant() == null && rhs.getConstant() == null )
1785            newValue.specialKind = Item.INTEGER_SUM;
1786        if (seen == IREM && lhs.specialKind == Item.HASHCODE_INT)
1787            newValue.specialKind = Item.HASHCODE_INT_REMAINDER;
1788        if (seen == IREM && lhs.specialKind == Item.RANDOM_INT)
1789            newValue.specialKind = Item.RANDOM_INT_REMAINDER;
1790        if (DEBUG) System.out.println("push: " + newValue);
1791        push(newValue);
1792    }
1793    
1794    private void pushByLongMath(int seen, Item lhs, Item rhs) {
1795        Item newValue = new Item("J");
1796        try {
1797    
1798        if ((rhs.getConstant() != null) && lhs.getConstant() != null) {
1799            
1800            Long JavaDoc lhsValue = ((Long JavaDoc) lhs.getConstant());
1801             if (seen == LSHL) {
1802                newValue =new Item("J", lhsValue << ((Number JavaDoc) rhs.getConstant()).intValue());
1803                if (((Number JavaDoc) rhs.getConstant()).intValue() >= 8) newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1804             }
1805            else if (seen == LSHR)
1806                newValue =new Item("J", lhsValue >> ((Number JavaDoc) rhs.getConstant()).intValue());
1807            else if (seen == LUSHR)
1808                newValue =new Item("J", lhsValue >>> ((Number JavaDoc) rhs.getConstant()).intValue());
1809        
1810            else {
1811                Long JavaDoc rhsValue = ((Long JavaDoc) rhs.getConstant());
1812            if (seen == LADD)
1813                newValue = new Item("J", lhsValue + rhsValue);
1814            else if (seen == LSUB)
1815                newValue = new Item("J", lhsValue - rhsValue);
1816            else if (seen == LMUL)
1817                newValue = new Item("J", lhsValue * rhsValue);
1818            else if (seen == LDIV)
1819                newValue =new Item("J", lhsValue / rhsValue);
1820            else if (seen == LAND) {
1821                newValue = new Item("J", lhsValue & rhsValue);
1822            if ((rhsValue&0xff) == 0 && rhsValue != 0 || (lhsValue&0xff) == 0 && lhsValue != 0 )
1823                newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1824            }
1825            else if (seen == LOR)
1826                newValue = new Item("J", lhsValue | rhsValue);
1827            else if (seen == LXOR)
1828                newValue =new Item("J", lhsValue ^ rhsValue);
1829            else if (seen == LREM)
1830                newValue =new Item("J", lhsValue % rhsValue);
1831            }
1832            }
1833         else if (rhs.getConstant() != null && seen == LSHL && ((Integer JavaDoc) rhs.getConstant()) >= 8)
1834            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1835        else if (lhs.getConstant() != null && seen == LAND && (((Long JavaDoc) lhs.getConstant()) & 0xff) == 0)
1836            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1837        else if (rhs.getConstant() != null && seen == LAND && (((Long JavaDoc) rhs.getConstant()) & 0xff) == 0)
1838            newValue.specialKind = Item.LOW_8_BITS_CLEAR;
1839        } catch (RuntimeException JavaDoc e) {
1840            // ignore it
1841
}
1842        push(newValue);
1843    }
1844    
1845    private void pushByFloatMath(int seen, Item it, Item it2) {
1846        Item result;
1847        if ((it.getConstant() != null) && it2.getConstant() != null) {
1848            if (seen == FADD)
1849                result =new Item("F", ((Float JavaDoc) it2.getConstant()) + ((Float JavaDoc) it.getConstant()));
1850            else if (seen == FSUB)
1851                result =new Item("F", ((Float JavaDoc) it2.getConstant()) - ((Float JavaDoc) it.getConstant()));
1852            else if (seen == FMUL)
1853                result =new Item("F", ((Float JavaDoc) it2.getConstant()) * ((Float JavaDoc) it.getConstant()));
1854            else if (seen == FDIV)
1855                result =new Item("F", ((Float JavaDoc) it2.getConstant()) / ((Float JavaDoc) it.getConstant()));
1856                else result =new Item("F");
1857        } else {
1858            result =new Item("F");
1859        }
1860        result.setSpecialKind(Item.FLOAT_MATH);
1861        push(result);
1862    }
1863    
1864    private void pushByDoubleMath(int seen, Item it, Item it2) {
1865        Item result;
1866        if ((it.getConstant() != null) && it2.getConstant() != null) {
1867            if (seen == DADD)
1868                result = new Item("D", ((Double JavaDoc) it2.getConstant()) + ((Double JavaDoc) it.getConstant()));
1869            else if (seen == DSUB)
1870                result = new Item("D", ((Double JavaDoc) it2.getConstant()) - ((Double JavaDoc) it.getConstant()));
1871            else if (seen == DMUL)
1872                result = new Item("D", ((Double JavaDoc) it2.getConstant()) * ((Double JavaDoc) it.getConstant()));
1873            else if (seen == DDIV)
1874                result = new Item("D", ((Double JavaDoc) it2.getConstant()) / ((Double JavaDoc) it.getConstant()));
1875            else
1876                result = new Item("D"); //?
1877
} else {
1878            result = new Item("D");
1879        }
1880        result.setSpecialKind(Item.FLOAT_MATH);
1881        push(result);
1882    }
1883    
1884    private void pushByInvoke(DismantleBytecode dbc, boolean popThis) {
1885        String JavaDoc signature = dbc.getSigConstantOperand();
1886        pop(PreorderVisitor.getNumberArguments(signature)+(popThis ? 1 : 0));
1887        pushBySignature(Type.getReturnType(signature).getSignature());
1888    }
1889    
1890    private String JavaDoc getStringFromIndex(DismantleBytecode dbc, int i) {
1891        ConstantUtf8 name = (ConstantUtf8) dbc.getConstantPool().getConstant(i);
1892        return name.getBytes();
1893    }
1894    
1895    private void pushBySignature(String JavaDoc s) {
1896        if ("V".equals(s))
1897            return;
1898        push(new Item(s, (Object JavaDoc) null));
1899    }
1900    
1901    private void pushByLocalStore(int register) {
1902        Item it = pop();
1903        if (it.getRegisterNumber() != register) {
1904        for(Item i : lvValues) if (i != null) {
1905            if (i.registerNumber == register) i.registerNumber = -1;
1906            if (i.fieldLoadedFromRegister == register) i.fieldLoadedFromRegister = -1;
1907        }
1908        for(Item i : stack) if (i != null) {
1909            if (i.registerNumber == register) i.registerNumber = -1;
1910            if (i.fieldLoadedFromRegister == register) i.fieldLoadedFromRegister = -1;
1911        }
1912        }
1913        setLVValue( register, it );
1914    }
1915    
1916    private void pushByLocalLoad(String JavaDoc signature, int register) {
1917        Item it = getLVValue(register);
1918        
1919        if (it == null) {
1920            Item item = new Item(signature);
1921            item.registerNumber = register;
1922            push(item);
1923        }
1924        else if (it.getRegisterNumber() >= 0)
1925            push(it);
1926        else {
1927            push(new Item(it, register));
1928            }
1929    }
1930    
1931    private void setLVValue(int index, Item value ) {
1932        int addCount = index - lvValues.size() + 1;
1933        while ((addCount--) > 0)
1934            lvValues.add(null);
1935        if (!useIterativeAnalysis && seenTransferOfControl)
1936            value = Item.merge(value, lvValues.get(index) );
1937        lvValues.set(index, value);
1938    }
1939    
1940    private Item getLVValue(int index) {
1941        if (index >= lvValues.size())
1942            return null;
1943            
1944        return lvValues.get(index);
1945    }
1946}
1947
1948// vim:ts=4
Popular Tags