KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > obfuscator > modules > ConstantAnalyzer


1 /* ConstantAnalyzer Copyright (C) 1999-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; see the file COPYING. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: ConstantAnalyzer.java.in,v 1.3.2.6 2002/05/28 17:34:16 hoenicke Exp $
18  */

19
20 package jode.obfuscator.modules;
21
22 import jode.AssertError;
23 import jode.GlobalOptions;
24 import jode.bytecode.*;
25 import jode.jvm.InterpreterException;
26 import jode.obfuscator.*;
27
28 import java.lang.reflect.Array JavaDoc;
29 import java.lang.reflect.Modifier JavaDoc;
30 import java.lang.reflect.InvocationTargetException JavaDoc;
31 import java.util.BitSet JavaDoc;
32
33 import java.util.Arrays JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.ListIterator JavaDoc;
41
42 /**
43  * Analyze the code, assuming every field that is not yet written to
44  * is constant. This may imply that some code is dead code.
45  *
46  * @author Jochen Hoenicke
47  */

48 public class ConstantAnalyzer extends SimpleAnalyzer
49     implements Opcodes, CodeAnalyzer {
50
51     BytecodeInfo bytecode;
52
53     private static ConstantRuntimeEnvironment runtime
54     = new ConstantRuntimeEnvironment();
55
56     private final static int CMP_EQ = 0;
57     private final static int CMP_NE = 1;
58     private final static int CMP_LT = 2;
59     private final static int CMP_GE = 3;
60     private final static int CMP_GT = 4;
61     private final static int CMP_LE = 5;
62     private final static int CMP_GREATER_MASK
63     = (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE);
64     private final static int CMP_LESS_MASK
65     = (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE);
66     private final static int CMP_EQUAL_MASK
67     = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ);
68
69     final static int CONSTANT = 0x02;
70     final static int CONSTANTFLOW = 0x04;
71     final static int RETASTORE = 0x08;
72     final static int RETURNINGJSR = 0x10;
73
74     private interface ConstantListener {
75     public void constantChanged();
76     }
77
78     private final static class JSRTargetInfo implements Cloneable JavaDoc {
79     Instruction jsrTarget;
80     BitSet JavaDoc usedLocals;
81
82     /**
83      * The dependent entries, that want to know if the bit set changed.
84      * This is either a StackLocalInfo (the ret info) or a single
85      * JSRTargetInfo or a Collection of JSRTargetInfos.
86      */

87     Object JavaDoc dependent;
88
89     public JSRTargetInfo(Instruction target) {
90         jsrTarget = target;
91         usedLocals = new BitSet JavaDoc();
92     }
93
94     public JSRTargetInfo copy() {
95         try {
96         JSRTargetInfo result = (JSRTargetInfo) clone();
97         result.usedLocals = (BitSet JavaDoc) usedLocals.clone();
98         addDependent(result);
99         return result;
100         } catch (CloneNotSupportedException JavaDoc ex) {
101         throw new IncompatibleClassChangeError JavaDoc(ex.getMessage());
102         }
103     }
104
105     private void addDependent(JSRTargetInfo result) {
106         if (dependent == null || dependent == result)
107         dependent = result;
108         else if (dependent instanceof JSRTargetInfo) {
109         Set JavaDoc newDeps = new HashSet JavaDoc();
110         newDeps.add(dependent);
111         newDeps.add(result);
112         } else if (dependent instanceof Collection JavaDoc) {
113         ((Collection JavaDoc) dependent).add(result);
114         }
115     }
116
117     public void setRetInfo(StackLocalInfo retInfo) {
118         dependent = retInfo;
119     }
120
121     public boolean uses(int localSlot) {
122         return usedLocals.get(localSlot);
123     }
124
125     public void addUsed(int localSlot) {
126         if (usedLocals.get(localSlot))
127         return;
128         usedLocals.set(localSlot);
129
130         if (dependent instanceof StackLocalInfo)
131         ((StackLocalInfo) dependent).enqueue();
132         else if (dependent instanceof JSRTargetInfo)
133         ((JSRTargetInfo) dependent).addUsed(localSlot);
134         else if (dependent instanceof Collection JavaDoc) {
135         Iterator JavaDoc iter = ((Collection JavaDoc) dependent).iterator();
136         while (iter.hasNext()) {
137             JSRTargetInfo dep = (JSRTargetInfo) iter.next();
138             dep.addUsed(localSlot);
139         }
140         }
141     }
142
143     public void merge(JSRTargetInfo o) {
144         o.addDependent(this);
145         for (int slot = 0; slot < o.usedLocals.size(); slot++) {
146         if (o.usedLocals.get(slot))
147             addUsed(slot);
148         }
149     }
150
151     public String JavaDoc toString() {
152         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(String.valueOf(jsrTarget));
153         if (dependent instanceof StackLocalInfo)
154         sb.append("->").append(((StackLocalInfo) dependent).instr);
155         return sb.append(usedLocals)
156         .append('_').append(hashCode()).toString();
157     }
158     }
159
160     private static class ConstValue implements ConstantListener {
161     public final static Object JavaDoc VOLATILE = new Object JavaDoc();
162     /**
163      * The constant value, VOLATILE if value is not constant.
164      * This may also be an instance of JSRTargetInfo
165      */

166     Object JavaDoc value;
167     /**
168      * The number of slots this value takes on the stack.
169      */

170     int stackSize;
171     /**
172      * The constant listeners, that want to be informed if this is
173      * no longer constant.
174      */

175     Set JavaDoc listeners;
176     
177     public ConstValue(Object JavaDoc constant) {
178         value = constant;
179         stackSize = (constant instanceof Double JavaDoc
180              || constant instanceof Long JavaDoc) ? 2 : 1;
181         listeners = new HashSet JavaDoc();
182     }
183     
184     public ConstValue(ConstValue constant) {
185         value = constant.value;
186         stackSize = constant.stackSize;
187         listeners = new HashSet JavaDoc();
188         constant.addConstantListener(this);
189     }
190     
191     public ConstValue(int stackSize) {
192         this.value = VOLATILE;
193         this.stackSize = stackSize;
194     }
195     
196     public ConstValue copy() {
197         return (value == VOLATILE) ? this
198         : new ConstValue(this);
199     }
200     
201     public void addConstantListener(ConstantListener l) {
202         listeners.add(l);
203     }
204     
205     public void removeConstantListener(ConstantListener l) {
206         listeners.remove(l);
207     }
208     
209     public void fireChanged() {
210         value = VOLATILE;
211         for (Iterator JavaDoc i = listeners.iterator(); i.hasNext(); )
212         ((ConstantListener) i.next()).constantChanged();
213         listeners = null;
214     }
215     
216     public void constantChanged() {
217         if (value != VOLATILE)
218         fireChanged();
219     }
220     
221     /**
222      * Merge the other value into this value.
223      */

224     public void merge(ConstValue other) {
225         if (this == other)
226         return;
227
228         if (value == null ? other.value == null
229         : value.equals(other.value)) {
230         if (value != VOLATILE) {
231             other.addConstantListener(this);
232             this.addConstantListener(other);
233         }
234         return;
235         }
236
237         if (value instanceof JSRTargetInfo
238         && other.value instanceof JSRTargetInfo
239         && (((JSRTargetInfo) value).jsrTarget
240             == ((JSRTargetInfo) other.value).jsrTarget)) {
241         ((JSRTargetInfo) value).merge((JSRTargetInfo) other.value);
242         return;
243         }
244
245         if (value != VOLATILE)
246         fireChanged();
247 // if (other.value != VOLATILE)
248
// other.fireChanged();
249
}
250
251     public String JavaDoc toString() {
252         return value == VOLATILE ? "vol("+stackSize+")" : ""+value;
253     }
254     }
255
256     private static class TodoQueue {
257     StackLocalInfo first;
258     }
259
260     private static class StackLocalInfo implements ConstantListener {
261     ConstValue[] stack;
262     ConstValue[] locals;
263     Instruction instr;
264     ConstantInfo constInfo;
265     StackLocalInfo retInfo;
266
267     StackLocalInfo nextOnQueue;
268
269     /**
270      * The queue that should be notified, if the constant values of
271      * this instruction changes. We put ourself on this queue in that
272      * case.
273      */

274     TodoQueue notifyQueue;
275
276     public ConstValue copy(ConstValue value) {
277         return (value == null) ? null : value.copy();
278     }
279
280     private StackLocalInfo(ConstValue[] stack,
281                    ConstValue[] locals,
282                    TodoQueue notifyQueue) {
283         this.stack = stack;
284         this.locals = new ConstValue[locals.length];
285         for (int i=0; i< locals.length; i++)
286         this.locals[i] = copy(locals[i]);
287         this.notifyQueue = notifyQueue;
288     }
289     
290     public StackLocalInfo(int numLocals,
291                   boolean isStatic, String JavaDoc methodTypeSig,
292                   TodoQueue notifyQueue) {
293         
294         String JavaDoc[] paramTypes
295         = TypeSignature.getParameterTypes(methodTypeSig);
296         locals = new ConstValue[numLocals];
297         stack = new ConstValue[0];
298         this.notifyQueue = notifyQueue;
299         int slot = 0;
300         if (!isStatic)
301         locals[slot++] = new ConstValue(1);
302         for (int i=0; i< paramTypes.length; i++) {
303         int stackSize = TypeSignature.getTypeSize(paramTypes[i]);
304         locals[slot] = unknownValue[stackSize-1];
305         slot += stackSize;
306         }
307     }
308
309     public final void enqueue() {
310         if (nextOnQueue == null) {
311         this.nextOnQueue = notifyQueue.first;
312         notifyQueue.first = this;
313         }
314     }
315     
316     public void constantChanged() {
317         enqueue();
318     }
319     
320     public StackLocalInfo poppush(int pops, ConstValue push) {
321         ConstValue[] newStack
322         = new ConstValue[stack.length - pops + push.stackSize];
323         ConstValue[] newLocals = (ConstValue[]) locals.clone();
324         System.arraycopy(stack, 0, newStack, 0, stack.length-pops);
325         newStack[stack.length-pops] = push.copy();
326         return new StackLocalInfo(newStack, newLocals, notifyQueue);
327     }
328
329     public StackLocalInfo pop(int pops) {
330         ConstValue[] newStack
331         = new ConstValue[stack.length - pops];
332         ConstValue[] newLocals = (ConstValue[]) locals.clone();
333         System.arraycopy(stack, 0, newStack, 0, stack.length-pops);
334         return new StackLocalInfo(newStack, newLocals, notifyQueue);
335     }
336
337     public StackLocalInfo dup(int count, int depth) {
338         ConstValue[] newStack
339         = new ConstValue[stack.length + count];
340         ConstValue[] newLocals = (ConstValue[]) locals.clone();
341         if (depth == 0)
342         System.arraycopy(stack, 0, newStack, 0, stack.length);
343         else {
344         int pos = stack.length - count - depth;
345         System.arraycopy(stack, 0, newStack, 0, pos);
346         for (int i=0; i < count; i++)
347             newStack[pos++] = copy(stack[stack.length-count + i]);
348         for (int i=0; i < depth; i++)
349             newStack[pos++] = copy(stack[stack.length-count-depth + i]);
350         }
351         for (int i=0; i < count; i++)
352         newStack[stack.length+i] = copy(stack[stack.length-count + i]);
353         return new StackLocalInfo(newStack, newLocals, notifyQueue);
354     }
355
356     public StackLocalInfo swap() {
357         ConstValue[] newStack
358         = new ConstValue[stack.length];
359         ConstValue[] newLocals = (ConstValue[]) locals.clone();
360         System.arraycopy(stack, 0, newStack, 0, stack.length - 2);
361         newStack[stack.length-2] = stack[stack.length-1].copy();
362         newStack[stack.length-1] = stack[stack.length-2].copy();
363         return new StackLocalInfo(newStack, newLocals, notifyQueue);
364     }
365
366     public StackLocalInfo copy() {
367         ConstValue[] newStack = (ConstValue[]) stack.clone();
368         ConstValue[] newLocals = (ConstValue[]) locals.clone();
369         return new StackLocalInfo(newStack, newLocals, notifyQueue);
370     }
371
372     public ConstValue getLocal(int slot) {
373         return locals[slot];
374     }
375
376     public ConstValue getStack(int depth) {
377         return stack[stack.length - depth];
378     }
379
380     public StackLocalInfo setLocal(int slot, ConstValue value) {
381         locals[slot] = value;
382         if (value != null && value.stackSize == 2)
383         locals[slot+1] = null;
384         for (int i=0; i< locals.length; i++) {
385         if (locals[i] != null
386             && locals[i].value instanceof JSRTargetInfo) {
387             JSRTargetInfo jsrInfo = (JSRTargetInfo)locals[i].value;
388             if (!jsrInfo.uses(slot)) {
389             jsrInfo = jsrInfo.copy();
390             locals[i] = locals[i].copy();
391             locals[i].value = jsrInfo;
392             jsrInfo.addUsed(slot);
393             }
394         }
395         }
396         for (int i=0; i< stack.length; i++) {
397         if (stack[i] != null
398             && stack[i].value instanceof JSRTargetInfo) {
399             JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value;
400             if (!jsrInfo.uses(slot)) {
401             jsrInfo = jsrInfo.copy();
402             stack[i] = stack[i].copy();
403             stack[i].value = jsrInfo;
404             jsrInfo.addUsed(slot);
405             }
406         }
407         }
408         return this;
409     }
410
411     public StackLocalInfo mergeRetLocals(JSRTargetInfo jsrTargetInfo,
412                          StackLocalInfo retInfo) {
413         for (int slot = 0; slot < locals.length; slot++) {
414         if (jsrTargetInfo.uses(slot))
415             locals[slot] = retInfo.locals[slot];
416         }
417         locals[retInfo.instr.getLocalSlot()] = null;
418
419         for (int i=0; i< locals.length; i++) {
420         if (locals[i] != null
421             && locals[i].value instanceof JSRTargetInfo) {
422             JSRTargetInfo jsrInfo = (JSRTargetInfo) locals[i].value;
423             jsrInfo = jsrInfo.copy();
424             locals[i] = locals[i].copy();
425             locals[i].value = jsrInfo;
426             for (int slot = 0; slot < locals.length; slot++) {
427             if (jsrTargetInfo.uses(slot))
428                 jsrInfo.addUsed(slot);
429             }
430         }
431         }
432         for (int i=0; i< stack.length; i++) {
433         if (stack[i] != null
434             && stack[i].value instanceof JSRTargetInfo) {
435             JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value;
436             jsrInfo = jsrInfo.copy();
437             stack[i] = stack[i].copy();
438             stack[i].value = jsrInfo;
439             for (int slot = 0; slot < locals.length; slot++) {
440             if (jsrTargetInfo.uses(slot))
441                 jsrInfo.addUsed(slot);
442             }
443         }
444         }
445         return this;
446     }
447     
448     public void merge(StackLocalInfo other) {
449         for (int i=0; i < locals.length; i++) {
450         if (locals[i] != null) {
451             if (other.locals[i] == null) {
452             locals[i].constantChanged();
453             locals[i] = null;
454             enqueue();
455             } else {
456             locals[i].merge(other.locals[i]);
457             }
458         }
459         }
460         if (stack.length != other.stack.length)
461         throw new jode.AssertError("stack length differs");
462         for (int i=0; i < stack.length; i++) {
463         if ((other.stack[i] == null) != (stack[i] == null))
464             throw new jode.AssertError("stack types differ");
465         else if (stack[i] != null)
466             stack[i].merge(other.stack[i]);
467         }
468     }
469
470     public String JavaDoc toString() {
471         return "Locals: "+Arrays.asList(locals)
472         +"Stack: "+Arrays.asList(stack)+ "Instr: "+instr;
473     }
474     }
475
476     private static class ConstantInfo implements ConstantListener {
477     ConstantInfo() {
478         this(0, null);
479     }
480
481     ConstantInfo(int flags) {
482         this(flags, null);
483     }
484
485     ConstantInfo(int flags, Object JavaDoc constant) {
486         this.flags = flags;
487         this.constant = constant;
488     }
489     
490     int flags;
491     /**
492      * The constant, may be an Instruction for CONSTANTFLOW.
493      */

494     Object JavaDoc constant;
495
496     public void constantChanged() {
497         constant = null;
498         flags &= ~(CONSTANT | CONSTANTFLOW);
499     }
500     }
501
502     private static ConstValue[] unknownValue = {
503     new ConstValue(1), new ConstValue(2)
504     };
505
506     private static ConstantInfo unknownConstInfo = new ConstantInfo();
507
508     public ConstantAnalyzer() {
509     }
510
511     public void mergeInfo(Instruction instr,
512               StackLocalInfo info) {
513     if (instr.getTmpInfo() == null) {
514         instr.setTmpInfo(info);
515         info.instr = instr;
516         info.enqueue();
517     } else
518         ((StackLocalInfo)instr.getTmpInfo()).merge(info);
519     }
520
521     public void handleReference(Reference ref, boolean isVirtual) {
522     Main.getClassBundle().reachableReference(ref, isVirtual);
523     }
524
525     public void handleClass(String JavaDoc clName) {
526     int i = 0;
527     while (i < clName.length() && clName.charAt(i) == '[')
528         i++;
529     if (i < clName.length() && clName.charAt(i) == 'L') {
530         clName = clName.substring(i+1, clName.length()-1);
531         Main.getClassBundle().reachableClass(clName);
532     }
533     }
534
535     public void handleOpcode(StackLocalInfo info, Identifier fieldListener) {
536     Instruction instr = info.instr;
537     info.constInfo = unknownConstInfo;
538
539     int opcode = instr.getOpcode();
540     Handler[] handlers = bytecode.getExceptionHandlers();
541     for (int i=0; i< handlers.length; i++) {
542         if (handlers[i].start.getAddr() <= instr.getAddr()
543         && handlers[i].end.getAddr() >= instr.getAddr())
544         mergeInfo(handlers[i].catcher,
545               info.poppush(info.stack.length, unknownValue[0]));
546     }
547     ConstValue result;
548     switch (opcode) {
549         case opc_nop:
550         mergeInfo(instr.getNextByAddr(), info.pop(0));
551         break;
552
553         case opc_ldc:
554         case opc_ldc2_w:
555         result = new ConstValue(instr.getConstant());
556         mergeInfo(instr.getNextByAddr(), info.poppush(0, result));
557         break;
558
559         case opc_iload: case opc_lload:
560         case opc_fload: case opc_dload: case opc_aload:
561         result = info.getLocal(instr.getLocalSlot());
562         if (result == null) {
563         dumpStackLocalInfo();
564         System.err.println(info);
565         System.err.println(instr);
566         }
567         if (result.value != ConstValue.VOLATILE) {
568         info.constInfo = new ConstantInfo(CONSTANT, result.value);
569         result.addConstantListener(info.constInfo);
570         }
571         mergeInfo(instr.getNextByAddr(),
572               info.poppush(0, result)
573               .setLocal(instr.getLocalSlot(), result.copy()));
574         break;
575         case opc_iaload: case opc_laload:
576         case opc_faload: case opc_daload: case opc_aaload:
577         case opc_baload: case opc_caload: case opc_saload: {
578 // ConstValue array = info.getStack(2);
579
// ConstValue index = info.getStack(1);
580
// ConstValue newValue = null;
581
// if (index.value != index.ConstValue.VOLATILE
582
// && array.value != array.ConstValue.VOLATILE
583
// && array.value != null) {
584
// int indexVal = ((Integer) index.value).intValue();
585
// Object content;
586
// switch(opcode) {
587
// case opc_baload:
588
// content = new Integer
589
// (array.value instanceof byte[]
590
// ? ((byte[])array.value)[indexVal]
591
// : ((boolean[])array.value)[indexVal] ? 1 : 0);
592
// case opc_caload:
593
// content = new Integer(((char[])array.value)[indexVal]);
594
// break;
595
// case opc_saload:
596
// content = new Integer(((short[])array.value)[indexVal]);
597
// break;
598
// case opc_iaload:
599
// case opc_laload:
600
// case opc_faload:
601
// case opc_daload:
602
// case opc_aaload:
603
// content = Array.get(array.value, indexVal);
604
// break;
605
// default:
606
// throw new jode.AssertError("Can't happen.");
607
// }
608
// result = new ConstValue(content);
609
// array.addConstantListener(result);
610
// index.addConstantListener(result);
611
// } else {
612
result = unknownValue[(opcode == opc_laload
613                    || opcode == opc_daload) ? 1 : 0];
614 // }
615
mergeInfo(instr.getNextByAddr(), info.poppush(2, result));
616         break;
617     }
618         case opc_istore: case opc_fstore: case opc_astore: {
619         result = info.getStack(1);
620         if (result.value instanceof JSRTargetInfo)
621         info.constInfo.flags |= RETASTORE;
622         mergeInfo(instr.getNextByAddr(),
623               info.pop(1).setLocal(instr.getLocalSlot(), result));
624         break;
625     }
626     case opc_lstore: case opc_dstore: {
627         mergeInfo(instr.getNextByAddr(),
628               info.pop(2).setLocal(instr.getLocalSlot(), info.getStack(2)));
629         break;
630     }
631         case opc_iastore: case opc_lastore:
632         case opc_fastore: case opc_dastore: case opc_aastore:
633         case opc_bastore: case opc_castore: case opc_sastore: {
634         int size = (opcode == opc_lastore
635             || opcode == opc_dastore) ? 2 : 1;
636         mergeInfo(instr.getNextByAddr(), info.pop(2+size));
637         break;
638     }
639         case opc_pop:
640         mergeInfo(instr.getNextByAddr(), info.pop(1));
641         break;
642     case opc_pop2:
643         mergeInfo(instr.getNextByAddr(), info.pop(2));
644         break;
645
646     case opc_dup: case opc_dup_x1: case opc_dup_x2:
647         case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
648         mergeInfo(instr.getNextByAddr(),
649               info.dup((opcode - (opc_dup - 3)) / 3,
650                    (opcode - (opc_dup - 3)) % 3));
651         break;
652         case opc_swap:
653         mergeInfo(instr.getNextByAddr(), info.swap());
654         break;
655
656         case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
657         case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
658         case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
659         case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
660         case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
661         case opc_iand: case opc_land:
662         case opc_ior : case opc_lor :
663         case opc_ixor: case opc_lxor: {
664         int size = 1 + (opcode - opc_iadd & 1);
665         ConstValue value1 = info.getStack(2*size);
666         ConstValue value2 = info.getStack(1*size);
667         boolean known = value1.value != ConstValue.VOLATILE
668         && value2.value != ConstValue.VOLATILE;
669         if (known) {
670         if (((opcode == opc_idiv || opcode == opc_irem)
671              && ((Integer JavaDoc)value2.value).intValue() == 0)
672             || ((opcode == opc_ldiv || opcode == opc_lrem)
673             && ((Long JavaDoc)value2.value).longValue() == 0))
674             known = false;
675         }
676         if (known) {
677         Object JavaDoc newValue;
678         switch (opcode) {
679         case opc_iadd:
680             newValue = new Integer JavaDoc
681             (((Integer JavaDoc)value1.value).intValue()
682              + ((Integer JavaDoc)value2.value).intValue());
683             break;
684         case opc_isub:
685             newValue = new Integer JavaDoc
686             (((Integer JavaDoc)value1.value).intValue()
687              - ((Integer JavaDoc)value2.value).intValue());
688             break;
689         case opc_imul:
690             newValue = new Integer JavaDoc
691             (((Integer JavaDoc)value1.value).intValue()
692              * ((Integer JavaDoc)value2.value).intValue());
693             break;
694         case opc_idiv:
695             newValue = new Integer JavaDoc
696             (((Integer JavaDoc)value1.value).intValue()
697              / ((Integer JavaDoc)value2.value).intValue());
698             break;
699         case opc_irem:
700             newValue = new Integer JavaDoc
701             (((Integer JavaDoc)value1.value).intValue()
702              % ((Integer JavaDoc)value2.value).intValue());
703             break;
704         case opc_iand:
705             newValue = new Integer JavaDoc
706             (((Integer JavaDoc)value1.value).intValue()
707              & ((Integer JavaDoc)value2.value).intValue());
708             break;
709         case opc_ior:
710             newValue = new Integer JavaDoc
711             (((Integer JavaDoc)value1.value).intValue()
712              | ((Integer JavaDoc)value2.value).intValue());
713             break;
714         case opc_ixor:
715             newValue = new Integer JavaDoc
716             (((Integer JavaDoc)value1.value).intValue()
717              ^ ((Integer JavaDoc)value2.value).intValue());
718             break;
719             
720         case opc_ladd:
721             newValue = new Long JavaDoc
722             (((Long JavaDoc)value1.value).longValue()
723              + ((Long JavaDoc)value2.value).longValue());
724             break;
725         case opc_lsub:
726             newValue = new Long JavaDoc
727             (((Long JavaDoc)value1.value).longValue()
728              - ((Long JavaDoc)value2.value).longValue());
729             break;
730         case opc_lmul:
731             newValue = new Long JavaDoc
732             (((Long JavaDoc)value1.value).longValue()
733              * ((Long JavaDoc)value2.value).longValue());
734             break;
735         case opc_ldiv:
736             newValue = new Long JavaDoc
737             (((Long JavaDoc)value1.value).longValue()
738              / ((Long JavaDoc)value2.value).longValue());
739             break;
740         case opc_lrem:
741             newValue = new Long JavaDoc
742             (((Long JavaDoc)value1.value).longValue()
743              % ((Long JavaDoc)value2.value).longValue());
744             break;
745         case opc_land:
746             newValue = new Long JavaDoc
747             (((Long JavaDoc)value1.value).longValue()
748              & ((Long JavaDoc)value2.value).longValue());
749             break;
750         case opc_lor:
751             newValue = new Long JavaDoc
752             (((Long JavaDoc)value1.value).longValue()
753              | ((Long JavaDoc)value2.value).longValue());
754             break;
755         case opc_lxor:
756             newValue = new Long JavaDoc
757             (((Long JavaDoc)value1.value).longValue()
758              ^ ((Long JavaDoc)value2.value).longValue());
759             break;
760             
761         case opc_fadd:
762             newValue = new Float JavaDoc
763             (((Float JavaDoc)value1.value).floatValue()
764              + ((Float JavaDoc)value2.value).floatValue());
765             break;
766         case opc_fsub:
767             newValue = new Float JavaDoc
768             (((Float JavaDoc)value1.value).floatValue()
769              - ((Float JavaDoc)value2.value).floatValue());
770             break;
771         case opc_fmul:
772             newValue = new Float JavaDoc
773             (((Float JavaDoc)value1.value).floatValue()
774              * ((Float JavaDoc)value2.value).floatValue());
775             break;
776         case opc_fdiv:
777             newValue = new Float JavaDoc
778             (((Float JavaDoc)value1.value).floatValue()
779              / ((Float JavaDoc)value2.value).floatValue());
780             break;
781         case opc_frem:
782             newValue = new Float JavaDoc
783             (((Float JavaDoc)value1.value).floatValue()
784              % ((Float JavaDoc)value2.value).floatValue());
785             break;
786             
787         case opc_dadd:
788             newValue = new Double JavaDoc
789             (((Double JavaDoc)value1.value).doubleValue()
790              + ((Double JavaDoc)value2.value).doubleValue());
791             break;
792         case opc_dsub:
793             newValue = new Double JavaDoc
794             (((Double JavaDoc)value1.value).doubleValue()
795              - ((Double JavaDoc)value2.value).doubleValue());
796             break;
797         case opc_dmul:
798             newValue = new Double JavaDoc
799             (((Double JavaDoc)value1.value).doubleValue()
800              * ((Double JavaDoc)value2.value).doubleValue());
801             break;
802         case opc_ddiv:
803             newValue = new Double JavaDoc
804             (((Double JavaDoc)value1.value).doubleValue()
805              / ((Double JavaDoc)value2.value).doubleValue());
806             break;
807         case opc_drem:
808             newValue = new Double JavaDoc
809             (((Double JavaDoc)value1.value).doubleValue()
810              % ((Double JavaDoc)value2.value).doubleValue());
811             break;
812         default:
813             throw new jode.AssertError("Can't happen.");
814         }
815         info.constInfo = new ConstantInfo(CONSTANT, newValue);
816         result = new ConstValue(newValue);
817         result.addConstantListener(info.constInfo);
818         value1.addConstantListener(result);
819         value2.addConstantListener(result);
820         } else
821         result = unknownValue[size-1];
822         mergeInfo(instr.getNextByAddr(), info.poppush(2*size, result));
823         break;
824     }
825         case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: {
826         int size = 1 + (opcode - opc_ineg & 1);
827         ConstValue value = info.getStack(size);
828         if (value.value != ConstValue.VOLATILE) {
829         Object JavaDoc newValue;
830         switch (opcode) {
831         case opc_ineg:
832             newValue = new Integer JavaDoc
833             (-((Integer JavaDoc)value.value).intValue());
834             break;
835         case opc_lneg:
836             newValue = new Long JavaDoc
837             (- ((Long JavaDoc)value.value).longValue());
838             break;
839         case opc_fneg:
840             newValue = new Float JavaDoc
841             (- ((Float JavaDoc)value.value).floatValue());
842             break;
843         case opc_dneg:
844             newValue = new Double JavaDoc
845             (- ((Double JavaDoc)value.value).doubleValue());
846             break;
847         default:
848             throw new jode.AssertError("Can't happen.");
849         }
850         info.constInfo = new ConstantInfo(CONSTANT, newValue);
851         result = new ConstValue(newValue);
852         result.addConstantListener(info.constInfo);
853         value.addConstantListener(result);
854         } else
855         result = unknownValue[size-1];
856         mergeInfo(instr.getNextByAddr(), info.poppush(size, result));
857         break;
858     }
859         case opc_ishl: case opc_lshl:
860         case opc_ishr: case opc_lshr:
861         case opc_iushr: case opc_lushr: {
862         int size = 1 + (opcode - opc_iadd & 1);
863         ConstValue value1 = info.getStack(size+1);
864         ConstValue value2 = info.getStack(1);
865         if (value1.value != ConstValue.VOLATILE
866         && value2.value != ConstValue.VOLATILE) {
867         Object JavaDoc newValue;
868         switch (opcode) {
869         case opc_ishl:
870             newValue = new Integer JavaDoc
871             (((Integer JavaDoc)value1.value).intValue()
872              << ((Integer JavaDoc)value2.value).intValue());
873             break;
874         case opc_ishr:
875             newValue = new Integer JavaDoc
876             (((Integer JavaDoc)value1.value).intValue()
877              >> ((Integer JavaDoc)value2.value).intValue());
878             break;
879         case opc_iushr:
880             newValue = new Integer JavaDoc
881             (((Integer JavaDoc)value1.value).intValue()
882              >>> ((Integer JavaDoc)value2.value).intValue());
883             break;
884
885         case opc_lshl:
886             newValue = new Long JavaDoc
887             (((Long JavaDoc)value1.value).longValue()
888              << ((Integer JavaDoc)value2.value).intValue());
889             break;
890         case opc_lshr:
891             newValue = new Long JavaDoc
892             (((Long JavaDoc)value1.value).longValue()
893              >> ((Integer JavaDoc)value2.value).intValue());
894             break;
895         case opc_lushr:
896             newValue = new Long JavaDoc
897             (((Long JavaDoc)value1.value).longValue()
898              >>> ((Integer JavaDoc)value2.value).intValue());
899             break;
900         default:
901             throw new jode.AssertError("Can't happen.");
902         }
903         info.constInfo = new ConstantInfo(CONSTANT, newValue);
904         result = new ConstValue(newValue);
905         result.addConstantListener(info.constInfo);
906         value1.addConstantListener(result);
907         value2.addConstantListener(result);
908         } else
909         result = unknownValue[size-1];
910         mergeInfo(instr.getNextByAddr(), info.poppush(size+1, result));
911         break;
912     }
913         case opc_iinc: {
914         ConstValue local = info.getLocal(instr.getLocalSlot());
915         if (local.value != ConstValue.VOLATILE) {
916         result = new ConstValue
917             (new Integer JavaDoc(((Integer JavaDoc)local.value).intValue()
918                  + instr.getIncrement()));
919         local.addConstantListener(result);
920         } else
921         result = unknownValue[0];
922         mergeInfo(instr.getNextByAddr(),
923               info.copy().setLocal(instr.getLocalSlot(), result));
924         break;
925     }
926         case opc_i2l: case opc_i2f: case opc_i2d:
927         case opc_l2i: case opc_l2f: case opc_l2d:
928         case opc_f2i: case opc_f2l: case opc_f2d:
929         case opc_d2i: case opc_d2l: case opc_d2f: {
930         int insize = 1 + ((opcode - opc_i2l) / 3 & 1);
931         ConstValue stack = info.getStack(insize);
932         if (stack.value != ConstValue.VOLATILE) {
933         Object JavaDoc newVal;
934         switch(opcode) {
935         case opc_l2i: case opc_f2i: case opc_d2i:
936             newVal = new Integer JavaDoc(((Number JavaDoc)stack.value).intValue());
937             break;
938         case opc_i2l: case opc_f2l: case opc_d2l:
939             newVal = new Long JavaDoc(((Number JavaDoc)stack.value).longValue());
940             break;
941         case opc_i2f: case opc_l2f: case opc_d2f:
942             newVal = new Float JavaDoc(((Number JavaDoc)stack.value).floatValue());
943             break;
944         case opc_i2d: case opc_l2d: case opc_f2d:
945             newVal = new Double JavaDoc(((Number JavaDoc)stack.value).doubleValue());
946             break;
947         default:
948             throw new jode.AssertError("Can't happen.");
949         }
950         info.constInfo = new ConstantInfo(CONSTANT, newVal);
951         result = new ConstValue(newVal);
952         result.addConstantListener(info.constInfo);
953         stack.addConstantListener(result);
954         } else {
955         switch (opcode) {
956         case opc_i2l: case opc_f2l: case opc_d2l:
957         case opc_i2d: case opc_l2d: case opc_f2d:
958             result = unknownValue[1];
959             break;
960         default:
961             result = unknownValue[0];
962         }
963         }
964         mergeInfo(instr.getNextByAddr(), info.poppush(insize, result));
965         break;
966         }
967         case opc_i2b: case opc_i2c: case opc_i2s: {
968         ConstValue stack = info.getStack(1);
969         if (stack.value != ConstValue.VOLATILE) {
970         int val = ((Integer JavaDoc)stack.value).intValue();
971         switch(opcode) {
972         case opc_i2b:
973             val = (byte) val;
974             break;
975         case opc_i2c:
976             val = (char) val;
977             break;
978         case opc_i2s:
979             val = (short) val;
980             break;
981         }
982         Integer JavaDoc newVal = new Integer JavaDoc(val);
983         info.constInfo = new ConstantInfo(CONSTANT, newVal);
984         result = new ConstValue(newVal);
985         stack.addConstantListener(info.constInfo);
986         stack.addConstantListener(result);
987         } else
988         result = unknownValue[0];
989         mergeInfo(instr.getNextByAddr(),
990               info.poppush(1, result));
991         break;
992     }
993         case opc_lcmp: {
994         ConstValue val1 = info.getStack(4);
995         ConstValue val2 = info.getStack(2);
996         if (val1.value != ConstValue.VOLATILE
997         && val2.value != ConstValue.VOLATILE) {
998         long value1 = ((Long JavaDoc) val1.value).longValue();
999         long value2 = ((Long JavaDoc) val1.value).longValue();
1000        Integer JavaDoc newVal = new Integer JavaDoc(value1 == value2 ? 0
1001                         : value1 < value2 ? -1 : 1);
1002        info.constInfo = new ConstantInfo(CONSTANT, newVal);
1003        result = new ConstValue(newVal);
1004        result.addConstantListener(info.constInfo);
1005        val1.addConstantListener(result);
1006        val2.addConstantListener(result);
1007        } else
1008        result = unknownValue[0];
1009        mergeInfo(instr.getNextByAddr(), info.poppush(4, result));
1010        break;
1011    }
1012        case opc_fcmpl: case opc_fcmpg: {
1013        ConstValue val1 = info.getStack(2);
1014        ConstValue val2 = info.getStack(1);
1015        if (val1.value != ConstValue.VOLATILE
1016        && val2.value != ConstValue.VOLATILE) {
1017        float value1 = ((Float JavaDoc) val1.value).floatValue();
1018        float value2 = ((Float JavaDoc) val1.value).floatValue();
1019        Integer JavaDoc newVal = new Integer JavaDoc
1020            (value1 == value2 ? 0
1021             : ( opcode == opc_fcmpg
1022             ? (value1 < value2 ? -1 : 1)
1023             : (value1 > value2 ? 1 : -1)));
1024        info.constInfo = new ConstantInfo(CONSTANT, newVal);
1025        result = new ConstValue(newVal);
1026        result.addConstantListener(info.constInfo);
1027        val1.addConstantListener(result);
1028        val2.addConstantListener(result);
1029        } else
1030        result = unknownValue[0];
1031        mergeInfo(instr.getNextByAddr(), info.poppush(2, result));
1032        break;
1033    }
1034        case opc_dcmpl: case opc_dcmpg: {
1035        ConstValue val1 = info.getStack(4);
1036        ConstValue val2 = info.getStack(2);
1037        if (val1.value != ConstValue.VOLATILE
1038        && val2.value != ConstValue.VOLATILE) {
1039        double value1 = ((Double JavaDoc) val1.value).doubleValue();
1040        double value2 = ((Double JavaDoc) val1.value).doubleValue();
1041        Integer JavaDoc newVal = new Integer JavaDoc
1042            (value1 == value2 ? 0
1043             : ( opcode == opc_dcmpg
1044             ? (value1 < value2 ? -1 : 1)
1045             : (value1 > value2 ? 1 : -1)));
1046        info.constInfo = new ConstantInfo(CONSTANT, newVal);
1047        result = new ConstValue(newVal);
1048        result.addConstantListener(info.constInfo);
1049        val1.addConstantListener(result);
1050        val2.addConstantListener(result);
1051        } else
1052        result = unknownValue[0];
1053        mergeInfo(instr.getNextByAddr(), info.poppush(4, result));
1054        break;
1055    }
1056    case opc_ifeq: case opc_ifne:
1057    case opc_iflt: case opc_ifge:
1058    case opc_ifgt: case opc_ifle:
1059    case opc_if_icmpeq: case opc_if_icmpne:
1060    case opc_if_icmplt: case opc_if_icmpge:
1061    case opc_if_icmpgt: case opc_if_icmple:
1062    case opc_if_acmpeq: case opc_if_acmpne:
1063    case opc_ifnull: case opc_ifnonnull: {
1064        int size = 1;
1065        ConstValue stacktop = info.getStack(1);
1066        ConstValue other = null;
1067        boolean known = stacktop.value != ConstValue.VOLATILE;
1068        if (opcode >= opc_if_icmpeq && opcode <= opc_if_acmpne) {
1069        other = info.getStack(2);
1070        size = 2;
1071        known &= other.value != ConstValue.VOLATILE;
1072        }
1073        if (known) {
1074        stacktop.addConstantListener(info);
1075        if (other != null)
1076            other.addConstantListener(info);
1077
1078        Instruction pc = instr.getNextByAddr();
1079        int opc_mask;
1080        if (opcode >= opc_if_acmpeq) {
1081            if (opcode >= opc_ifnull) {
1082            opc_mask = stacktop.value == null
1083                ? CMP_EQUAL_MASK : CMP_GREATER_MASK;
1084            opcode -= opc_ifnull;
1085            } else {
1086            opc_mask = stacktop.value == other.value
1087                ? CMP_EQUAL_MASK : CMP_GREATER_MASK;
1088            opcode -= opc_if_acmpeq;
1089            }
1090        } else {
1091            int value = ((Integer JavaDoc) stacktop.value).intValue();
1092            if (opcode >= opc_if_icmpeq) {
1093            int val1 = ((Integer JavaDoc) other.value).intValue();
1094            opc_mask = (val1 == value ? CMP_EQUAL_MASK
1095                    : val1 < value ? CMP_LESS_MASK
1096                    : CMP_GREATER_MASK);
1097            opcode -= opc_if_icmpeq;
1098            } else {
1099            opc_mask = (value == 0 ? CMP_EQUAL_MASK
1100                    : value < 0 ? CMP_LESS_MASK
1101                    : CMP_GREATER_MASK);
1102            opcode -= opc_ifeq;
1103            }
1104        }
1105
1106        if ((opc_mask & (1<<opcode)) != 0)
1107            pc = instr.getSingleSucc();
1108
1109        info.constInfo = new ConstantInfo(CONSTANTFLOW, pc);
1110        mergeInfo(pc, info.pop(size));
1111        } else {
1112        mergeInfo(instr.getNextByAddr(), info.pop(size));
1113        mergeInfo(instr.getSingleSucc(), info.pop(size));
1114        }
1115        break;
1116    }
1117        case opc_goto:
1118        mergeInfo(instr.getSingleSucc(), info.copy());
1119        break;
1120        case opc_lookupswitch: {
1121        ConstValue stacktop = info.getStack(1);
1122        if (stacktop.value != ConstValue.VOLATILE) {
1123        stacktop.addConstantListener(info);
1124        Instruction pc;
1125        int value = ((Integer JavaDoc) stacktop.value).intValue();
1126        int[] values = instr.getValues();
1127        pc = instr.getSuccs()[values.length];
1128        for (int i=0; i< values.length; i++) {
1129            if (values[i] == value) {
1130            pc = instr.getSuccs()[i];
1131            break;
1132            }
1133        }
1134        info.constInfo = new ConstantInfo(CONSTANTFLOW, pc);
1135        mergeInfo(pc, info.pop(1));
1136        } else {
1137        for (int i=0; i < instr.getSuccs().length; i++)
1138            mergeInfo(instr.getSuccs()[i], info.pop(1));
1139        }
1140        break;
1141        }
1142        case opc_jsr:
1143// dumpStackLocalInfo();
1144
// System.err.println(instr);
1145
if (instr.getSingleSucc().getOpcode() != opc_astore)
1146        throw new RuntimeException JavaDoc("Can't handle jsr to non astores");
1147        StackLocalInfo oldJsrInfo =
1148        (StackLocalInfo) instr.getSingleSucc().getTmpInfo();
1149        if (oldJsrInfo != null) {
1150        result = oldJsrInfo.getStack(1);
1151        if (oldJsrInfo.retInfo != null
1152            && result.value instanceof JSRTargetInfo) {
1153            mergeInfo(instr.getNextByAddr(),
1154                  info.copy()
1155                  .mergeRetLocals((JSRTargetInfo) result.value,
1156                          oldJsrInfo.retInfo));
1157        }
1158        } else {
1159        result = new ConstValue
1160            (new JSRTargetInfo(instr.getSingleSucc()));
1161        }
1162        mergeInfo(instr.getSingleSucc(), info.poppush(0, result));
1163        break;
1164    case opc_ret: {
1165// dumpStackLocalInfo();
1166
// System.err.println(instr);
1167
result = info.getLocal(instr.getLocalSlot());
1168        JSRTargetInfo jsrInfo = (JSRTargetInfo) result.value;
1169        jsrInfo.setRetInfo(info);
1170        result.addConstantListener(info);
1171        Instruction jsrTarget = jsrInfo.jsrTarget;
1172        StackLocalInfo jsrTargetStackInfo =
1173        (StackLocalInfo) jsrTarget.getTmpInfo();
1174        jsrTargetStackInfo.retInfo = info;
1175        jsrTargetStackInfo.constInfo.flags |= RETURNINGJSR;
1176        Instruction[] jsrs = jsrTarget.getPreds();
1177        for (int i=0; i < jsrs.length; i++) {
1178        Instruction jsr = jsrs[i];
1179        if (jsr.getTmpInfo() != null) {
1180            mergeInfo(jsr.getNextByAddr(),
1181                  ((StackLocalInfo) jsr.getTmpInfo()).copy()
1182                  .mergeRetLocals(jsrInfo, info));
1183        }
1184        }
1185        break;
1186    }
1187        case opc_ireturn: case opc_lreturn:
1188        case opc_freturn: case opc_dreturn: case opc_areturn:
1189        case opc_return:
1190        case opc_athrow:
1191        break;
1192
1193    case opc_putstatic:
1194    case opc_putfield: {
1195        FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr);
1196        Reference ref = instr.getReference();
1197        int size = TypeSignature.getTypeSize(ref.getType());
1198        if (fi != null && !fi.isNotConstant()) {
1199        ConstValue stacktop = info.getStack(size);
1200        Object JavaDoc fieldVal = fi.getConstant();
1201        if (fieldVal == null)
1202            fieldVal = runtime.getDefaultValue(ref.getType());
1203        if (stacktop.value == null ? fieldVal == null
1204            : stacktop.value.equals(fieldVal)) {
1205            stacktop.addConstantListener(info);
1206        } else {
1207            fi.setNotConstant();
1208            fieldNotConstant(fi);
1209        }
1210        }
1211        size += (opcode == opc_putstatic) ? 0 : 1;
1212        mergeInfo(instr.getNextByAddr(), info.pop(size));
1213        break;
1214    }
1215    case opc_getstatic:
1216    case opc_getfield: {
1217        int size = (opcode == opc_getstatic) ? 0 : 1;
1218        FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr);
1219        Reference ref = instr.getReference();
1220        int typesize = TypeSignature.getTypeSize(ref.getType());
1221        if (fi != null) {
1222        if (fi.isNotConstant()) {
1223            fi.setReachable();
1224            result = unknownValue[typesize - 1];
1225        } else {
1226            Object JavaDoc obj = fi.getConstant();
1227            if (obj == null)
1228            obj = runtime.getDefaultValue(ref.getType());
1229            info.constInfo = new ConstantInfo(CONSTANT, obj);
1230            result = new ConstValue(obj);
1231            result.addConstantListener(info.constInfo);
1232            fi.addFieldListener(fieldListener);
1233        }
1234        } else
1235        result = unknownValue[typesize - 1];
1236        mergeInfo(instr.getNextByAddr(), info.poppush(size, result));
1237        break;
1238    }
1239    case opc_invokespecial:
1240    case opc_invokestatic:
1241    case opc_invokeinterface:
1242    case opc_invokevirtual: {
1243        canonizeReference(instr);
1244        Reference ref = instr.getReference();
1245        boolean constant = true;
1246        int size = 0;
1247        Object JavaDoc cls = null;
1248        String JavaDoc[] paramTypes
1249        = TypeSignature.getParameterTypes(ref.getType());
1250        Object JavaDoc[] args = new Object JavaDoc[paramTypes.length];
1251        ConstValue clsValue = null;
1252        ConstValue[] argValues = new ConstValue[paramTypes.length];
1253
1254        for (int i = paramTypes.length - 1; i >= 0; i--) {
1255        size += TypeSignature.getTypeSize(paramTypes[i]);
1256        Object JavaDoc value = (argValues[i] = info.getStack(size)).value;
1257        if (value != ConstValue.VOLATILE)
1258            args[i] = value;
1259        else
1260            constant = false;
1261        }
1262        
1263        if (opcode != opc_invokestatic) {
1264        size++;
1265        clsValue = info.getStack(size);
1266        cls = clsValue.value;
1267        if (cls == ConstValue.VOLATILE || cls == null)
1268            constant = false;
1269        }
1270        String JavaDoc retType = TypeSignature.getReturnType(ref.getType());
1271        if (retType.equals("V")) {
1272        handleReference(ref, opcode == opc_invokevirtual
1273                || opcode == opc_invokeinterface);
1274        mergeInfo(instr.getNextByAddr(), info.pop(size));
1275        break;
1276        }
1277        if (constant && !runtime.isWhite(retType)) {
1278        /* This is not a valid constant type */
1279        constant = false;
1280        }
1281        Object JavaDoc methodResult = null;
1282        if (constant) {
1283        try {
1284            methodResult = runtime.invokeMethod
1285            (ref, opcode != opc_invokespecial, cls, args);
1286        } catch (InterpreterException ex) {
1287            constant = false;
1288            if (jode.GlobalOptions.verboseLevel > 3)
1289            GlobalOptions.err.println("Can't interpret "+ref+": "
1290                          + ex.getMessage());
1291            /* result is not constant */
1292        } catch (InvocationTargetException JavaDoc ex) {
1293            constant = false;
1294            if (jode.GlobalOptions.verboseLevel > 3)
1295            GlobalOptions.err.println("Method "+ref
1296                          +" throwed exception: "
1297                          + ex.getTargetException());
1298            /* method always throws exception ? */
1299        }
1300        }
1301        ConstValue returnVal;
1302        if (!constant) {
1303        handleReference(ref, opcode == opc_invokevirtual
1304                || opcode == opc_invokeinterface);
1305        int retsize = TypeSignature.getTypeSize(retType);
1306        returnVal = unknownValue[retsize - 1];
1307        } else {
1308        info.constInfo = new ConstantInfo(CONSTANT, methodResult);
1309        returnVal = new ConstValue(methodResult);
1310        returnVal.addConstantListener(info.constInfo);
1311        if (clsValue != null)
1312            clsValue.addConstantListener(returnVal);
1313        for (int i=0; i< argValues.length; i++)
1314            argValues[i].addConstantListener(returnVal);
1315        }
1316        mergeInfo(instr.getNextByAddr(), info.poppush(size, returnVal));
1317        break;
1318    }
1319
1320        case opc_new: {
1321        handleClass(instr.getClazzType());
1322        mergeInfo(instr.getNextByAddr(), info.poppush(0, unknownValue[0]));
1323        break;
1324        }
1325        case opc_arraylength: {
1326// ConstValue array = info.getStack(1);
1327
// if (array.value != ConstValue.VOLATILE
1328
// && array.value != null) {
1329
// Integer newValue = new Integer(Array.getLength(array.value));
1330
// info.constInfo = new ConstantInfo(CONSTANT, newValue);
1331
// result = new ConstValue(newValue);
1332
// result.addConstantListener(info.constInfo);
1333
// array.addConstantListener(result);
1334
// } else
1335
result = unknownValue[0];
1336        mergeInfo(instr.getNextByAddr(), info.poppush(1, result));
1337        break;
1338    }
1339        case opc_checkcast: {
1340        handleClass(instr.getClazzType());
1341        mergeInfo(instr.getNextByAddr(), info.pop(0));
1342        break;
1343        }
1344        case opc_instanceof: {
1345        handleClass(instr.getClazzType());
1346        mergeInfo(instr.getNextByAddr(), info.poppush(1, unknownValue[0]));
1347        break;
1348        }
1349        case opc_monitorenter:
1350        case opc_monitorexit:
1351        mergeInfo(instr.getNextByAddr(), info.pop(1));
1352        break;
1353        case opc_multianewarray:
1354        handleClass(instr.getClazzType());
1355        mergeInfo(instr.getNextByAddr(),
1356              info.poppush(instr.getDimensions(), unknownValue[0]));
1357        break;
1358        default:
1359            throw new IllegalArgumentException JavaDoc("Invalid opcode "+opcode);
1360        }
1361    }
1362
1363    public void fieldNotConstant(FieldIdentifier fi) {
1364    for (Iterator JavaDoc iter = bytecode.getInstructions().iterator();
1365         iter.hasNext(); ) {
1366        Instruction instr = (Instruction) iter.next();
1367        if (instr.getOpcode() == opc_getfield
1368        || instr.getOpcode() == opc_getstatic) {
1369        Reference ref = instr.getReference();
1370        if (ref.getName().equals(fi.getName())
1371            && ref.getType().equals(fi.getType())
1372            && instr.getTmpInfo() != null) {
1373            ((StackLocalInfo) instr.getTmpInfo()).enqueue();
1374        }
1375        }
1376    }
1377    }
1378
1379    public void dumpStackLocalInfo() {
1380    for (Iterator JavaDoc iter = bytecode.getInstructions().iterator();
1381         iter.hasNext(); ) {
1382        Instruction instr = (Instruction) iter.next();
1383        System.err.println(""+instr.getTmpInfo());
1384        System.err.println(instr.getDescription());
1385    }
1386    }
1387
1388    public void analyzeCode(MethodIdentifier methodIdent,
1389                BytecodeInfo bytecode) {
1390    this.bytecode = bytecode;
1391    TodoQueue modifiedQueue = new TodoQueue();
1392    MethodInfo minfo = bytecode.getMethodInfo();
1393
1394    for (Iterator JavaDoc iter = bytecode.getInstructions().iterator();
1395         iter.hasNext(); ) {
1396        Instruction instr = (Instruction) iter.next();
1397        instr.setTmpInfo(null);
1398    }
1399
1400    StackLocalInfo firstInfo = new StackLocalInfo
1401        (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(),
1402         modifiedQueue);
1403    firstInfo.instr = (Instruction) bytecode.getInstructions().get(0);
1404    firstInfo.instr.setTmpInfo(firstInfo);
1405    firstInfo.enqueue();
1406    runtime.setFieldListener(methodIdent);
1407    while (modifiedQueue.first != null) {
1408        StackLocalInfo info = modifiedQueue.first;
1409        modifiedQueue.first = info.nextOnQueue;
1410        info.nextOnQueue = null;
1411        handleOpcode(info, methodIdent);
1412    }
1413    runtime.setFieldListener(null);
1414
1415    Handler[] handlers = bytecode.getExceptionHandlers();
1416    for (int i=0; i< handlers.length; i++) {
1417        if (handlers[i].catcher.getTmpInfo() != null
1418        && handlers[i].type != null)
1419        Main.getClassBundle().reachableClass(handlers[i].type);
1420    }
1421    for (Iterator JavaDoc iter = bytecode.getInstructions().iterator();
1422         iter.hasNext(); ) {
1423        Instruction instr = (Instruction) iter.next();
1424        StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo();
1425        if (info != null) {
1426        if (info.constInfo.flags == 0)
1427            instr.setTmpInfo(unknownConstInfo);
1428        else
1429            instr.setTmpInfo(info.constInfo);
1430        }
1431    }
1432    }
1433
1434    public static void replaceWith(ListIterator JavaDoc iter, Instruction instr,
1435                   Instruction replacement) {
1436    switch(instr.getOpcode()) {
1437    case opc_goto:
1438        case opc_ldc:
1439        case opc_ldc2_w:
1440        case opc_iload: case opc_lload:
1441        case opc_fload: case opc_dload: case opc_aload:
1442    case opc_getstatic:
1443        if (replacement == null)
1444        iter.remove();
1445        else
1446        iter.set(replacement);
1447        return;
1448    case opc_ifeq: case opc_ifne:
1449    case opc_iflt: case opc_ifge:
1450    case opc_ifgt: case opc_ifle:
1451    case opc_ifnull: case opc_ifnonnull:
1452    case opc_arraylength:
1453    case opc_getfield:
1454        case opc_i2l: case opc_i2f: case opc_i2d:
1455        case opc_f2i: case opc_f2l: case opc_f2d:
1456        case opc_i2b: case opc_i2c: case opc_i2s:
1457        case opc_ineg: case opc_fneg:
1458        iter.set(new Instruction(opc_pop));
1459        break;
1460    case opc_lcmp:
1461    case opc_dcmpg: case opc_dcmpl:
1462        case opc_ladd: case opc_dadd:
1463        case opc_lsub: case opc_dsub:
1464        case opc_lmul: case opc_dmul:
1465        case opc_ldiv: case opc_ddiv:
1466        case opc_lrem: case opc_drem:
1467    case opc_land: case opc_lor : case opc_lxor:
1468        iter.set(new Instruction(opc_pop2));
1469        iter.add(new Instruction(opc_pop2));
1470        break;
1471    case opc_if_icmpeq: case opc_if_icmpne:
1472    case opc_if_icmplt: case opc_if_icmpge:
1473    case opc_if_icmpgt: case opc_if_icmple:
1474    case opc_if_acmpeq: case opc_if_acmpne:
1475    case opc_fcmpg: case opc_fcmpl:
1476        case opc_l2i: case opc_l2f: case opc_l2d:
1477        case opc_d2i: case opc_d2l: case opc_d2f:
1478    case opc_lneg: case opc_dneg:
1479        case opc_iadd: case opc_fadd:
1480        case opc_isub: case opc_fsub:
1481        case opc_imul: case opc_fmul:
1482        case opc_idiv: case opc_fdiv:
1483        case opc_irem: case opc_frem:
1484        case opc_iand: case opc_ior : case opc_ixor:
1485        case opc_ishl: case opc_ishr: case opc_iushr:
1486        case opc_iaload: case opc_laload:
1487        case opc_faload: case opc_daload: case opc_aaload:
1488        case opc_baload: case opc_caload: case opc_saload:
1489        iter.set(new Instruction(opc_pop2));
1490        break;
1491
1492    case opc_lshl: case opc_lshr: case opc_lushr:
1493        iter.set(new Instruction(opc_pop));
1494        iter.add(new Instruction(opc_pop2));
1495        break;
1496    case opc_putstatic:
1497    case opc_putfield:
1498        if (TypeSignature
1499        .getTypeSize(instr.getReference().getType()) == 2) {
1500        iter.set(new Instruction(opc_pop2));
1501        if (instr.getOpcode() == opc_putfield)
1502            iter.add(new Instruction(opc_pop));
1503        } else
1504        iter.set(new Instruction(instr.getOpcode() == opc_putfield
1505                     ? opc_pop2 : opc_pop));
1506        break;
1507    case opc_invokespecial:
1508    case opc_invokestatic:
1509    case opc_invokeinterface:
1510    case opc_invokevirtual: {
1511        Reference ref = instr.getReference();
1512        String JavaDoc[] pt = TypeSignature.getParameterTypes(ref.getType());
1513        int len = pt.length;
1514
1515        if (len > 0) {
1516        iter.set(new Instruction(TypeSignature.getTypeSize(pt[--len])
1517                     + opc_pop - 1));
1518        for (int i = len - 1; i >= 0; i--)
1519            iter.add(new Instruction(TypeSignature.getTypeSize(pt[i])
1520                         + opc_pop - 1));
1521        if (instr.getOpcode() != opc_invokestatic)
1522            iter.add(new Instruction(opc_pop));
1523        } else if (instr.getOpcode() != opc_invokestatic) {
1524        iter.set(new Instruction(opc_pop));
1525        } else {
1526        if (replacement == null)
1527            iter.remove();
1528        else
1529            iter.set(replacement);
1530        return;
1531        }
1532        
1533    }
1534    }
1535    if (replacement != null)
1536        iter.add(replacement);
1537    }
1538    
1539    public void appendJump(ListIterator JavaDoc iter, Instruction dest) {
1540    /* Add a goto instruction after this opcode. */
1541    Instruction gotoInstr = new Instruction(Instruction.opc_goto);
1542    gotoInstr.setSuccs(dest);
1543    iter.add(gotoInstr);
1544    }
1545    
1546    public void transformCode(BytecodeInfo bytecode) {
1547    for (ListIterator JavaDoc iter = bytecode.getInstructions().listIterator();
1548         iter.hasNext(); ) {
1549        Instruction instr = (Instruction) iter.next();
1550        ConstantInfo info = (ConstantInfo) instr.getTmpInfo();
1551        instr.setTmpInfo(null);
1552
1553        if (info == null
1554        || (info.flags & (RETURNINGJSR | RETASTORE)) == RETASTORE) {
1555        /* This instruction can't be reached logically, or
1556         * it is a return value astore, that should be removed */

1557        iter.remove();
1558        } else if ((info.flags & CONSTANT) != 0) {
1559        if (instr.getOpcode() > opc_ldc2_w) {
1560            Instruction ldcInstr
1561            = new Instruction(info.constant instanceof Long JavaDoc
1562                      || info.constant instanceof Double JavaDoc
1563                      ? opc_ldc2_w : opc_ldc);
1564            ldcInstr.setConstant(info.constant);
1565            replaceWith(iter, instr, ldcInstr);
1566            if (GlobalOptions.verboseLevel > 2)
1567            GlobalOptions.err.println
1568                (bytecode + ": Replacing " + instr
1569                 + " with constant " + info.constant);
1570        }
1571        } else if ((info.flags & CONSTANTFLOW) != 0) {
1572        Instruction pc = (Instruction) info.constant;
1573        if (instr.getOpcode() >= opc_if_icmpeq
1574            && instr.getOpcode() <= opc_if_acmpne)
1575            iter.set(new Instruction(opc_pop2));
1576        else
1577            iter.set(new Instruction(opc_pop));
1578        if (GlobalOptions.verboseLevel > 2)
1579            GlobalOptions.err.println
1580            (bytecode + ": Replacing " + instr
1581             + " with goto " + pc.getAddr());
1582        while (iter.hasNext()) {
1583            ConstantInfo nextinfo = (ConstantInfo)
1584            ((Instruction) iter.next()).getTmpInfo();
1585            if (nextinfo != null) {
1586            Instruction nextInstr = (Instruction) iter.previous();
1587            if (pc != nextInstr)
1588                appendJump(iter, pc);
1589            break;
1590            }
1591            /* Next instruction can't be reached logically */
1592            iter.remove();
1593        }
1594        
1595        } else {
1596        int opcode = instr.getOpcode();
1597        switch (opcode) {
1598        case opc_nop:
1599            iter.remove();
1600            break;
1601
1602        case opc_jsr:
1603            ConstantInfo jsrinfo = (ConstantInfo)
1604            instr.getSingleSucc().getTmpInfo();
1605            if ((jsrinfo.flags & RETURNINGJSR) != 0)
1606            /* A normal jsr, don't change it */
1607            break;
1608
1609            /* This means, the jsr will never return. We
1610             * replace it with a goto, the jsr will transform
1611             * itself to remove the astore operation.
1612             */

1613            Instruction gotoInstr = new Instruction(opc_goto);
1614            gotoInstr.setSuccs(instr.getSingleSucc());
1615            iter.set(gotoInstr);
1616            /* fall through */
1617        case opc_goto:
1618        case opc_ifeq: case opc_ifne:
1619        case opc_iflt: case opc_ifge:
1620        case opc_ifgt: case opc_ifle:
1621        case opc_ifnull: case opc_ifnonnull:
1622        case opc_if_icmpeq: case opc_if_icmpne:
1623        case opc_if_icmplt: case opc_if_icmpge:
1624        case opc_if_icmpgt: case opc_if_icmple:
1625        case opc_if_acmpeq: case opc_if_acmpne:
1626
1627            while (iter.hasNext()) {
1628            ConstantInfo nextinfo = (ConstantInfo)
1629                ((Instruction) iter.next()).getTmpInfo();
1630            if (nextinfo != null
1631                && ((nextinfo.flags & (RETURNINGJSR | RETASTORE))
1632                != RETASTORE)) {
1633
1634                Instruction nextInstr
1635                = (Instruction) iter.previous();
1636                if (instr.getSingleSucc() == nextInstr) {
1637                /* put iter in sane state */
1638                iter.previous();
1639                iter.next();
1640                replaceWith(iter, instr, null);
1641                }
1642                break;
1643            }
1644            /* Next instruction can be removed */
1645            iter.remove();
1646            }
1647            break;
1648
1649        case opc_putstatic:
1650        case opc_putfield: {
1651            Reference ref = instr.getReference();
1652            FieldIdentifier fi = (FieldIdentifier)
1653            Main.getClassBundle().getIdentifier(ref);
1654            if (fi != null
1655            && (Main.stripping & Main.STRIP_UNREACH) != 0
1656            && !fi.isReachable()) {
1657            replaceWith(iter, instr, null);
1658            }
1659            break;
1660        }
1661        }
1662        }
1663    }
1664    }
1665}
1666
Popular Tags