KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > go > trove > classfile > InstructionList


1 /* ====================================================================
2  * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3  * ====================================================================
4  * The Tea Software License, Version 1.1
5  *
6  * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Walt Disney Internet Group (http://opensource.go.com/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact opensource@dig.com.
31  *
32  * 5. Products derived from this software may not be called "Tea",
33  * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34  * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35  * written permission of the Walt Disney Internet Group.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * For more information about Tea, please see http://opensource.go.com/.
51  */

52
53 package com.go.trove.classfile;
54
55 import java.util.*;
56 import java.io.*;
57
58 /******************************************************************************
59  * The InstructionList class is used by the CodeBuilder to perform lower-level
60  * bookkeeping operations and flow analysis.
61  *
62  * @author Brian S O'Neill
63  * @version
64  * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
65  * @see CodeBuilder
66  */

67 class InstructionList implements CodeBuffer {
68     private static final boolean DEBUG = false;
69
70     Instruction mFirst;
71     Instruction mLast;
72
73     boolean mResolved = false;
74
75     private List mExceptionHandlers = new ArrayList(4);
76     private List mLocalVariables = new ArrayList();
77
78     private int mMaxStack;
79     private int mMaxLocals;
80
81     private byte[] mByteCodes;
82     private int mBufferLength;
83
84     protected InstructionList() {
85         super();
86     }
87
88     /**
89      * Returns an immutable collection of all the instructions in this
90      * InstructionList.
91      */

92     public Collection getInstructions() {
93         return new AbstractCollection() {
94             public Iterator iterator() {
95                 return new Iterator() {
96                     private Instruction mNext = mFirst;
97
98                     public boolean hasNext() {
99                         return mNext != null;
100                     }
101
102                     public Object JavaDoc next() {
103                         if (mNext == null) {
104                             throw new NoSuchElementException();
105                         }
106
107                         Instruction current = mNext;
108                         mNext = mNext.mNext;
109                         return current;
110                     }
111
112                     public void remove() {
113                         throw new UnsupportedOperationException JavaDoc();
114                     }
115                 };
116             }
117
118             public int size() {
119                 int count = 0;
120                 for (Instruction i = mFirst; i != null; i = i.mNext) {
121                     count++;
122                 }
123                 return count;
124             }
125         };
126     }
127
128     public int getMaxStackDepth() {
129         resolve();
130         return mMaxStack;
131     }
132
133     public int getMaxLocals() {
134         resolve();
135         return mMaxLocals;
136     }
137
138     public byte[] getByteCodes() {
139         resolve();
140         return mByteCodes;
141     }
142
143     public ExceptionHandler[] getExceptionHandlers() {
144         resolve();
145
146         ExceptionHandler[] handlers =
147             new ExceptionHandler[mExceptionHandlers.size()];
148         return (ExceptionHandler[])mExceptionHandlers.toArray(handlers);
149     }
150
151     public void addExceptionHandler(ExceptionHandler handler) {
152         mExceptionHandlers.add(handler);
153     }
154
155     public LocalVariable createLocalVariable(String JavaDoc name,
156                                              TypeDescriptor type) {
157         LocalVariable var = new LocalVariableImpl(name, type, -1);
158         mLocalVariables.add(var);
159         return var;
160     }
161
162     public LocalVariable createLocalParameter(String JavaDoc name,
163                                               TypeDescriptor type,
164                                               int number) {
165         LocalVariableImpl var = new LocalVariableImpl(name, type, number);
166         mLocalVariables.add(var);
167         if (mFirst == null) {
168             // Make sure there is an initial instruction. Create a pseudo one.
169
LabelInstruction label = new LabelInstruction();
170             label.setLocation();
171             mFirst = label;
172         }
173         
174         // Parameters are initialized first, so ensure flow analysis starts
175
// at the beginning.
176
var.addStoreInstruction(mFirst);
177
178         return var;
179     }
180
181     private void resolve() {
182         if (mResolved) {
183             return;
184         }
185
186         if (!DEBUG) {
187             resolve0();
188         }
189         else {
190             try {
191                 resolve0();
192             }
193             finally {
194                 System.out.println("-- Instructions --");
195                 
196                 Iterator it = getInstructions().iterator();
197                 while (it.hasNext()) {
198                     System.out.println(it.next());
199                 }
200             }
201         }
202     }
203
204     private void resolve0() {
205         mMaxStack = 0;
206         mMaxLocals = 0;
207
208         Instruction instr;
209
210         // Sweep through the instructions, marking them as not being
211
// visted by flow analysis and set fake locations.
212
int instrCount = 0;
213         for (instr = mFirst; instr != null; instr = instr.mNext) {
214             instr.mStackDepth = -1;
215             instr.mLocation = instrCount++;
216         }
217
218         // Assign variable numbers using the simplest technique.
219

220         int size = mLocalVariables.size();
221         List activeLocationBits = new ArrayList(size);
222         for (int i=0; i<size; i++) {
223             LocalVariableImpl var = (LocalVariableImpl)mLocalVariables.get(i);
224             if (var.getNumber() < 0) {
225                 var.setNumber(mMaxLocals);
226             }
227             
228             int max = var.getNumber() + (var.isDoubleWord() ? 2 : 1);
229             if (max > mMaxLocals) {
230                 mMaxLocals = max;
231             }
232         }
233
234         /*
235         // Perform variable flow analysis for each local variable, in order to
236         // determine which register it should be assigned.
237
238         int size = mLocalVariables.size();
239         List activeLocationBits = new ArrayList(size);
240         for (int i=0; i<size; i++) {
241             LocalVariableImpl var = (LocalVariableImpl)mLocalVariables.get(i);
242             BitList activeLocations = new BitList(instrCount);
243             activeLocationBits.add(activeLocations);
244
245             // Start flow analysis at store variable instructions.
246             Iterator it = var.iterateStoreInstructions();
247             while (it.hasNext()) {
248                 Instruction enter = (Instruction)it.next();
249                 variableResolve(var, enter, activeLocations,
250                                 new BitList(instrCount), false);
251             }
252             
253             // Continue flow analysis into all exception handlers that wrap
254             // the active locations.
255             boolean passAgain;
256             do {
257                 passAgain = false;
258                 it = mExceptionHandlers.iterator();
259                 while (it.hasNext()) {
260                     ExceptionHandler handler = (ExceptionHandler)it.next();
261                     if (!isIntersecting(activeLocations, handler)) {
262                         continue;
263                     }
264                     Instruction enter =
265                         (Instruction)handler.getCatchLocation();
266                     passAgain =
267                         variableResolve(var, enter, activeLocations,
268                                         new BitList(instrCount), false);
269                     passAgain = false;
270                 }
271             } while (passAgain);
272
273             if (!var.isFixedNumber()) {
274                 var.setNumber(-1);
275
276                 // Assign variable number by checking first if it can be shared
277                 // with another variable of the same size.
278
279                 boolean[] conflicts = new boolean[mMaxLocals];
280
281                 for (int j=0; j<i; j++) {
282                     LocalVariable av = (LocalVariable)mLocalVariables.get(j);
283                     if (av.getNumber() < 0 ||
284                         av.isDoubleWord() != var.isDoubleWord()) {
285                         continue;
286                     }
287                     BitList alocs = (BitList)activeLocationBits.get(j);
288                     if (isIntersecting(alocs, activeLocations)) {
289                         conflicts[av.getNumber()] = true;
290                         if (av.getNumber() == var.getNumber()) {
291                             var.setNumber(-1);
292                         }
293                     }
294                     else if (conflicts[av.getNumber()]) {
295                         var.setNumber(-1);
296                     }
297                     else {
298                         var.setNumber(av.getNumber());
299                     }
300                 }
301                 
302                 if (var.getNumber() < 0) {
303                     var.setNumber(mMaxLocals);
304                 }
305             }
306
307             int max = var.getNumber() + (var.isDoubleWord() ? 2 : 1);
308             if (max > mMaxLocals) {
309                 mMaxLocals = max;
310             }
311
312             // TODO
313             //var.setLocations(activeLocations);
314         }
315
316         activeLocationBits = null;
317         */

318
319         // Perform stack flow analysis to determine the max stack size.
320

321         // Start the flow analysis at the first instruction.
322
Map subAdjustMap = new HashMap(11);
323         stackResolve(0, mFirst, subAdjustMap);
324
325         // Continue flow analysis into exception handler entry points.
326
Iterator it = mExceptionHandlers.iterator();
327         while (it.hasNext()) {
328             ExceptionHandler handler = (ExceptionHandler)it.next();
329             Instruction enter = (Instruction)handler.getCatchLocation();
330             stackResolve(1, enter, subAdjustMap);
331         }
332
333         // Okay, build up the byte code and set real instruction locations.
334
// Multiple passes may be required because instructions may adjust
335
// their size as locations are set. Changing size affects the
336
// locations of other instructions, so that is why additional passes
337
// are required.
338

339         boolean passAgain;
340         do {
341             passAgain = false;
342
343             mByteCodes = new byte[16];
344             mBufferLength = 0;
345
346             for (instr = mFirst; instr != null; instr = instr.mNext) {
347                 if (!instr.isResolved()) {
348                     passAgain = true;
349                 }
350
351                 if (instr instanceof Label) {
352                     if (instr.mLocation != mBufferLength) {
353                         if (instr.mLocation >= 0) {
354                             // If the location of this label is not where it
355
// should be, (most likely because an instruction
356
// needed to expand in size) then do another pass.
357
passAgain = true;
358                         }
359
360                         instr.mLocation = mBufferLength;
361                     }
362                 }
363                 else {
364                     instr.mLocation = mBufferLength;
365
366                     byte[] bytes = instr.getBytes();
367                     if (bytes != null) {
368                         if (passAgain) {
369                             // If there is going to be another pass, don't
370
// bother collecting bytes into the array. Just
371
// expand the the length variable.
372
mBufferLength += bytes.length;
373                         }
374                         else {
375                             addBytes(bytes);
376                         }
377                     }
378                 }
379             }
380         } while (passAgain); // do {} while ();
381

382         if (mBufferLength != mByteCodes.length) {
383             byte[] newBytes = new byte[mBufferLength];
384             System.arraycopy(mByteCodes, 0, newBytes, 0, mBufferLength);
385             mByteCodes = newBytes;
386         }
387
388         // Set resolved at end because during resolution, this field gets
389
// set false again while changes are being made to the list
390
// of instructions.
391
mResolved = true;
392     }
393
394     private void addBytes(byte[] code) {
395         growBuffer(code.length);
396         System.arraycopy(code, 0, mByteCodes, mBufferLength, code.length);
397         mBufferLength += code.length;
398     }
399
400     private void growBuffer(int amount) {
401         if ((mBufferLength + amount) > mByteCodes.length) {
402             int newCapacity = mByteCodes.length * 2;
403             if ((mBufferLength + amount) > newCapacity) {
404                 newCapacity = mBufferLength + amount;
405             }
406
407             byte[] newBuffer = new byte[newCapacity];
408             System.arraycopy(mByteCodes, 0, newBuffer, 0, mBufferLength);
409             mByteCodes = newBuffer;
410         }
411     }
412
413     /*
414     private boolean variableResolve(LocalVariableImpl var,
415                                     Instruction instr,
416                                     BitList activeLocations,
417                                     BitList possibleLocations,
418                                     boolean fork) {
419         while (instr != null) {
420             int instrLoc = instr.getLocation();
421
422             if (activeLocations.get(instrLoc)) {
423                 activeLocations.or(possibleLocations);
424                 if (possibleLocations.isAllClear()) {
425                     return false;
426                 }
427                 else {
428                     possibleLocations.clear();
429                     return true;
430                 }
431             }
432
433             if (possibleLocations.get(instrLoc)) {
434                 return false;
435             }
436
437             possibleLocations.set(instrLoc);
438
439             if (instr instanceof LocalOperandInstruction &&
440                 ((LocalOperandInstruction)instr).getLocalVariable() == var) {
441
442                 if (instr instanceof StoreLocalInstruction) {
443                     activeLocations.set(instrLoc);
444                     if (fork) {
445                         possibleLocations.clear(instrLoc);
446                     }
447                     else {
448                         possibleLocations.clear();
449                     }
450                 }
451                 else {
452                     activeLocations.or(possibleLocations);
453                     possibleLocations.clear();
454                 }
455             }
456
457             // Determine the next instruction to flow down to.
458             Instruction next = null;
459
460             if (instr.isFlowThrough()) {
461                 if ((next = instr.mNext) == null) {
462                     throw new RuntimeException
463                         ("Execution flows through end of method");
464                 }
465             }
466
467             Location[] targets = instr.getBranchTargets();
468             if (targets != null) {
469                 for (int i=0; i<targets.length; i++) {
470                     LabelInstruction targetInstr =
471                         (LabelInstruction)targets[i];
472
473                     if (i == 0 && next == null) {
474                         // Flow to the first target if instruction doesn't
475                         // flow to its next instruction.
476                         next = targetInstr;
477                         continue;
478                     }
479
480                     variableResolve
481                         (var, targetInstr, activeLocations,
482                          possibleLocations, true);
483                 }
484             }
485
486             instr = next;
487         }
488
489         return true;
490     }
491
492     private boolean isIntersecting(BitList a, BitList b) {
493         a = (BitList)a.clone();
494         a.and(b);
495         return !a.isAllClear();
496     }
497
498     private boolean isIntersecting(BitList bits, LocationRange range) {
499         // TODO: how efficient is this?
500         int start = range.getStartLocation().getLocation();
501         int end = range.getEndLocation().getLocation();
502
503         for (int i=start; i<end; i++) {
504             if (bits.get(i)) {
505                 return true;
506             }
507         }
508
509         return false;
510     }
511     */

512
513     private int stackResolve(int stackDepth,
514                              Instruction instr,
515                              Map subAdjustMap) {
516         while (instr != null) {
517             // Set the stack depth, marking this instruction as being visited.
518
// If already visited, break out of this flow.
519
if (instr.mStackDepth < 0) {
520                 instr.mStackDepth = stackDepth;
521             }
522             else {
523                 if (instr.mStackDepth != stackDepth) {
524                     throw new RuntimeException JavaDoc
525                         ("Stack depth different at previously visited " +
526                          "instruction: " + instr.mStackDepth +
527                          " != " + stackDepth);
528                 }
529
530                 break;
531             }
532
533             // Determine the next instruction to flow down to.
534
Instruction next = null;
535
536             if (instr.isFlowThrough()) {
537                 if ((next = instr.mNext) == null) {
538                     throw new RuntimeException JavaDoc
539                         ("Execution flows through end of method");
540                 }
541             }
542
543             stackDepth += instr.getStackAdjustment();
544             if (stackDepth > mMaxStack) {
545                 mMaxStack = stackDepth;
546             }
547             else if (stackDepth < 0) {
548                 throw new RuntimeException JavaDoc("Stack depth is negative: " +
549                                            stackDepth);
550             }
551
552             Location[] targets = instr.getBranchTargets();
553             if (targets != null) {
554                 for (int i=0; i<targets.length; i++) {
555                     LabelInstruction targetInstr =
556                         (LabelInstruction)targets[i];
557
558                     if (i == 0 && next == null) {
559                         // Flow to the first target if instruction doesn't
560
// flow to its next instruction.
561
next = targetInstr;
562                         continue;
563                     }
564
565                     if (!instr.isSubroutineCall()) {
566                         stackResolve
567                             (stackDepth, targetInstr, subAdjustMap);
568                     }
569                     else {
570                         Integer JavaDoc subAdjust =
571                             (Integer JavaDoc)subAdjustMap.get(targetInstr);
572                         
573                         if (subAdjust == null) {
574                             int newDepth =
575                                 stackResolve(stackDepth, targetInstr,
576                                              subAdjustMap);
577                             subAdjust = new Integer JavaDoc(newDepth - stackDepth);
578                             subAdjustMap.put(targetInstr, subAdjust);
579                         }
580                         
581                         stackDepth += subAdjust.intValue();
582                     }
583                 }
584             }
585
586             instr = next;
587         }
588
589         return stackDepth;
590     }
591
592     private class LocalVariableImpl implements LocalVariable {
593         private String JavaDoc mName;
594         private TypeDescriptor mType;
595         private boolean mIsDoubleWord;
596         
597         private int mNumber;
598         private boolean mFixed;
599
600         private List mStoreInstructions;
601         private SortedSet mLocationRangeSet;
602
603         public LocalVariableImpl(String JavaDoc name, TypeDescriptor type,
604                                  int number) {
605             mName = name;
606             mType = type;
607             Class JavaDoc clazz = type.getClassArg();
608             mIsDoubleWord = clazz == long.class || clazz == double.class;
609             mNumber = number;
610             if (number >= 0) {
611                 mFixed = true;
612             }
613             mStoreInstructions = new ArrayList();
614         }
615         
616         /**
617          * May return null if this LocalVariable is unnamed.
618          */

619         public String JavaDoc getName() {
620             return mName;
621         }
622         
623         public void setName(String JavaDoc name) {
624             mName = name;
625         }
626         
627         public TypeDescriptor getType() {
628             return mType;
629         }
630         
631         public boolean isDoubleWord() {
632             return mIsDoubleWord;
633         }
634         
635         public int getNumber() {
636             return mNumber;
637         }
638         
639         public void setNumber(int number) {
640             mNumber = number;
641         }
642
643         public SortedSet getLocationRangeSet() {
644             return mLocationRangeSet;
645         }
646         
647         public void setLocations(Set locations) {
648             /* TODO
649             List sortedLocations = new ArrayList(locations);
650             Collections.sort(sortedLocations);
651
652             mLocationRangeSet = new TreeSet();
653             
654             Iterator it = sortedLocations.iterator();
655             Instruction first = null;
656             Instruction last = null;
657             while (it.hasNext()) {
658                 Instruction instr = (Instruction)it.next();
659                 if (first == null) {
660                     first = last = instr;
661                 }
662                 else if (last.mNext == instr) {
663                     last = instr;
664                 }
665                 else {
666                     if (last.mNext != null) {
667                         last = last.mNext;
668                     }
669                     mLocationRangeSet.add(new LocationRangeImpl(first, last));
670                     first = last = instr;
671                 }
672             }
673
674             if (first != null && last != null) {
675                 if (last.mNext != null) {
676                     last = last.mNext;
677                 }
678                 mLocationRangeSet.add(new LocationRangeImpl(first, last));
679             }
680
681             mLocationRangeSet =
682                 Collections.unmodifiableSortedSet(mLocationRangeSet);
683             */

684         }
685
686         public boolean isFixedNumber() {
687             return mFixed;
688         }
689
690         public void addStoreInstruction(Instruction instr) {
691             mStoreInstructions.add(instr);
692         }
693
694         public Iterator iterateStoreInstructions() {
695             return mStoreInstructions.iterator();
696         }
697
698         public String JavaDoc toString() {
699             if (getName() != null) {
700                 return String.valueOf(getType()) + ' ' + getName();
701             }
702             else {
703                 return String.valueOf(getType());
704             }
705         }
706     }
707
708     /////////////////////////////////////////////////////////////////////////
709
//
710
// Begin inner class definitions for instructions of the InstructionList.
711
//
712
/////////////////////////////////////////////////////////////////////////
713

714     /**************************************************************************
715      * An Instruction is an element in an InstructionList, and represents a
716      * Java byte code instruction.
717      *
718      * @author Brian S O'Neill
719      * @version
720      * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
721      */

722     public abstract class Instruction implements Location {
723         private int mStackAdjust;
724
725         Instruction mPrev;
726         Instruction mNext;
727     
728         // Indicates what the stack depth is when this instruction is reached.
729
// Is -1 if not reached. Flow analysis sets this value.
730
int mStackDepth = -1;
731
732         // Indicates the address of this instruction is, or -1 if not known.
733
int mLocation = -1;
734
735         /**
736          * Newly created instructions are automatically added to the
737          * InstructionList.
738          */

739         public Instruction(int stackAdjust) {
740             mStackAdjust = stackAdjust;
741             add();
742         }
743
744         /**
745          * This constructor allows sub-classes to disable auto-adding to the
746          * InstructionList.
747          */

748         protected Instruction(int stackAdjust, boolean addInstruction) {
749             mStackAdjust = stackAdjust;
750
751             if (addInstruction) {
752                 add();
753             }
754         }
755
756         /**
757          * Add this instruction to the end of the InstructionList. If the
758          * Instruction is already in the list, then it is moved to the end.
759          */

760         protected void add() {
761             InstructionList.this.mResolved = false;
762
763             if (mPrev != null) {
764                 mPrev.mNext = mNext;
765             }
766
767             if (mNext != null) {
768                 mNext.mPrev = mPrev;
769             }
770
771             mNext = null;
772             
773             if (InstructionList.this.mFirst == null) {
774                 mPrev = null;
775                 InstructionList.this.mFirst = this;
776             }
777             else {
778                 mPrev = InstructionList.this.mLast;
779                 InstructionList.this.mLast.mNext = this;
780             }
781             
782             InstructionList.this.mLast = this;
783         }
784
785         /**
786          * Insert an Instruction immediately following this one.
787          */

788         public void insert(Instruction instr) {
789             InstructionList.this.mResolved = false;
790
791             instr.mPrev = this;
792             instr.mNext = mNext;
793
794             mNext = instr;
795
796             if (this == InstructionList.this.mLast) {
797                 InstructionList.this.mLast = instr;
798             }
799         }
800
801         /**
802          * Removes this Instruction from its parent InstructionList.
803          */

804         public void remove() {
805             InstructionList.this.mResolved = false;
806             
807             if (mPrev != null) {
808                 mPrev.mNext = mNext;
809             }
810             
811             if (mNext != null) {
812                 mNext.mPrev = mPrev;
813             }
814             
815             if (this == InstructionList.this.mFirst) {
816                 InstructionList.this.mFirst = mNext;
817             }
818             
819             if (this == InstructionList.this.mLast) {
820                 InstructionList.this.mLast = mPrev;
821             }
822             
823             mPrev = null;
824             mNext = null;
825         }
826
827         /**
828          * Replace this Instruction with another one.
829          */

830         public void replace(Instruction replacement) {
831             if (replacement == null) {
832                 remove();
833                 return;
834             }
835
836             InstructionList.this.mResolved = false;
837
838             replacement.mPrev = mPrev;
839             replacement.mNext = mNext;
840
841             if (mPrev != null) {
842                 mPrev.mNext = replacement;
843             }
844             
845             if (mNext != null) {
846                 mNext.mPrev = replacement;
847             }
848             
849             if (this == InstructionList.this.mFirst) {
850                 InstructionList.this.mFirst = replacement;
851             }
852             
853             if (this == InstructionList.this.mLast) {
854                 InstructionList.this.mLast = replacement;
855             }
856         }
857         
858         /**
859          * Returns a positive, negative or zero value indicating what affect
860          * this generated instruction has on the runtime stack.
861          */

862         public int getStackAdjustment() {
863             return mStackAdjust;
864         }
865         
866         /**
867          * Returns the stack depth for when this instruction is reached. If the
868          * value is negative, then this instruction is never reached.
869          */

870         public int getStackDepth() {
871             return mStackDepth;
872         }
873         
874         /**
875          * Returns the address of this instruction or -1 if not known.
876          */

877         public int getLocation() {
878             return mLocation;
879         }
880         
881         /**
882          * Returns all of the targets that this instruction may branch to. Not
883          * all instructions support branching, and null is returned by default.
884          */

885         public Location[] getBranchTargets() {
886             return null;
887         }
888         
889         /**
890          * Returns true if execution flow may continue after this instruction.
891          * It may be a goto, a method return, an exception throw or a
892          * subroutine return. Default implementation returns true.
893          */

894         public boolean isFlowThrough() {
895             return true;
896         }
897
898         public boolean isSubroutineCall() {
899             return false;
900         }
901         
902         /**
903          * Returns null if this is a pseudo instruction and no bytes are
904          * generated.
905          */

906         public abstract byte[] getBytes();
907         
908         /**
909          * An instruction is resolved when it has all information needed to
910          * generate correct byte code.
911          */

912         public abstract boolean isResolved();
913
914         public int compareTo(Object JavaDoc obj) {
915             if (this == obj) {
916                 return 0;
917             }
918             Location other = (Location)obj;
919
920             int loca = getLocation();
921             int locb = other.getLocation();
922
923             if (loca < locb) {
924                 return -1;
925             }
926             else if (loca > locb) {
927                 return 1;
928             }
929             else {
930                 return 0;
931             }
932         }
933
934         /**
935          * Returns a string containing the type of this instruction, the stack
936          * adjustment and the list of byte codes. Unvisted instructions are
937          * marked with an asterisk.
938          */

939         public String JavaDoc toString() {
940             String JavaDoc name = getClass().getName();
941             int index = name.lastIndexOf('.');
942             if (index >= 0) {
943                 name = name.substring(index + 1);
944             }
945             index = name.lastIndexOf('$');
946             if (index >= 0) {
947                 name = name.substring(index + 1);
948             }
949             
950             StringBuffer JavaDoc buf = new StringBuffer JavaDoc(name.length() + 20);
951             
952             int adjust = getStackAdjustment();
953             int depth = getStackDepth();
954
955             if (depth >= 0) {
956                 buf.append(' ');
957             }
958             else {
959                 buf.append('*');
960             }
961             
962             buf.append('[');
963             buf.append(mLocation);
964             buf.append("] ");
965             
966             buf.append(name);
967             buf.append(" (");
968             
969             if (depth >= 0) {
970                 buf.append(depth);
971                 buf.append(" + ");
972                 buf.append(adjust);
973                 buf.append(" = ");
974                 buf.append(depth + adjust);
975             }
976             else {
977                 buf.append(adjust);
978             }
979             
980             buf.append(") ");
981             
982             try {
983                 byte[] bytes = getBytes();
984                 boolean wide = false;
985                 if (bytes != null) {
986                     for (int i=0; i<bytes.length; i++) {
987                         if (i > 0) {
988                             buf.append(',');
989                         }
990                         
991                         byte code = bytes[i];
992                         
993                         if (i == 0 || wide) {
994                             buf.append(Opcode.getMnemonic(code));
995                             wide = code == Opcode.WIDE;
996                         }
997                         else {
998                             buf.append(code & 0xff);
999                         }
1000                    }
1001                }
1002            }
1003            catch (Exception JavaDoc e) {
1004            }
1005
1006            return buf.toString();
1007        }
1008    }
1009
1010    /**************************************************************************
1011     * Defines a psuedo instruction for a label. No byte code is ever generated
1012     * from a label. Labels are not automatically added to the list.
1013     *
1014     * @author Brian S O'Neill
1015     * @version
1016     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1017     */

1018    public class LabelInstruction extends Instruction implements Label {
1019        public LabelInstruction() {
1020            super(0, false);
1021        }
1022
1023        /**
1024         * Set this label's branch location to be the current address
1025         * in this label's parent CodeBuilder or InstructionList.
1026         *
1027         * @return This Label.
1028         */

1029        public Label setLocation() {
1030            add();
1031            return this;
1032        }
1033
1034        /**
1035         * @return -1 when not resolved yet
1036         */

1037        public int getLocation() throws IllegalStateException JavaDoc {
1038            int loc;
1039            if ((loc = mLocation) < 0) {
1040                if (mPrev == null && mNext == null) {
1041                    throw new IllegalStateException JavaDoc
1042                        ("Label location is not set");
1043                }
1044            }
1045
1046            return loc;
1047        }
1048
1049        /**
1050         * Always returns null.
1051         */

1052        public byte[] getBytes() {
1053            return null;
1054        }
1055        
1056        public boolean isResolved() {
1057            return getLocation() >= 0;
1058        }
1059    }
1060
1061    /**************************************************************************
1062     * Defines a code instruction and has storage for byte codes.
1063     *
1064     * @author Brian S O'Neill
1065     * @version
1066     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1067     */

1068    public class CodeInstruction extends Instruction {
1069        protected byte[] mBytes;
1070        
1071        public CodeInstruction(int stackAdjust) {
1072            super(stackAdjust);
1073        }
1074        
1075        protected CodeInstruction(int stackAdjust, boolean addInstruction) {
1076            super(stackAdjust, addInstruction);
1077        }
1078
1079        public CodeInstruction(int stackAdjust, byte b) {
1080            super(stackAdjust);
1081            mBytes = new byte[] {b};
1082        }
1083        
1084        public CodeInstruction(int stackAdjust, byte[] bytes) {
1085            super(stackAdjust);
1086            mBytes = bytes;
1087        }
1088        
1089        public boolean isFlowThrough() {
1090            if (mBytes != null && mBytes.length > 0) {
1091                switch (mBytes[0]) {
1092                case Opcode.GOTO:
1093                case Opcode.GOTO_W:
1094                case Opcode.IRETURN:
1095                case Opcode.LRETURN:
1096                case Opcode.FRETURN:
1097                case Opcode.DRETURN:
1098                case Opcode.ARETURN:
1099                case Opcode.RETURN:
1100                case Opcode.ATHROW:
1101                    return false;
1102                }
1103            }
1104            
1105            return true;
1106        }
1107        
1108        public byte[] getBytes() {
1109            return mBytes;
1110        }
1111        
1112        public boolean isResolved() {
1113            return true;
1114        }
1115    }
1116
1117    /**************************************************************************
1118     * Defines a branch instruction, like a goto, jsr or any conditional
1119     * branch.
1120     *
1121     * @author Brian S O'Neill
1122     * @version
1123     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1124     */

1125    public class BranchInstruction extends CodeInstruction {
1126        private Location mTarget;
1127        private boolean mHasShortHop = false;
1128        private boolean mIsSub = false;
1129
1130        public BranchInstruction(int stackAdjust,
1131                                 byte opcode, Location target) {
1132            this(stackAdjust, true, opcode, target);
1133        }
1134
1135        private BranchInstruction(int stackAdjust, boolean addInstruction,
1136                                  byte opcode, Location target) {
1137            super(stackAdjust, addInstruction);
1138            
1139            mTarget = target;
1140            
1141            switch (opcode) {
1142            case Opcode.GOTO_W:
1143            case Opcode.JSR_W:
1144                mIsSub = true;
1145                mBytes = new byte[5];
1146                mBytes[0] = opcode;
1147                break;
1148            case Opcode.JSR:
1149                mIsSub = true;
1150                // Flow through to next case.
1151
case Opcode.GOTO:
1152            case Opcode.IF_ACMPEQ:
1153            case Opcode.IF_ACMPNE:
1154            case Opcode.IF_ICMPEQ:
1155            case Opcode.IF_ICMPNE:
1156            case Opcode.IF_ICMPLT:
1157            case Opcode.IF_ICMPGE:
1158            case Opcode.IF_ICMPGT:
1159            case Opcode.IF_ICMPLE:
1160            case Opcode.IFEQ:
1161            case Opcode.IFNE:
1162            case Opcode.IFLT:
1163            case Opcode.IFGE:
1164            case Opcode.IFGT:
1165            case Opcode.IFLE:
1166            case Opcode.IFNONNULL:
1167            case Opcode.IFNULL:
1168                mBytes = new byte[3];
1169                mBytes[0] = opcode;
1170                break;
1171            default:
1172                throw new IllegalArgumentException JavaDoc
1173                    ("Opcode not a branch instruction: " +
1174                     Opcode.getMnemonic(opcode));
1175            }
1176        }
1177        
1178        public Location[] getBranchTargets() {
1179            return new Location[] {mTarget};
1180        }
1181        
1182        public boolean isSubroutineCall() {
1183            return mIsSub;
1184        }
1185
1186        public byte[] getBytes() {
1187            if (!isResolved() || mHasShortHop) {
1188                return mBytes;
1189            }
1190            
1191            int offset = mTarget.getLocation() - mLocation;
1192            byte opcode = mBytes[0];
1193            
1194            if (opcode == Opcode.GOTO_W || opcode == Opcode.JSR_W) {
1195                mBytes[1] = (byte)(offset >> 24);
1196                mBytes[2] = (byte)(offset >> 16);
1197                mBytes[3] = (byte)(offset >> 8);
1198                mBytes[4] = (byte)(offset >> 0);
1199            }
1200            else if (-32768 <= offset && offset <= 32767) {
1201                mBytes[1] = (byte)(offset >> 8);
1202                mBytes[2] = (byte)(offset >> 0);
1203            }
1204            else if (opcode == Opcode.GOTO || opcode == Opcode.JSR) {
1205                mBytes = new byte[5];
1206                if (opcode == Opcode.GOTO) {
1207                    mBytes[0] = Opcode.GOTO_W;
1208                }
1209                else {
1210                    mBytes[0] = Opcode.JSR_W;
1211                }
1212                mBytes[1] = (byte)(offset >> 24);
1213                mBytes[2] = (byte)(offset >> 16);
1214                mBytes[3] = (byte)(offset >> 8);
1215                mBytes[4] = (byte)(offset >> 0);
1216            }
1217            else {
1218                // The if branch requires a 32 bit offset.
1219

1220                // Convert:
1221
//
1222
// if <cond> goto target
1223
// // reached if <cond> false
1224
// target: // reached if <cond> true
1225

1226                // to this:
1227
//
1228
// if not <cond> goto shortHop
1229
// goto_w target
1230
// shortHop: // reached if <cond> false
1231
// target: // reached if <cond> true
1232

1233                mHasShortHop = true;
1234                
1235                opcode = Opcode.reverseIfOpcode(opcode);
1236                
1237                mBytes[0] = opcode;
1238                mBytes[1] = (byte)0;
1239                mBytes[2] = (byte)8;
1240                
1241                // insert goto_w instruction after this one.
1242
insert
1243                    (new BranchInstruction(0, false, Opcode.GOTO_W, mTarget));
1244            }
1245            
1246            return mBytes;
1247        }
1248        
1249        public boolean isResolved() {
1250            return mTarget.getLocation() >= 0;
1251        }
1252    }
1253
1254    /**************************************************************************
1255     * Defines an instruction that has a single operand which references a
1256     * constant in the constant pool.
1257     *
1258     * @author Brian S O'Neill
1259     * @version
1260     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1261     */

1262    public class ConstantOperandInstruction extends CodeInstruction {
1263        private ConstantInfo mInfo;
1264        
1265        public ConstantOperandInstruction(int stackAdjust,
1266                                          byte[] bytes,
1267                                          ConstantInfo info) {
1268            super(stackAdjust, bytes);
1269            mInfo = info;
1270        }
1271        
1272        public byte[] getBytes() {
1273            int index = mInfo.getIndex();
1274            
1275            if (index < 0) {
1276                throw new RuntimeException JavaDoc("Constant pool index not resolved");
1277            }
1278            
1279            mBytes[1] = (byte)(index >> 8);
1280            mBytes[2] = (byte)index;
1281            
1282            return mBytes;
1283        }
1284        
1285        public boolean isResolved() {
1286            return mInfo.getIndex() >= 0;
1287        }
1288    }
1289
1290    /**************************************************************************
1291     * Defines an instruction that loads a constant onto the stack from the
1292     * constant pool.
1293     *
1294     * @author Brian S O'Neill
1295     * @version
1296     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1297     */

1298    public class LoadConstantInstruction extends CodeInstruction {
1299        private ConstantInfo mInfo;
1300        private boolean mWideOnly;
1301        
1302        public LoadConstantInstruction(int stackAdjust,
1303                                       ConstantInfo info) {
1304            this(stackAdjust, info, false);
1305        }
1306
1307        public LoadConstantInstruction(int stackAdjust,
1308                                       ConstantInfo info,
1309                                       boolean wideOnly) {
1310            super(stackAdjust);
1311            mInfo = info;
1312            mWideOnly = wideOnly;
1313        }
1314        
1315        public boolean isFlowThrough() {
1316            return true;
1317        }
1318        
1319        public byte[] getBytes() {
1320            int index = mInfo.getIndex();
1321            
1322            if (index < 0) {
1323                throw new RuntimeException JavaDoc("Constant pool index not resolved");
1324            }
1325            
1326            if (mWideOnly) {
1327                byte[] bytes = new byte[3];
1328                bytes[0] = Opcode.LDC2_W;
1329                bytes[1] = (byte)(index >> 8);
1330                bytes[2] = (byte)index;
1331                return bytes;
1332            }
1333            else if (index <= 255) {
1334                byte[] bytes = new byte[2];
1335                bytes[0] = Opcode.LDC;
1336                bytes[1] = (byte)index;
1337                return bytes;
1338            }
1339            else {
1340                byte[] bytes = new byte[3];
1341                bytes[0] = Opcode.LDC_W;
1342                bytes[1] = (byte)(index >> 8);
1343                bytes[2] = (byte)index;
1344                return bytes;
1345            }
1346        }
1347        
1348        public boolean isResolved() {
1349            return mInfo.getIndex() >= 0;
1350        }
1351    }
1352
1353    /**************************************************************************
1354     * Defines an instruction that contains an operand for referencing a
1355     * LocalVariable.
1356     *
1357     * @author Brian S O'Neill
1358     * @version
1359     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1360     */

1361    public class LocalOperandInstruction extends CodeInstruction {
1362        protected LocalVariable mLocal;
1363        
1364        public LocalOperandInstruction(int stackAdjust,
1365                                       LocalVariable local) {
1366            super(stackAdjust);
1367            mLocal = local;
1368        }
1369        
1370        public boolean isResolved() {
1371            return mLocal.getNumber() >= 0;
1372        }
1373        
1374        public LocalVariable getLocalVariable() {
1375            return mLocal;
1376        }
1377        
1378        public int getVariableNumber() {
1379            int varNum = mLocal.getNumber();
1380            
1381            if (varNum < 0) {
1382                throw new RuntimeException JavaDoc
1383                    ("Local variable number not resolved");
1384            }
1385            
1386            return varNum;
1387        }
1388    }
1389
1390    /**************************************************************************
1391     * Defines an instruction that loads a local variable onto the stack.
1392     *
1393     * @author Brian S O'Neill
1394     * @version
1395     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1396     */

1397    public class LoadLocalInstruction extends LocalOperandInstruction {
1398        public LoadLocalInstruction(int stackAdjust,
1399                                    LocalVariable local) {
1400            super(stackAdjust, local);
1401        }
1402        
1403        public boolean isFlowThrough() {
1404            return true;
1405        }
1406        
1407        public byte[] getBytes() {
1408            int varNum = getVariableNumber();
1409            byte opcode;
1410            boolean writeIndex = false;
1411
1412            TypeDescriptor type = mLocal.getType();
1413            Class JavaDoc clazz;
1414            if (type.getDimensions() > 0) {
1415                clazz = null;
1416            }
1417            else {
1418                clazz = type.getClassArg();
1419            }
1420
1421            switch(varNum) {
1422            case 0:
1423                if (clazz == null || !clazz.isPrimitive()) {
1424                    opcode = Opcode.ALOAD_0;
1425                }
1426                else if (clazz == long.class) {
1427                    opcode = Opcode.LLOAD_0;
1428                }
1429                else if (clazz == float.class) {
1430                    opcode = Opcode.FLOAD_0;
1431                }
1432                else if (clazz == double.class) {
1433                    opcode = Opcode.DLOAD_0;
1434                }
1435                else {
1436                    opcode = Opcode.ILOAD_0;
1437                }
1438                break;
1439            case 1:
1440                if (clazz == null || !clazz.isPrimitive()) {
1441                    opcode = Opcode.ALOAD_1;
1442                }
1443                else if (clazz == long.class) {
1444                    opcode = Opcode.LLOAD_1;
1445                }
1446                else if (clazz == float.class) {
1447                    opcode = Opcode.FLOAD_1;
1448                }
1449                else if (clazz == double.class) {
1450                    opcode = Opcode.DLOAD_1;
1451                }
1452                else {
1453                    opcode = Opcode.ILOAD_1;
1454                }
1455                break;
1456            case 2:
1457                if (clazz == null || !clazz.isPrimitive()) {
1458                    opcode = Opcode.ALOAD_2;
1459                }
1460                else if (clazz == long.class) {
1461                    opcode = Opcode.LLOAD_2;
1462                }
1463                else if (clazz == float.class) {
1464                    opcode = Opcode.FLOAD_2;
1465                }
1466                else if (clazz == double.class) {
1467                    opcode = Opcode.DLOAD_2;
1468                }
1469                else {
1470                    opcode = Opcode.ILOAD_2;
1471                }
1472                break;
1473            case 3:
1474                if (clazz == null || !clazz.isPrimitive()) {
1475                    opcode = Opcode.ALOAD_3;
1476                }
1477                else if (clazz == long.class) {
1478                    opcode = Opcode.LLOAD_3;
1479                }
1480                else if (clazz == float.class) {
1481                    opcode = Opcode.FLOAD_3;
1482                }
1483                else if (clazz == double.class) {
1484                    opcode = Opcode.DLOAD_3;
1485                }
1486                else {
1487                    opcode = Opcode.ILOAD_3;
1488                }
1489                break;
1490            default:
1491                writeIndex = true;
1492                
1493                if (clazz == null || !clazz.isPrimitive()) {
1494                    opcode = Opcode.ALOAD;
1495                }
1496                else if (clazz == long.class) {
1497                    opcode = Opcode.LLOAD;
1498                }
1499                else if (clazz == float.class) {
1500                    opcode = Opcode.FLOAD;
1501                }
1502                else if (clazz == double.class) {
1503                    opcode = Opcode.DLOAD;
1504                }
1505                else {
1506                    opcode = Opcode.ILOAD;
1507                }
1508                break;
1509            }
1510
1511            if (!writeIndex) {
1512                mBytes = new byte[] { opcode };
1513            }
1514            else {
1515                if (varNum <= 255) {
1516                    mBytes = new byte[] { opcode, (byte)varNum };
1517                }
1518                else {
1519                    mBytes = new byte[]
1520                    {
1521                        Opcode.WIDE,
1522                        opcode,
1523                        (byte)(varNum >> 8),
1524                        (byte)varNum
1525                    };
1526                }
1527            }
1528            
1529            return mBytes;
1530        }
1531    }
1532
1533    /**************************************************************************
1534     * Defines an instruction that stores a value from the stack into a local
1535     * variable.
1536     *
1537     * @author Brian S O'Neill
1538     * @version
1539     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1540     */

1541    public class StoreLocalInstruction extends LocalOperandInstruction {
1542        public StoreLocalInstruction(int stackAdjust,
1543                                     LocalVariable local) {
1544            super(stackAdjust, local);
1545            ((LocalVariableImpl)local).addStoreInstruction(this);
1546        }
1547        
1548        public boolean isFlowThrough() {
1549            return true;
1550        }
1551        
1552        public byte[] getBytes() {
1553            int varNum = getVariableNumber();
1554            byte opcode;
1555            boolean writeIndex = false;
1556
1557            TypeDescriptor type = mLocal.getType();
1558            Class JavaDoc clazz;
1559            if (type.getDimensions() > 0) {
1560                clazz = null;
1561            }
1562            else {
1563                clazz = type.getClassArg();
1564            }
1565            
1566            switch(varNum) {
1567            case 0:
1568                if (clazz == null || !clazz.isPrimitive()) {
1569                    opcode = Opcode.ASTORE_0;
1570                }
1571                else if (clazz == long.class) {
1572                    opcode = Opcode.LSTORE_0;
1573                }
1574                else if (clazz == float.class) {
1575                    opcode = Opcode.FSTORE_0;
1576                }
1577                else if (clazz == double.class) {
1578                    opcode = Opcode.DSTORE_0;
1579                }
1580                else {
1581                    opcode = Opcode.ISTORE_0;
1582                }
1583                break;
1584            case 1:
1585                if (clazz == null || !clazz.isPrimitive()) {
1586                    opcode = Opcode.ASTORE_1;
1587                }
1588                else if (clazz == long.class) {
1589                    opcode = Opcode.LSTORE_1;
1590                }
1591                else if (clazz == float.class) {
1592                    opcode = Opcode.FSTORE_1;
1593                }
1594                else if (clazz == double.class) {
1595                    opcode = Opcode.DSTORE_1;
1596                }
1597                else {
1598                    opcode = Opcode.ISTORE_1;
1599                }
1600                break;
1601            case 2:
1602                if (clazz == null || !clazz.isPrimitive()) {
1603                    opcode = Opcode.ASTORE_2;
1604                }
1605                else if (clazz == long.class) {
1606                    opcode = Opcode.LSTORE_2;
1607                }
1608                else if (clazz == float.class) {
1609                    opcode = Opcode.FSTORE_2;
1610                }
1611                else if (clazz == double.class) {
1612                    opcode = Opcode.DSTORE_2;
1613                }
1614                else {
1615                    opcode = Opcode.ISTORE_2;
1616                }
1617                break;
1618            case 3:
1619                if (clazz == null || !clazz.isPrimitive()) {
1620                    opcode = Opcode.ASTORE_3;
1621                }
1622                else if (clazz == long.class) {
1623                    opcode = Opcode.LSTORE_3;
1624                }
1625                else if (clazz == float.class) {
1626                    opcode = Opcode.FSTORE_3;
1627                }
1628                else if (clazz == double.class) {
1629                    opcode = Opcode.DSTORE_3;
1630                }
1631                else {
1632                    opcode = Opcode.ISTORE_3;
1633                }
1634                break;
1635            default:
1636                writeIndex = true;
1637                
1638                if (clazz == null || !clazz.isPrimitive()) {
1639                    opcode = Opcode.ASTORE;
1640                }
1641                else if (clazz == long.class) {
1642                    opcode = Opcode.LSTORE;
1643                }
1644                else if (clazz == float.class) {
1645                    opcode = Opcode.FSTORE;
1646                }
1647                else if (clazz == double.class) {
1648                    opcode = Opcode.DSTORE;
1649                }
1650                else {
1651                    opcode = Opcode.ISTORE;
1652                }
1653                break;
1654            }
1655            
1656            if (!writeIndex) {
1657                mBytes = new byte[] { opcode };
1658            }
1659            else {
1660                if (varNum <= 255) {
1661                    mBytes = new byte[] { opcode, (byte)varNum };
1662                }
1663                else {
1664                    mBytes = new byte[]
1665                    {
1666                        Opcode.WIDE,
1667                        opcode,
1668                        (byte)(varNum >> 8),
1669                        (byte)varNum
1670                    };
1671                }
1672            }
1673            
1674            return mBytes;
1675        }
1676    }
1677    
1678    /**************************************************************************
1679     * Defines a ret instruction for returning from a jsr call.
1680     *
1681     * @author Brian S O'Neill
1682     * @version
1683     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1684     */

1685    public class RetInstruction extends LocalOperandInstruction {
1686        public RetInstruction(LocalVariable local) {
1687            super(0, local);
1688        }
1689        
1690        public boolean isFlowThrough() {
1691            return false;
1692        }
1693        
1694        public byte[] getBytes() {
1695            int varNum = getVariableNumber();
1696            
1697            if (varNum <= 255) {
1698                mBytes = new byte[] { Opcode.RET, (byte)varNum };
1699            }
1700            else {
1701                mBytes = new byte[]
1702                {
1703                    Opcode.WIDE,
1704                    Opcode.RET,
1705                    (byte)(varNum >> 8),
1706                    (byte)varNum
1707                };
1708            }
1709            
1710            return mBytes;
1711        }
1712    }
1713
1714    /**************************************************************************
1715     * Defines a specialized instruction that increments a local variable by
1716     * a signed 16-bit amount.
1717     *
1718     * @author Brian S O'Neill
1719     * @version
1720     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1721     */

1722    public class ShortIncrementInstruction extends LocalOperandInstruction {
1723        private short mAmount;
1724        
1725        public ShortIncrementInstruction(LocalVariable local, short amount) {
1726            super(0, local);
1727            mAmount = amount;
1728        }
1729        
1730        public boolean isFlowThrough() {
1731            return true;
1732        }
1733        
1734        public byte[] getBytes() {
1735            int varNum = getVariableNumber();
1736            
1737            if ((-128 <= mAmount && mAmount <= 127) && varNum <= 255) {
1738                mBytes = new byte[]
1739                { Opcode.IINC,
1740                  (byte)varNum,
1741                  (byte)mAmount
1742                };
1743            }
1744            else {
1745                mBytes = new byte[]
1746                {
1747                    Opcode.WIDE,
1748                    Opcode.IINC,
1749                    (byte)(varNum >> 8),
1750                    (byte)varNum,
1751                    (byte)(mAmount >> 8),
1752                    (byte)mAmount
1753                };
1754            }
1755            
1756            return mBytes;
1757        }
1758    }
1759
1760    /**************************************************************************
1761     * Defines a switch instruction. The choice of which actual switch
1762     * implementation to use (table or lookup switch) is determined
1763     * automatically based on which generates to the smallest amount of bytes.
1764     *
1765     * @author Brian S O'Neill
1766     * @version
1767     * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
1768     */

1769    public class SwitchInstruction extends CodeInstruction {
1770        private int[] mCases;
1771        private Location[] mLocations;
1772        private Location mDefaultLocation;
1773        
1774        private byte mOpcode;
1775        
1776        private int mSmallest;
1777        private int mLargest;
1778        
1779        public SwitchInstruction(int[] casesParam,
1780                                 Location[] locationsParam,
1781                                 Location defaultLocation) {
1782            // A SwitchInstruction always adjusts the stack by -1 because it
1783
// pops the switch key off the stack.
1784
super(-1);
1785
1786            if (casesParam.length != locationsParam.length) {
1787                throw new IllegalArgumentException JavaDoc
1788                    ("Switch cases and locations sizes differ: " +
1789                     casesParam.length + ", " + locationsParam.length);
1790            }
1791            
1792            mCases = new int[casesParam.length];
1793            System.arraycopy(casesParam, 0, mCases, 0, casesParam.length);
1794            
1795            mLocations = new Location[locationsParam.length];
1796            System.arraycopy(locationsParam, 0, mLocations,
1797                             0, locationsParam.length);
1798            
1799            mDefaultLocation = defaultLocation;
1800            
1801            // First sort the cases and locations.
1802
sort(0, mCases.length - 1);
1803            
1804            // Check for duplicate cases.
1805
int lastCase = 0;
1806            for (int i=0; i<mCases.length; i++) {
1807                if (i > 0 && mCases[i] == lastCase) {
1808                    throw new RuntimeException JavaDoc("Duplicate switch cases: " +
1809                                               lastCase);
1810                }
1811                lastCase = mCases[i];
1812            }
1813            
1814            // Now determine which kind of switch to use.
1815

1816            mSmallest = mCases[0];
1817            mLargest = mCases[mCases.length - 1];
1818            int tSize = 12 + 4 * (mLargest - mSmallest + 1);
1819            
1820            int lSize = 8 + 8 * mCases.length;
1821            
1822            if (tSize <= lSize) {
1823                mOpcode = Opcode.TABLESWITCH;
1824            }
1825            else {
1826                mOpcode = Opcode.LOOKUPSWITCH;
1827            }
1828        }
1829        
1830        public Location[] getBranchTargets() {
1831            Location[] targets = new Location[mLocations.length + 1];
1832            System.arraycopy(mLocations, 0, targets, 0, mLocations.length);
1833            targets[targets.length - 1] = mDefaultLocation;
1834            
1835            return targets;
1836        }
1837        
1838        public boolean isFlowThrough() {
1839            return false;
1840        }
1841        
1842        public byte[] getBytes() {
1843            int length = 1;
1844            int pad = 3 - (mLocation & 3);
1845            length += pad;
1846            
1847            if (mOpcode == Opcode.TABLESWITCH) {
1848                length += 12 + 4 * (mLargest - mSmallest + 1);
1849            }
1850            else {
1851                length += 8 + 8 * mCases.length;
1852            }
1853            
1854            mBytes = new byte[length];
1855            
1856            if (!isResolved()) {
1857                return mBytes;
1858            }
1859            
1860            mBytes[0] = mOpcode;
1861            int cursor = pad + 1;
1862            
1863            int defaultOffset = mDefaultLocation.getLocation() - mLocation;
1864            mBytes[cursor++] = (byte)(defaultOffset >> 24);
1865            mBytes[cursor++] = (byte)(defaultOffset >> 16);
1866            mBytes[cursor++] = (byte)(defaultOffset >> 8);
1867            mBytes[cursor++] = (byte)(defaultOffset >> 0);
1868            
1869            if (mOpcode == Opcode.TABLESWITCH) {
1870                mBytes[cursor++] = (byte)(mSmallest >> 24);
1871                mBytes[cursor++] = (byte)(mSmallest >> 16);
1872                mBytes[cursor++] = (byte)(mSmallest >> 8);
1873                mBytes[cursor++] = (byte)(mSmallest >> 0);
1874                
1875                mBytes[cursor++] = (byte)(mLargest >> 24);
1876                mBytes[cursor++] = (byte)(mLargest >> 16);
1877                mBytes[cursor++] = (byte)(mLargest >> 8);
1878                mBytes[cursor++] = (byte)(mLargest >> 0);
1879                
1880                int index = 0;
1881                for (int case_ = mSmallest; case_ <= mLargest; case_++) {
1882                    if (case_ == mCases[index]) {
1883                        int offset =
1884                            mLocations[index].getLocation() - mLocation;
1885                        mBytes[cursor++] = (byte)(offset >> 24);
1886                        mBytes[cursor++] = (byte)(offset >> 16);
1887                        mBytes[cursor++] = (byte)(offset >> 8);
1888                        mBytes[cursor++] = (byte)(offset >> 0);
1889                        
1890                        index++;
1891                    }
1892                    else {
1893                        mBytes[cursor++] = (byte)(defaultOffset >> 24);
1894                        mBytes[cursor++] = (byte)(defaultOffset >> 16);
1895                        mBytes[cursor++] = (byte)(defaultOffset >> 8);
1896                        mBytes[cursor++] = (byte)(defaultOffset >> 0);
1897                    }
1898                }
1899            }
1900            else {
1901                mBytes[cursor++] = (byte)(mCases.length >> 24);
1902                mBytes[cursor++] = (byte)(mCases.length >> 16);
1903                mBytes[cursor++] = (byte)(mCases.length >> 8);
1904                mBytes[cursor++] = (byte)(mCases.length >> 0);
1905                
1906                for (int index = 0; index < mCases.length; index++) {
1907                    int case_ = mCases[index];
1908                    
1909                    mBytes[cursor++] = (byte)(case_ >> 24);
1910                    mBytes[cursor++] = (byte)(case_ >> 16);
1911                    mBytes[cursor++] = (byte)(case_ >> 8);
1912                    mBytes[cursor++] = (byte)(case_ >> 0);
1913                    
1914                    int offset = mLocations[index].getLocation() - mLocation;
1915                    mBytes[cursor++] = (byte)(offset >> 24);
1916                    mBytes[cursor++] = (byte)(offset >> 16);
1917                    mBytes[cursor++] = (byte)(offset >> 8);
1918                    mBytes[cursor++] = (byte)(offset >> 0);
1919                }
1920            }
1921            
1922            return mBytes;
1923        }
1924
1925        public boolean isResolved() {
1926            if (mDefaultLocation.getLocation() >= 0) {
1927                for (int i=0; i<mLocations.length; i++) {
1928                    if (mLocations[i].getLocation() < 0) {
1929                        break;
1930                    }
1931                }
1932                
1933                return true;
1934            }
1935            
1936            return false;
1937        }
1938        
1939        private void sort(int left, int right) {
1940            if (left >= right) {
1941                return;
1942            }
1943            
1944            swap(left, (left + right) / 2); // move middle element to 0
1945

1946            int last = left;
1947            
1948            for (int i = left + 1; i <= right; i++) {
1949                if (mCases[i] < mCases[left]) {
1950                    swap(++last, i);
1951                }
1952            }
1953            
1954            swap(left, last);
1955            sort(left, last-1);
1956            sort(last + 1, right);
1957        }
1958        
1959        private void swap(int i, int j) {
1960            int tempInt = mCases[i];
1961            mCases[i] = mCases[j];
1962            mCases[j] = tempInt;
1963            
1964            Location tempLocation = mLocations[i];
1965            mLocations[i] = mLocations[j];
1966            mLocations[j] = tempLocation;
1967        }
1968    }
1969}
1970
Popular Tags