KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > CodeBuilder


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import org.cojen.classfile.attribute.CodeAttr;
20 import org.cojen.classfile.constant.ConstantClassInfo;
21 import org.cojen.classfile.constant.ConstantFieldInfo;
22
23 /**
24  * This class is used as an aid in generating code for a method.
25  * It controls the max stack, local variable allocation, labels and bytecode.
26  *
27  * @author Brian S O'Neill
28  */

29 public class CodeBuilder extends AbstractCodeAssembler implements CodeBuffer, CodeAssembler {
30     private final CodeAttr mCodeAttr;
31     private final ClassFile mClassFile;
32     private final ConstantPool mCp;
33
34     private final InstructionList mInstructions;
35
36     private final LocalVariable mThisReference;
37     private final LocalVariable[] mParameters;
38
39     private final int mTarget;
40
41     private final boolean mSaveLineNumberInfo;
42     private final boolean mSaveLocalVariableInfo;
43
44     /**
45      * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
46      * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
47      */

48     public CodeBuilder(MethodInfo info) {
49         this(info, true, false);
50     }
51
52     /**
53      * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
54      * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
55      *
56      * @param saveLineNumberInfo When set false, all calls to mapLineNumber
57      * are ignored. By default, this value is true.
58      * @param saveLocalVariableInfo When set true, all local variable
59      * usage information is saved in the ClassFile. By default, this value
60      * is false.
61      * @see #mapLineNumber
62      */

63     public CodeBuilder(MethodInfo info, boolean saveLineNumberInfo,
64                        boolean saveLocalVariableInfo) {
65
66         String JavaDoc target = info.getClassFile().getTarget();
67         if ("1.0".equals(target)) {
68             mTarget = 0x00010000;
69         } else if ("1.1".equals(target)) {
70             mTarget = 0x00010001;
71         } else if ("1.2".equals(target)) {
72             mTarget = 0x00010002;
73         } else if ("1.3".equals(target)) {
74             mTarget = 0x00010003;
75         } else if ("1.4".equals(target)) {
76             mTarget = 0x00010004;
77         } else if ("1.5".equals(target)) {
78             mTarget = 0x00010005;
79         } else if ("1.6".equals(target)) {
80             mTarget = 0x00010006;
81         } else {
82             mTarget = 0x00010000;
83         }
84
85         mCodeAttr = info.getCodeAttr();
86         mClassFile = info.getClassFile();
87         mCp = mClassFile.getConstantPool();
88         mInstructions = new InstructionList();
89
90         mCodeAttr.setCodeBuffer(this);
91
92         mSaveLineNumberInfo = saveLineNumberInfo;
93         mSaveLocalVariableInfo = saveLocalVariableInfo;
94
95         // Create LocalVariable references for "this" reference and other
96
// passed in parameters.
97

98         LocalVariable localVar;
99
100         if (info.getModifiers().isStatic()) {
101             mThisReference = null;
102         } else {
103             localVar = mInstructions.createLocalParameter("this", mClassFile.getType());
104             mThisReference = localVar;
105
106             if (saveLocalVariableInfo) {
107                 mCodeAttr.localVariableUse(localVar);
108             }
109         }
110
111         TypeDesc[] paramTypes = info.getMethodDescriptor().getParameterTypes();
112         int paramSize = paramTypes.length;
113
114         mParameters = new LocalVariable[paramSize];
115
116         for (int i = 0; i<paramTypes.length; i++) {
117             localVar = mInstructions.createLocalParameter(null, paramTypes[i]);
118             mParameters[i] = localVar;
119             if (saveLocalVariableInfo) {
120                 mCodeAttr.localVariableUse(localVar);
121             }
122         }
123     }
124
125     public int getMaxStackDepth() {
126         return mInstructions.getMaxStackDepth();
127     }
128
129     public int getMaxLocals() {
130         return mInstructions.getMaxLocals();
131     }
132
133     public byte[] getByteCodes() {
134         return mInstructions.getByteCodes();
135     }
136
137     public ExceptionHandler[] getExceptionHandlers() {
138         return mInstructions.getExceptionHandlers();
139     }
140
141     private void addCode(int stackAdjust, byte opcode) {
142         mInstructions.new CodeInstruction(stackAdjust, new byte[] {opcode});
143     }
144
145     private void addCode(int stackAdjust, byte opcode, byte operand) {
146         mInstructions.new CodeInstruction
147             (stackAdjust, new byte[] {opcode, operand});
148     }
149
150     private void addCode(int stackAdjust, byte opcode, short operand) {
151         mInstructions.new CodeInstruction
152             (stackAdjust,
153              new byte[] {opcode, (byte)(operand >> 8), (byte)operand});
154     }
155
156     private void addCode(int stackAdjust, byte opcode, int operand) {
157         byte[] bytes = new byte[5];
158
159         bytes[0] = opcode;
160         bytes[1] = (byte)(operand >> 24);
161         bytes[2] = (byte)(operand >> 16);
162         bytes[3] = (byte)(operand >> 8);
163         bytes[4] = (byte)operand;
164
165         mInstructions.new CodeInstruction(stackAdjust, bytes);
166     }
167
168     private void addCode(int stackAdjust, byte opcode, ConstantInfo info) {
169         // The zeros get filled in later, when the ConstantInfo index
170
// is resolved.
171
mInstructions.new ConstantOperandInstruction
172             (stackAdjust,
173              new byte[] {opcode, (byte)0, (byte)0}, info);
174     }
175
176     private String JavaDoc getClassName(TypeDesc classDesc) throws IllegalArgumentException JavaDoc {
177         if (classDesc.isPrimitive()) {
178             throw new IllegalArgumentException JavaDoc("Primitive type not allowed");
179         }
180         if (classDesc.isArray()) {
181             throw new IllegalArgumentException JavaDoc("Array type not allowed");
182         }
183         return classDesc.getRootName();
184     }
185
186     public int getParameterCount() {
187         return mParameters.length;
188     }
189
190     public LocalVariable getParameter(int index) {
191         return mParameters[index];
192     }
193
194     public LocalVariable createLocalVariable(String JavaDoc name, TypeDesc type) {
195         LocalVariable localVar = mInstructions.createLocalVariable(name, type);
196
197         if (mSaveLocalVariableInfo) {
198             mCodeAttr.localVariableUse(localVar);
199         }
200
201         return localVar;
202     }
203
204     public Label createLabel() {
205         return mInstructions.new LabelInstruction();
206     }
207
208     public void exceptionHandler(Location startLocation,
209                                  Location endLocation,
210                                  String JavaDoc catchClassName) {
211         Location catchLocation = createLabel().setLocation();
212
213         ConstantClassInfo catchClass;
214         if (catchClassName == null) {
215             catchClass = null;
216         } else {
217             catchClass = mCp.addConstantClass(catchClassName);
218         }
219
220         ExceptionHandler handler =
221             new ExceptionHandler(startLocation, endLocation,
222                                  catchLocation, catchClass);
223
224         mInstructions.addExceptionHandler(handler);
225     }
226     
227     public void mapLineNumber(int lineNumber) {
228         if (mSaveLineNumberInfo) {
229             mCodeAttr.mapLineNumber(createLabel().setLocation(), lineNumber);
230         }
231     }
232
233     // load-constant-to-stack style instructions
234

235     public void loadNull() {
236         addCode(1, Opcode.ACONST_NULL);
237     }
238
239     public void loadConstant(String JavaDoc value) {
240         if (value == null) {
241             loadNull();
242             return;
243         }
244
245         int strlen = value.length();
246
247         if (strlen <= (65535 / 3)) {
248             // Guaranteed to fit in a Java UTF encoded string.
249
ConstantInfo info = mCp.addConstantString(value);
250             mInstructions.new LoadConstantInstruction(1, info);
251             return;
252         }
253
254         // Compute actual UTF length.
255

256         int utflen = 0;
257
258         for (int i=0; i<strlen; i++) {
259             int c = value.charAt(i);
260             if ((c >= 0x0001) && (c <= 0x007F)) {
261                 utflen++;
262             } else if (c > 0x07FF) {
263                 utflen += 3;
264             } else {
265                 utflen += 2;
266             }
267         }
268
269         if (utflen <= 65535) {
270             ConstantInfo info = mCp.addConstantString(value);
271             mInstructions.new LoadConstantInstruction(1, info);
272             return;
273         }
274
275         // Break string up into chunks and construct in a StringBuffer.
276

277         TypeDesc stringBufferDesc;
278         if (mTarget >= 0x00010005) {
279             stringBufferDesc = TypeDesc.forClass("java.lang.StringBuilder");
280         } else {
281             stringBufferDesc = TypeDesc.forClass(StringBuffer JavaDoc.class);
282         }
283         
284         TypeDesc intDesc = TypeDesc.INT;
285         TypeDesc stringDesc = TypeDesc.STRING;
286         TypeDesc[] stringParam = new TypeDesc[] {stringDesc};
287         
288         newObject(stringBufferDesc);
289         dup();
290         loadConstant(strlen);
291         invokeConstructor(stringBufferDesc, new TypeDesc[] {intDesc});
292         
293         int beginIndex;
294         int endIndex = 0;
295         
296         while (endIndex < strlen) {
297             beginIndex = endIndex;
298
299             // Make each chunk as large as possible.
300
utflen = 0;
301             for (; endIndex < strlen; endIndex++) {
302                 int c = value.charAt(endIndex);
303                 int size;
304                 if ((c >= 0x0001) && (c <= 0x007F)) {
305                     size = 1;
306                 } else if (c > 0x07FF) {
307                     size = 3;
308                 } else {
309                     size = 2;
310                 }
311
312                 if ((utflen + size) > 65535) {
313                     break;
314                 } else {
315                     utflen += size;
316                 }
317             }
318
319             String JavaDoc substr = value.substring(beginIndex, endIndex);
320
321             ConstantInfo info = mCp.addConstantString(substr);
322             mInstructions.new LoadConstantInstruction(1, info);
323
324             invokeVirtual(stringBufferDesc, "append",
325                           stringBufferDesc, stringParam);
326         }
327         
328         invokeVirtual(stringBufferDesc, "toString", stringDesc, null);
329     }
330
331     public void loadConstant(TypeDesc type) throws IllegalStateException JavaDoc {
332         if (type == null) {
333             loadNull();
334             return;
335         }
336
337         if (type.isPrimitive()) {
338             if (mTarget < 0x00010001) {
339                 throw new IllegalStateException JavaDoc
340                     ("Loading constant primitive classes not supported below target version 1.1");
341             }
342             loadStaticField(type.toObjectType(), "TYPE", TypeDesc.forClass(Class JavaDoc.class));
343         } else {
344             if (mTarget < 0x00010005) {
345                 throw new IllegalStateException JavaDoc
346                     ("Loading constant object classes not supported below target version 1.5");
347             }
348             ConstantInfo info = mCp.addConstantClass(type);
349             mInstructions.new LoadConstantInstruction(1, info);
350         }
351     }
352
353     public void loadConstant(boolean value) {
354         loadConstant(value ? 1 : 0);
355     }
356
357     public void loadConstant(int value) {
358         if (-1 <= value && value <= 5) {
359             byte op;
360
361             switch(value) {
362             case -1:
363                 op = Opcode.ICONST_M1;
364                 break;
365             case 0:
366                 op = Opcode.ICONST_0;
367                 break;
368             case 1:
369                 op = Opcode.ICONST_1;
370                 break;
371             case 2:
372                 op = Opcode.ICONST_2;
373                 break;
374             case 3:
375                 op = Opcode.ICONST_3;
376                 break;
377             case 4:
378                 op = Opcode.ICONST_4;
379                 break;
380             case 5:
381                 op = Opcode.ICONST_5;
382                 break;
383             default:
384                 op = Opcode.NOP;
385             }
386
387             addCode(1, op);
388         } else if (-128 <= value && value <= 127) {
389             addCode(1, Opcode.BIPUSH, (byte)value);
390         } else if (-32768 <= value && value <= 32767) {
391             addCode(1, Opcode.SIPUSH, (short)value);
392         } else {
393             ConstantInfo info = mCp.addConstantInteger(value);
394             mInstructions.new LoadConstantInstruction(1, info);
395         }
396     }
397
398     public void loadConstant(long value) {
399         if (value == 0) {
400             addCode(2, Opcode.LCONST_0);
401         } else if (value == 1) {
402             addCode(2, Opcode.LCONST_1);
403         } else {
404             ConstantInfo info = mCp.addConstantLong(value);
405             mInstructions.new LoadConstantInstruction(2, info, true);
406         }
407     }
408
409     public void loadConstant(float value) {
410         if (value == 0) {
411             addCode(1, Opcode.FCONST_0);
412         } else if (value == 1) {
413             addCode(1, Opcode.FCONST_1);
414         } else if (value == 2) {
415             addCode(1, Opcode.FCONST_2);
416         } else {
417             ConstantInfo info = mCp.addConstantFloat(value);
418             mInstructions.new LoadConstantInstruction(1, info);
419         }
420     }
421
422     public void loadConstant(double value) {
423         if (value == 0) {
424             addCode(2, Opcode.DCONST_0);
425         } else if (value == 1) {
426             addCode(2, Opcode.DCONST_1);
427         } else {
428             ConstantInfo info = mCp.addConstantDouble(value);
429             mInstructions.new LoadConstantInstruction(2, info, true);
430         }
431     }
432
433     // load-local-to-stack style instructions
434

435     public void loadLocal(LocalVariable local) {
436         if (local == null) {
437             throw new IllegalArgumentException JavaDoc("No local variable specified");
438         }
439         int stackAdjust = local.getType().isDoubleWord() ? 2 : 1;
440         mInstructions.new LoadLocalInstruction(stackAdjust, local);
441     }
442
443     public void loadThis() {
444         if (mThisReference != null) {
445             loadLocal(mThisReference);
446         } else {
447             throw new IllegalStateException JavaDoc
448                 ("Attempt to load \"this\" reference in a static method");
449         }
450     }
451
452     // store-from-stack-to-local style instructions
453

454     public void storeLocal(LocalVariable local) {
455         if (local == null) {
456             throw new IllegalArgumentException JavaDoc("No local variable specified");
457         }
458         int stackAdjust = local.getType().isDoubleWord() ? -2 : -1;
459         mInstructions.new StoreLocalInstruction(stackAdjust, local);
460     }
461
462     // load-to-stack-from-array style instructions
463

464     public void loadFromArray(TypeDesc type) {
465         byte op;
466         int stackAdjust = -1;
467
468         switch (type.getTypeCode()) {
469         case TypeDesc.INT_CODE:
470             op = Opcode.IALOAD;
471             break;
472         case TypeDesc.BOOLEAN_CODE:
473         case TypeDesc.BYTE_CODE:
474             op = Opcode.BALOAD;
475             break;
476         case TypeDesc.SHORT_CODE:
477             op = Opcode.SALOAD;
478             break;
479         case TypeDesc.CHAR_CODE:
480             op = Opcode.CALOAD;
481             break;
482         case TypeDesc.FLOAT_CODE:
483             op = Opcode.FALOAD;
484             break;
485         case TypeDesc.LONG_CODE:
486             stackAdjust = 0;
487             op = Opcode.LALOAD;
488             break;
489         case TypeDesc.DOUBLE_CODE:
490             stackAdjust = 0;
491             op = Opcode.DALOAD;
492             break;
493         default:
494             op = Opcode.AALOAD;
495             break;
496         }
497
498         addCode(stackAdjust, op);
499     }
500
501     // store-to-array-from-stack style instructions
502

503     public void storeToArray(TypeDesc type) {
504         byte op;
505         int stackAdjust = -3;
506
507         switch (type.getTypeCode()) {
508         case TypeDesc.INT_CODE:
509             op = Opcode.IASTORE;
510             break;
511         case TypeDesc.BOOLEAN_CODE:
512         case TypeDesc.BYTE_CODE:
513             op = Opcode.BASTORE;
514             break;
515         case TypeDesc.SHORT_CODE:
516             op = Opcode.SASTORE;
517             break;
518         case TypeDesc.CHAR_CODE:
519             op = Opcode.CASTORE;
520             break;
521         case TypeDesc.FLOAT_CODE:
522             op = Opcode.FASTORE;
523             break;
524         case TypeDesc.LONG_CODE:
525             stackAdjust = -4;
526             op = Opcode.LASTORE;
527             break;
528         case TypeDesc.DOUBLE_CODE:
529             stackAdjust = -4;
530             op = Opcode.DASTORE;
531             break;
532         default:
533             op = Opcode.AASTORE;
534             break;
535         }
536
537         addCode(stackAdjust, op);
538     }
539
540     // load-field-to-stack style instructions
541

542     public void loadField(String JavaDoc fieldName,
543                           TypeDesc type) {
544         getfield(0, Opcode.GETFIELD, constantField(fieldName, type), type);
545     }
546
547     public void loadField(String JavaDoc className,
548                           String JavaDoc fieldName,
549                           TypeDesc type) {
550
551         getfield(0, Opcode.GETFIELD,
552                  mCp.addConstantField(className, fieldName, type),
553                  type);
554     }
555
556     public void loadField(TypeDesc classDesc,
557                           String JavaDoc fieldName,
558                           TypeDesc type) {
559
560         loadField(getClassName(classDesc), fieldName, type);
561     }
562
563     public void loadStaticField(String JavaDoc fieldName,
564                                 TypeDesc type) {
565
566         getfield(1, Opcode.GETSTATIC, constantField(fieldName, type), type);
567     }
568
569     public void loadStaticField(String JavaDoc className,
570                                 String JavaDoc fieldName,
571                                 TypeDesc type) {
572
573         getfield(1, Opcode.GETSTATIC,
574                  mCp.addConstantField(className, fieldName, type),
575                  type);
576     }
577
578     public void loadStaticField(TypeDesc classDesc,
579                                 String JavaDoc fieldName,
580                                 TypeDesc type) {
581
582         loadStaticField(getClassName(classDesc), fieldName, type);
583     }
584
585     private void getfield(int stackAdjust, byte opcode, ConstantInfo info,
586                           TypeDesc type) {
587         if (type.isDoubleWord()) {
588             stackAdjust++;
589         }
590         addCode(stackAdjust, opcode, info);
591     }
592
593     private ConstantFieldInfo constantField(String JavaDoc fieldName,
594                                             TypeDesc type) {
595         return mCp.addConstantField
596             (mClassFile.getClassName(), fieldName, type);
597     }
598
599     // store-to-field-from-stack style instructions
600

601     public void storeField(String JavaDoc fieldName,
602                            TypeDesc type) {
603
604         putfield(-1, Opcode.PUTFIELD, constantField(fieldName, type), type);
605     }
606
607     public void storeField(String JavaDoc className,
608                            String JavaDoc fieldName,
609                            TypeDesc type) {
610
611         putfield(-1, Opcode.PUTFIELD,
612                  mCp.addConstantField(className, fieldName, type),
613                  type);
614     }
615
616     public void storeField(TypeDesc classDesc,
617                            String JavaDoc fieldName,
618                            TypeDesc type) {
619
620         storeField(getClassName(classDesc), fieldName, type);
621     }
622
623     public void storeStaticField(String JavaDoc fieldName,
624                                  TypeDesc type) {
625
626         putfield(0, Opcode.PUTSTATIC, constantField(fieldName, type), type);
627     }
628
629     public void storeStaticField(String JavaDoc className,
630                                  String JavaDoc fieldName,
631                                  TypeDesc type) {
632
633         putfield(0, Opcode.PUTSTATIC,
634                  mCp.addConstantField(className, fieldName, type),
635                  type);
636     }
637
638     public void storeStaticField(TypeDesc classDesc,
639                                  String JavaDoc fieldName,
640                                  TypeDesc type) {
641
642         storeStaticField(getClassName(classDesc), fieldName, type);
643     }
644
645     private void putfield(int stackAdjust, byte opcode, ConstantInfo info,
646                           TypeDesc type) {
647         if (type.isDoubleWord()) {
648             stackAdjust -= 2;
649         } else {
650             stackAdjust--;
651         }
652         addCode(stackAdjust, opcode, info);
653     }
654
655     // return style instructions
656

657     public void returnVoid() {
658         addCode(0, Opcode.RETURN);
659     }
660
661     public void returnValue(TypeDesc type) {
662         int stackAdjust = -1;
663         byte op;
664
665         switch (type.getTypeCode()) {
666         case TypeDesc.INT_CODE:
667         case TypeDesc.BOOLEAN_CODE:
668         case TypeDesc.BYTE_CODE:
669         case TypeDesc.SHORT_CODE:
670         case TypeDesc.CHAR_CODE:
671             op = Opcode.IRETURN;
672             break;
673         case TypeDesc.FLOAT_CODE:
674             op = Opcode.FRETURN;
675             break;
676         case TypeDesc.LONG_CODE:
677             stackAdjust = -2;
678             op = Opcode.LRETURN;
679             break;
680         case TypeDesc.DOUBLE_CODE:
681             stackAdjust = -2;
682             op = Opcode.DRETURN;
683             break;
684         case TypeDesc.VOID_CODE:
685             stackAdjust = 0;
686             op = Opcode.RETURN;
687             break;
688         default:
689             op = Opcode.ARETURN;
690             break;
691         }
692
693         addCode(stackAdjust, op);
694     }
695
696     // numerical conversion style instructions
697

698     public void convert(TypeDesc fromType, TypeDesc toType) {
699         convert(fromType, toType, CONVERT_FP_NORMAL);
700     }
701
702     public void convert(TypeDesc fromType, TypeDesc toType, int fpConvertMode) {
703         if (fpConvertMode < 0 || fpConvertMode > CONVERT_FP_RAW_BITS) {
704             throw new IllegalArgumentException JavaDoc("Illegal floating point conversion mode");
705         }
706
707         if (toType == TypeDesc.OBJECT) {
708             if (fromType.isPrimitive()) {
709                 toType = fromType.toObjectType();
710             } else {
711                 return;
712             }
713         }
714
715         if (fromType == toType) {
716             return;
717         }
718
719         TypeDesc fromPrimitiveType = fromType.toPrimitiveType();
720         if (fromPrimitiveType == null) {
721             if (!toType.isPrimitive()) {
722                 Class JavaDoc fromClass = fromType.toClass();
723                 if (fromClass != null) {
724                     Class JavaDoc toClass = toType.toClass();
725                     if (toClass != null && toClass.isAssignableFrom(fromClass)) {
726                         return;
727                     }
728                 }
729             }
730             throw invalidConversion(fromType, toType);
731         }
732         int fromTypeCode = fromPrimitiveType.getTypeCode();
733
734         if (toType.toClass() == Number JavaDoc.class) {
735             switch (fromTypeCode) {
736             case TypeDesc.INT_CODE:
737             case TypeDesc.BYTE_CODE:
738             case TypeDesc.SHORT_CODE:
739             case TypeDesc.LONG_CODE:
740             case TypeDesc.FLOAT_CODE:
741             case TypeDesc.DOUBLE_CODE:
742                 if (fromType.isPrimitive()) {
743                     toType = fromType.toObjectType();
744                 } else {
745                     return;
746                 }
747             }
748         }
749
750         TypeDesc toPrimitiveType = toType.toPrimitiveType();
751         if (toPrimitiveType == null) {
752             throw invalidConversion(fromType, toType);
753         }
754         int toTypeCode = toPrimitiveType.getTypeCode();
755
756         // Location is set at end, after doConversion.
757
Label end = createLabel();
758
759         doConversion: {
760             int stackAdjust = 0;
761             byte op;
762             
763             switch (fromTypeCode) {
764             case TypeDesc.INT_CODE:
765             case TypeDesc.BYTE_CODE:
766             case TypeDesc.SHORT_CODE:
767             case TypeDesc.CHAR_CODE:
768             case TypeDesc.BOOLEAN_CODE:
769                 switch (toTypeCode) {
770                 case TypeDesc.BYTE_CODE:
771                     op = (fromTypeCode == TypeDesc.BYTE_CODE) ?
772                         Opcode.NOP : Opcode.I2B;
773                     break;
774                 case TypeDesc.SHORT_CODE:
775                     op = (fromTypeCode == TypeDesc.SHORT_CODE) ?
776                         Opcode.NOP : Opcode.I2S;
777                     break;
778                 case TypeDesc.CHAR_CODE:
779                     op = (fromTypeCode == TypeDesc.CHAR_CODE) ?
780                         Opcode.NOP : Opcode.I2C;
781                     break;
782                 case TypeDesc.FLOAT_CODE:
783                     op = Opcode.I2F;
784                     break;
785                 case TypeDesc.LONG_CODE:
786                     stackAdjust = 1;
787                     op = Opcode.I2L;
788                     break;
789                 case TypeDesc.DOUBLE_CODE:
790                     stackAdjust = 1;
791                     op = Opcode.I2D;
792                     break;
793                 case TypeDesc.INT_CODE:
794                     op = Opcode.NOP;
795                     break;
796                 case TypeDesc.BOOLEAN_CODE:
797                     if (!fromType.isPrimitive()) {
798                         if (!toType.isPrimitive()) {
799                             nullConvert(end);
800                         }
801                         unbox(fromType, fromPrimitiveType);
802                     }
803                     toBoolean(!toType.isPrimitive());
804                     break doConversion;
805                 default:
806                     throw invalidConversion(fromType, toType);
807                 }
808                 break;
809                 
810             case TypeDesc.LONG_CODE:
811                 switch (toTypeCode) {
812                 case TypeDesc.INT_CODE:
813                     stackAdjust = -1;
814                     op = Opcode.L2I;
815                     break;
816                 case TypeDesc.FLOAT_CODE:
817                     stackAdjust = -1;
818                     op = Opcode.L2F;
819                     break;
820                 case TypeDesc.DOUBLE_CODE:
821                     op = Opcode.L2D;
822                     break;
823                 case TypeDesc.BYTE_CODE:
824                 case TypeDesc.CHAR_CODE:
825                 case TypeDesc.SHORT_CODE:
826                     addCode(-1, Opcode.L2I);
827                     convert(TypeDesc.INT, toPrimitiveType);
828                     // fall through
829
case TypeDesc.LONG_CODE:
830                     op = Opcode.NOP;
831                     break;
832                 case TypeDesc.BOOLEAN_CODE:
833                     if (!fromType.isPrimitive()) {
834                         if (!toType.isPrimitive()) {
835                             nullConvert(end);
836                         }
837                         unbox(fromType, fromPrimitiveType);
838                     }
839                     loadConstant(0L);
840                     math(Opcode.LCMP);
841                     toBoolean(!toType.isPrimitive());
842                     break doConversion;
843                 default:
844                     throw invalidConversion(fromType, toType);
845                 }
846                 break;
847                 
848             case TypeDesc.FLOAT_CODE:
849                 switch (toTypeCode) {
850                 case TypeDesc.INT_CODE:
851                     op = Opcode.F2I;
852                     break;
853                 case TypeDesc.LONG_CODE:
854                     stackAdjust = 1;
855                     op = Opcode.F2L;
856                     break;
857                 case TypeDesc.DOUBLE_CODE:
858                     stackAdjust = 1;
859                     op = Opcode.F2D;
860                     break;
861                 case TypeDesc.BYTE_CODE:
862                 case TypeDesc.CHAR_CODE:
863                 case TypeDesc.SHORT_CODE:
864                     addCode(0, Opcode.F2I);
865                     convert(TypeDesc.INT, toPrimitiveType);
866                     // fall through
867
case TypeDesc.FLOAT_CODE:
868                     op = Opcode.NOP;
869                     break;
870                 case TypeDesc.BOOLEAN_CODE:
871                     if (!fromType.isPrimitive()) {
872                         if (!toType.isPrimitive()) {
873                             nullConvert(end);
874                         }
875                         unbox(fromType, fromPrimitiveType);
876                     }
877                     loadConstant(0.0f);
878                     math(Opcode.FCMPG);
879                     toBoolean(!toType.isPrimitive());
880                     break doConversion;
881                 default:
882                     throw invalidConversion(fromType, toType);
883                 }
884                 break;
885                 
886             case TypeDesc.DOUBLE_CODE:
887                 switch (toTypeCode) {
888                 case TypeDesc.INT_CODE:
889                     stackAdjust = -1;
890                     op = Opcode.D2I;
891                     break;
892                 case TypeDesc.FLOAT_CODE:
893                     stackAdjust = -1;
894                     op = Opcode.D2F;
895                     break;
896                 case TypeDesc.LONG_CODE:
897                     op = Opcode.D2L;
898                     break;
899                 case TypeDesc.BYTE_CODE:
900                 case TypeDesc.CHAR_CODE:
901                 case TypeDesc.SHORT_CODE:
902                     addCode(-1, Opcode.D2I);
903                     convert(TypeDesc.INT, toPrimitiveType);
904                     // fall through
905
case TypeDesc.DOUBLE_CODE:
906                     op = Opcode.NOP;
907                     break;
908                 case TypeDesc.BOOLEAN_CODE:
909                     if (!fromType.isPrimitive()) {
910                         if (!toType.isPrimitive()) {
911                             nullConvert(end);
912                         }
913                         unbox(fromType, fromPrimitiveType);
914                     }
915                     loadConstant(0.0d);
916                     math(Opcode.DCMPG);
917                     toBoolean(!toType.isPrimitive());
918                     break doConversion;
919                 default:
920                     throw invalidConversion(fromType, toType);
921                 }
922                 break;
923                 
924             default:
925                 throw invalidConversion(fromType, toType);
926             }
927             
928             if (!fromType.isPrimitive()) {
929                 if (!toType.isPrimitive()) {
930                     nullConvert(end);
931                 }
932                 unbox(fromType, fromPrimitiveType);
933             }
934
935             if (toType.isPrimitive()) {
936                 if (op != Opcode.NOP) {
937                     convertPrimitive(stackAdjust, op, fpConvertMode);
938                 }
939             } else {
940                 if (op == Opcode.NOP) {
941                     prebox(toPrimitiveType, toType);
942                 } else if (!fromPrimitiveType.isDoubleWord() &&
943                            toPrimitiveType.isDoubleWord()) {
944                     // Slight optimization here. Perform prebox on single word value,
945
// depending on what conversion is being applied.
946
prebox(fromPrimitiveType, toType);
947                     convertPrimitive(stackAdjust, op, fpConvertMode);
948                 } else {
949                     convertPrimitive(stackAdjust, op, fpConvertMode);
950                     prebox(toPrimitiveType, toType);
951                 }
952                 box(toPrimitiveType, toType);
953             }
954         }
955
956         end.setLocation();
957     }
958
959     /**
960      * @param from must be an object type
961      * @param to must be a primitive type
962      */

963     private void unbox(TypeDesc from, TypeDesc to) {
964         String JavaDoc methodName;
965
966         switch (to.getTypeCode()) {
967         case TypeDesc.BOOLEAN_CODE:
968             methodName = "booleanValue";
969             break;
970         case TypeDesc.CHAR_CODE:
971             methodName = "charValue";
972             break;
973         case TypeDesc.FLOAT_CODE:
974             methodName = "floatValue";
975             break;
976         case TypeDesc.DOUBLE_CODE:
977             methodName = "doubleValue";
978             break;
979         case TypeDesc.BYTE_CODE:
980             methodName = "byteValue";
981             break;
982         case TypeDesc.SHORT_CODE:
983             methodName = "shortValue";
984             break;
985         case TypeDesc.INT_CODE:
986             methodName = "intValue";
987             break;
988         case TypeDesc.LONG_CODE:
989             methodName = "longValue";
990             break;
991         default:
992             return;
993         }
994
995         invokeVirtual(from.getRootName(), methodName, to, null);
996     }
997
998     /**
999      * @param from must be a primitive type
1000     * @param to must be an object type
1001     */

1002    private void prebox(TypeDesc from, TypeDesc to) {
1003        if (mTarget >= 0x00010005) {
1004            // No need to prebox since static valueOf method can be called
1005
// instead.
1006
return;
1007        }
1008
1009        // Wouldn't it be cool if I could walk backwards in the instruction
1010
// list and insert the new-dup pair before the value to box was even
1011
// put on the stack?
1012

1013        switch (from.getTypeCode()) {
1014        default:
1015            break;
1016        case TypeDesc.BOOLEAN_CODE:
1017            if (to.toPrimitiveType().getTypeCode() == TypeDesc.BOOLEAN_CODE) {
1018                break;
1019            }
1020            // fall through
1021
case TypeDesc.CHAR_CODE:
1022        case TypeDesc.FLOAT_CODE:
1023        case TypeDesc.BYTE_CODE:
1024        case TypeDesc.SHORT_CODE:
1025        case TypeDesc.INT_CODE:
1026            newObject(to);
1027            dupX1();
1028            swap();
1029            break;
1030        case TypeDesc.DOUBLE_CODE:
1031        case TypeDesc.LONG_CODE:
1032            newObject(to);
1033            dupX2();
1034            dupX2();
1035            pop();
1036            break;
1037        }
1038    }
1039
1040    /**
1041     * @param from must be a primitive type
1042     * @param to must be an object type
1043     */

1044    private void box(TypeDesc from, TypeDesc to) {
1045        if (mTarget >= 0x00010005) {
1046            // Call the new valueOf method.
1047
invokeStatic(to.getRootName(), "valueOf", to, new TypeDesc[] {from});
1048            return;
1049        }
1050
1051        switch (from.getTypeCode()) {
1052        case TypeDesc.BOOLEAN_CODE:
1053            toBoolean(true);
1054            break;
1055        case TypeDesc.CHAR_CODE:
1056        case TypeDesc.FLOAT_CODE:
1057        case TypeDesc.BYTE_CODE:
1058        case TypeDesc.SHORT_CODE:
1059        case TypeDesc.INT_CODE:
1060        case TypeDesc.DOUBLE_CODE:
1061        case TypeDesc.LONG_CODE:
1062            invokeConstructor(to.getRootName(), new TypeDesc[]{from});
1063            break;
1064        }
1065    }
1066
1067    // Converts an int on the stack to a boolean.
1068
private void toBoolean(boolean box) {
1069        if (box && mTarget >= 0x00010004) {
1070            // Call the new valueOf method.
1071
invokeStatic("java.lang.Boolean", "valueOf",
1072                         TypeDesc.BOOLEAN.toObjectType(),
1073                         new TypeDesc[] {TypeDesc.BOOLEAN});
1074            return;
1075        }
1076
1077        Label nonZero = createLabel();
1078        Label done = createLabel();
1079        ifZeroComparisonBranch(nonZero, "!=");
1080        if (box) {
1081            TypeDesc newType = TypeDesc.BOOLEAN.toObjectType();
1082            loadStaticField(newType.getRootName(), "FALSE", newType);
1083            branch(done);
1084            nonZero.setLocation();
1085            loadStaticField(newType.getRootName(), "TRUE", newType);
1086        } else {
1087            loadConstant(false);
1088            branch(done);
1089            nonZero.setLocation();
1090            loadConstant(true);
1091        }
1092        done.setLocation();
1093    }
1094
1095    private void convertPrimitive(int stackAdjust, byte op, int fpConvertMode) {
1096        if (fpConvertMode != CONVERT_FP_NORMAL) {
1097            switch (op) {
1098            case Opcode.I2F:
1099                invokeStatic("java.lang.Float", "intBitsToFloat", TypeDesc.FLOAT,
1100                             new TypeDesc[] {TypeDesc.INT});
1101                return;
1102
1103            case Opcode.L2D:
1104                invokeStatic("java.lang.Double", "longBitsToDouble", TypeDesc.DOUBLE,
1105                             new TypeDesc[] {TypeDesc.LONG});
1106                return;
1107
1108            case Opcode.F2I:
1109                if (fpConvertMode == CONVERT_FP_RAW_BITS) {
1110                    invokeStatic("java.lang.Float", "floatToRawIntBits", TypeDesc.INT,
1111                                 new TypeDesc[] {TypeDesc.FLOAT});
1112                } else {
1113                    invokeStatic("java.lang.Float", "floatToIntBits", TypeDesc.INT,
1114                                 new TypeDesc[] {TypeDesc.FLOAT});
1115                }
1116                return;
1117
1118            case Opcode.D2L:
1119                if (fpConvertMode == CONVERT_FP_RAW_BITS) {
1120                    invokeStatic("java.lang.Double", "doubleToRawLongBits", TypeDesc.LONG,
1121                                 new TypeDesc[] {TypeDesc.DOUBLE});
1122                } else {
1123                    invokeStatic("java.lang.Double", "doubleToLongBits", TypeDesc.LONG,
1124                                 new TypeDesc[] {TypeDesc.DOUBLE});
1125                }
1126                return;
1127            }
1128        }
1129
1130        addCode(stackAdjust, op);
1131    }
1132
1133    // Check if from object is null. If so, no need to convert, and don't throw
1134
// a NullPointerException. Assumes that from type and to type are objects.
1135
private void nullConvert(Label end) {
1136        LocalVariable temp = createLocalVariable("temp", TypeDesc.OBJECT);
1137        storeLocal(temp);
1138        loadLocal(temp);
1139        Label notNull = createLabel();
1140        ifNullBranch(notNull, false);
1141        loadNull();
1142        branch(end);
1143        notNull.setLocation();
1144        loadLocal(temp);
1145    }
1146
1147    private IllegalArgumentException JavaDoc invalidConversion
1148        (TypeDesc from, TypeDesc to)
1149    {
1150        throw new IllegalArgumentException JavaDoc
1151            ("Invalid conversion: " + from.getFullName() + " to " +
1152             to.getFullName());
1153    }
1154
1155    // invocation style instructions
1156

1157    public void invokeVirtual(String JavaDoc methodName,
1158                              TypeDesc ret,
1159                              TypeDesc[] params) {
1160
1161        ConstantInfo info = mCp.addConstantMethod
1162            (mClassFile.getClassName(), methodName, ret, params);
1163
1164        int stackAdjust = returnSize(ret) - 1;
1165        if (params != null) {
1166            stackAdjust -= argSize(params);
1167        }
1168
1169        addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1170    }
1171
1172    public void invokeVirtual(String JavaDoc className,
1173                              String JavaDoc methodName,
1174                              TypeDesc ret,
1175                              TypeDesc[] params) {
1176        ConstantInfo info =
1177            mCp.addConstantMethod(className, methodName, ret, params);
1178
1179        int stackAdjust = returnSize(ret) - 1;
1180        if (params != null) {
1181            stackAdjust -= argSize(params);
1182        }
1183
1184        addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1185    }
1186
1187    public void invokeVirtual(TypeDesc classDesc,
1188                              String JavaDoc methodName,
1189                              TypeDesc ret,
1190                              TypeDesc[] params) {
1191
1192        invokeVirtual(getClassName(classDesc), methodName, ret, params);
1193    }
1194
1195    public void invokeStatic(String JavaDoc methodName,
1196                             TypeDesc ret,
1197                             TypeDesc[] params) {
1198        ConstantInfo info = mCp.addConstantMethod
1199            (mClassFile.getClassName(), methodName, ret, params);
1200
1201        int stackAdjust = returnSize(ret) - 0;
1202        if (params != null) {
1203            stackAdjust -= argSize(params);
1204        }
1205
1206        addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1207    }
1208
1209    public void invokeStatic(String JavaDoc className,
1210                             String JavaDoc methodName,
1211                             TypeDesc ret,
1212                             TypeDesc[] params) {
1213        ConstantInfo info =
1214            mCp.addConstantMethod(className, methodName, ret, params);
1215
1216        int stackAdjust = returnSize(ret) - 0;
1217        if (params != null) {
1218            stackAdjust -= argSize(params);
1219        }
1220
1221        addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1222    }
1223
1224    public void invokeStatic(TypeDesc classDesc,
1225                             String JavaDoc methodName,
1226                             TypeDesc ret,
1227                             TypeDesc[] params) {
1228
1229        invokeStatic(getClassName(classDesc), methodName, ret, params);
1230    }
1231
1232    public void invokeInterface(String JavaDoc className,
1233                                String JavaDoc methodName,
1234                                TypeDesc ret,
1235                                TypeDesc[] params) {
1236
1237        ConstantInfo info =
1238            mCp.addConstantInterfaceMethod(className, methodName, ret, params);
1239
1240        int paramCount = 1;
1241        if (params != null) {
1242            paramCount += argSize(params);
1243        }
1244
1245        int stackAdjust = returnSize(ret) - paramCount;
1246
1247        byte[] bytes = new byte[5];
1248
1249        bytes[0] = Opcode.INVOKEINTERFACE;
1250        //bytes[1] = (byte)0;
1251
//bytes[2] = (byte)0;
1252
bytes[3] = (byte)paramCount;
1253        //bytes[4] = (byte)0;
1254

1255        mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info);
1256    }
1257
1258    public void invokeInterface(TypeDesc classDesc,
1259                                String JavaDoc methodName,
1260                                TypeDesc ret,
1261                                TypeDesc[] params) {
1262
1263        invokeInterface(getClassName(classDesc), methodName, ret, params);
1264    }
1265
1266    public void invokePrivate(String JavaDoc methodName,
1267                              TypeDesc ret,
1268                              TypeDesc[] params) {
1269        ConstantInfo info = mCp.addConstantMethod
1270            (mClassFile.getClassName(), methodName, ret, params);
1271
1272        int stackAdjust = returnSize(ret) - 1;
1273        if (params != null) {
1274            stackAdjust -= argSize(params);
1275        }
1276
1277        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1278    }
1279
1280    public void invokeSuper(String JavaDoc superClassName,
1281                            String JavaDoc methodName,
1282                            TypeDesc ret,
1283                            TypeDesc[] params) {
1284        ConstantInfo info =
1285            mCp.addConstantMethod(superClassName, methodName, ret, params);
1286
1287        int stackAdjust = returnSize(ret) - 1;
1288        if (params != null) {
1289            stackAdjust -= argSize(params);
1290        }
1291
1292        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1293    }
1294
1295    public void invokeSuper(TypeDesc superClassDesc,
1296                            String JavaDoc methodName,
1297                            TypeDesc ret,
1298                            TypeDesc[] params) {
1299
1300        invokeSuper(getClassName(superClassDesc), methodName, ret, params);
1301    }
1302
1303    public void invokeConstructor(TypeDesc[] params) {
1304        ConstantInfo info =
1305            mCp.addConstantConstructor(mClassFile.getClassName(), params);
1306
1307        int stackAdjust = -1;
1308        if (params != null) {
1309            stackAdjust -= argSize(params);
1310        }
1311
1312        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1313    }
1314
1315    public void invokeConstructor(String JavaDoc className, TypeDesc[] params) {
1316        ConstantInfo info = mCp.addConstantConstructor(className, params);
1317
1318        int stackAdjust = -1;
1319        if (params != null) {
1320            stackAdjust -= argSize(params);
1321        }
1322
1323        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1324    }
1325
1326    public void invokeConstructor(TypeDesc classDesc, TypeDesc[] params) {
1327        invokeConstructor(getClassName(classDesc), params);
1328    }
1329
1330    public void invokeSuperConstructor(TypeDesc[] params) {
1331        invokeConstructor(mClassFile.getSuperClassName(), params);
1332    }
1333
1334    private int returnSize(TypeDesc ret) {
1335        if (ret == null || ret == TypeDesc.VOID) {
1336            return 0;
1337        }
1338        if (ret.isDoubleWord()) {
1339            return 2;
1340        }
1341        return 1;
1342    }
1343
1344    private int argSize(TypeDesc[] params) {
1345        int size = 0;
1346        if (params != null) {
1347            for (int i=0; i<params.length; i++) {
1348                size += returnSize(params[i]);
1349            }
1350        }
1351        return size;
1352    }
1353
1354    // creation style instructions
1355

1356    public void newObject(TypeDesc type) {
1357        if (type.isArray()) {
1358            newObject(type, 1);
1359        } else {
1360            ConstantInfo info = mCp.addConstantClass(type);
1361            addCode(1, Opcode.NEW, info);
1362        }
1363    }
1364
1365    public void newObject(TypeDesc type, int dimensions) {
1366        if (dimensions <= 0) {
1367            // If type refers to an array, then this code is bogus.
1368
ConstantInfo info = mCp.addConstantClass(type);
1369            addCode(1, Opcode.NEW, info);
1370            return;
1371        }
1372
1373        TypeDesc componentType = type.getComponentType();
1374
1375        if (dimensions == 1) {
1376            if (componentType.isPrimitive()) {
1377                addCode(0, Opcode.NEWARRAY, (byte)componentType.getTypeCode());
1378                return;
1379            }
1380            addCode(0, Opcode.ANEWARRAY, mCp.addConstantClass(componentType));
1381            return;
1382        }
1383
1384        int stackAdjust = -(dimensions - 1);
1385        ConstantInfo info = mCp.addConstantClass(type);
1386        byte[] bytes = new byte[4];
1387
1388        bytes[0] = Opcode.MULTIANEWARRAY;
1389        //bytes[1] = (byte)0;
1390
//bytes[2] = (byte)0;
1391
bytes[3] = (byte)dimensions;
1392        
1393        mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info);
1394    }
1395
1396    // stack operation style instructions
1397

1398    public void dup() {
1399        addCode(1, Opcode.DUP);
1400    }
1401
1402    public void dupX1() {
1403        addCode(1, Opcode.DUP_X1);
1404    }
1405
1406    public void dupX2() {
1407        addCode(1, Opcode.DUP_X2);
1408    }
1409
1410    public void dup2() {
1411        addCode(2, Opcode.DUP2);
1412    }
1413
1414    public void dup2X1() {
1415        addCode(2, Opcode.DUP2_X1);
1416    }
1417
1418    public void dup2X2() {
1419        addCode(2, Opcode.DUP2_X2);
1420    }
1421
1422    public void pop() {
1423        addCode(-1, Opcode.POP);
1424    }
1425
1426    public void pop2() {
1427        addCode(-2, Opcode.POP2);
1428    }
1429
1430    public void swap() {
1431        addCode(0, Opcode.SWAP);
1432    }
1433
1434    public void swap2() {
1435        dup2X2();
1436        pop2();
1437    }
1438
1439    // flow control instructions
1440

1441    private void branch(int stackAdjust, Location location, byte opcode) {
1442        mInstructions.new BranchInstruction(stackAdjust, opcode, location);
1443    }
1444
1445    public void branch(Location location) {
1446        branch(0, location, Opcode.GOTO);
1447    }
1448
1449    public void ifNullBranch(Location location, boolean choice) {
1450        branch(-1, location, choice ? Opcode.IFNULL : Opcode.IFNONNULL);
1451    }
1452
1453    public void ifEqualBranch(Location location, boolean choice) {
1454        branch(-2, location, choice ? Opcode.IF_ACMPEQ : Opcode.IF_ACMPNE);
1455    }
1456
1457    public void ifZeroComparisonBranch(Location location, String JavaDoc choice)
1458        throws IllegalArgumentException JavaDoc {
1459
1460        choice = choice.intern();
1461
1462        byte opcode;
1463        if (choice == "==") {
1464            opcode = Opcode.IFEQ;
1465        } else if (choice == "!=") {
1466            opcode = Opcode.IFNE;
1467        } else if (choice == "<") {
1468            opcode = Opcode.IFLT;
1469        } else if (choice == ">=") {
1470            opcode = Opcode.IFGE;
1471        } else if (choice == ">") {
1472            opcode = Opcode.IFGT;
1473        } else if (choice == "<=") {
1474            opcode = Opcode.IFLE;
1475        } else {
1476            throw new IllegalArgumentException JavaDoc
1477                ("Invalid comparision choice: " + choice);
1478        }
1479        
1480        branch(-1, location, opcode);
1481    }
1482
1483    public void ifComparisonBranch(Location location, String JavaDoc choice)
1484        throws IllegalArgumentException JavaDoc {
1485
1486        choice = choice.intern();
1487
1488        byte opcode;
1489        if (choice == "==") {
1490            opcode = Opcode.IF_ICMPEQ;
1491        } else if (choice == "!=") {
1492            opcode = Opcode.IF_ICMPNE;
1493        } else if (choice == "<") {
1494            opcode = Opcode.IF_ICMPLT;
1495        } else if (choice == ">=") {
1496            opcode = Opcode.IF_ICMPGE;
1497        } else if (choice == ">") {
1498            opcode = Opcode.IF_ICMPGT;
1499        } else if (choice == "<=") {
1500            opcode = Opcode.IF_ICMPLE;
1501        } else {
1502            throw new IllegalArgumentException JavaDoc
1503                ("Invalid comparision choice: " + choice);
1504        }
1505
1506        branch(-2, location, opcode);
1507    }
1508
1509    public void switchBranch(int[] cases,
1510                             Location[] locations, Location defaultLocation) {
1511
1512        mInstructions.new SwitchInstruction(cases, locations, defaultLocation);
1513    }
1514
1515    public void jsr(Location location) {
1516        // Adjust the stack by one to make room for the return address.
1517
branch(1, location, Opcode.JSR);
1518    }
1519
1520    public void ret(LocalVariable local) {
1521        if (local == null) {
1522            throw new IllegalArgumentException JavaDoc("No local variable specified");
1523        }
1524
1525        mInstructions.new RetInstruction(local);
1526    }
1527
1528    // math instructions
1529

1530    public void math(byte opcode) {
1531        int stackAdjust;
1532        
1533        switch(opcode) {
1534        case Opcode.INEG:
1535        case Opcode.LNEG:
1536        case Opcode.FNEG:
1537        case Opcode.DNEG:
1538            stackAdjust = 0;
1539            break;
1540        case Opcode.IADD:
1541        case Opcode.ISUB:
1542        case Opcode.IMUL:
1543        case Opcode.IDIV:
1544        case Opcode.IREM:
1545        case Opcode.IAND:
1546        case Opcode.IOR:
1547        case Opcode.IXOR:
1548        case Opcode.ISHL:
1549        case Opcode.ISHR:
1550        case Opcode.IUSHR:
1551        case Opcode.FADD:
1552        case Opcode.FSUB:
1553        case Opcode.FMUL:
1554        case Opcode.FDIV:
1555        case Opcode.FREM:
1556        case Opcode.FCMPG:
1557        case Opcode.FCMPL:
1558        case Opcode.LSHL:
1559        case Opcode.LSHR:
1560        case Opcode.LUSHR:
1561            stackAdjust = -1;
1562            break;
1563        case Opcode.LADD:
1564        case Opcode.LSUB:
1565        case Opcode.LMUL:
1566        case Opcode.LDIV:
1567        case Opcode.LREM:
1568        case Opcode.LAND:
1569        case Opcode.LOR:
1570        case Opcode.LXOR:
1571        case Opcode.DADD:
1572        case Opcode.DSUB:
1573        case Opcode.DMUL:
1574        case Opcode.DDIV:
1575        case Opcode.DREM:
1576            stackAdjust = -2;
1577            break;
1578        case Opcode.LCMP:
1579        case Opcode.DCMPG:
1580        case Opcode.DCMPL:
1581            stackAdjust = -3;
1582            break;
1583        default:
1584            throw new IllegalArgumentException JavaDoc
1585                ("Not a math opcode: " + Opcode.getMnemonic(opcode));
1586        }
1587
1588        addCode(stackAdjust, opcode);
1589    }
1590
1591    // miscellaneous instructions
1592

1593    public void arrayLength() {
1594        addCode(0, Opcode.ARRAYLENGTH);
1595    }
1596
1597    public void throwObject() {
1598        addCode(-1, Opcode.ATHROW);
1599    }
1600
1601    public void checkCast(TypeDesc type) {
1602        ConstantInfo info = mCp.addConstantClass(type);
1603        addCode(0, Opcode.CHECKCAST, info);
1604    }
1605
1606    public void instanceOf(TypeDesc type) {
1607        ConstantInfo info = mCp.addConstantClass(type);
1608        addCode(0, Opcode.INSTANCEOF, info);
1609    }
1610
1611    public void integerIncrement(LocalVariable local, int amount) {
1612        if (local == null) {
1613            throw new IllegalArgumentException JavaDoc("No local variable specified");
1614        }
1615
1616        if (-32768 <= amount && amount <= 32767) {
1617            mInstructions.new ShortIncrementInstruction(local, (short)amount);
1618        } else {
1619            // Amount can't possibly fit in a 16-bit value, so use regular
1620
// instructions instead.
1621

1622            loadLocal(local);
1623            loadConstant(amount);
1624            math(Opcode.IADD);
1625            storeLocal(local);
1626        }
1627    }
1628
1629    public void monitorEnter() {
1630        addCode(-1, Opcode.MONITORENTER);
1631    }
1632
1633    public void monitorExit() {
1634        addCode(-1, Opcode.MONITOREXIT);
1635    }
1636
1637    public void nop() {
1638        addCode(0, Opcode.NOP);
1639    }
1640
1641    public void breakpoint() {
1642        addCode(0, Opcode.BREAKPOINT);
1643    }
1644}
1645
Popular Tags