KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > Snippit


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 package jbet;
32 import java.io.*;
33 import java.util.*;
34
35 /**
36  * This class encapsulates a list of instructions, including
37  * exception ranges. All branches are stored as pointers so
38  * non-length preserveing transformations can be made with ease.
39  *
40  * A lot of the functionality in this class is only meant to be called
41  * by MethodInfo, specificly, the functions involveing reading and
42  * writeing to a file. They really aren't usefull on their own.
43  *
44  * Things that specify ranges in the classfile are of the form [a, b)
45  * that is highly inconvienient because there is nothing for b to
46  * point to if it is off the end of the snippit; therefore Snippit
47  * stores ranges as [a, b] internaly and translates to the half-open
48  * form when reading and writing.
49  *
50  * all of the insert instructions destroy their arguements. This is
51  * because copying a snippit is a rather expensive operation.
52  *
53  *
54  * @author Larry D'Anna
55  * @version 0.1
56  * @since JDK 1.1.8 */

57
58 public class Snippit {
59
60     public static String JavaDoc JbetLogFacility = "snippit";
61
62     Instruction head, tail;
63     public Vector exVector; // ExceptionRec's
64
public Vector lvVector; // LocalVarRec's
65
public Vector lnVector; // LineNumberRec's
66

67
68     /* These fields are refreshed at reading and writing. Any
69        destructive operation on this snippit can destroy them */

70
71     int codelength;
72     Instruction [] pc2instr;
73     boolean stale;
74     boolean
75     emptyLocalTable = false,
76     emptyLineTable = false;
77
78
79     ExceptionRec findExceptionRec(Instruction instr, Type throwType) throws ClassFileException {
80     for (int i = 0; i < exVector.size(); i++) {
81         ExceptionRec ex = exAt(i);
82         Type catchType = new Type(ex.catchType, 0);
83         if (!throwType.isa(catchType)) continue;
84         for (Instruction j = ex.start.instr;; j = j.next) {
85         if (j == instr) return ex;
86         if (j == ex.end.instr) break;
87         }
88     }
89     return null;
90     }
91
92     /* get an Enumeration of Instructions. You should use this
93        instead of following the pointers manualy*/

94
95     public InstrEnum instrs() {
96     return new InstrEnum(head);
97     }
98
99     /* add a line number record for each instruction. usefull for stack
100        traces */

101     
102     public void addLinesAsPCs(ConstantPool cp) {
103     resolveConstants(cp);
104     for (Instruction instr = head; instr != null; instr = instr.next) {
105         int pc = instr.pc();
106         lnVector.addElement( new LineNumRec(instr, pc) );
107     }
108     }
109
110     void relocate (Hashtable subs) {
111     for (Instruction instr = head; instr != null; instr = instr.next) {
112         if (instr.usesClass() || instr.usesMethod() || instr.usesField())
113         instr.setClassRef( Util.relocate(instr.classRef(), subs) );
114
115         if (instr.usesMethod())
116         instr.setDescriptor( instr.descriptor().relocate_new(subs) );
117
118         if (instr.usesField())
119         instr.setType( instr.type().relocate_new(subs) );
120     }
121     }
122
123     void setPcs() {
124     int i = 0;
125     for (Instruction instr = head; instr != null; instr = instr.next)
126         instr.setPc( i++ );
127     }
128
129     /* this copy constructor should be avoided if possible. It has to do a
130      * lot of work to duplicate the entire link structure of snippit */

131     public Snippit (Snippit s) {
132     head = tail = null;
133
134     Instruction [] pc2instrTemp = null;
135     if (s.pc2instr != null) {
136         codelength = s.codelength;
137         pc2instrTemp = new Instruction [ codelength ];
138     }
139     else
140         pc2instrTemp = new Instruction [ s.maxcodesize() ];
141
142     Vector ceVector = new Vector();
143     int index = 0;
144     Instruction next;
145     for (Instruction instr = s.head; instr != null; instr = next) {
146         next = instr.next;
147         instr.setIndex(index++);
148         instr = instr.dup();
149         pc2instrTemp[ instr.pc() ] = instr;
150         ceVector.addElement(instr);
151         push(instr);
152     }
153     pc2instr = pc2instrTemp;
154
155     exVector = new Vector( s.exVector.size() );
156     lvVector = new Vector( s.lvVector.size() );
157     lnVector = new Vector( s.lnVector.size() );
158
159     for (int i = 0; i < ceVector.size(); i++) {
160         Instruction instr = (Instruction) ceVector.elementAt(i);
161         if (instr.usesBranch())
162         instr.branchTarget().instr = (Instruction) ceVector.elementAt
163             (instr.branchTarget().instr.index());
164         if (instr.isSwitch()) {
165         BranchTarget [] sa = instr.switchArray();
166         for (int j = 0 ; j < sa.length; j++)
167             sa[j].instr = (Instruction) ceVector.elementAt( sa[j].instr.index());
168         }
169     }
170
171     for (int i = 0; i < s.exVector.size(); i++) {
172         ExceptionRec ex = s.exAt(i);
173         exVector.addElement( new ExceptionRec
174         ( (Instruction) ceVector.elementAt (ex.start.instr.index()),
175           (Instruction) ceVector.elementAt (ex.end.instr.index()),
176           (Instruction) ceVector.elementAt (ex.handler.instr.index()),
177           ex.catchType) );;
178     }
179
180     for (int i = 0; i < s.lnVector.size(); i++) {
181         LineNumRec ln = s.lnAt(i);
182         lnVector.addElement( new LineNumRec( (Instruction) ceVector.elementAt
183                          (ln.start.instr.index()), ln.lineNumber ));
184     }
185
186     
187     for (int i = 0; i < s.lvVector.size(); i++) {
188         LocalVarRec lv = s.lvAt(i);
189         lvVector.addElement( new LocalVarRec
190         ( (Instruction) ceVector.elementAt (lv.start.instr.index()),
191           (Instruction) ceVector.elementAt (lv.end.instr.index()),
192           lv.name, lv.descriptor, lv.index ) );
193     }
194     }
195
196
197     /* create an empty snippit */
198
199     public Snippit () {
200     head = tail = null;
201     exVector = new Vector();
202     lvVector = new Vector();
203     lnVector = new Vector();
204     }
205
206     void resolveConstants (ConstantPool constantPool) {
207     for (Instruction instr = head; instr != null; instr = instr.next)
208         instr.resolveConstants(constantPool);
209     for (int i = 0; i < lvVector.size(); i++)
210         ((LocalVarRec)lvVector.elementAt(i)).resolveConstants(constantPool);
211     for (int i = 0; i < exVector.size(); i++)
212         ((ExceptionRec)exVector.elementAt(i)).resolveConstants(constantPool);
213     resolveBranches();
214     }
215
216     /* called by MethodInfo to assimilate the line recs */
217
218     void addLines (LineNumRec [] lines)
219     throws ClassFileException {
220
221     if (lines != null) {
222         if (lines.length == 0)
223         emptyLineTable = true;
224         lnVector.ensureCapacity(lines.length);
225         for (int i = 0; i < lines.length; i++) {
226         lines[i].start.instr = pc2instr[ lines[i].start.offset ];
227         lnVector.addElement (lines[i]);
228         }
229     }
230     }
231
232     /* called by MethodInfo to assimilate the local var recs */
233
234     void addLocals(LocalVarRec [] locals, ConstantPool constantPool)
235     throws ClassFileException {
236     
237     if (locals != null) {
238         if (locals.length == 0)
239         emptyLocalTable = true;
240         lvVector.ensureCapacity(locals.length);
241         for (int i = 0; i < locals.length; i++) {
242         LocalVarRec rec = locals[i];
243         rec.start.instr = pc2instr[ rec.start.offset ];
244         if (rec.start.offset + rec.length == codelength)
245             rec.end.instr = tail;
246         else {
247             rec.end.instr = pc2instr[ rec.start.offset + rec.length ].prev;
248             if (rec.end.instr == null) throw new ClassFileException
249             ("end marker points to first instruction");
250         }
251         lvVector.addElement (rec);
252         }
253     }
254     }
255     
256
257     /* called by MethodInfo to create a Snippit from the bytecode array. */
258
259     Snippit (byte [] code, ExceptionRec [] exceptions, ConstantPool constantPool)
260     throws ClassFileException, RuntimeException JavaDoc {
261     codelength = code.length;
262
263     head = tail = null;
264     exVector = new Vector ();
265     lvVector = new Vector ();
266     lnVector = new Vector ();
267
268     Instruction [] pc2instrTemp = new Instruction [ code.length ];
269
270     DataInputStream dataIn = new DataInputStream ( new ByteArrayInputStream(code) );
271
272     try {
273         for (int i = 0; i < code.length;) {
274         Instruction instr = new Instruction();
275         int size = instr.readFile (dataIn, i, constantPool);
276         instr.setPc(i);
277         push(instr);
278         pc2instrTemp[i] = instr;
279         i += size;
280         
281         }
282     } catch (IOException e) {
283         e.printStackTrace(Jbet.debug);
284         throw new RuntimeException JavaDoc ("caught an odd IOException: " + e.getMessage());
285     }
286     pc2instr = pc2instrTemp;
287
288     for (int i = 0; i < exceptions.length; i++) {
289         ExceptionRec rec = exceptions[i];
290         rec.start.instr = pc2instr[rec.start.offset];
291         if (rec.end.offset == codelength)
292         rec.end.instr = tail;
293         else {
294         rec.end.instr = pc2instr[rec.end.offset].prev;
295         if (rec.end.instr == null) throw new ClassFileException
296             ("end marker points to first instruction");
297         }
298         rec.handler.instr = pc2instr[rec.handler.offset];
299         exVector.addElement(rec);
300     }
301     for (Instruction instr = head; instr != null; instr = instr.next) {
302         
303         if (instr.usesBranch() ) {
304         /*
305          * Handles most branching instructions, which branch to
306          * a single location.
307          */

308         int offset = instr.branchTarget().offset;
309         int tIndex = instr.pc() + offset;
310         Instruction target = pc2instr[tIndex];
311         instr.branchTarget().instr = target;
312         }
313
314         if (instr.isSwitch() ) {
315         for (int i = 0; i < instr.switchArray().length; i++) {
316             int offset = instr.switchArray()[i].offset;
317             int tIndex = instr.pc() + offset;
318             Instruction target = pc2instr[tIndex];
319             instr.switchArray()[i].instr = target;
320         }
321         }
322     }
323     }
324
325     /* this will set the branch targets of all the instructions. It
326        uses a rather bruteish algorithm to deal with long jumps. If
327        it notices that one is required it will upgrade that
328        instruction, fix pc() for all subsequent instructions, and
329        start all over again. It does not downgrade any existing long
330        jumps if it is possible, because who knows if some dumb javac
331        might decide to use them when it doesn't have to, and then our
332        tests would fail */

333
334     void resolveBranches() {
335     if (unresolved.size() != 0) throw new IllegalStateException JavaDoc
336         ("this snippit contains unresolved branch targets: " +
337          ((BranchTarget)unresolved.elementAt(0)).label); /**/
338
339
340     DataOutputStream devNull = new DataOutputStream( new DevNullStream() );
341     codelength = 0;
342     for (Instruction instr = head; instr != null; instr = instr.next) {
343         instr.setPc( codelength );
344         try {
345         codelength += instr.writeFile(devNull, codelength);
346         } catch (IOException e) {
347         throw new RuntimeException JavaDoc("IOException caught from a DevNullStream!");
348         }
349     }
350     
351     while_loop:
352     while (true) {
353         for (Instruction instr = head; instr != null; instr = instr.next) {
354         if (instr.usesBranch()) {
355             int offset = instr.branchTarget().instr.pc() - instr.pc();
356             instr.branchTarget().offset = offset;
357             if ((offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)
358             && !instr.isLongjump()) {
359             instr.setLongjump(true);
360             for (Instruction i = instr.next; i != null; i = i.next)
361                 i.setPc( i.pc() + 2 );
362             codelength += 2;
363             continue while_loop;
364             }
365         }
366         if (instr.isSwitch())
367             for (int j = 0; j < instr.switchArray().length; j++) {
368             instr.switchArray()[j].offset =
369                 instr.switchArray()[j].instr.pc() - instr.pc();
370             }
371         }
372         break while_loop;
373     }
374
375     for (int i = 0; i < exVector.size(); i++) {
376         ExceptionRec rec = (ExceptionRec) exVector.elementAt (i);
377         rec.start.offset = rec.start.instr.pc();
378         if (rec.end.instr == tail)
379         rec.end.offset = codelength;
380         else
381         rec.end.offset = rec.end.instr.next.pc();
382         rec.handler.offset = rec.handler.instr.pc();
383     }
384
385     for (int i = 0; i < lnVector.size(); i++) {
386         LineNumRec rec = (LineNumRec) lnVector.elementAt(i);
387         rec.start.offset = rec.start.instr.pc();
388     }
389
390     for (int i = 0; i < lvVector.size(); i++) {
391         LocalVarRec rec = (LocalVarRec) lvVector.elementAt(i);
392         rec.start.offset = rec.start.instr.pc();
393         if (rec.end.instr == tail)
394         rec.length = codelength - rec.start.offset;
395         else
396         rec.length = rec.end.instr.next.pc() - rec.start.offset;
397     }
398     
399     pc2instr = new Instruction [ codelength ];
400     for (Instruction instr = head; instr != null; instr = instr.next)
401         pc2instr[ instr.pc() ] = instr;
402     }
403
404
405     /* called by MethodInfo */
406
407     void writeCodeAndExceptions(DataOutputStream dataOut) throws IOException {
408     
409     if (codelength==0)
410         throw new IOException("attempt to write empty Snippit");
411
412     dataOut.writeInt (codelength);
413     int index = 0;
414     for (Instruction instr = head; instr != null; instr = instr.next)
415         index += instr.writeFile( dataOut, index );
416
417     dataOut.writeShort ( exVector.size() );
418     for (int i=0; i < exVector.size(); i++)
419         ((ExceptionRec)exVector.elementAt(i)).writeFile( dataOut );
420     }
421
422
423     boolean hasLocals() {
424     return lvVector.size() != 0 || emptyLocalTable;
425     }
426     
427
428     boolean hasLineNums() {
429     return lnVector.size() != 0 || emptyLineTable;
430     }
431
432     /* called by MethodInfo */
433
434     void writeLineNums (DataOutputStream dataOut) throws IOException {
435     dataOut.writeShort ( lnVector.size() );
436     for (int i = 0; i < lnVector.size(); i++)
437         ((LineNumRec)lnVector.elementAt(i)).writeFile (dataOut);
438     }
439
440     /* called by MethodInfo */
441
442     GenericAttribute genLineNumAttr(ConstantPool constantPool) {
443     if (lnVector.size() == 0 && !emptyLineTable)
444         return null;
445     GenericAttribute attr = new GenericAttribute ("LineNumberTable",
446                               constantPool);
447     attr.writer = lineNumWriter();
448     return attr;
449     }
450
451     /* called by MethodInfo */
452
453     AttributeWriter lineNumWriter() {
454     final int lnsize = lnVector.size();
455     return new AttributeWriter() {
456         public void write (DataOutputStream dataOut)
457             throws IOException, RuntimeException JavaDoc {
458             dataOut.writeShort (lnsize);
459             for (int i = 0; i < lnsize; i++)
460             ((LineNumRec)lnVector.elementAt(i)).writeFile(dataOut);
461         }
462         public int size() {
463             return 2 + lnsize*4;
464         }
465         };
466     }
467         
468     /* called by MethodInfo */
469     int lineNumSize() {
470     return lnVector.size() * 4;
471     }
472
473     /* called by MethodInfo */
474     int localsSize() {
475     return lvVector.size() * 10;
476     }
477
478     /* called by MethodInfo */
479     int codeSize() {
480     return 4 + codelength;
481     }
482
483     /* called by MethodInfo */
484     int exceptionsSize() {
485     return 2 + 8*exVector.size();
486     }
487
488     Instruction lookupPc(int pc) {
489     if (pc2instr == null)
490         throw new RuntimeException JavaDoc("lookupPc called when pc2instr==null");
491     else
492         return pc2instr[pc];
493     }
494
495     /* called by MethodInfo */
496     void writeLocals(DataOutputStream dataOut) throws IOException {
497     dataOut.writeShort ( lvVector.size() );
498     for (int i = 0; i < lvVector.size(); i++)
499         ((LocalVarRec)lvVector.elementAt(i)).writeFile (dataOut);
500     }
501
502     /* called by MethodInfo */
503     GenericAttribute genLocalsAttr(ConstantPool constantPool) {
504     if (lvVector.size() == 0 && !emptyLocalTable)
505         return null;
506     GenericAttribute attr = new GenericAttribute ("LocalVariableTable",
507                               constantPool);
508     attr.writer = localsWriter();
509     
510     return attr;
511     }
512
513     /* called by MethodInfo */
514     AttributeWriter localsWriter() {
515     final int lvsize = lvVector.size();
516     return new AttributeWriter() {
517         public void write (DataOutputStream dataOut)
518             throws IOException, RuntimeException JavaDoc {
519             dataOut.writeShort (lvsize);
520             for (int i = 0; i < lvsize; i++)
521             ((LocalVarRec)lvVector.elementAt(i)).writeFile(dataOut);
522         }
523         public int size() {
524             return 2 + lvsize*10;
525         }
526         };
527     }
528
529
530     /* convience functions to access the vectors */
531
532     public ExceptionRec exAt (int i) {
533     return (ExceptionRec) exVector.elementAt(i);
534     }
535
536     public int numEx() { return exVector.size(); }
537
538     public LineNumRec lnAt (int i) {
539     return (LineNumRec) lnVector.elementAt(i);
540     }
541
542     public LocalVarRec lvAt (int i) {
543     return (LocalVarRec) lvVector.elementAt(i);
544     }
545
546     public Instruction first() { return head; };
547     public Instruction last() { return tail; };
548      
549     void insertBefore(Instruction instr, Instruction newinst) {
550     pc2instr = null;
551     if (instr == head)
552         unshift(newinst);
553     else {
554         newinst.prev = instr.prev;
555         newinst.next = instr;
556         newinst.prev.next = newinst;
557         newinst.next.prev = newinst;
558     }
559     }
560
561     public boolean empty() { return head==null; }
562
563     /*
564      * This willl insert snippit at the exact same point that
565      * instr is. This means that things pointing to instr
566      * will now point to snippit.first()
567      */

568     public void insertAt(Instruction instr, Snippit snippit) {
569     pc2instr = null;
570     if (snippit.empty())
571         return;
572     snippit.push( instr.dup() );
573     instr.copy( snippit.shift_norec() );
574     insertAfter(instr, snippit);
575     }
576     
577     /* same as above, except we remove instr. usefull for emulating
578        instructions */

579     public void insertOver(Instruction instr, Snippit snippit) {
580     pc2instr = null;
581     if (snippit.empty())
582         remove(instr);
583     instr.copy( snippit.shift_norec() );
584     insertAfter(instr, snippit);
585     }
586     
587     public void insertAfter(Instruction instr, Instruction newinst) {
588     pc2instr = null;
589     if (instr == tail)
590         push(newinst);
591     else {
592         newinst.prev = instr;
593         newinst.next = instr.next;
594         newinst.prev.next = newinst;
595         newinst.next.prev = newinst;
596     }
597     }
598
599
600     /* grap snippits recs and puth them in our vectors */
601     public void grabRecs(Snippit snippit) {
602     exVector.ensureCapacity ( exVector.size() + snippit.exVector.size() );
603     lvVector.ensureCapacity ( lvVector.size() + snippit.lvVector.size() );
604     lnVector.ensureCapacity ( lnVector.size() + snippit.lnVector.size() );
605     for (int i = 0; i < snippit.exVector.size(); i++)
606         exVector.addElement( snippit.exVector.elementAt(i) );
607     for (int i = 0; i < snippit.lvVector.size(); i++)
608         lvVector.addElement( snippit.lvVector.elementAt(i) );
609     for (int i = 0; i < snippit.lnVector.size(); i++)
610         lnVector.addElement( snippit.lnVector.elementAt(i) );
611     }
612
613     public void insertAfter(Instruction instr, Snippit snippit) {
614     pc2instr = null;
615     grabRecs(snippit);
616     Instruction next;
617     for (Instruction p = snippit.tail; p != null; p = next) {
618         next = p.prev;
619         insertAfter(instr, p);
620     }
621     }
622
623     public void insertBefore(Instruction instr, Snippit snippit) {
624     pc2instr = null;
625     grabRecs(snippit);
626     Instruction next;
627     for (Instruction p = snippit.head; p != null; p = next) {
628         next = p.next;
629         insertBefore(instr, p);
630     }
631     }
632
633     void redirect(Instruction from, Instruction to, BranchTarget bt) {
634     if (bt.instr == from)
635         bt.instr = to;
636     }
637
638     /* change all pointers to "from" into pointers to "to". I'm not
639        actualy useing this now. It was part of my diabolical schemes
640        to deal with the half open ranges, before i just decided to
641        make them closed */

642
643     public void redirect(Instruction from, Instruction to) {
644     for(Instruction p = head; p != null; p = p.next) {
645         if (p.usesBranch())
646         redirect(from, to, p.branchTarget());
647         if (p.isSwitch())
648         for (int j = 0; j < p.switchArray().length; j++)
649             redirect(from, to, p.switchArray()[j]);
650     }
651     for (int i = 0; i < exVector.size(); i++) {
652         redirect(from, to, exAt(i).start);
653         redirect(from, to, exAt(i).end);
654         redirect(from, to, exAt(i).handler);
655     }
656     for (int i = 0; i < lvVector.size(); i++) {
657         redirect(from, to, lvAt(i).start);
658         redirect(from, to, lvAt(i).end);
659     }
660     for (int i = 0; i < lnVector.size(); i++)
661         redirect(from, to, lnAt(i).start);
662     }
663
664     
665     /* append snippit to the end of this */
666
667     public void append (Snippit snippit) {
668     if (tail == null) {
669         grabRecs(snippit);
670         head = snippit.head;
671         tail = snippit.tail;
672     } else
673         insertAfter(tail, snippit);
674     }
675
676     /* prepned snippit to this */
677     public void prepend (Snippit snippit) {
678     if (head == null) {
679         grabRecs(snippit);
680         head = snippit.head;
681         tail = snippit.tail;
682     } else
683         insertBefore(head, snippit);
684     }
685     
686     /* append isntr */
687     public void push(Instruction instr) {
688     pc2instr = null;
689     if (tail == null) {
690         head = tail = instr;
691         instr.next = instr.prev = null;
692     } else {
693         instr.next = null;
694         instr.prev = tail;
695         tail.next = instr;
696         tail = instr;
697     }
698     }
699     
700     /* prepend instr */
701     public void unshift(Instruction instr) {
702     pc2instr = null;
703     if (head == null) {
704         head = tail = instr;
705         instr.next = instr.prev = null;
706     } else {
707         instr.prev = null;
708         instr.next = head;
709         head.prev = instr;
710         head = instr;
711     }
712     }
713
714     /* remove instr */
715     public void remove(Instruction instr) {
716     pc2instr = null;
717     removeFromRecs(instr);
718     if (instr==head)
719         shift();
720     else if (instr==tail)
721         pop();
722     else {
723         instr.prev.next = instr.next;
724         instr.next.prev = instr.prev;
725     }
726     }
727
728     public Snippit splitAt (Instruction last) {
729     Snippit next = new Snippit();
730     next.head = last.next;
731     next.tail = tail;
732
733     next.head.prev = null;
734     last.next = null; // ???
735

736     tail = last;
737     tail.next = null;
738
739     return next;
740     }
741
742     void removeFromRecs (Instruction instr) {
743     for (int i = 0; i < lnVector.size(); i++) {
744         LineNumRec rec = lnAt(i);
745         if (rec.start.instr == instr) {
746         if (instr.next == null)
747             lnVector.removeElementAt(i);
748         else {
749             boolean keep = true;
750             for (int j = 0; j < lnVector.size() && keep; j++)
751             if (lnAt(j).start.instr == instr.next)
752                 keep = false;
753             if (keep)
754             rec.start.instr = instr.next;
755             else
756             lnVector.removeElementAt(i);
757         }
758         }
759     }
760
761     }
762
763     public Instruction pop() throws ArrayIndexOutOfBoundsException JavaDoc {
764     if (tail == null) throw new ArrayIndexOutOfBoundsException JavaDoc
765         ("tried to pop an empty Snippit");
766     removeFromRecs(tail);
767     return pop_norec();
768     }
769
770     /* remove the last instr and return it */
771     public Instruction pop_norec() throws ArrayIndexOutOfBoundsException JavaDoc {
772     pc2instr = null;
773     if (head == tail)
774         head = null;
775     Instruction ret = tail;
776     tail = ret.prev;
777     tail.next = null;
778     return ret;
779     }
780
781     public Instruction shift() throws ArrayIndexOutOfBoundsException JavaDoc {
782     if (head == null)
783         throw new ArrayIndexOutOfBoundsException JavaDoc
784         ("tried to shift an empty Snippit");
785     removeFromRecs(head);
786     return shift_norec();
787     }
788
789     /* remove the first instruction and return it */
790     public Instruction shift_norec() throws ArrayIndexOutOfBoundsException JavaDoc {
791     pc2instr = null;
792     if (tail == head)
793         tail = null;
794     Instruction ret = head;
795     head = ret.next;
796     if (head != null)
797         head.prev = null;
798     return ret;
799     }
800
801     public void comment (String JavaDoc s) {
802         if (!Jbet.compact) {
803             push ( new Instruction().setSpush(s));
804             push ( new Instruction().setPop());
805         }
806     }
807
808     /** append useful instruction sequences
809      *
810      * @param t type of operands
811      * @param x number to dup or pop
812      * @return this
813      */

814
815     public Snippit setDupX (Type t, int x) {
816     if (t.category() == 0) throw new
817         IllegalStateException JavaDoc("dupX of category 0!");
818     if (t.category() == 1) {
819         if (x == -1) {
820         push (new Instruction().setPop());
821         }
822         else if (x > 2) {
823         push (new Instruction().setDup());
824         if ((x & 1) == 0) {
825             push (new Instruction().setDup());
826         }
827
828         for (int i = 0; i < ((x-1)>>1); i++) {
829             push (new Instruction().setDup2());
830         }
831         }
832         else {
833         for (int i = 0; i < x; i++)
834             push (new Instruction().setDup());
835         }
836     }
837     else {
838         if (x == -1) {
839         push (new Instruction().setPop2());
840         }
841         for (int i = 0; i < x; i++)
842         push (new Instruction().setDup2());
843     }
844
845     return this;
846     }
847
848     public Snippit setPopX (Type t, int x) {
849     int n = t.category() * x;
850
851     for (int i = 0; i < n >> 1; i++)
852         push (new Instruction().setPop2());
853
854     if (n > 0 && (n & 1) != 0) {
855         push (new Instruction().setPop());
856     }
857
858     return this;
859     }
860
861     /* System.out.println (s) */
862     public Snippit println (String JavaDoc s) {
863     push (new Instruction().setGetstatic ("java/lang/System", "out", Type.PRINTSTREAM));
864     push (new Instruction().setSpush (s));
865     push (new Instruction().setInvokeVirtual ("java/io/PrintStream", "println", new Descriptor (Type.STRING, Type.VOID)));
866     return this;
867     }
868
869     /* System.out.println (x); x on stack */
870     public Snippit println (Type t) {
871     t = t.compType();
872     if (t.category() == 1) {
873         push (new Instruction().setDup());
874         push (new Instruction().setGetstatic ("java/lang/System", "out", Type.PRINTSTREAM));
875         push (new Instruction().setSwap ());
876         push (new Instruction().setInvokeVirtual ("java/io/PrintStream", "println", new Descriptor (t, Type.VOID)));
877     }
878     else {
879         push (new Instruction().setDup2());
880         push (new Instruction().setGetstatic ("java/lang/System", "out", Type.PRINTSTREAM));
881         push (new Instruction().setDup_x2 ());
882         push (new Instruction().setPop());
883         push (new Instruction().setInvokeVirtual ("java/io/PrintStream", "println", new Descriptor (t, Type.VOID)));
884     }
885     return this;
886     }
887
888     public abstract static class Instructions
889     {
890     abstract void f (Snippit out);
891     Type type () { return Type.VOID; }
892     }
893
894     public static Instructions cString (final String JavaDoc s) {
895     return new Instructions() {
896         void f (Snippit out) {
897             out.push (new Instruction().setSpush (s));
898         }
899         Type type() { return Type.STRING; }
900         };
901     }
902
903     /* print the concatenation of all strings */
904     public Snippit println (Instructions[] strings) {
905
906     if (strings.length == 1) {
907         push (new Instruction().setGetstatic ("java/lang/System", "out", Type.PRINTSTREAM));
908         strings[0].f (this);
909         push (new Instruction().setInvokeVirtual ("java/io/PrintStream", "println",
910                               new Descriptor (strings[0].type(), Type.VOID)));
911     }
912     else {
913         push (new Instruction().setGetstatic ("java/lang/System", "out", Type.PRINTSTREAM));
914         push (new Instruction().setNew ("java/lang/StringBuffer"));
915         push (new Instruction().setDup ());
916         strings[0].f (this);
917         push (new Instruction().setInvokeSpecial ("java/lang/StringBuffer", "<init>",
918                               new Descriptor (strings[0].type().compType(), Type.VOID)));
919
920         for (int i = 1; i < strings.length; i++) {
921         strings[i].f (this);
922         push (new Instruction().setInvokeVirtual ("java/lang/StringBuffer", "append",
923                               new Descriptor (strings[i].type().compType(), Type.STRINGBUFFER)));
924         }
925
926         push (new Instruction().setInvokeVirtual ("java/lang/StringBuffer", "toString", new Descriptor (Type.STRING)));
927         push (new Instruction().setInvokeVirtual ("java/io/PrintStream", "println", new Descriptor (Type.STRING, Type.VOID)));
928     }
929     return this;
930     }
931
932     public Snippit println (Instructions a, Instructions b) {
933     Instructions[] A = new Instructions[2];
934     A[0] = a; A[1] = b;
935     return println (A);
936     }
937     
938     /* move the top of stack so that it is under the portion of the stack specified by ts
939        @param top Type of data on top of stack
940        @param ts Type of elements under top
941     */

942     public void moveDown (Type top, Type[] ts)
943     {
944     int topc = top.category();
945     int count = 0;
946     for (int i = 0; i < ts.length; i++)
947         count += ts[i].category();
948
949     switch (count) {
950     case 1:
951         if (topc == 1)
952         push (new Instruction().setSwap());
953         else {
954         push (new Instruction().setPop2());
955         }
956         break;
957
958     case 2:
959         if (topc == 1) {
960         push (new Instruction().setPop());
961         } else {
962         push (new Instruction().setPop2());
963         }
964         break;
965
966     default:
967         throw new IllegalStateException JavaDoc ("moveDown isn't finished");
968     }
969     }
970
971     /* functions to print out records */
972
973     void printExceptions (LineWriter out) {
974     int exsize = exVector.size();
975     for (int i = 0; i < exsize; i++)
976         ((ExceptionRec)exVector.elementAt(i)).print(out);
977     }
978
979     void printLines (LineWriter out) {
980     int lnsize = lnVector.size();
981
982     for (int i = 0; i < lnsize; i++)
983         out.println( "\t" + ((LineNumRec)lnVector.elementAt(i)).recString() );
984     }
985
986     void printLocals (LineWriter out) {
987     int lvsize;
988     out.print("");
989     lvsize = lvVector.size();
990
991     for (int i = 0; i < lvsize; i++)
992         out.println( "\t" + ((LocalVarRec)lvVector.elementAt(i)).recString() );
993     }
994
995
996
997     /* this is a convience fucnction to interpret the local variable
998      records for you. Just call it on each instruction as you loop
999      through the snippit and locals.get(new Integer(i)) will contain
1000     the local variable record for variable i at this point in the
1001     snippit */

1002    void advanceLocals(Instruction instr, Hashtable locals) {
1003    for (int j = 0; j < lvVector.size(); j++) {
1004        LocalVarRec rec = (LocalVarRec) lvVector.elementAt(j);
1005
1006        if (rec.start.instr == instr ||
1007        (instr.isStore() && instr.next == rec.start.instr))
1008        locals.put( rec.integer(), rec );
1009
1010        if (rec.end.instr.next == instr) {
1011        LocalVarRec curr = (LocalVarRec) locals.get(rec.integer());
1012        if (curr == rec)
1013            locals.remove(rec.integer());
1014        }
1015    }
1016    }
1017    
1018    public void printCode (LineWriter out, boolean lines) {
1019    printCode (out, lines, false);
1020    }
1021    
1022    public void printCode (LineWriter out, boolean lines, boolean counts) {
1023    int lvsize = lvVector.size();
1024    int lnsize = lnVector.size();
1025    
1026    Hashtable locals = new Hashtable();
1027    int line = -1;
1028    int n = 0;
1029    
1030    for (Instruction instr = head; instr != null; instr = instr.next, n++) {
1031        if (instr.opCode() == Instruction.AOP_SPUSH && // ldc-pop comments
1032
instr.next != null &&
1033        instr.next.opCode() == Instruction.OP_POP) {
1034        out.print ("\t" + instr.pc());
1035        if (lines) {
1036            out.print( "\t" );
1037            if (line != -1)
1038            out.print( line );
1039        }
1040        out.println("\t\t; " + instr.immediate_s());
1041        instr = instr.next;
1042        n++;
1043        continue;
1044        }
1045        
1046        advanceLocals(instr, locals);
1047
1048        if (lines) {
1049        for (int j = 0; j < lnsize; j++) {
1050            LineNumRec rec = (LineNumRec) lnVector.elementAt(j);
1051            if (rec.start.instr == instr)
1052            line = rec.lineNumber;
1053        }
1054        }
1055
1056        out.print( "\t" + instr.pc() );
1057        if (lines) {
1058        out.print( "\t" );
1059        if (line != -1)
1060            out.print( line );
1061        }
1062        if (counts) {
1063        out.print ("\t");
1064        out.print (n);
1065        }
1066        out.print( "\t" + instr.recString() );
1067        
1068        if (instr.usesLocals()) {
1069        int lvt = instr.lvtIndex();
1070        LocalVarRec rec = (LocalVarRec) locals.get (new Integer JavaDoc(lvt));
1071        if (rec != null)
1072            out.print (" " + rec.name + " " + rec.descriptor.toString() );
1073        }
1074
1075        out.println();
1076    }
1077    }
1078
1079    public int maxcodesize ()
1080    {
1081    int size = 0;
1082
1083    for (Instruction instr = head; instr != null; instr = instr.next)
1084        size += instr.maxsize();
1085
1086    return size;
1087    }
1088
1089    Hashtable labels = new Hashtable();
1090    Vector unresolved = new Vector();
1091
1092
1093    private String JavaDoc ins2lab(Hashtable tab, BranchTarget bt) {
1094    String JavaDoc ret = ins2lab(tab, bt.instr);
1095    return ret;
1096    }
1097
1098    /* utility function for disassemble. gets a label that points to
1099       instr, createing one if needed */

1100    private String JavaDoc ins2lab(Hashtable tab, Instruction instr) {
1101    String JavaDoc label = (String JavaDoc) tab.get(instr);
1102    if (label == null) {
1103        for (int i = 1;; i++) {
1104        label = ""+i;
1105        if (labels.get(label) == null) {
1106            labels.put(label, instr);
1107            break;
1108        }
1109        }
1110        tab.put(instr, label);
1111    }
1112    return label;
1113    }
1114
1115    /* disassemble this snippit. print prefix before each line */
1116    public void disassemble (LineWriter out, String JavaDoc prefix) {
1117    Hashtable tab = new Hashtable();
1118    for (Enumeration e = labels.keys(); e.hasMoreElements();) {
1119        String JavaDoc label = (String JavaDoc) e.nextElement();
1120        Instruction instr = (Instruction) labels.get(label);
1121        tab.put(instr, label);
1122    }
1123    for (int i = 0; i < exVector.size(); i++) {
1124        ExceptionRec rec = exAt(i);
1125        out.println(prefix + ".exception " + ins2lab(tab, rec.start) +
1126            " " + ins2lab(tab, rec.end) + " " + rec.catchType
1127            + " " + ins2lab(tab, rec.handler));
1128    }
1129    for (int i = 0; i < lvVector.size(); i++) {
1130        LocalVarRec rec = lvAt(i);
1131        out.println(prefix + ".local " + rec.index + " " + rec.name + " "
1132            + rec.descriptor + " " + ins2lab(tab, rec.start) +
1133            " " + ins2lab(tab, rec.end));
1134    }
1135    
1136    for (Instruction i = head; i != null; i = i.next) {
1137        if (i.usesBranch())
1138        ins2lab(tab, i.branchTarget());
1139        if (i.isSwitch())
1140        for (int j = 0; j < i.switchArray().length; j++)
1141            ins2lab(tab,i.switchArray()[j]);
1142    }
1143
1144    for (Instruction i = head; i != null; i = i.next) {
1145        String JavaDoc label = (String JavaDoc) tab.get(i);
1146        if (label != null)
1147        out.println(prefix + label + ":");
1148        for (int j = 0; j < lnVector.size(); j++)
1149        if (lnAt(j).start.instr == i)
1150            out.println(prefix + ".line " + lnAt(j).lineNumber);
1151        if (i.usesBranch())
1152        if (i.isSwitch()) {
1153            out.print(prefix + " " + i.recString(false) + " " +
1154                  ins2lab(tab, i.branchTarget()));
1155            BranchTarget[] swa = i.switchArray();
1156            if (i.opCode() == Instruction.OP_TABLESWITCH)
1157            for (int j = 0; j < swa.length; j++)
1158                out.print(" " + (i.immediate()+j) + ":" + ins2lab(tab,swa[j]));
1159            else
1160            for (int j = 0; j < swa.length; j++)
1161                out.print(" " + swa[j].key + ":" + ins2lab(tab,swa[j]));
1162            out.println(prefix);
1163            
1164        } else
1165            out.println(prefix + " " + i.recString(false) + " " +
1166                ins2lab(tab, i.branchTarget()));
1167        else
1168        out.println(prefix + " " + i.recString());
1169    }
1170    }
1171    
1172
1173
1174    /* get the instruction pointed to by label */
1175    Instruction getLabel(String JavaDoc label) {
1176    return (Instruction) labels.get(label);
1177    }
1178
1179    /* set a label and resolve all unresolved references to it */
1180    void defineLabel(String JavaDoc label, Instruction instr) {
1181    for (int i = 0; i < unresolved.size();) {
1182        BranchTarget bt = (BranchTarget) unresolved.elementAt(i);
1183        if (bt.label.equals(label)) {
1184        bt.label = null;
1185        bt.instr = instr;
1186        unresolved.removeElementAt(i);
1187        } else
1188        i++;
1189    }
1190    labels.put(label, instr);
1191    }
1192
1193
1194    /* assemble the instructions in str and append them to the end */
1195    public void assemble (String JavaDoc str) throws ClassFileException {
1196    assemble(new Lexer(new StringReader(str), "string"), null, 0, null);
1197    }
1198
1199    static final int INS_AT = 1;
1200    static final int INS_AFTER = 2;
1201    static final int INS_BEFORE = 3;
1202    static final int INS_OVER = 4;
1203
1204    /* util function for assemble */
1205    private void setupBranchTarget(BranchTarget bt, String JavaDoc label) {
1206    Instruction instr = getLabel(label);
1207    if (instr == null) {
1208        bt.label = label;
1209        unresolved.addElement(bt);
1210    } else
1211        bt.instr = instr;
1212    }
1213
1214
1215    static String JavaDoc parse_label(Lexer lexer) {
1216    lexer.push(Lexer.ST_ASM);
1217    String JavaDoc s = lexer.match(Token.TAG).text;
1218    lexer.pop();
1219    return s;
1220    }
1221
1222    /**
1223     * This assembles a snippit, and possibly some options for a methodinfo
1224     * Lexer is the input stream, place is where to put the assembled
1225     * instructions and state is INS_AT, INS_OVER, INS_AFTER, or INS_BEFORE.
1226     * if place is null it will just append them, and if mi is null then
1227     * it will not accept any MethodInfo options
1228     *
1229     * I know it's kind of wrong to have this thing take a methodinfo and
1230     * modify it, but hey, it's easy that way.
1231     */

1232
1233    public void assemble (Lexer lexer, Instruction place, int state, MethodInfo mi) throws ClassFileException {
1234    Token tok;
1235    Vector curr = new Vector();
1236    lexer.push(Lexer.ST_ASM);
1237
1238    while (true) {
1239        lexer.state = Lexer.ST_ASM;
1240        while ( lexer.peek().type == ';' ) lexer.read();
1241        tok = lexer.peek();
1242        lexer.state = Lexer.ST_ASM_ARG;
1243        if (tok.type == Token.LABEL) {
1244        lexer.read();
1245        String JavaDoc label = tok.text;
1246        if ( labels.get(label) != null )
1247            lexer.die("label allready defined: "+label);
1248        curr.addElement(label);
1249        continue;
1250        }
1251        if (tok.type == Token.TAG) {
1252        if (mi != null) {
1253            if (tok.text.equals(".maxstack")) {
1254            lexer.read();
1255            int i = lexer.parse_int();
1256            lexer.term();
1257            mi.maxStack = i;
1258            continue;
1259            }
1260            if (tok.text.equals(".maxlocals")) {
1261            lexer.read();
1262            int i = lexer.parse_int();
1263            lexer.term();
1264            mi.maxLocals = i;
1265            continue;
1266            }
1267            if (tok.text.equals(".throws")) {
1268            lexer.read();
1269            String JavaDoc s = lexer.parse_name();
1270            lexer.term();
1271            mi.exceptions.addElement(s);
1272            continue;
1273            }
1274            if (tok.text.equals(".synthetic")) {
1275            lexer.read();
1276            lexer.term();
1277            mi.synthetic = true;
1278            continue;
1279            }
1280            if (tok.text.equals(".deprecated")) {
1281            lexer.read();
1282            lexer.term();
1283            mi.deprecated = true;
1284            continue;
1285            }
1286            if (tok.text.equals(".flags")) {
1287            lexer.read();
1288            int flags = lexer.parse_flags(MethodInfo.ACC_ALL_MFLAGS);
1289            lexer.term();
1290            mi.accessFlags = flags;
1291            continue;
1292            }
1293        }
1294        if (tok.text.equals(".exception")) {
1295            lexer.read();
1296            String JavaDoc startlab = parse_label(lexer);
1297            String JavaDoc endlab = parse_label(lexer);
1298            String JavaDoc type = lexer.parse_name();
1299            if (type.equals("null")) type = null;
1300            String JavaDoc handlerlab = parse_label(lexer);
1301            lexer.term();
1302            ExceptionRec rec = new ExceptionRec();
1303            setupBranchTarget(rec.start, startlab);
1304            setupBranchTarget(rec.end, endlab);
1305            setupBranchTarget(rec.handler, handlerlab);
1306            rec.catchType = type;
1307            exVector.addElement(rec);
1308            continue;
1309        }
1310        if (tok.text.equals(".local")) {
1311            lexer.read();
1312            int index = lexer.parse_int();
1313            String JavaDoc name = lexer.parse_name();
1314            Type type = lexer.parse_type();
1315            String JavaDoc startlab = parse_label(lexer);
1316            String JavaDoc endlab = parse_label(lexer);
1317            lexer.term();
1318            LocalVarRec rec = new LocalVarRec();
1319            setupBranchTarget(rec.start, startlab);
1320            setupBranchTarget(rec.end, endlab);
1321            rec.index = index;
1322            rec.name = name;
1323            rec.descriptor = type;
1324            lvVector.addElement(rec);
1325            continue;
1326        }
1327        if (tok.text.equals(".line")) {
1328            lexer.read();
1329            int num = lexer.parse_int();
1330            lexer.push(Lexer.ST_ASM);
1331            String JavaDoc lab = lexer.peek().type == ';' ?
1332            null : parse_label(lexer);
1333            lexer.pop();
1334            lexer.term();
1335            LineNumRec rec = new LineNumRec();
1336            rec.lineNumber = num;
1337            if (lab == null)
1338            curr.addElement(rec);
1339            else
1340            setupBranchTarget(rec.start, lab);
1341            lnVector.addElement(rec);
1342            continue;
1343        }
1344
1345
1346        Instruction instr = parseInstruction(lexer);
1347        for (int i = 0; i < curr.size(); i++) {
1348            Object JavaDoc o = curr.elementAt(i);
1349            if (o instanceof LineNumRec)
1350            ((LineNumRec) o).start.instr = instr;
1351            else
1352            defineLabel((String JavaDoc) o, instr);
1353        }
1354        curr.removeAllElements();
1355        if (place==null)
1356            push(instr);
1357        else
1358            switch(state) {
1359            case INS_AT:
1360            insertAfter(place, place.dup());
1361            case INS_OVER:
1362            place.copy( instr );
1363            state = INS_AFTER;
1364            break;
1365            case INS_AFTER:
1366            insertAfter(place, instr);
1367            place = instr;
1368            break;
1369            case INS_BEFORE:
1370            insertBefore(place, instr);
1371            place = instr;
1372            state = INS_AFTER;
1373            break;
1374            }
1375        continue;
1376        }
1377        if (tok.type == Token.EOF || tok.type == '}') {
1378        if (curr.size() != 0) lexer.die
1379                      ("label or .line without an instruction following");
1380        lexer.pop();
1381        return;
1382        }
1383        lexer.unexpected(tok);
1384    }
1385    }
1386
1387    /* parse a single instruction */
1388
1389    Instruction parseInstruction (Lexer lexer) throws ClassFileException {
1390    String JavaDoc cname = null, name = null;
1391    Type type = null;
1392    Descriptor descriptor = null;
1393    Instruction ret= new Instruction();
1394    ret.initialize();
1395    int save, lvtIndex;
1396    
1397    String JavaDoc op = lexer.match(Token.TAG).text;
1398    int opc = Instruction.mnemonic2opcode(op);
1399    int switchVal = opc;
1400    
1401    while (true) switch (switchVal) {
1402    case Instruction.OP_IFEQ:
1403    case Instruction.OP_IFNE:
1404    case Instruction.OP_IFLT:
1405    case Instruction.OP_IFGE:
1406    case Instruction.OP_IFGT:
1407    case Instruction.OP_IFLE:
1408    case Instruction.OP_IF_ICMPEQ:
1409    case Instruction.OP_IF_ICMPNE:
1410    case Instruction.OP_IF_ICMPLT:
1411    case Instruction.OP_IF_ICMPGE:
1412    case Instruction.OP_IF_ICMPGT:
1413    case Instruction.OP_IF_ICMPLE:
1414    case Instruction.OP_IF_ACMPEQ:
1415    case Instruction.OP_IF_ACMPNE:
1416    case Instruction.OP_JSR:
1417    case Instruction.OP_IFNULL:
1418    case Instruction.OP_IFNONNULL:
1419    case Instruction.OP_GOTO: {
1420        String JavaDoc label = parse_label(lexer);
1421        lexer.term();
1422        ret.setOpCode( opc );
1423        ret.setBranchTarget( new BranchTarget() );
1424        setupBranchTarget(ret.branchTarget(), label);
1425        return ret;
1426    }
1427
1428    case Instruction.OP_LOOKUPSWITCH:
1429    case Instruction.OP_TABLESWITCH: {
1430        String JavaDoc default_lab = parse_label(lexer);
1431        Vector sv = new Vector();
1432        int base = 0;
1433        boolean first = true;
1434        for (int i = 0; lexer.peek().type != ';'; i++) {
1435        BranchTarget bt = new BranchTarget();
1436        bt.key = lexer.parse_int();
1437        if (opc == Instruction.OP_TABLESWITCH)
1438            if (first) {
1439            first = false;
1440            base = bt.key;
1441            } else if (bt.key != base + i) lexer.die
1442                               ("tableswitch with non-contiguous cases");
1443        lexer.match(':');
1444        String JavaDoc label = parse_label(lexer);
1445        setupBranchTarget(bt, label);
1446        sv.addElement(bt);
1447        }
1448        lexer.term();
1449        if (sv.size() == 0) lexer.die ("switch has no cases");
1450        BranchTarget [] sa = new BranchTarget [ sv.size() ];
1451        sv.copyInto(sa);
1452        
1453        ret.setOpCode(opc);
1454        ret.setBranchTarget( new BranchTarget() );
1455        setupBranchTarget( ret.branchTarget(), default_lab );
1456        if (opc == Instruction.OP_TABLESWITCH)
1457        ret.setImmediate(base);
1458        ret.setSwitchArray( sa );
1459        return ret;
1460    }
1461        
1462
1463    case Instruction.OP_NOP:
1464    case Instruction.OP_MONITORENTER:
1465    case Instruction.OP_MONITOREXIT:
1466    case Instruction.OP_IRETURN:
1467    case Instruction.OP_LRETURN:
1468    case Instruction.OP_FRETURN:
1469    case Instruction.OP_DRETURN:
1470    case Instruction.OP_ARETURN:
1471    case Instruction.OP_RETURN:
1472    case Instruction.OP_ATHROW:
1473    case Instruction.OP_ACONST_NULL:
1474    case Instruction.OP_POP:
1475    case Instruction.OP_POP2:
1476    case Instruction.OP_DUP:
1477    case Instruction.OP_DUP_X1:
1478    case Instruction.OP_DUP_X2:
1479    case Instruction.OP_DUP2:
1480    case Instruction.OP_DUP2_X1:
1481    case Instruction.OP_DUP2_X2:
1482    case Instruction.OP_SWAP:
1483    case Instruction.OP_IADD:
1484    case Instruction.OP_LADD:
1485    case Instruction.OP_FADD:
1486    case Instruction.OP_DADD:
1487    case Instruction.OP_ISUB:
1488    case Instruction.OP_LSUB:
1489    case Instruction.OP_FSUB:
1490    case Instruction.OP_DSUB:
1491    case Instruction.OP_IMUL:
1492    case Instruction.OP_LMUL:
1493    case Instruction.OP_FMUL:
1494    case Instruction.OP_DMUL:
1495    case Instruction.OP_IDIV:
1496    case Instruction.OP_LDIV:
1497    case Instruction.OP_FDIV:
1498    case Instruction.OP_DDIV:
1499    case Instruction.OP_IREM:
1500    case Instruction.OP_LREM:
1501    case Instruction.OP_FREM:
1502    case Instruction.OP_DREM:
1503    case Instruction.OP_INEG:
1504    case Instruction.OP_LNEG:
1505    case Instruction.OP_FNEG:
1506    case Instruction.OP_DNEG:
1507    case Instruction.OP_ISHL:
1508    case Instruction.OP_LSHL:
1509    case Instruction.OP_ISHR:
1510    case Instruction.OP_LSHR:
1511    case Instruction.OP_IUSHR:
1512    case Instruction.OP_LUSHR:
1513    case Instruction.OP_IAND:
1514    case Instruction.OP_LAND:
1515    case Instruction.OP_IOR:
1516    case Instruction.OP_LOR:
1517    case Instruction.OP_IXOR:
1518    case Instruction.OP_LXOR:
1519    case Instruction.OP_LCMP:
1520    case Instruction.OP_FCMPG:
1521    case Instruction.OP_FCMPL:
1522    case Instruction.OP_DCMPG:
1523    case Instruction.OP_DCMPL:
1524    case Instruction.OP_I2B:
1525    case Instruction.OP_I2C:
1526    case Instruction.OP_I2D:
1527    case Instruction.OP_L2I:
1528    case Instruction.OP_L2F:
1529    case Instruction.OP_L2D:
1530    case Instruction.OP_F2I:
1531    case Instruction.OP_F2L:
1532    case Instruction.OP_F2D:
1533    case Instruction.OP_D2I:
1534    case Instruction.OP_D2L:
1535    case Instruction.OP_D2F:
1536    case Instruction.OP_I2F:
1537    case Instruction.OP_I2L:
1538    case Instruction.OP_I2S:
1539    case Instruction.OP_IALOAD:
1540    case Instruction.OP_LALOAD:
1541    case Instruction.OP_FALOAD:
1542    case Instruction.OP_DALOAD:
1543    case Instruction.OP_AALOAD:
1544    case Instruction.OP_CALOAD:
1545    case Instruction.OP_SALOAD:
1546    case Instruction.OP_BALOAD:
1547    case Instruction.OP_IASTORE:
1548    case Instruction.OP_LASTORE:
1549    case Instruction.OP_FASTORE:
1550    case Instruction.OP_DASTORE:
1551    case Instruction.OP_AASTORE:
1552    case Instruction.OP_BASTORE:
1553    case Instruction.OP_CASTORE:
1554    case Instruction.OP_SASTORE:
1555    case Instruction.OP_ARRAYLENGTH:
1556        lexer.term();
1557        ret.setOpCode( opc );
1558        return ret;
1559
1560
1561
1562    case Instruction.OP_ILOAD:
1563    case Instruction.OP_FLOAD:
1564    case Instruction.OP_LLOAD:
1565    case Instruction.OP_DLOAD:
1566    case Instruction.OP_ALOAD:
1567    case Instruction.OP_ISTORE:
1568    case Instruction.OP_FSTORE:
1569    case Instruction.OP_LSTORE:
1570    case Instruction.OP_DSTORE:
1571    case Instruction.OP_ASTORE:
1572    case Instruction.OP_RET:
1573        lexer.push(Lexer.ST_ASM_ARG);
1574        lvtIndex = (int) lexer.match(Token.INT).l;
1575        lexer.pop();
1576        lexer.term();
1577        ret.setOpCode( opc );
1578        ret.setLvtIndex(lvtIndex);
1579        return ret;
1580
1581    case Instruction.OP_IINC:
1582        ret.setOpCode(opc);
1583        ret.setImmediate( lexer.parse_int() );
1584        ret.setLvtIndex( lexer.parse_int() );
1585        lexer.term();
1586        return ret;
1587
1588    case Instruction.OP_NEWARRAY:
1589        ret.setOpCode(opc);
1590        ret.setOpCode(opc);
1591        ret.setImmediate( lexer.parse_int() );
1592        lexer.term();
1593        return ret;
1594
1595    case Instruction.OP_ILOAD_0:
1596    case Instruction.OP_ILOAD_1:
1597    case Instruction.OP_ILOAD_2:
1598    case Instruction.OP_ILOAD_3:
1599    case Instruction.OP_FLOAD_0:
1600    case Instruction.OP_FLOAD_1:
1601    case Instruction.OP_FLOAD_2:
1602    case Instruction.OP_FLOAD_3:
1603    case Instruction.OP_LLOAD_0:
1604    case Instruction.OP_LLOAD_1:
1605    case Instruction.OP_LLOAD_2:
1606    case Instruction.OP_LLOAD_3:
1607    case Instruction.OP_DLOAD_0:
1608    case Instruction.OP_DLOAD_1:
1609    case Instruction.OP_DLOAD_2:
1610    case Instruction.OP_DLOAD_3:
1611    case Instruction.OP_ALOAD_0:
1612    case Instruction.OP_ALOAD_1:
1613    case Instruction.OP_ALOAD_2:
1614    case Instruction.OP_ALOAD_3:
1615    case Instruction.OP_ISTORE_0:
1616    case Instruction.OP_ISTORE_1:
1617    case Instruction.OP_ISTORE_2:
1618    case Instruction.OP_ISTORE_3:
1619    case Instruction.OP_FSTORE_0:
1620    case Instruction.OP_FSTORE_1:
1621    case Instruction.OP_FSTORE_2:
1622    case Instruction.OP_FSTORE_3:
1623    case Instruction.OP_LSTORE_0:
1624    case Instruction.OP_LSTORE_1:
1625    case Instruction.OP_LSTORE_2:
1626    case Instruction.OP_LSTORE_3:
1627    case Instruction.OP_DSTORE_0:
1628    case Instruction.OP_DSTORE_1:
1629    case Instruction.OP_DSTORE_2:
1630    case Instruction.OP_DSTORE_3:
1631    case Instruction.OP_ASTORE_0:
1632    case Instruction.OP_ASTORE_1:
1633    case Instruction.OP_ASTORE_2:
1634    case Instruction.OP_ASTORE_3:
1635        lexer.term();
1636        ret.setRealOpCode( opc );
1637        ret.setVarAccess(opc);
1638        return ret;
1639
1640
1641
1642    case Instruction.OP_DCONST_0:
1643        case Instruction.OP_DCONST_1:
1644        ret.setImmediate_f( (float) (opc - Instruction.OP_DCONST_0) );
1645        ret.setOpCode( Instruction.AOP_DPUSH );
1646        ret.setRealOpCode( opc );
1647        lexer.term();
1648        return ret;
1649
1650    case Instruction.OP_FCONST_0:
1651    case Instruction.OP_FCONST_1:
1652    case Instruction.OP_FCONST_2:
1653        ret.setImmediate_f( (float) (opc - Instruction.OP_FCONST_0) );
1654        ret.setOpCode( Instruction.AOP_FPUSH );
1655        ret.setRealOpCode( opc );
1656        lexer.term();
1657        return ret;
1658
1659    case Instruction.OP_LCONST_0:
1660    case Instruction.OP_LCONST_1:
1661        ret.setImmediate( opc - Instruction.OP_LCONST_0 );
1662        ret.setRealOpCode(opc);
1663        ret.setOpCode( Instruction.AOP_LPUSH );
1664        lexer.term();
1665        return ret;
1666
1667    case Instruction.OP_ICONST_M1:
1668    case Instruction.OP_ICONST_0:
1669    case Instruction.OP_ICONST_1:
1670    case Instruction.OP_ICONST_2:
1671    case Instruction.OP_ICONST_3:
1672    case Instruction.OP_ICONST_4:
1673    case Instruction.OP_ICONST_5:
1674        ret.setImmediate( opc - Instruction.OP_ICONST_0 );
1675        ret.setRealOpCode(opc);
1676        ret.setOpCode( Instruction.AOP_IPUSH );
1677        lexer.term();
1678        return ret;
1679
1680    case Instruction.OP_BIPUSH:
1681    case Instruction.OP_SIPUSH:
1682        ret.setRealOpCode(opc);
1683        ret.setOpCode(Instruction.AOP_IPUSH);
1684        ret.setImmediate( lexer.parse_int() );
1685        lexer.term();
1686        return ret;
1687        
1688
1689    case Instruction.OP_LDC2_W:
1690        ret.setRealOpCode(opc);
1691        if (lexer.peek().type == Token.FLOAT) {
1692        ret.setOpCode(Instruction.AOP_DPUSH);
1693        ret.setImmediate_f( lexer.parse_double() );
1694        } else if (lexer.peek().type == Token.INT) {
1695        ret.setOpCode(Instruction.AOP_LPUSH);
1696        ret.setImmediate_l( lexer.parse_long() );
1697        } else lexer.unexpected(lexer.read());
1698        lexer.term();
1699        return ret;
1700
1701    case Instruction.OP_LDC:
1702    case Instruction.OP_LDC_W:
1703        ret.setRealOpCode(opc);
1704        switch (lexer.peek().type) {
1705        case Token.STRING:
1706        ret.setOpCode(Instruction.AOP_SPUSH);
1707        ret.setImmediate_s(lexer.parse_string());
1708        break;
1709        case Token.FLOAT:
1710        ret.setOpCode(Instruction.AOP_FPUSH);
1711        ret.setImmediate_f( lexer.parse_double() );
1712        break;
1713        case Token.INT:
1714        ret.setOpCode(Instruction.AOP_IPUSH);
1715        ret.setImmediate_l( lexer.parse_long() );
1716        break;
1717        default:
1718        lexer.unexpected(lexer.read());
1719        }
1720        lexer.term();
1721        return ret;
1722
1723    case Instruction.AOP_IPUSH:
1724    case Instruction.AOP_LPUSH:
1725        ret.setImmediate_l( lexer.parse_long() );
1726        lexer.term();
1727        ret.setOpCode(opc);
1728        return ret;
1729
1730    case Instruction.OP_INVOKESPECIAL:
1731    case Instruction.OP_INVOKESTATIC:
1732    case Instruction.OP_INVOKEVIRTUAL:
1733    case Instruction.OP_INVOKEINTERFACE:
1734        lexer.push(Lexer.ST_ASM_ARG);
1735        cname = lexer.parse_name();
1736        lexer.match('.');
1737        name = lexer.parse_name();
1738        descriptor = lexer.parseOptDescriptor(cname, name);
1739        lexer.pop();
1740        lexer.term();
1741        ret.setOpCode(opc);
1742        ret.setClassRef(cname);
1743        ret.setElemName(name);
1744        ret.setDescriptor(descriptor);
1745        return ret;
1746
1747    case Instruction.OP_GETSTATIC:
1748    case Instruction.OP_PUTSTATIC:
1749    case Instruction.OP_GETFIELD:
1750    case Instruction.OP_PUTFIELD:
1751        lexer.push(Lexer.ST_ASM_ARG);
1752        cname = lexer.parse_name();
1753        lexer.match('.');
1754        name = lexer.parse_name();
1755        type = lexer.parseOptType(cname, name);
1756        lexer.pop();
1757        lexer.term();
1758        ret.setOpCode(opc);
1759        ret.setClassRef(cname);
1760        ret.setElemName(name);
1761        ret.setType(type);
1762        return ret;
1763
1764    case Instruction.OP_NEW:
1765    case Instruction.OP_ANEWARRAY:
1766    case Instruction.OP_CHECKCAST:
1767    case Instruction.OP_INSTANCEOF:
1768        cname = lexer.parse_name();
1769        lexer.term();
1770        ret.setOpCode(opc);
1771        ret.setClassRef(cname);
1772        return ret;
1773
1774    case Instruction.OP_MULTIANEWARRAY:
1775        ret.setClassRef( lexer.parse_name() );
1776        ret.setImmediate( lexer.parse_int() );
1777        lexer.term();
1778        ret.setOpCode(opc);
1779        return ret;
1780        
1781    default:
1782        lexer.die("bad opcode " + op);
1783    }
1784    }
1785}
1786
Popular Tags