KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > bytecode > BytecodeInfo


1 /* BytecodeInfo 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 Lesser 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 Lesser General Public License
14  * along with this program; see the file COPYING.LESSER. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: BytecodeInfo.java.in,v 4.9.2.8 2002/06/11 08:40:31 hoenicke Exp $
18  */

19
20 package jode.bytecode;
21 import jode.GlobalOptions;
22 import java.io.DataInputStream JavaDoc;
23 import java.io.DataOutputStream JavaDoc;
24 import java.io.ByteArrayInputStream JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.EOFException JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.BitSet JavaDoc;
29 import java.util.Stack JavaDoc;
30 import java.util.Vector JavaDoc;
31 import java.util.Enumeration JavaDoc;
32 import java.util.NoSuchElementException JavaDoc;
33
34 import java.util.List JavaDoc;
35 import java.util.AbstractSequentialList JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.ListIterator JavaDoc;
38
39
40 /**
41  * This class represents the byte code of a method. Each instruction is
42  * stored in an Instruction instance.
43  *
44  * We canonicalize some opcodes: wide opcodes are mapped to short ones,
45  * opcodes that load a constant are mapped to opc_ldc or opc_ldc2_w, and
46  * opc_xload_x / opc_xstore_x opcodes are mapped to opc_xload / opc_xstore.
47  */

48 public class BytecodeInfo extends BinaryInfo implements Opcodes {
49
50     private MethodInfo methodInfo;
51     private int maxStack, maxLocals;
52     private Handler[] exceptionHandlers;
53     private LocalVariableInfo[] lvt;
54     private LineNumber[] lnt;
55     
56     /**
57      * A array of instructions, indexed by address. This array is only
58      * valid while reading the code.
59      */

60     private Instruction[] instrs;
61
62     private InstructionList instructions;
63
64     private class InstructionList extends AbstractSequentialList JavaDoc {
65     Instruction borderInstr;
66     int instructionCount = 0;
67
68     InstructionList() {
69         // opc_impdep1 is used as border instruction, it may not
70
// occur in bytecode.
71
borderInstr = new Instruction(opc_impdep1);
72         borderInstr.nextByAddr = borderInstr.prevByAddr = borderInstr;
73     }
74
75     public int size() {
76         return instructionCount;
77     }
78
79     Instruction get0(int index) {
80         Instruction instr = borderInstr;
81         if (index < instructionCount / 2) {
82         for (int i=0; i <= index; i++)
83             instr = instr.nextByAddr;
84         } else {
85         for (int i=instructionCount; i > index; i--)
86             instr = instr.prevByAddr;
87         }
88         return instr;
89     }
90
91     public Object JavaDoc get(int index) {
92         if (index < 0 || index >= instructionCount)
93         throw new IllegalArgumentException JavaDoc();
94         return get0(index);
95     }
96
97     public boolean add(Object JavaDoc o) {
98         /* optimize add, since it is called many times by read() */
99         instructionCount++;
100         borderInstr.prevByAddr.appendInstruction((Instruction) o,
101                              BytecodeInfo.this);
102         return true;
103     }
104
105     public ListIterator JavaDoc listIterator(final int startIndex) {
106         if (startIndex < 0 || startIndex > instructionCount)
107         throw new IllegalArgumentException JavaDoc();
108         return new ListIterator JavaDoc() {
109         Instruction instr = get0(startIndex);
110         Instruction toRemove = null;
111         int index = startIndex;
112         
113         public boolean hasNext() {
114             return index < instructionCount;
115         }
116
117         public boolean hasPrevious() {
118             return index > 0;
119         }
120         
121         public Object JavaDoc next() {
122             if (index >= instructionCount)
123             throw new NoSuchElementException JavaDoc();
124             index++;
125             toRemove = instr;
126             instr = instr.nextByAddr;
127 // System.err.println("next: "+toRemove.getDescription());
128
return toRemove;
129         }
130
131         public Object JavaDoc previous() {
132             if (index == 0)
133             throw new NoSuchElementException JavaDoc();
134             index--;
135             instr = instr.prevByAddr;
136             toRemove = instr;
137 // System.err.println("prev: "+toRemove.getDescription());
138
return toRemove;
139         }
140
141         public int nextIndex() {
142             return index;
143         }
144
145         public int previousIndex() {
146             return index - 1;
147         }
148         
149         public void remove() {
150             if (toRemove == null)
151             throw new IllegalStateException JavaDoc();
152 // System.err.println("remove: "+toRemove.getDescription());
153
instructionCount--;
154             if (instr == toRemove)
155             instr = instr.nextByAddr;
156             else
157             index--;
158             toRemove.removeInstruction(BytecodeInfo.this);
159             toRemove = null;
160         }
161
162         public void add(Object JavaDoc o) {
163             instructionCount++;
164             index++;
165 // System.err.println("add: "
166
// +((Instruction)o).getDescription()
167
// +" after "+instr.prevByAddr
168
// .getDescription());
169
instr.prevByAddr.appendInstruction((Instruction) o,
170                                BytecodeInfo.this);
171             toRemove = null;
172         }
173
174         public void set(Object JavaDoc o) {
175             if (toRemove == null)
176             throw new IllegalStateException JavaDoc();
177 // System.err.println("replace "+toRemove.getDescription()
178
// +" with "
179
// +((Instruction)o).getDescription());
180
toRemove.replaceInstruction((Instruction) o,
181                         BytecodeInfo.this);
182             if (instr == toRemove)
183             instr = (Instruction) o;
184             toRemove = (Instruction) o;
185         }
186         };
187     }
188
189     void setLastAddr(int addr) {
190         borderInstr.setAddr(addr);
191     }
192
193     int getCodeLength() {
194         return borderInstr.getAddr();
195     }
196     }
197
198     public BytecodeInfo(MethodInfo mi) {
199     methodInfo = mi;
200     }
201
202     private final static Object JavaDoc[] constants = {
203     null,
204     new Integer JavaDoc(-1), new Integer JavaDoc(0), new Integer JavaDoc(1),
205     new Integer JavaDoc(2), new Integer JavaDoc(3), new Integer JavaDoc(4), new Integer JavaDoc(5),
206     new Long JavaDoc(0), new Long JavaDoc(1),
207     new Float JavaDoc(0), new Float JavaDoc(1), new Float JavaDoc(2),
208     new Double JavaDoc(0), new Double JavaDoc(1)
209     };
210
211     protected void readAttribute(String JavaDoc name, int length, ConstantPool cp,
212                  DataInputStream JavaDoc input,
213                  int howMuch) throws IOException JavaDoc {
214     if ((howMuch & KNOWNATTRIBS) != 0
215         && name.equals("LocalVariableTable")) {
216         if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
217         GlobalOptions.err.println("LocalVariableTable of "+methodInfo);
218             int count = input.readUnsignedShort();
219         if (length != 2 + count * 10) {
220         if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
221             GlobalOptions.err.println("Illegal LVT length, ignoring it");
222         return;
223         }
224         lvt = new LocalVariableInfo[count];
225             for (int i=0; i < count; i++) {
226         lvt[i] = new LocalVariableInfo();
227                 int start = input.readUnsignedShort();
228                 int end = start + input.readUnsignedShort();
229         int nameIndex = input.readUnsignedShort();
230         int typeIndex = input.readUnsignedShort();
231         int slot = input.readUnsignedShort();
232         Instruction startInstr =
233             start >= 0 && start < instrs.length ? instrs[start] : null;
234         Instruction endInstr;
235         if (end >=0 && end < instrs.length)
236             endInstr = instrs[end] == null ? null
237             : instrs[end].getPrevByAddr();
238         else {
239             endInstr = null;
240             for (int nr = instrs.length - 1; nr >= 0; nr--) {
241             if (instrs[nr] != null) {
242                 if (instrs[nr].getNextAddr() == end)
243                 endInstr = instrs[nr];
244                 break;
245             }
246             }
247         }
248
249         if (startInstr == null
250             || endInstr == null
251             || nameIndex == 0 || typeIndex == 0
252             || slot >= maxLocals
253             || cp.getTag(nameIndex) != cp.UTF8
254             || cp.getTag(typeIndex) != cp.UTF8) {
255
256             // This is probably an evil lvt as created by HashJava
257
// simply ignore it.
258
if ((GlobalOptions.debuggingFlags
259              & GlobalOptions.DEBUG_LVT) != 0)
260             GlobalOptions.err.println
261                 ("Illegal entry, ignoring LVT");
262             lvt = null;
263             return;
264         }
265         lvt[i].start = startInstr;
266         lvt[i].end = endInstr;
267         lvt[i].name = cp.getUTF8(nameIndex);
268                 lvt[i].type = cp.getUTF8(typeIndex);
269                 lvt[i].slot = slot;
270                 if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
271                     GlobalOptions.err.println("\t" + lvt[i].name + ": "
272                        + lvt[i].type
273                        +" range "+start+" - "+end
274                        +" slot "+slot);
275             }
276     } else if ((howMuch & KNOWNATTRIBS) != 0
277            && name.equals("LineNumberTable")) {
278         int count = input.readUnsignedShort();
279         if (length != 2 + count * 4) {
280         GlobalOptions.err.println
281             ("Illegal LineNumberTable, ignoring it");
282         return;
283         }
284         lnt = new LineNumber[count];
285         for (int i = 0; i < count; i++) {
286         lnt[i] = new LineNumber();
287         int start = input.readUnsignedShort();
288         Instruction startInstr = instrs[start];
289         if (startInstr == null) {
290             GlobalOptions.err.println
291             ("Illegal entry, ignoring LineNumberTable table");
292             lnt = null;
293             return;
294         }
295         lnt[i].start = startInstr;
296         lnt[i].linenr = input.readUnsignedShort();
297         }
298     } else
299         super.readAttribute(name, length, cp, input, howMuch);
300     }
301
302     public void read(ConstantPool cp,
303              DataInputStream JavaDoc input) throws IOException JavaDoc {
304         maxStack = input.readUnsignedShort();
305         maxLocals = input.readUnsignedShort();
306     instructions = new InstructionList();
307         int codeLength = input.readInt();
308     instrs = new Instruction[codeLength];
309     int[][] succAddrs = new int[codeLength][];
310     {
311         int addr = 0;
312         while (addr < codeLength) {
313         Instruction instr;
314         int length;
315         int opcode = input.readUnsignedByte();
316         if ((GlobalOptions.debuggingFlags
317              & GlobalOptions.DEBUG_BYTECODE) != 0)
318         if ((GlobalOptions.debuggingFlags
319              & GlobalOptions.DEBUG_BYTECODE) != 0)
320             GlobalOptions.err.print(addr+": "+opcodeString[opcode]);
321
322         switch (opcode) {
323         case opc_wide: {
324             int wideopcode = input.readUnsignedByte();
325             switch (wideopcode) {
326             case opc_iload: case opc_fload: case opc_aload:
327             case opc_istore: case opc_fstore: case opc_astore: {
328             int slot = input.readUnsignedShort();
329             if (slot >= maxLocals)
330                 throw new ClassFormatError JavaDoc
331                 ("Invalid local slot "+slot);
332             instr = new Instruction(wideopcode);
333             instr.setLocalSlot(slot);
334             length = 4;
335             if ((GlobalOptions.debuggingFlags
336                  & GlobalOptions.DEBUG_BYTECODE) != 0)
337                 GlobalOptions.err.print
338                 (" " + opcodeString[wideopcode] + " " + slot);
339             break;
340             }
341             case opc_lload: case opc_dload:
342             case opc_lstore: case opc_dstore: {
343             int slot = input.readUnsignedShort();
344             if (slot >= maxLocals-1)
345                 throw new ClassFormatError JavaDoc
346                 ("Invalid local slot "+slot);
347             instr = new Instruction(wideopcode);
348             instr.setLocalSlot(slot);
349             length = 4;
350             if ((GlobalOptions.debuggingFlags
351                  & GlobalOptions.DEBUG_BYTECODE) != 0)
352                 GlobalOptions.err.print
353                 (" " + opcodeString[wideopcode] + " " + slot);
354             break;
355             }
356             case opc_ret: {
357             int slot = input.readUnsignedShort();
358             if (slot >= maxLocals)
359                 throw new ClassFormatError JavaDoc
360                 ("Invalid local slot "+slot);
361             instr = new Instruction(wideopcode);
362             instr.setLocalSlot(slot);
363             length = 4;
364             if ((GlobalOptions.debuggingFlags
365                  & GlobalOptions.DEBUG_BYTECODE) != 0)
366                 GlobalOptions.err.print(" ret "+slot);
367             break;
368             }
369             case opc_iinc: {
370             int slot = input.readUnsignedShort();
371             if (slot >= maxLocals)
372                 throw new ClassFormatError JavaDoc
373                 ("Invalid local slot "+slot);
374             instr = new Instruction(wideopcode);
375             instr.setLocalSlot(slot);
376             instr.setIncrement(input.readShort());
377             length = 6;
378             if ((GlobalOptions.debuggingFlags
379                  & GlobalOptions.DEBUG_BYTECODE) != 0)
380                 GlobalOptions.err.print
381                 (" iinc " + slot + " " + instr.getIncrement());
382             break;
383             }
384             default:
385             throw new ClassFormatError JavaDoc("Invalid wide opcode "
386                            +wideopcode);
387             }
388             break;
389         }
390         case opc_iload_0: case opc_iload_1:
391         case opc_iload_2: case opc_iload_3:
392         case opc_lload_0: case opc_lload_1:
393         case opc_lload_2: case opc_lload_3:
394         case opc_fload_0: case opc_fload_1:
395         case opc_fload_2: case opc_fload_3:
396         case opc_dload_0: case opc_dload_1:
397         case opc_dload_2: case opc_dload_3:
398         case opc_aload_0: case opc_aload_1:
399         case opc_aload_2: case opc_aload_3: {
400             int slot = (opcode-opc_iload_0) & 3;
401             if (slot >= maxLocals)
402             throw new ClassFormatError JavaDoc
403                 ("Invalid local slot "+slot);
404             instr = new Instruction(opc_iload +
405                         (opcode-opc_iload_0)/4);
406             instr.setLocalSlot(slot);
407             length = 1;
408             break;
409         }
410         case opc_istore_0: case opc_istore_1:
411         case opc_istore_2: case opc_istore_3:
412         case opc_fstore_0: case opc_fstore_1:
413         case opc_fstore_2: case opc_fstore_3:
414         case opc_astore_0: case opc_astore_1:
415         case opc_astore_2: case opc_astore_3: {
416             int slot = (opcode-opc_istore_0) & 3;
417             if (slot >= maxLocals)
418             throw new ClassFormatError JavaDoc
419                 ("Invalid local slot "+slot);
420             instr = new Instruction(opc_istore +
421                          (opcode-opc_istore_0)/4);
422             instr.setLocalSlot(slot);
423             length = 1;
424             break;
425         }
426         case opc_lstore_0: case opc_lstore_1:
427         case opc_lstore_2: case opc_lstore_3:
428         case opc_dstore_0: case opc_dstore_1:
429         case opc_dstore_2: case opc_dstore_3: {
430             int slot = (opcode-opc_istore_0) & 3;
431             if (slot >= maxLocals-1)
432             throw new ClassFormatError JavaDoc
433                 ("Invalid local slot "+slot);
434             instr = new Instruction(opc_istore
435                          + (opcode-opc_istore_0)/4);
436             instr.setLocalSlot(slot);
437             length = 1;
438             break;
439         }
440         case opc_iload: case opc_fload: case opc_aload:
441         case opc_istore: case opc_fstore: case opc_astore: {
442             int slot = input.readUnsignedByte();
443             if (slot >= maxLocals)
444             throw new ClassFormatError JavaDoc
445                 ("Invalid local slot "+slot);
446             instr = new Instruction(opcode);
447             instr.setLocalSlot(slot);
448             length = 2;
449             if ((GlobalOptions.debuggingFlags
450              & GlobalOptions.DEBUG_BYTECODE) != 0)
451             GlobalOptions.err.print(" "+slot);
452             break;
453         }
454         case opc_lstore: case opc_dstore:
455         case opc_lload: case opc_dload: {
456             int slot = input.readUnsignedByte();
457             if (slot >= maxLocals - 1)
458             throw new ClassFormatError JavaDoc
459                 ("Invalid local slot "+slot);
460             instr = new Instruction(opcode);
461             instr.setLocalSlot(slot);
462             length = 2;
463             if ((GlobalOptions.debuggingFlags
464              & GlobalOptions.DEBUG_BYTECODE) != 0)
465             GlobalOptions.err.print(" "+slot);
466             break;
467         }
468         case opc_ret: {
469             int slot = input.readUnsignedByte();
470             if (slot >= maxLocals)
471             throw new ClassFormatError JavaDoc
472                 ("Invalid local slot "+slot);
473             instr = new Instruction(opcode);
474             instr.setLocalSlot(slot);
475             length = 2;
476             if ((GlobalOptions.debuggingFlags
477              & GlobalOptions.DEBUG_BYTECODE) != 0)
478             GlobalOptions.err.print(" "+slot);
479             break;
480         }
481         case opc_aconst_null:
482         case opc_iconst_m1:
483         case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
484         case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
485         case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
486             instr = new Instruction(opc_ldc);
487             instr.setConstant
488             (constants[opcode - opc_aconst_null]);
489             length = 1;
490             break;
491         case opc_lconst_0: case opc_lconst_1:
492         case opc_dconst_0: case opc_dconst_1:
493             instr = new Instruction(opc_ldc2_w);
494             instr.setConstant
495             (constants[opcode - opc_aconst_null]);
496             length = 1;
497             break;
498         case opc_bipush:
499             instr = new Instruction(opc_ldc);
500             instr.setConstant(new Integer JavaDoc(input.readByte()));
501             length = 2;
502             break;
503         case opc_sipush:
504             instr = new Instruction(opc_ldc);
505             instr.setConstant(new Integer JavaDoc(input.readShort()));
506             length = 3;
507             break;
508         case opc_ldc: {
509             int index = input.readUnsignedByte();
510             int tag = cp.getTag(index);
511             if (tag != cp.STRING
512              && tag != cp.INTEGER && tag != cp.FLOAT)
513             throw new ClassFormatException
514                 ("wrong constant tag: "+tag);
515             instr = new Instruction(opcode);
516             instr.setConstant(cp.getConstant(index));
517             length = 2;
518             break;
519         }
520         case opc_ldc_w: {
521             int index = input.readUnsignedShort();
522             int tag = cp.getTag(index);
523             if (tag != cp.STRING
524              && tag != cp.INTEGER && tag != cp.FLOAT)
525             throw new ClassFormatException
526                 ("wrong constant tag: "+tag);
527             instr = new Instruction(opc_ldc);
528             instr.setConstant(cp.getConstant(index));
529             length = 3;
530             break;
531         }
532         case opc_ldc2_w: {
533             int index = input.readUnsignedShort();
534             int tag = cp.getTag(index);
535             if (tag != cp.LONG && tag != cp.DOUBLE)
536             throw new ClassFormatException
537                 ("wrong constant tag: "+tag);
538             instr = new Instruction(opcode);
539             instr.setConstant(cp.getConstant(index));
540             length = 3;
541             break;
542         }
543         case opc_iinc: {
544             int slot = input.readUnsignedByte();
545             if (slot >= maxLocals)
546             throw new ClassFormatError JavaDoc
547                 ("Invalid local slot "+slot);
548             instr = new Instruction(opcode);
549             instr.setLocalSlot(slot);
550             instr.setIncrement(input.readByte());
551             length = 3;
552             if ((GlobalOptions.debuggingFlags
553              & GlobalOptions.DEBUG_BYTECODE) != 0)
554             GlobalOptions.err.print
555                 (" " + slot + " " + instr.getIncrement());
556             break;
557         }
558         case opc_goto:
559         case opc_jsr:
560         case opc_ifeq: case opc_ifne:
561         case opc_iflt: case opc_ifge:
562         case opc_ifgt: case opc_ifle:
563         case opc_if_icmpeq: case opc_if_icmpne:
564         case opc_if_icmplt: case opc_if_icmpge:
565         case opc_if_icmpgt: case opc_if_icmple:
566         case opc_if_acmpeq: case opc_if_acmpne:
567         case opc_ifnull: case opc_ifnonnull:
568             instr = new Instruction(opcode);
569             length = 3;
570             succAddrs[addr] = new int[] { addr+input.readShort() };
571             if ((GlobalOptions.debuggingFlags
572              & GlobalOptions.DEBUG_BYTECODE) != 0)
573             GlobalOptions.err.print(" "+succAddrs[addr][0]);
574             break;
575
576         case opc_goto_w:
577         case opc_jsr_w:
578             instr = new Instruction(opcode - (opc_goto_w - opc_goto));
579             length = 5;
580             succAddrs[addr] = new int[] { addr+input.readInt() };
581             if ((GlobalOptions.debuggingFlags
582              & GlobalOptions.DEBUG_BYTECODE) != 0)
583             GlobalOptions.err.print(" "+succAddrs[addr][0]);
584             break;
585
586         case opc_tableswitch: {
587             length = 3 - (addr % 4);
588             input.readFully(new byte[length]);
589             int def = input.readInt();
590             int low = input.readInt();
591             int high = input.readInt();
592             int[] dests = new int[high-low+1];
593             int npairs = 0;
594             for (int i=0; i < dests.length; i++) {
595             dests[i] = input.readInt();
596             if (dests[i] != def)
597                 npairs++;
598             }
599             instr = new Instruction(opc_lookupswitch);
600             succAddrs[addr] = new int[npairs + 1];
601             int[] values = new int[npairs];
602             int pos = 0;
603             for (int i=0; i < dests.length; i++) {
604             if (dests[i] != def) {
605                 values[pos] = i+low;
606                 succAddrs[addr][pos] = addr + dests[i];
607                 pos++;
608             }
609             }
610             succAddrs[addr][npairs] = addr + def;
611             instr.setValues(values);
612             length += 13 + 4 * (high-low+1);
613             break;
614         }
615         case opc_lookupswitch: {
616             length = 3 - (addr % 4);
617             input.readFully(new byte[length]);
618             int def = input.readInt();
619             int npairs = input.readInt();
620             instr = new Instruction(opcode);
621             succAddrs[addr] = new int[npairs + 1];
622             int[] values = new int[npairs];
623             for (int i=0; i < npairs; i++) {
624             values[i] = input.readInt();
625             if (i > 0 && values[i-1] >= values[i])
626                 throw new ClassFormatException
627                 ("lookupswitch not sorted");
628             succAddrs[addr][i] = addr + input.readInt();
629             }
630             succAddrs[addr][npairs] = addr + def;
631             instr.setValues(values);
632             length += 9 + 8 * npairs;
633             break;
634         }
635                 
636         case opc_getstatic:
637         case opc_getfield:
638         case opc_putstatic:
639         case opc_putfield:
640         case opc_invokespecial:
641         case opc_invokestatic:
642         case opc_invokevirtual: {
643             int index = input.readUnsignedShort();
644             int tag = cp.getTag(index);
645             if (opcode < opc_invokevirtual) {
646             if (tag != cp.FIELDREF)
647                 throw new ClassFormatException
648                 ("field tag mismatch: "+tag);
649             } else {
650             if (tag != cp.METHODREF)
651                 throw new ClassFormatException
652                 ("method tag mismatch: "+tag);
653             }
654             Reference ref = cp.getRef(index);
655             if (ref.getName().charAt(0) == '<'
656             && (!ref.getName().equals("<init>")
657                 || opcode != opc_invokespecial))
658             throw new ClassFormatException
659                 ("Illegal call of special method/field "+ref);
660             instr = new Instruction(opcode);
661             instr.setReference(ref);
662             length = 3;
663             if ((GlobalOptions.debuggingFlags
664              & GlobalOptions.DEBUG_BYTECODE) != 0)
665             GlobalOptions.err.print(" "+ref);
666             break;
667         }
668         case opc_invokeinterface: {
669             int index = input.readUnsignedShort();
670             int tag = cp.getTag(index);
671             if (tag != cp.INTERFACEMETHODREF)
672             throw new ClassFormatException
673                 ("interface tag mismatch: "+tag);
674             Reference ref = cp.getRef(index);
675             if (ref.getName().charAt(0) == '<')
676             throw new ClassFormatException
677                 ("Illegal call of special method "+ref);
678             int nargs = input.readUnsignedByte();
679             if (TypeSignature.getArgumentSize(ref.getType())
680             != nargs - 1)
681             throw new ClassFormatException
682                 ("Interface nargs mismatch: "+ref+" vs. "+nargs);
683             if (input.readUnsignedByte() != 0)
684             throw new ClassFormatException
685                 ("Interface reserved param not zero");
686
687             instr = new Instruction(opcode);
688             instr.setReference(ref);
689             length = 5;
690             if ((GlobalOptions.debuggingFlags
691              & GlobalOptions.DEBUG_BYTECODE) != 0)
692             GlobalOptions.err.print(" "+ref);
693             break;
694         }
695
696         case opc_new:
697         case opc_checkcast:
698         case opc_instanceof: {
699             String JavaDoc type = cp.getClassType(input.readUnsignedShort());
700             if (opcode == opc_new && type.charAt(0) == '[')
701             throw new ClassFormatException
702                 ("Can't create array with opc_new");
703             instr = new Instruction(opcode);
704             instr.setClazzType(type);
705             length = 3;
706             if ((GlobalOptions.debuggingFlags
707              & GlobalOptions.DEBUG_BYTECODE) != 0)
708             GlobalOptions.err.print(" "+type);
709             break;
710         }
711         case opc_multianewarray: {
712             String JavaDoc type = cp.getClassType(input.readUnsignedShort());
713             int dims = input.readUnsignedByte();
714             if (dims == 0)
715             throw new ClassFormatException
716                 ("multianewarray dimension is 0.");
717             for (int i=0; i < dims; i++) {
718             /* Note that since type is a valid type
719              * signature, there must be a non bracket
720              * character, before the string is over.
721              * So there is no StringIndexOutOfBoundsException.
722              */

723             if (type.charAt(i) != '[')
724                 throw new ClassFormatException
725                 ("multianewarray called for non array:"+ type);
726             }
727             instr = new Instruction(opcode);
728             instr.setClazzType(type);
729             instr.setDimensions(dims);
730             length = 4;
731             if ((GlobalOptions.debuggingFlags
732              & GlobalOptions.DEBUG_BYTECODE) != 0)
733             GlobalOptions.err.print(" " + type + " " + dims);
734             break;
735         }
736         case opc_anewarray: {
737             String JavaDoc type = cp.getClassType(input.readUnsignedShort());
738             instr = new Instruction(opc_multianewarray);
739             instr.setClazzType(("["+type).intern());
740             instr.setDimensions(1);
741             length = 3;
742             if ((GlobalOptions.debuggingFlags
743              & GlobalOptions.DEBUG_BYTECODE) != 0)
744             GlobalOptions.err.print(" "+type);
745             break;
746         }
747         case opc_newarray: {
748             char sig = newArrayTypes.charAt
749             (input.readUnsignedByte()-4);
750             String JavaDoc type = new String JavaDoc (new char[] { '[', sig });
751             if ((GlobalOptions.debuggingFlags
752              & GlobalOptions.DEBUG_BYTECODE) != 0)
753             GlobalOptions.err.print(" "+type);
754             instr = new Instruction(opc_multianewarray);
755             instr.setClazzType(type);
756             instr.setDimensions(1);
757             length = 2;
758             break;
759         }
760         
761         case opc_nop:
762         case opc_iaload: case opc_laload: case opc_faload:
763         case opc_daload: case opc_aaload:
764         case opc_baload: case opc_caload: case opc_saload:
765         case opc_iastore: case opc_lastore: case opc_fastore:
766         case opc_dastore: case opc_aastore:
767         case opc_bastore: case opc_castore: case opc_sastore:
768         case opc_pop: case opc_pop2:
769         case opc_dup: case opc_dup_x1: case opc_dup_x2:
770         case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
771         case opc_swap:
772         case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
773         case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
774         case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
775         case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
776         case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
777         case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
778         case opc_ishl: case opc_lshl:
779         case opc_ishr: case opc_lshr:
780         case opc_iushr: case opc_lushr:
781         case opc_iand: case opc_land:
782         case opc_ior: case opc_lor:
783         case opc_ixor: case opc_lxor:
784         case opc_i2l: case opc_i2f: case opc_i2d:
785         case opc_l2i: case opc_l2f: case opc_l2d:
786         case opc_f2i: case opc_f2l: case opc_f2d:
787         case opc_d2i: case opc_d2l: case opc_d2f:
788         case opc_i2b: case opc_i2c: case opc_i2s:
789         case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
790         case opc_dcmpl: case opc_dcmpg:
791         case opc_ireturn: case opc_lreturn:
792         case opc_freturn: case opc_dreturn: case opc_areturn:
793         case opc_return:
794         case opc_athrow:
795         case opc_arraylength:
796         case opc_monitorenter: case opc_monitorexit:
797             instr = new Instruction(opcode);
798             length = 1;
799             break;
800         default:
801             throw new ClassFormatError JavaDoc("Invalid opcode "+opcode);
802         }
803         if ((GlobalOptions.debuggingFlags
804              & GlobalOptions.DEBUG_BYTECODE) != 0)
805             GlobalOptions.err.println();
806
807         instrs[addr] = instr;
808         instructions.add(instr);
809
810         addr += length;
811         instructions.setLastAddr(addr);
812         }
813         if (addr != codeLength)
814         throw new ClassFormatError JavaDoc("last instruction too long");
815     }
816     for (Iterator JavaDoc iter = instructions.iterator(); iter.hasNext(); ) {
817         Instruction instr = (Instruction) iter.next();
818         int addr = instr.getAddr();
819         if (succAddrs[addr] != null) {
820         int length = succAddrs[addr].length;
821         Instruction[] succs = new Instruction[length];
822         for (int i=0; i < length; i++) {
823             int succAddr = succAddrs[addr][i];
824             if (succAddr < 0 || succAddr > codeLength
825             || instrs[succAddr] == null)
826             throw new ClassFormatException
827                 ("Illegal jump target at "
828                  +this+"@"+addr);
829             succs[i] = instrs[succAddr];
830         }
831         instr.setSuccs(succs);
832         }
833     }
834     succAddrs = null;
835
836     {
837         int handlersLength = input.readUnsignedShort();
838         exceptionHandlers = new Handler[handlersLength];
839         for (int i=0; i< handlersLength; i ++) {
840         exceptionHandlers[i] = new Handler();
841         exceptionHandlers[i].start
842             = instrs[input.readUnsignedShort()];
843         exceptionHandlers[i].end
844             = instrs[input.readUnsignedShort()].getPrevByAddr();
845         exceptionHandlers[i].catcher
846             = instrs[input.readUnsignedShort()];
847         int index = input.readUnsignedShort();
848         exceptionHandlers[i].type = (index == 0) ? null
849             : cp.getClassName(index);
850
851         if (exceptionHandlers[i].catcher.getOpcode() == opc_athrow) {
852             /* There is an obfuscator, which inserts bogus
853              * exception entries jumping directly to a throw
854              * instruction. Remove those handlers.
855              */

856             handlersLength--;
857             i--;
858             continue;
859         }
860
861         if (exceptionHandlers[i].start.getAddr()
862                <= exceptionHandlers[i].catcher.getAddr()
863             && exceptionHandlers[i].end.getAddr()
864                >= exceptionHandlers[i].catcher.getAddr())
865         {
866             /* Javac 1.4 is a bit paranoid with finally and
867              * synchronize blocks and even breaks the JLS.
868              * We fix it here. Hopefully this won't produce
869              * any other problems.
870              */

871             if (exceptionHandlers[i].start
872             == exceptionHandlers[i].catcher) {
873             handlersLength--;
874             i--;
875             } else {
876             exceptionHandlers[i].end =
877                 exceptionHandlers[i].catcher.getPrevByAddr();
878             }
879         }
880         }
881         if (handlersLength < exceptionHandlers.length) {
882         Handler[] newHandlers = new Handler[handlersLength];
883         System.arraycopy(exceptionHandlers, 0, newHandlers, 0,
884                  handlersLength);
885         exceptionHandlers = newHandlers;
886         }
887     }
888     readAttributes(cp, input, FULLINFO);
889     instrs = null;
890     }
891
892     public void dumpCode(java.io.PrintWriter JavaDoc output) {
893     for (Iterator JavaDoc iter = instructions.iterator(); iter.hasNext(); ) {
894         Instruction instr = (Instruction) iter.next();
895         output.println(instr.getDescription() + " "
896                + Integer.toHexString(hashCode()));
897         Instruction[] succs = instr.getSuccs();
898         if (succs != null) {
899         output.print("\tsuccs: "+succs[0]);
900         for (int i = 1; i < succs.length; i++)
901             output.print(", "+succs[i]);
902         output.println();
903         }
904         if (instr.getPreds() != null) {
905         output.print("\tpreds: " + instr.getPreds()[0]);
906         for (int i=1; i < instr.getPreds().length; i++)
907             output.print(", " + instr.getPreds()[i]);
908         output.println();
909         }
910     }
911     for (int i=0; i< exceptionHandlers.length; i++) {
912         output.println("catch " + exceptionHandlers[i].type
913                + " from " + exceptionHandlers[i].start
914                + " to " + exceptionHandlers[i].end
915                + " catcher " + exceptionHandlers[i].catcher);
916     }
917     }
918
919     public void reserveSmallConstants(GrowableConstantPool gcp) {
920     next_instr:
921     for (Iterator JavaDoc iter = instructions.iterator(); iter.hasNext(); ) {
922         Instruction instr = (Instruction) iter.next();
923         if (instr.getOpcode() == opc_ldc) {
924         Object JavaDoc constant = instr.getConstant();
925         if (constant == null)
926             continue next_instr;
927         for (int i=1; i < constants.length; i++) {
928             if (constant.equals(constants[i]))
929             continue next_instr;
930         }
931         if (constant instanceof Integer JavaDoc) {
932             int value = ((Integer JavaDoc) constant).intValue();
933             if (value >= Short.MIN_VALUE
934             && value <= Short.MAX_VALUE)
935             continue next_instr;
936         }
937         gcp.reserveConstant(constant);
938         }
939     }
940     }
941
942     private void calculateMaxStack() {
943     maxStack = 0;
944     int[] stackHeights = new int[instructions.getCodeLength()];
945     int[] poppush = new int[2];
946     Stack JavaDoc todo = new Stack JavaDoc();
947
948     for (int i=0; i < stackHeights.length; i++)
949         stackHeights[i] = -1;
950
951     stackHeights[0] = 0;
952     todo.push(instructions.get(0));
953     while (!todo.isEmpty()) {
954         Instruction instr = (Instruction) todo.pop();
955         Instruction next = instr.getNextByAddr();
956         Instruction[] succs = instr.getSuccs();
957         int addr = instr.getAddr();
958         instr.getStackPopPush(poppush);
959         int sh = stackHeights[addr] - poppush[0] + poppush[1];
960 // System.err.println("Instr: "+instr.getDescription()+
961
// "; before: "+stackHeights[addr]+" after: "+sh);
962
if (maxStack < sh)
963         maxStack = sh;
964         if (instr.getOpcode() == opc_jsr) {
965         if (stackHeights[next.getAddr()] == -1) {
966             stackHeights[next.getAddr()] = sh - 1;
967             todo.push(next);
968         }
969         if (stackHeights[succs[0].getAddr()] == -1) {
970             stackHeights[succs[0].getAddr()] = sh;
971             todo.push(succs[0]);
972         }
973         } else {
974         if (succs != null) {
975             for (int i=0; i < succs.length; i++) {
976             if (stackHeights[succs[i].getAddr()] == -1) {
977                 stackHeights[succs[i].getAddr()] = sh;
978                 todo.push(succs[i]);
979             }
980             }
981         }
982         if (!instr.doesAlwaysJump()
983             && stackHeights[next.getAddr()] == -1) {
984             stackHeights[next.getAddr()] = sh;
985             todo.push(next);
986         }
987         }
988         for (int i=0; i< exceptionHandlers.length; i++) {
989         if (exceptionHandlers[i].start.compareTo(instr) <= 0
990             && exceptionHandlers[i].end.compareTo(instr) >= 0) {
991             int catcher = exceptionHandlers[i].catcher.getAddr();
992             if (stackHeights[catcher] == -1) {
993             stackHeights[catcher] = 1;
994             todo.push(exceptionHandlers[i].catcher);
995             }
996         }
997         }
998     }
999 // System.err.println("New maxStack: "+maxStack+" Locals: "+maxLocals);
1000
}
1001
1002    public void prepareWriting(GrowableConstantPool gcp) {
1003    /* Recalculate addr, length, maxStack, maxLocals and add all
1004     * constants to gcp */

1005    int addr = 0;
1006    maxLocals = (methodInfo.isStatic() ? 0 : 1) +
1007        TypeSignature.getArgumentSize(methodInfo.getType());
1008    
1009    for (Iterator JavaDoc iter = instructions.iterator(); iter.hasNext(); ) {
1010        Instruction instr = (Instruction) iter.next();
1011        int opcode = instr.getOpcode();
1012        instr.setAddr(addr);
1013        int length;
1014    switch_opc:
1015        switch (opcode) {
1016        case opc_ldc:
1017        case opc_ldc2_w: {
1018        Object JavaDoc constant = instr.getConstant();
1019        if (constant == null) {
1020            length = 1;
1021            break switch_opc;
1022        }
1023        for (int i=1; i < constants.length; i++) {
1024            if (constant.equals(constants[i])) {
1025            length = 1;
1026            break switch_opc;
1027            }
1028        }
1029        if (opcode == opc_ldc2_w) {
1030            gcp.putLongConstant(constant);
1031            length = 3;
1032            break switch_opc;
1033        }
1034        if (constant instanceof Integer JavaDoc) {
1035            int value = ((Integer JavaDoc) constant).intValue();
1036            if (value >= Byte.MIN_VALUE
1037            && value <= Byte.MAX_VALUE) {
1038            length = 2;
1039            break switch_opc;
1040            } else if (value >= Short.MIN_VALUE
1041                   && value <= Short.MAX_VALUE) {
1042            length = 3;
1043            break switch_opc;
1044            }
1045        }
1046        if (gcp.putConstant(constant) < 256) {
1047            length = 2;
1048        } else {
1049            length = 3;
1050        }
1051        break;
1052        }
1053        case opc_iinc: {
1054        int slot = instr.getLocalSlot();
1055        int increment = instr.getIncrement();
1056        if (slot < 256
1057            && increment >= Byte.MIN_VALUE
1058            && increment <= Byte.MAX_VALUE)
1059            length = 3;
1060        else
1061            length = 6;
1062        if (slot >= maxLocals)
1063            maxLocals = slot + 1;
1064        break;
1065        }
1066        case opc_iload: case opc_fload: case opc_aload:
1067        case opc_istore: case opc_fstore: case opc_astore: {
1068        int slot = instr.getLocalSlot();
1069        if (slot < 4)
1070            length = 1;
1071        else if (slot < 256)
1072            length = 2;
1073        else
1074            length = 4;
1075        if (slot >= maxLocals)
1076            maxLocals = slot + 1;
1077        break;
1078        }
1079        case opc_lload: case opc_dload:
1080        case opc_lstore: case opc_dstore: {
1081        int slot = instr.getLocalSlot();
1082        if (slot < 4)
1083            length = 1;
1084        else if (slot < 256)
1085            length = 2;
1086        else
1087            length = 4;
1088        if (slot+1 >= maxLocals)
1089            maxLocals = slot + 2;
1090        break;
1091        }
1092        case opc_ret: {
1093        int slot = instr.getLocalSlot();
1094        if (slot < 256)
1095            length = 2;
1096        else
1097            length = 4;
1098        if (slot >= maxLocals)
1099            maxLocals = slot + 1;
1100        break;
1101        }
1102        case opc_lookupswitch: {
1103        length = 3-(addr % 4);
1104        int[] values = instr.getValues();
1105        int npairs = values.length;
1106        if (npairs > 0) {
1107            int tablesize = values[npairs-1] - values[0] + 1;
1108            if (4 + tablesize * 4 < 8 * npairs) {
1109            // Use a table switch
1110
length += 13 + 4 * tablesize;
1111            break;
1112            }
1113        }
1114        // Use a lookup switch
1115
length += 9 + 8 * npairs;
1116        break;
1117        }
1118        case opc_goto: case opc_jsr: {
1119        int dist = instr.getSingleSucc().getAddr() - instr.getAddr();
1120        if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
1121            /* wide goto / jsr */
1122            length = 5;
1123            break;
1124        }
1125        /* fall through */
1126        }
1127        case opc_ifeq: case opc_ifne:
1128        case opc_iflt: case opc_ifge:
1129        case opc_ifgt: case opc_ifle:
1130        case opc_if_icmpeq: case opc_if_icmpne:
1131        case opc_if_icmplt: case opc_if_icmpge:
1132        case opc_if_icmpgt: case opc_if_icmple:
1133        case opc_if_acmpeq: case opc_if_acmpne:
1134        case opc_ifnull: case opc_ifnonnull:
1135        length = 3;
1136        break;
1137        case opc_multianewarray: {
1138        if (instr.getDimensions() == 1) {
1139            String JavaDoc clazz = instr.getClazzType().substring(1);
1140            if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) {
1141            length = 2;
1142            } else {
1143            gcp.putClassType(clazz);
1144            length = 3;
1145            }
1146        } else {
1147            gcp.putClassType(instr.getClazzType());
1148            length = 4;
1149        }
1150        break;
1151        }
1152        case opc_getstatic:
1153        case opc_getfield:
1154        case opc_putstatic:
1155        case opc_putfield:
1156        gcp.putRef(gcp.FIELDREF, instr.getReference());
1157        length = 3;
1158        break;
1159        case opc_invokespecial:
1160        case opc_invokestatic:
1161        case opc_invokevirtual:
1162        gcp.putRef(gcp.METHODREF, instr.getReference());
1163        length = 3;
1164        break;
1165        case opc_invokeinterface:
1166        gcp.putRef(gcp.INTERFACEMETHODREF, instr.getReference());
1167        length = 5;
1168        break;
1169        case opc_new:
1170        case opc_checkcast:
1171        case opc_instanceof:
1172        gcp.putClassType(instr.getClazzType());
1173        length = 3;
1174        break;
1175        case opc_nop:
1176        case opc_iaload: case opc_laload: case opc_faload:
1177        case opc_daload: case opc_aaload:
1178        case opc_baload: case opc_caload: case opc_saload:
1179        case opc_iastore: case opc_lastore: case opc_fastore:
1180        case opc_dastore: case opc_aastore:
1181        case opc_bastore: case opc_castore: case opc_sastore:
1182        case opc_pop: case opc_pop2:
1183        case opc_dup: case opc_dup_x1: case opc_dup_x2:
1184        case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
1185        case opc_swap:
1186        case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
1187        case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
1188        case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
1189        case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
1190        case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
1191        case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
1192        case opc_ishl: case opc_lshl:
1193        case opc_ishr: case opc_lshr:
1194        case opc_iushr: case opc_lushr:
1195        case opc_iand: case opc_land:
1196        case opc_ior: case opc_lor:
1197        case opc_ixor: case opc_lxor:
1198        case opc_i2l: case opc_i2f: case opc_i2d:
1199        case opc_l2i: case opc_l2f: case opc_l2d:
1200        case opc_f2i: case opc_f2l: case opc_f2d:
1201        case opc_d2i: case opc_d2l: case opc_d2f:
1202        case opc_i2b: case opc_i2c: case opc_i2s:
1203        case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
1204        case opc_dcmpl: case opc_dcmpg:
1205        case opc_ireturn: case opc_lreturn:
1206        case opc_freturn: case opc_dreturn: case opc_areturn:
1207        case opc_return:
1208        case opc_athrow:
1209        case opc_arraylength:
1210        case opc_monitorenter: case opc_monitorexit:
1211        length = 1;
1212        break;
1213        default:
1214        throw new ClassFormatError JavaDoc("Invalid opcode "+opcode);
1215        }
1216        addr += length;
1217    }
1218    instructions.setLastAddr(addr);
1219    try {
1220        calculateMaxStack();
1221    } catch (RuntimeException JavaDoc ex) {
1222        ex.printStackTrace();
1223        dumpCode(GlobalOptions.err);
1224    }
1225    for (int i=0; i< exceptionHandlers.length; i++)
1226        if (exceptionHandlers[i].type != null)
1227        gcp.putClassName(exceptionHandlers[i].type);
1228    if (lvt != null) {
1229        gcp.putUTF8("LocalVariableTable");
1230            for (int i=0; i < lvt.length; i++) {
1231        gcp.putUTF8(lvt[i].name);
1232        gcp.putUTF8(lvt[i].type);
1233            }
1234    }
1235    if (lnt != null)
1236        gcp.putUTF8("LineNumberTable");
1237    prepareAttributes(gcp);
1238    }
1239
1240    protected int getKnownAttributeCount() {
1241    int count = 0;
1242    if (lvt != null)
1243        count++;
1244    if (lnt != null)
1245        count++;
1246    return count;
1247    }
1248
1249    public void writeKnownAttributes(GrowableConstantPool gcp,
1250                     DataOutputStream JavaDoc output)
1251    throws IOException JavaDoc {
1252    if (lvt != null) {
1253        output.writeShort(gcp.putUTF8("LocalVariableTable"));
1254            int count = lvt.length;
1255        int length = 2 + 10 * count;
1256        output.writeInt(length);
1257        output.writeShort(count);
1258            for (int i=0; i < count; i++) {
1259        output.writeShort(lvt[i].start.getAddr());
1260        output.writeShort(lvt[i].end.getAddr() + lvt[i].end.getLength()
1261                  - lvt[i].start.getAddr());
1262        output.writeShort(gcp.putUTF8(lvt[i].name));
1263        output.writeShort(gcp.putUTF8(lvt[i].type));
1264        output.writeShort(lvt[i].slot);
1265            }
1266    }
1267    if (lnt != null) {
1268        output.writeShort(gcp.putUTF8("LineNumberTable"));
1269            int count = lnt.length;
1270        int length = 2 + 4 * count;
1271        output.writeInt(length);
1272        output.writeShort(count);
1273            for (int i=0; i < count; i++) {
1274        output.writeShort(lnt[i].start.getAddr());
1275        output.writeShort(lnt[i].linenr);
1276            }
1277    }
1278    }
1279
1280    public void write(GrowableConstantPool gcp,
1281              DataOutputStream JavaDoc output) throws IOException JavaDoc {
1282    output.writeShort(maxStack);
1283    output.writeShort(maxLocals);
1284    output.writeInt(instructions.getCodeLength());
1285    for (Iterator JavaDoc iter = instructions.iterator(); iter.hasNext(); ) {
1286        Instruction instr = (Instruction) iter.next();
1287        int opcode = instr.getOpcode();
1288        switch_opc:
1289        switch (opcode) {
1290        case opc_iload: case opc_lload:
1291        case opc_fload: case opc_dload: case opc_aload:
1292        case opc_istore: case opc_lstore:
1293        case opc_fstore: case opc_dstore: case opc_astore: {
1294        int slot = instr.getLocalSlot();
1295        if (slot < 4) {
1296            if (opcode < opc_istore)
1297            output.writeByte(opc_iload_0
1298                     + 4*(opcode-opc_iload)
1299                     + slot);
1300            else
1301            output.writeByte(opc_istore_0
1302                     + 4*(opcode-opc_istore)
1303                     + slot);
1304        } else if (slot < 256) {
1305            output.writeByte(opcode);
1306            output.writeByte(slot);
1307        } else {
1308            output.writeByte(opc_wide);
1309            output.writeByte(opcode);
1310            output.writeShort(slot);
1311        }
1312        break;
1313        }
1314        case opc_ret: {
1315        int slot = instr.getLocalSlot();
1316        if (slot < 256) {
1317            output.writeByte(opcode);
1318            output.writeByte(slot);
1319        } else {
1320            output.writeByte(opc_wide);
1321            output.writeByte(opcode);
1322            output.writeShort(slot);
1323        }
1324        break;
1325        }
1326        case opc_ldc:
1327        case opc_ldc2_w: {
1328        Object JavaDoc constant = instr.getConstant();
1329        if (constant == null) {
1330            output.writeByte(opc_aconst_null);
1331            break switch_opc;
1332        }
1333        for (int i=1; i < constants.length; i++) {
1334            if (constant.equals(constants[i])) {
1335            output.writeByte(opc_aconst_null + i);
1336            break switch_opc;
1337            }
1338        }
1339        if (opcode == opc_ldc2_w) {
1340            output.writeByte(opcode);
1341            output.writeShort(gcp.putLongConstant(constant));
1342        } else {
1343            if (constant instanceof Integer JavaDoc) {
1344            int value = ((Integer JavaDoc) constant).intValue();
1345            if (value >= Byte.MIN_VALUE
1346                && value <= Byte.MAX_VALUE) {
1347                
1348                output.writeByte(opc_bipush);
1349                output.writeByte(((Integer JavaDoc)constant)
1350                         .intValue());
1351                break switch_opc;
1352            } else if (value >= Short.MIN_VALUE
1353                   && value <= Short.MAX_VALUE) {
1354                output.writeByte(opc_sipush);
1355                output.writeShort(((Integer JavaDoc)constant)
1356                          .intValue());
1357                break switch_opc;
1358            }
1359            }
1360            if (instr.getLength() == 2) {
1361            output.writeByte(opc_ldc);
1362            output.writeByte(gcp.putConstant(constant));
1363            } else {
1364            output.writeByte(opc_ldc_w);
1365            output.writeShort(gcp.putConstant(constant));
1366            }
1367        }
1368        break;
1369        }
1370        case opc_iinc: {
1371        int slot = instr.getLocalSlot();
1372        int incr = instr.getIncrement();
1373        if (instr.getLength() == 3) {
1374            output.writeByte(opcode);
1375            output.writeByte(slot);
1376            output.writeByte(incr);
1377        } else {
1378            output.writeByte(opc_wide);
1379            output.writeByte(opcode);
1380            output.writeShort(slot);
1381            output.writeShort(incr);
1382        }
1383        break;
1384        }
1385        case opc_goto:
1386        case opc_jsr:
1387        if (instr.getLength() == 5) {
1388            /* wide goto or jsr */
1389            output.writeByte(opcode + (opc_goto_w - opc_goto));
1390            output.writeInt(instr.getSingleSucc().getAddr()
1391                    - instr.getAddr());
1392            break;
1393        }
1394        /* fall through */
1395        case opc_ifeq: case opc_ifne:
1396        case opc_iflt: case opc_ifge:
1397        case opc_ifgt: case opc_ifle:
1398        case opc_if_icmpeq: case opc_if_icmpne:
1399        case opc_if_icmplt: case opc_if_icmpge:
1400        case opc_if_icmpgt: case opc_if_icmple:
1401        case opc_if_acmpeq: case opc_if_acmpne:
1402        case opc_ifnull: case opc_ifnonnull:
1403        output.writeByte(opcode);
1404        output.writeShort(instr.getSingleSucc().getAddr()
1405                  - instr.getAddr());
1406        break;
1407
1408        case opc_lookupswitch: {
1409        int align = 3-(instr.getAddr() % 4);
1410        int[] values = instr.getValues();
1411        int npairs = values.length;
1412        int defAddr = instr.getSuccs()[npairs].getAddr()
1413            - instr.getAddr();
1414
1415        if (npairs > 0) {
1416            int tablesize = values[npairs-1] - values[0] + 1;
1417            if (4 + tablesize * 4 < 8 * npairs) {
1418            // Use a table switch
1419
output.writeByte(opc_tableswitch);
1420            output.write(new byte[align]);
1421            /* def */
1422            output.writeInt(defAddr);
1423            /* low */
1424            output.writeInt(values[0]);
1425            /* high */
1426            output.writeInt(values[npairs-1]);
1427            int pos = values[0];
1428            for (int i = 0; i < npairs; i++) {
1429                while (pos++ < values[i])
1430                output.writeInt(defAddr);
1431                output.writeInt(instr.getSuccs()[i].getAddr()
1432                        - instr.getAddr());
1433            }
1434            break;
1435            }
1436        }
1437        // Use a lookup switch
1438
output.writeByte(opc_lookupswitch);
1439        output.write(new byte[align]);
1440        /* def */
1441        output.writeInt(defAddr);
1442        output.writeInt(npairs);
1443        for (int i=0; i < npairs; i++) {
1444            output.writeInt(values[i]);
1445            output.writeInt(instr.getSuccs()[i].getAddr()
1446                    -instr.getAddr());
1447        }
1448        break;
1449        }
1450
1451        case opc_getstatic:
1452        case opc_getfield:
1453        case opc_putstatic:
1454        case opc_putfield:
1455        output.writeByte(opcode);
1456        output.writeShort(gcp.putRef(gcp.FIELDREF,
1457                         instr.getReference()));
1458        break;
1459
1460        case opc_invokespecial:
1461        case opc_invokestatic:
1462        case opc_invokeinterface:
1463        case opc_invokevirtual: {
1464        Reference ref = instr.getReference();
1465        output.writeByte(opcode);
1466        if (opcode == opc_invokeinterface) {
1467            output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, ref));
1468            output.writeByte
1469            (TypeSignature.getArgumentSize(ref.getType()) + 1);
1470            output.writeByte(0);
1471        } else
1472            output.writeShort(gcp.putRef(gcp.METHODREF, ref));
1473        break;
1474        }
1475        case opc_new:
1476        case opc_checkcast:
1477        case opc_instanceof:
1478        output.writeByte(opcode);
1479        output.writeShort(gcp.putClassType(instr.getClazzType()));
1480        break;
1481        case opc_multianewarray:
1482        if (instr.getDimensions() == 1) {
1483            String JavaDoc clazz = instr.getClazzType().substring(1);
1484            int index = newArrayTypes.indexOf(clazz.charAt(0));
1485            if (index != -1) {
1486            output.writeByte(opc_newarray);
1487            output.writeByte(index + 4);
1488            } else {
1489            output.writeByte(opc_anewarray);
1490            output.writeShort(gcp.putClassType(clazz));
1491            }
1492        } else {
1493            output.writeByte(opcode);
1494            output.writeShort(gcp.putClassType(instr.getClazzType()));
1495            output.writeByte(instr.getDimensions());
1496        }
1497        break;
1498
1499        case opc_nop:
1500        case opc_iaload: case opc_laload: case opc_faload:
1501        case opc_daload: case opc_aaload:
1502        case opc_baload: case opc_caload: case opc_saload:
1503        case opc_iastore: case opc_lastore: case opc_fastore:
1504        case opc_dastore: case opc_aastore:
1505        case opc_bastore: case opc_castore: case opc_sastore:
1506        case opc_pop: case opc_pop2:
1507        case opc_dup: case opc_dup_x1: case opc_dup_x2:
1508        case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
1509        case opc_swap:
1510        case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
1511        case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
1512        case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
1513        case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
1514        case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
1515        case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
1516        case opc_ishl: case opc_lshl:
1517        case opc_ishr: case opc_lshr:
1518        case opc_iushr: case opc_lushr:
1519        case opc_iand: case opc_land:
1520        case opc_ior: case opc_lor:
1521        case opc_ixor: case opc_lxor:
1522        case opc_i2l: case opc_i2f: case opc_i2d:
1523        case opc_l2i: case opc_l2f: case opc_l2d:
1524        case opc_f2i: case opc_f2l: case opc_f2d:
1525        case opc_d2i: case opc_d2l: case opc_d2f:
1526        case opc_i2b: case opc_i2c: case opc_i2s:
1527        case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
1528        case opc_dcmpl: case opc_dcmpg:
1529        case opc_ireturn: case opc_lreturn:
1530        case opc_freturn: case opc_dreturn: case opc_areturn:
1531        case opc_return:
1532        case opc_athrow:
1533        case opc_arraylength:
1534        case opc_monitorenter: case opc_monitorexit:
1535        output.writeByte(opcode);
1536        break;
1537        default:
1538        throw new ClassFormatError JavaDoc("Invalid opcode "+opcode);
1539        }
1540    }
1541
1542    output.writeShort(exceptionHandlers.length);
1543    for (int i=0; i< exceptionHandlers.length; i++) {
1544        output.writeShort(exceptionHandlers[i].start.getAddr());
1545        output.writeShort(exceptionHandlers[i].end.getNextByAddr().getAddr());
1546        output.writeShort(exceptionHandlers[i].catcher.getAddr());
1547        output.writeShort((exceptionHandlers[i].type == null) ? 0
1548                  : gcp.putClassName(exceptionHandlers[i].type));
1549    }
1550    writeAttributes(gcp, output);
1551    }
1552
1553    public void dropInfo(int howMuch) {
1554    if ((howMuch & KNOWNATTRIBS) != 0) {
1555        lvt = null;
1556        lnt = null;
1557    }
1558    super.dropInfo(howMuch);
1559    }
1560
1561    public int getSize() {
1562    /* maxStack: 2
1563     * maxLocals: 2
1564     * code: 4 + codeLength
1565     * exc count: 2
1566     * exceptions: n * 8
1567     * attributes:
1568     * lvt_name: 2
1569     * lvt_length: 4
1570     * lvt_count: 2
1571     * lvt_entries: n * 10
1572     * attributes:
1573     * lnt_name: 2
1574     * lnt_length: 4
1575     * lnt_count: 2
1576     * lnt_entries: n * 4
1577     */

1578    int size = 0;
1579    if (lvt != null)
1580        size += 8 + lvt.length * 10;
1581    if (lnt != null)
1582        size += 8 + lnt.length * 4;
1583    return 10 + instructions.getCodeLength()
1584        + exceptionHandlers.length * 8
1585        + getAttributeSize() + size;
1586    }
1587
1588    public int getMaxStack() {
1589        return maxStack;
1590    }
1591
1592    public int getMaxLocals() {
1593        return maxLocals;
1594    }
1595
1596    public MethodInfo getMethodInfo() {
1597    return methodInfo;
1598    }
1599
1600    public List JavaDoc getInstructions() {
1601    return instructions;
1602    }
1603
1604    public Handler[] getExceptionHandlers() {
1605    return exceptionHandlers;
1606    }
1607
1608    public LocalVariableInfo[] getLocalVariableTable() {
1609    return lvt;
1610    }
1611
1612    public LineNumber[] getLineNumberTable() {
1613    return lnt;
1614    }
1615
1616    public void setExceptionHandlers(Handler[] handlers) {
1617        exceptionHandlers = handlers;
1618    }
1619
1620    public void setLocalVariableTable(LocalVariableInfo[] newLvt) {
1621    lvt = newLvt;
1622    }
1623
1624    public void setLineNumberTable(LineNumber[] newLnt) {
1625    lnt = newLnt;
1626    }
1627
1628    public String JavaDoc toString() {
1629        return "Bytecode "+methodInfo;
1630    }
1631}
1632
Popular Tags