KickJava   Java API By Example, From Geeks To Geeks.

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


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.lang.reflect.*;
56
57 /******************************************************************************
58  * This class is used as an aid in generating code for a method.
59  * It controls the max stack, local variable allocation, labels and bytecode.
60  *
61  * @author Brian S O'Neill
62  * @version
63  * <!--$$Revision:--> 27 <!-- $-->, <!--$$JustDate:--> 01/05/14 <!-- $-->
64  */

65 public class CodeBuilder implements CodeBuffer, CodeAssembler {
66     private CodeAttr mCodeAttr;
67     private ClassFile mClassFile;
68     private ConstantPool mCp;
69
70     private InstructionList mInstructions = new InstructionList();
71
72     private LocalVariable mThisReference;
73     private LocalVariable[] mParameters;
74
75     private boolean mSaveLineNumberInfo;
76     private boolean mSaveLocalVariableInfo;
77
78     /**
79      * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
80      * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
81      */

82     public CodeBuilder(MethodInfo info) {
83         this(info, true, false);
84     }
85
86     /**
87      * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
88      * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
89      *
90      * @param saveLineNumberInfo When set false, all calls to mapLineNumber
91      * are ignored. By default, this value is true.
92      *
93      * @param saveLocalVariableInfo When set true, all local variable
94      * usage information is saved in the ClassFile. By default, this value
95      * is false.
96      *
97      * @see #mapLineNumber
98      */

99     public CodeBuilder(MethodInfo info, boolean saveLineNumberInfo,
100                        boolean saveLocalVariableInfo) {
101         mCodeAttr = info.getCodeAttr();
102         mClassFile = info.getClassFile();
103         mCp = mClassFile.getConstantPool();
104
105         mCodeAttr.setCodeBuffer(this);
106
107         mSaveLineNumberInfo = saveLineNumberInfo;
108         mSaveLocalVariableInfo = saveLocalVariableInfo;
109
110         // Create LocalVariable references for "this" reference and other
111
// passed in parameters.
112

113         LocalVariable localVar;
114         int varNum = 0;
115
116         if (!info.getAccessFlags().isStatic()) {
117             localVar = mInstructions.createLocalParameter
118                 ("this", mClassFile.getType(), varNum++);
119             mThisReference = localVar;
120
121             if (saveLocalVariableInfo) {
122                 mCodeAttr.localVariableUse(localVar);
123             }
124         }
125
126         TypeDescriptor[] paramTypes =
127             info.getMethodDescriptor().getParameterTypes();
128         int paramSize = paramTypes.length;
129
130         mParameters = new LocalVariable[paramSize];
131
132         for (int i = 0; i<paramTypes.length; i++) {
133             localVar = mInstructions.createLocalParameter
134                 (null, paramTypes[i], varNum);
135             varNum += (localVar.isDoubleWord() ? 2 : 1);
136             mParameters[i] = localVar;
137
138             if (saveLocalVariableInfo) {
139                 mCodeAttr.localVariableUse(localVar);
140             }
141         }
142     }
143
144     public int getMaxStackDepth() {
145         return mInstructions.getMaxStackDepth();
146     }
147
148     public int getMaxLocals() {
149         return mInstructions.getMaxLocals();
150     }
151
152     public byte[] getByteCodes() {
153         return mInstructions.getByteCodes();
154     }
155
156     public ExceptionHandler[] getExceptionHandlers() {
157         return mInstructions.getExceptionHandlers();
158     }
159
160     private void addCode(int stackAdjust, byte opcode) {
161         mInstructions.new CodeInstruction(stackAdjust, new byte[] {opcode});
162     }
163
164     private void addCode(int stackAdjust, byte opcode, byte operand) {
165         mInstructions.new CodeInstruction
166             (stackAdjust, new byte[] {opcode, operand});
167     }
168
169     private void addCode(int stackAdjust, byte opcode, short operand) {
170         mInstructions.new CodeInstruction
171             (stackAdjust,
172              new byte[] {opcode, (byte)(operand >> 8), (byte)operand});
173     }
174
175     private void addCode(int stackAdjust, byte opcode, int operand) {
176         byte[] bytes = new byte[5];
177
178         bytes[0] = opcode;
179         bytes[1] = (byte)(operand >> 24);
180         bytes[2] = (byte)(operand >> 16);
181         bytes[3] = (byte)(operand >> 8);
182         bytes[4] = (byte)operand;
183
184         mInstructions.new CodeInstruction(stackAdjust, bytes);
185     }
186
187     private void addCode(int stackAdjust, byte opcode, ConstantInfo info) {
188         // The zeros get filled in later, when the ConstantInfo index
189
// is resolved.
190
mInstructions.new ConstantOperandInstruction
191             (stackAdjust,
192              new byte[] {opcode, (byte)0, (byte)0}, info);
193     }
194
195     /**
196      * Returns LocalVariable references for all the parameters passed into
197      * the method being assembled, not including any "this" reference.
198      * Returns a zero-length array if there are no passed in parameters.
199      *
200      * <p>The names of the LocalVariables returned by this method are initially
201      * set to null. It is encouraged that a name be provided.
202      */

203     public LocalVariable[] getParameters() {
204         return (LocalVariable[])mParameters.clone();
205     }
206
207     /**
208      * Creates a LocalVariable reference from a name and type. Although name
209      * is optional, it is encouraged that a name be provided. Names do not
210      * need to be unique.
211      *
212      * @param name Optional name for the LocalVariable.
213      * @param type The type of data that the requested LocalVariable can
214      * store.
215      */

216     public LocalVariable createLocalVariable(String JavaDoc name,
217                                              TypeDescriptor type) {
218         LocalVariable localVar = mInstructions.createLocalVariable(name, type);
219
220         if (mSaveLocalVariableInfo) {
221             mCodeAttr.localVariableUse(localVar);
222         }
223
224         return localVar;
225     }
226
227     /**
228      * Creates a label, whose location must be set. To create a label and
229      * locate it here, the following example demonstrates how the call to
230      * setLocation can be chained:
231      *
232      * <pre>
233      * CodeBuilder builder;
234      * ...
235      * Label label = builder.createLabel().setLocation();
236      * </pre>
237      *
238      * @see Label#setLocation
239      */

240     public Label createLabel() {
241         return mInstructions.new LabelInstruction();
242     }
243
244     /**
245      * Sets up an exception handler located here, the location of the next
246      * code to be generated.
247      *
248      * @param startLocation Location or label at the start of the section of
249      * code to be wrapped by an exception handler.
250      * @param endLocation Location or label directly after the end of the
251      * section of code.
252      * @param catchClassName The name of the type of exception to be caught;
253      * if null, then catch every object.
254      */

255     public void exceptionHandler(Location startLocation,
256                                  Location endLocation,
257                                  String JavaDoc catchClassName) {
258         Location catchLocation = createLabel().setLocation();
259
260         ConstantClassInfo catchClass;
261         if (catchClassName == null) {
262             catchClass = null;
263         }
264         else {
265             catchClass = ConstantClassInfo.make(mCp, catchClassName);
266         }
267
268         ExceptionHandler handler =
269             new ExceptionHandler(startLocation, endLocation,
270                                  catchLocation, catchClass);
271
272         mInstructions.addExceptionHandler(handler);
273     }
274     
275     /**
276      * Map the location of the next code to be generated to a line number
277      * in source code. This enables line numbers in a stack trace from the
278      * generated code.
279      */

280     public void mapLineNumber(int lineNumber) {
281         if (mSaveLineNumberInfo) {
282             mCodeAttr.mapLineNumber(createLabel().setLocation(), lineNumber);
283         }
284     }
285
286     // load-constant-to-stack style instructions
287

288     /**
289      * Generates code that loads a constant string value onto the stack.
290      * If value is null, the generated code loads a null onto the stack.
291      * Strings that exceed 65535 UTF encoded bytes in length are loaded by
292      * creating a StringBuffer, appending substrings, and then converting to a
293      * String.
294      */

295     public void loadConstant(String JavaDoc value) {
296         if (value == null) {
297             addCode(1, Opcode.ACONST_NULL);
298             return;
299         }
300
301         int strlen = value.length();
302
303         if (strlen <= (65535 / 3)) {
304             // Guaranteed to fit in a Java UTF encoded string.
305
ConstantInfo info = ConstantStringInfo.make(mCp, value);
306             mInstructions.new LoadConstantInstruction(1, info);
307             return;
308         }
309
310         // Compute actual UTF length.
311

312         int utflen = 0;
313
314         for (int i=0; i<strlen; i++) {
315             int c = value.charAt(i);
316             if ((c >= 0x0001) && (c <= 0x007F)) {
317                 utflen++;
318             }
319             else if (c > 0x07FF) {
320                 utflen += 3;
321             }
322             else {
323                 utflen += 2;
324             }
325         }
326
327         if (utflen <= 65535) {
328             ConstantInfo info = ConstantStringInfo.make(mCp, value);
329             mInstructions.new LoadConstantInstruction(1, info);
330             return;
331         }
332
333         // Break string up into chunks and construct in a StringBuffer.
334

335         TypeDescriptor stringBufferDesc =
336             new TypeDescriptor(StringBuffer JavaDoc.class);
337         
338         TypeDescriptor intDesc = new TypeDescriptor(int.class);
339         TypeDescriptor stringDesc = new TypeDescriptor(String JavaDoc.class);
340         TypeDescriptor[] stringParam = new TypeDescriptor[] {stringDesc};
341         
342         newObject(stringBufferDesc);
343         dup();
344         loadConstant(strlen);
345         invokeConstructor("java.lang.StringBuffer",
346                           new TypeDescriptor[] {intDesc});
347             
348         int beginIndex;
349         int endIndex = 0;
350         
351         while (endIndex < strlen) {
352             beginIndex = endIndex;
353
354             // Make each chunk as large as possible.
355
utflen = 0;
356             for (; endIndex < strlen; endIndex++) {
357                 int c = value.charAt(endIndex);
358                 int size;
359                 if ((c >= 0x0001) && (c <= 0x007F)) {
360                     size = 1;
361                 }
362                 else if (c > 0x07FF) {
363                     size = 3;
364                 }
365                 else {
366                     size = 2;
367                 }
368
369                 if ((utflen + size) > 65535) {
370                     break;
371                 }
372                 else {
373                     utflen += size;
374                 }
375             }
376
377             String JavaDoc substr = value.substring(beginIndex, endIndex);
378
379             ConstantInfo info = ConstantStringInfo.make(mCp, substr);
380             mInstructions.new LoadConstantInstruction(1, info);
381
382             invokeVirtual("java.lang.StringBuffer", "append",
383                           stringBufferDesc, stringParam);
384         }
385         
386         invokeVirtual("java.lang.StringBuffer", "toString",
387                       stringDesc, null);
388     }
389
390     /**
391      * Generates code that loads a constant boolean value onto the stack.
392      */

393     public void loadConstant(boolean value) {
394         loadConstant(value?1:0);
395     }
396
397     /**
398      * Generates code that loads a constant int, char, short or byte value
399      * onto the stack.
400      */

401     public void loadConstant(int value) {
402         if (-1 <= value && value <= 5) {
403             byte op;
404
405             switch(value) {
406             case -1:
407                 op = Opcode.ICONST_M1;
408                 break;
409             case 0:
410                 op = Opcode.ICONST_0;
411                 break;
412             case 1:
413                 op = Opcode.ICONST_1;
414                 break;
415             case 2:
416                 op = Opcode.ICONST_2;
417                 break;
418             case 3:
419                 op = Opcode.ICONST_3;
420                 break;
421             case 4:
422                 op = Opcode.ICONST_4;
423                 break;
424             case 5:
425                 op = Opcode.ICONST_5;
426                 break;
427             default:
428                 op = Opcode.NOP;
429             }
430
431             addCode(1, op);
432         }
433         else if (-128 <= value && value <= 127) {
434             addCode(1, Opcode.BIPUSH, (byte)value);
435         }
436         else if (-32768 <= value && value <= 32767) {
437             addCode(1, Opcode.SIPUSH, (short)value);
438         }
439         else {
440             ConstantInfo info = ConstantIntegerInfo.make(mCp, value);
441             mInstructions.new LoadConstantInstruction(1, info);
442         }
443     }
444
445     /**
446      * Generates code that loads a constant long value onto the stack.
447      */

448     public void loadConstant(long value) {
449         if (value == 0) {
450             addCode(2, Opcode.LCONST_0);
451         }
452         else if (value == 1) {
453             addCode(2, Opcode.LCONST_1);
454         }
455         else {
456             ConstantInfo info = ConstantLongInfo.make(mCp, value);
457             mInstructions.new LoadConstantInstruction(2, info, true);
458         }
459     }
460
461     /**
462      * Generates code that loads a constant float value onto the stack.
463      */

464     public void loadConstant(float value) {
465         if (value == 0) {
466             addCode(1, Opcode.FCONST_0);
467         }
468         else if (value == 1) {
469             addCode(1, Opcode.FCONST_1);
470         }
471         else if (value == 2) {
472             addCode(1, Opcode.FCONST_2);
473         }
474         else {
475             ConstantInfo info = ConstantFloatInfo.make(mCp, value);
476             mInstructions.new LoadConstantInstruction(1, info);
477         }
478     }
479
480     /**
481      * Generates code that loads a constant double value onto the stack.
482      */

483     public void loadConstant(double value) {
484         if (value == 0) {
485             addCode(2, Opcode.DCONST_0);
486         }
487         else if (value == 1) {
488             addCode(2, Opcode.DCONST_1);
489         }
490         else {
491             ConstantInfo info = ConstantDoubleInfo.make(mCp, value);
492             mInstructions.new LoadConstantInstruction(2, info, true);
493         }
494     }
495
496     // load-local-to-stack style instructions
497

498     /**
499      * Generates code that loads a local variable onto the stack. Parameters
500      * passed to a method and the "this" reference are all considered local
501      * variables, as well as any that were created.
502      *
503      * @param local The local variable reference
504      * @see #getParameters
505      * @see #createLocalVariable
506      */

507     public void loadLocal(LocalVariable local) {
508         if (local == null) {
509             throw new NullPointerException JavaDoc("No local variable specified");
510         }
511
512         TypeDescriptor type = local.getType();
513         Class JavaDoc clazz = type.getClassArg();
514
515         int stackAdjust = 1;
516
517         if (clazz != null && type.getDimensions() == 0 &&
518             (clazz == long.class || clazz == double.class)) {
519
520             stackAdjust++;
521         }
522
523         mInstructions.new LoadLocalInstruction(stackAdjust, local);
524     }
525
526     /**
527      * Loads a reference to "this" onto the stack. Static methods have no
528      * "this" reference, and an exception is thrown when attempting to
529      * generate "this" in a static method.
530      */

531     public void loadThis() {
532         if (mThisReference != null) {
533             loadLocal(mThisReference);
534         }
535         else {
536             throw new RuntimeException JavaDoc
537                 ("Attempt to load \"this\" reference in a static method");
538         }
539     }
540
541     // store-from-stack-to-local style instructions
542

543     /**
544      * Generates code that pops a value off of the stack into a local variable.
545      * Parameters passed to a method and the "this" reference are all
546      * considered local variables, as well as any that were created.
547      *
548      * @param local The local variable reference
549      * @see #getParameters
550      * @see #createLocalVariable
551      */

552     public void storeLocal(LocalVariable local) {
553         if (local == null) {
554             throw new NullPointerException JavaDoc("No local variable specified");
555         }
556
557         TypeDescriptor type = local.getType();
558         Class JavaDoc clazz = type.getClassArg();
559
560         int stackAdjust = -1;
561
562         if (clazz != null && type.getDimensions() == 0 &&
563             (clazz == long.class || clazz == double.class)) {
564
565             stackAdjust--;
566         }
567
568         mInstructions.new StoreLocalInstruction(stackAdjust, local);
569     }
570
571     // load-to-stack-from-array style instructions
572

573     /**
574      * Generates code that loads a value from an array. An array
575      * reference followed by an index must be on the stack. The array
576      * reference and index are replaced by the value retrieved from the array
577      * after the generated instruction has executed.
578      *
579      * <p>The type doesn't need to be an exact match for objects. Object.class
580      * works fine for all objects. For primitive types, use the class that
581      * matches that type. For an int the type is int.class.
582      *
583      * @param type The type of data stored in the array.
584      */

585     public void loadFromArray(Class JavaDoc type) {
586         byte op;
587         int stackAdjust;
588
589         if (type == int.class) {
590             stackAdjust = -1;
591             op = Opcode.IALOAD;
592         }
593         else if (type == boolean.class || type == byte.class) {
594             stackAdjust = -1;
595             op = Opcode.BALOAD;
596         }
597         else if (type == short.class) {
598             stackAdjust = -1;
599             op = Opcode.SALOAD;
600         }
601         else if (type == char.class) {
602             stackAdjust = -1;
603             op = Opcode.CALOAD;
604         }
605         else if (type == long.class) {
606             stackAdjust = 0;
607             op = Opcode.LALOAD;
608         }
609         else if (type == float.class) {
610             stackAdjust = -1;
611             op = Opcode.FALOAD;
612         }
613         else if (type == double.class) {
614             stackAdjust = 0;
615             op = Opcode.DALOAD;
616         }
617         else {
618             stackAdjust = -1;
619             op = Opcode.AALOAD;
620         }
621
622         addCode(stackAdjust, op);
623     }
624
625     // store-to-array-from-stack style instructions
626

627     /**
628      * Generates code that stores a value to an array. An array
629      * reference followed by an index, followed by a value (or two if a long
630      * or double) must be on the stack. All items on the stack are gone
631      * after the generated instruction has executed.
632      *
633      * <p>The type doesn't need to be an exact match for objects. Object.class
634      * works fine for all objects. For primitive types, use the class that
635      * matches that type. For an int the type is int.class.
636      *
637      * @param type The type of data stored in the array.
638      */

639     public void storeToArray(Class JavaDoc type) {
640         byte op;
641         int stackAdjust;
642
643         if (type == int.class) {
644             stackAdjust = -3;
645             op = Opcode.IASTORE;
646         }
647         else if (type == boolean.class || type == byte.class) {
648             stackAdjust = -3;
649             op = Opcode.BASTORE;
650         }
651         else if (type == short.class) {
652             stackAdjust = -3;
653             op = Opcode.SASTORE;
654         }
655         else if (type == char.class) {
656             stackAdjust = -3;
657             op = Opcode.CASTORE;
658         }
659         else if (type == long.class) {
660             stackAdjust = -4;
661             op = Opcode.LASTORE;
662         }
663         else if (type == float.class) {
664             stackAdjust = -3;
665             op = Opcode.FASTORE;
666         }
667         else if (type == double.class) {
668             stackAdjust = -4;
669             op = Opcode.DASTORE;
670         }
671         else {
672             stackAdjust = -3;
673             op = Opcode.AASTORE;
674         }
675
676         addCode(stackAdjust, op);
677     }
678
679     // load-field-to-stack style instructions
680

681     /**
682      * Generates code that loads a value from a field from this class.
683      * An object reference must be on the stack. After the generated code
684      * has executed, the object reference is replaced by the value retrieved
685      * from the field.
686      */

687     public void loadField(String JavaDoc fieldName,
688                           TypeDescriptor type) {
689         getfield(0, Opcode.GETFIELD, constantField(fieldName, type), type);
690     }
691
692     /**
693      * Generates code that loads a value from a field from any class.
694      * An object reference must be on the stack. After the generated code
695      * has executed, the object reference is replaced by the value retrieved
696      * from the field.
697      */

698     public void loadField(String JavaDoc className,
699                           String JavaDoc fieldName,
700                           TypeDescriptor type) {
701
702         getfield(0, Opcode.GETFIELD,
703                  mCp.addConstantField(className, fieldName, type),
704                  type);
705     }
706
707     /**
708      * Generates code that loads a value from a static field from this class.
709      * After the generated code has executed, the value retrieved is placed
710      * on the stack.
711      */

712     public void loadStaticField(String JavaDoc fieldName,
713                                 TypeDescriptor type) {
714
715         getfield(1, Opcode.GETSTATIC, constantField(fieldName, type), type);
716     }
717
718     /**
719      * Generates code that loads a value from a static field from any class.
720      * After the generated code has executed, the value retrieved is placed
721      * on the stack.
722      */

723     public void loadStaticField(String JavaDoc className,
724                                 String JavaDoc fieldName,
725                                 TypeDescriptor type) {
726
727         getfield(1, Opcode.GETSTATIC,
728                  mCp.addConstantField(className, fieldName, type),
729                  type);
730     }
731
732     private void getfield(int stackAdjust, byte opcode, ConstantInfo info,
733                           TypeDescriptor type) {
734
735         Class JavaDoc clazz = type.getClassArg();
736         if (clazz != null && type.getDimensions() == 0 &&
737             (clazz == long.class || clazz == double.class)) {
738             stackAdjust++;
739         }
740
741         addCode(stackAdjust, opcode, info);
742     }
743
744     private ConstantFieldInfo constantField(String JavaDoc fieldName,
745                                             TypeDescriptor type) {
746         return mCp.addConstantField
747             (mClassFile.getClassName(), fieldName, type);
748     }
749
750     // store-to-field-from-stack style instructions
751

752     /**
753      * Generates code that stores a value into a field from this class.
754      * An object reference and value must be on the stack. After the generated
755      * code has executed, the object reference and value are gone from
756      * the stack.
757      */

758     public void storeField(String JavaDoc fieldName,
759                            TypeDescriptor type) {
760
761         putfield(-1, Opcode.PUTFIELD, constantField(fieldName, type), type);
762     }
763
764     /**
765      * Generates code that stores a value into a field from any class.
766      * An object reference and value must be on the stack. After the generated
767      * code has executed, the object reference and value are gone from
768      * the stack.
769      */

770     public void storeField(String JavaDoc className,
771                            String JavaDoc fieldName,
772                            TypeDescriptor type) {
773
774         putfield(-1, Opcode.PUTFIELD,
775                  mCp.addConstantField(className, fieldName, type),
776                  type);
777     }
778
779     /**
780      * Generates code that stores a value into a field from this class.
781      * A value must be on the stack. After the generated
782      * code has executed, the value is gone from the stack.
783      */

784     public void storeStaticField(String JavaDoc fieldName,
785                                  TypeDescriptor type) {
786
787         putfield(0, Opcode.PUTSTATIC, constantField(fieldName, type), type);
788     }
789
790     /**
791      * Generates code that stores a value into a field from any class.
792      * A value must be on the stack. After the generated
793      * code has executed, the value is gone from the stack.
794      */

795     public void storeStaticField(String JavaDoc className,
796                                  String JavaDoc fieldName,
797                                  TypeDescriptor type) {
798
799         putfield(0, Opcode.PUTSTATIC,
800                  mCp.addConstantField(className, fieldName, type),
801                  type);
802     }
803
804     private void putfield(int stackAdjust, byte opcode, ConstantInfo info,
805                           TypeDescriptor type) {
806
807         Class JavaDoc clazz = type.getClassArg();
808         if (clazz != null && type.getDimensions() == 0 &&
809             (clazz == long.class || clazz == double.class)) {
810         
811             stackAdjust -= 2;
812         }
813         else {
814             stackAdjust--;
815         }
816
817         addCode(stackAdjust, opcode, info);
818     }
819
820     // return style instructions
821

822     /**
823      * Generates code that returns void.
824      */

825     public void returnVoid() {
826         addCode(0, Opcode.RETURN);
827     }
828
829     /**
830      * Generates code that returns an object or primitive type. The value to
831      * return must be on the stack.
832      *
833      * <p>The type doesn't need to be an exact match for objects. Object.class
834      * works fine for all objects. For primitive types, use the class that
835      * matches that type. For an int the type is int.class.
836      */

837     public void returnValue(Class JavaDoc type) {
838         int stackAdjust = -1;
839         byte op;
840
841         if (type == int.class ||
842             type == boolean.class ||
843             type == byte.class ||
844             type == short.class ||
845             type == char.class) {
846
847             op = Opcode.IRETURN;
848         }
849         else if (type == long.class) {
850             stackAdjust--;
851             op = Opcode.LRETURN;
852         }
853         else if (type == float.class) {
854             op = Opcode.FRETURN;
855         }
856         else if (type == double.class) {
857             stackAdjust--;
858             op = Opcode.DRETURN;
859         }
860         else if (type == void.class) {
861             stackAdjust++;
862             op = Opcode.RETURN;
863         }
864         else {
865             op = Opcode.ARETURN;
866         }
867
868         addCode(stackAdjust, op);
869     }
870
871     // numerical conversion style instructions
872

873     /**
874      * Generates code that converts the value of a primitive type already
875      * on the stack.
876      */

877     public void convert(Class JavaDoc fromType, Class JavaDoc toType) {
878         int stackAdjust = 0;
879         byte op;
880
881         if (fromType == int.class ||
882             fromType == boolean.class ||
883             fromType == byte.class ||
884             fromType == short.class ||
885             fromType == char.class) {
886             
887             if (toType == byte.class) {
888                 op = Opcode.I2B;
889             }
890             else if (toType == short.class) {
891                 op = Opcode.I2S;
892             }
893             else if (toType == char.class) {
894                 op = Opcode.I2C;
895             }
896             else if (toType == float.class) {
897                 op = Opcode.I2F;
898             }
899             else if (toType == long.class) {
900                 stackAdjust = 1;
901                 op = Opcode.I2L;
902             }
903             else if (toType == double.class) {
904                 stackAdjust = 1;
905                 op = Opcode.I2D;
906             }
907             else if (toType == int.class) {
908                 return;
909             }
910             else {
911                 throw new RuntimeException JavaDoc("Invalid conversion: int to " +
912                                            toType);
913             }
914
915             addCode(stackAdjust, op);
916             return;
917         }
918         else if (fromType == long.class) {
919             if (toType == int.class) {
920                 stackAdjust = -1;
921                 op = Opcode.L2I;
922             }
923             else if (toType == float.class) {
924                 stackAdjust = -1;
925                 op = Opcode.L2F;
926             }
927             else if (toType == double.class) {
928                 op = Opcode.L2D;
929             }
930             else if (toType == byte.class ||
931                      toType == char.class ||
932                      toType == short.class) {
933                 
934                 convert(fromType, int.class);
935                 convert(int.class, toType);
936                 return;
937             }
938             else if (toType == long.class) {
939                 return;
940             }
941             else {
942                 throw new RuntimeException JavaDoc("Invalid conversion: long to " +
943                                            toType);
944             }
945
946             addCode(stackAdjust, op);
947             return;
948         }
949         else if (fromType == float.class) {
950             if (toType == int.class) {
951                 op = Opcode.F2I;
952             }
953             else if (toType == long.class) {
954                 stackAdjust = 1;
955                 op = Opcode.F2L;
956             }
957             else if (toType == double.class) {
958                 stackAdjust = 1;
959                 op = Opcode.F2D;
960             }
961             else if (toType == byte.class ||
962                      toType == char.class ||
963                      toType == short.class) {
964                 
965                 convert(fromType, int.class);
966                 convert(int.class, toType);
967                 return;
968             }
969             else if (toType == float.class) {
970                 return;
971             }
972             else {
973                 throw new RuntimeException JavaDoc("Invalid conversion: float to " +
974                                            toType);
975             }
976             
977             addCode(stackAdjust, op);
978             return;
979         }
980         else if (fromType == double.class) {
981             if (toType == int.class) {
982                 stackAdjust = -1;
983                 op = Opcode.D2I;
984             }
985             else if (toType == float.class) {
986                 stackAdjust = -1;
987                 op = Opcode.D2F;
988             }
989             else if (toType == long.class) {
990                 op = Opcode.D2L;
991             }
992             else if (toType == byte.class ||
993                      toType == char.class ||
994                      toType == short.class) {
995                 
996                 convert(fromType, int.class);
997                 convert(int.class, toType);
998                 return;
999             }
1000            else if (toType == double.class) {
1001                return;
1002            }
1003            else {
1004                throw new RuntimeException JavaDoc("Invalid conversion: double to " +
1005                                           toType);
1006            }
1007
1008            addCode(stackAdjust, op);
1009            return;
1010        }
1011        else {
1012            throw new RuntimeException JavaDoc("Invalid conversion: " + fromType +
1013                                       " to " + toType);
1014        }
1015    }
1016
1017    // invocation style instructions
1018

1019    /**
1020     * Generates code to invoke a method in any class. If the method is
1021     * non-static, the object reference and the method's argument(s) must be
1022     * on the stack. If the method is static and has any arguments, just
1023     * the method's arguments must be on the stack.
1024     */

1025    public void invoke(Method method) {
1026        TypeDescriptor ret = new TypeDescriptor(method.getReturnType());
1027
1028        Class JavaDoc[] paramClasses = method.getParameterTypes();
1029        TypeDescriptor[] params = new TypeDescriptor[paramClasses.length];
1030        for (int i=0; i<params.length; i++) {
1031            params[i] = new TypeDescriptor(paramClasses[i]);
1032        }
1033
1034        Class JavaDoc clazz = method.getDeclaringClass();
1035
1036        if (Modifier.isStatic(method.getModifiers())) {
1037            invokeStatic(clazz.getName(),
1038                         method.getName(),
1039                         ret,
1040                         params);
1041        }
1042        else if (clazz.isInterface()) {
1043            invokeInterface(clazz.getName(),
1044                            method.getName(),
1045                            ret,
1046                            params);
1047        }
1048        else {
1049            invokeVirtual(clazz.getName(),
1050                          method.getName(),
1051                          ret,
1052                          params);
1053        }
1054    }
1055
1056    /**
1057     * Generates code to invoke a class constructor in any class. The object
1058     * reference and the constructor's argument(s) must be on the stack.
1059     */

1060    public void invoke(Constructor constructor) {
1061        Class JavaDoc[] paramClasses = constructor.getParameterTypes();
1062        TypeDescriptor[] params = new TypeDescriptor[paramClasses.length];
1063        for (int i=0; i<params.length; i++) {
1064            params[i] = new TypeDescriptor(paramClasses[i]);
1065        }
1066
1067        invokeConstructor(constructor.getDeclaringClass().toString(), params);
1068    }
1069
1070    /**
1071     * Generates code to invoke a virtual method in this class. The object
1072     * reference and the method's argument(s) must be on the stack.
1073     *
1074     * @param ret May be null if method returns void.
1075     * @param params May be null if method takes no parameters.
1076     */

1077    public void invokeVirtual(String JavaDoc methodName,
1078                              TypeDescriptor ret,
1079                              TypeDescriptor[] params) {
1080
1081        ConstantInfo info = mCp.addConstantMethod
1082            (mClassFile.getClassName(), methodName, ret, params);
1083
1084        int stackAdjust = returnSize(ret) - 1;
1085        if (params != null) {
1086            stackAdjust -= argSize(params);
1087        }
1088
1089        addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1090    }
1091
1092    /**
1093     * Generates code to invoke a virtual method in any class. The object
1094     * reference and the method's argument(s) must be on the stack.
1095     *
1096     * @param ret May be null if method returns void.
1097     * @param params May be null if method takes no parameters.
1098     */

1099    public void invokeVirtual(String JavaDoc className,
1100                              String JavaDoc methodName,
1101                              TypeDescriptor ret,
1102                              TypeDescriptor[] params) {
1103        ConstantInfo info =
1104            mCp.addConstantMethod(className, methodName, ret, params);
1105
1106        int stackAdjust = returnSize(ret) - 1;
1107        if (params != null) {
1108            stackAdjust -= argSize(params);
1109        }
1110
1111        addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1112    }
1113
1114    /**
1115     * Generates code to invoke a static method in this class. The method's
1116     * argument(s) must be on the stack.
1117     *
1118     * @param ret May be null if method returns void.
1119     * @param params May be null if method takes no parameters.
1120     */

1121    public void invokeStatic(String JavaDoc methodName,
1122                             TypeDescriptor ret,
1123                             TypeDescriptor[] params) {
1124        ConstantInfo info = mCp.addConstantMethod
1125            (mClassFile.getClassName(), methodName, ret, params);
1126
1127        int stackAdjust = returnSize(ret) - 0;
1128        if (params != null) {
1129            stackAdjust -= argSize(params);
1130        }
1131
1132        addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1133    }
1134
1135    /**
1136     * Generates code to invoke a static method in any class. The method's
1137     * argument(s) must be on the stack.
1138     *
1139     * @param ret May be null if method returns void.
1140     * @param params May be null if method takes no parameters.
1141     */

1142    public void invokeStatic(String JavaDoc className,
1143                             String JavaDoc methodName,
1144                             TypeDescriptor ret,
1145                             TypeDescriptor[] params) {
1146        ConstantInfo info =
1147            mCp.addConstantMethod(className, methodName, ret, params);
1148
1149        int stackAdjust = returnSize(ret) - 0;
1150        if (params != null) {
1151            stackAdjust -= argSize(params);
1152        }
1153
1154        addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1155    }
1156
1157    /**
1158     * Generates code to invoke an interface method in any class. The object
1159     * reference and the method's argument(s) must be on the stack.
1160     *
1161     * @param ret May be null if method returns void.
1162     * @param params May be null if method takes no parameters.
1163     */

1164    public void invokeInterface(String JavaDoc className,
1165                                String JavaDoc methodName,
1166                                TypeDescriptor ret,
1167                                TypeDescriptor[] params) {
1168
1169        ConstantInfo info =
1170            mCp.addConstantInterfaceMethod(className, methodName, ret, params);
1171
1172        int paramCount = 1;
1173        if (params != null) {
1174            paramCount += argSize(params);
1175        }
1176
1177        int stackAdjust = returnSize(ret) - paramCount;
1178
1179        byte[] bytes = new byte[5];
1180
1181        bytes[0] = Opcode.INVOKEINTERFACE;
1182        bytes[1] = (byte)0;
1183        bytes[2] = (byte)0;
1184        bytes[3] = (byte)paramCount;
1185        bytes[4] = (byte)0;
1186
1187        mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info);
1188    }
1189
1190    /**
1191     * Generates code to invoke a private method in this class.
1192     * The object reference and the method's argument(s) must be on the stack.
1193     *
1194     * @param ret May be null if method returns void.
1195     * @param params May be null if method takes no parameters.
1196     */

1197    public void invokePrivate(String JavaDoc methodName,
1198                              TypeDescriptor ret,
1199                              TypeDescriptor[] params) {
1200        ConstantInfo info = mCp.addConstantMethod
1201            (mClassFile.getClassName(), methodName, ret, params);
1202
1203        int stackAdjust = returnSize(ret) - 1;
1204        if (params != null) {
1205            stackAdjust -= argSize(params);
1206        }
1207
1208        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1209    }
1210
1211    /**
1212     * Generates code to invoke a method in the super class.
1213     * The object reference and the method's argument(s) must be on the stack.
1214     *
1215     * @param ret May be null if method returns void.
1216     * @param params May be null if method takes no parameters.
1217     */

1218    public void invokeSuper(String JavaDoc superClassName,
1219                            String JavaDoc methodName,
1220                            TypeDescriptor ret,
1221                            TypeDescriptor[] params) {
1222        ConstantInfo info =
1223            mCp.addConstantMethod(superClassName, methodName, ret, params);
1224
1225        int stackAdjust = returnSize(ret) - 1;
1226        if (params != null) {
1227            stackAdjust -= argSize(params);
1228        }
1229
1230        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1231    }
1232
1233    /**
1234     * Generates code to invoke a method in the super class.
1235     * The object reference and the method's argument(s) must be on the stack.
1236     */

1237    public void invokeSuper(Method method) {
1238        TypeDescriptor ret = new TypeDescriptor(method.getReturnType());
1239
1240        Class JavaDoc[] paramClasses = method.getParameterTypes();
1241        TypeDescriptor[] params = new TypeDescriptor[paramClasses.length];
1242        for (int i=0; i<params.length; i++) {
1243            params[i] = new TypeDescriptor(paramClasses[i]);
1244        }
1245
1246        invokeSuper(method.getDeclaringClass().getName(),
1247                    method.getName(),
1248                    ret,
1249                    params);
1250    }
1251
1252    /**
1253     * Generates code to invoke a class constructor in this class. The object
1254     * reference and the constructor's argument(s) must be on the stack.
1255     *
1256     * @param params May be null if constructor takes no parameters.
1257     */

1258    public void invokeConstructor(TypeDescriptor[] params) {
1259        ConstantInfo info =
1260            mCp.addConstantConstructor(mClassFile.getClassName(), params);
1261
1262        int stackAdjust = -1;
1263        if (params != null) {
1264            stackAdjust -= argSize(params);
1265        }
1266
1267        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1268    }
1269
1270    /**
1271     * Generates code to invoke a class constructor in any class. The object
1272     * reference and the constructor's argument(s) must be on the stack.
1273     *
1274     * @param params May be null if constructor takes no parameters.
1275     */

1276    public void invokeConstructor(String JavaDoc className, TypeDescriptor[] params) {
1277        ConstantInfo info = mCp.addConstantConstructor(className, params);
1278
1279        int stackAdjust = -1;
1280        if (params != null) {
1281            stackAdjust -= argSize(params);
1282        }
1283
1284        addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1285    }
1286
1287    /**
1288     * Generates code to invoke a super class constructor. The object
1289     * reference and the constructor's argument(s) must be on the stack.
1290     *
1291     * @param params May be null if constructor takes no parameters.
1292     */

1293    public void invokeSuperConstructor(TypeDescriptor[] params) {
1294        invokeConstructor(mClassFile.getSuperClassName(), params);
1295    }
1296
1297    /**
1298     * Generates code to invoke a super class constructor. The object
1299     * reference and the constructor's argument(s) must be on the stack.
1300     */

1301    public void invokeSuper(Constructor constructor) {
1302        Class JavaDoc[] paramClasses = constructor.getParameterTypes();
1303        TypeDescriptor[] params = new TypeDescriptor[paramClasses.length];
1304        for (int i=0; i<params.length; i++) {
1305            params[i] = new TypeDescriptor(paramClasses[i]);
1306        }
1307
1308        invokeSuperConstructor(params);
1309    }
1310
1311    private int returnSize(TypeDescriptor ret) {
1312        if (ret == null) return 0;
1313
1314        String JavaDoc className = ret.getClassName();
1315        
1316        if (className.equals(void.class.getName())) {
1317            return 0;
1318        }
1319        else if (className.equals(long.class.getName()) ||
1320                 className.equals(double.class.getName())) {
1321            return 2;
1322        }
1323        else {
1324            return 1;
1325        }
1326    }
1327
1328    private int argSize(TypeDescriptor[] params) {
1329        int size = 0;
1330        if (params != null) {
1331            for (int i=0; i<params.length; i++) {
1332                String JavaDoc className = params[i].getClassName();
1333                if (params[i].getDimensions() == 0 &&
1334                    (className.equals(long.class.getName()) ||
1335                     className.equals(double.class.getName()))) {
1336                    size += 2;
1337                }
1338                else {
1339                    size++;
1340                }
1341            }
1342        }
1343
1344        return size;
1345    }
1346
1347    // creation style instructions
1348

1349    /**
1350     * Generates code to create a new object. Unless the new object is an
1351     * array, it is invalid until a constructor method is invoked on it.
1352     * When creating arrays, the size for each dimension must be on the
1353     * operand stack.
1354     *
1355     * @see #invokeConstructor
1356     */

1357    public void newObject(TypeDescriptor type) {
1358        int dim = type.getSpecifiedDimensions();
1359
1360        if (dim == 0) {
1361            ConstantInfo info = mCp.addConstantClass(type);
1362            addCode(1, Opcode.NEW, info);
1363            return;
1364        }
1365
1366        TypeDescriptor componentType = type.getComponentType();
1367
1368        if (dim == 1) {
1369            if (componentType.getDimensions() == 0) {
1370                Class JavaDoc clazz = componentType.getClassArg();
1371
1372                if (clazz != null && clazz.isPrimitive()) {
1373                    byte atype = (byte)0;
1374                    
1375                    if (clazz == int.class) {
1376                        atype = (byte)10;
1377                    }
1378                    else if (clazz == byte.class) {
1379                        atype = (byte)8;
1380                    }
1381                    else if (clazz == boolean.class) {
1382                        atype = (byte)4;
1383                    }
1384                    else if (clazz == char.class) {
1385                        atype = (byte)5;
1386                    }
1387                    else if (clazz == float.class) {
1388                        atype = (byte)6;
1389                    }
1390                    else if (clazz == double.class) {
1391                        atype = (byte)7;
1392                    }
1393                    else if (clazz == short.class) {
1394                        atype = (byte)9;
1395                    }
1396                    else if (clazz == long.class) {
1397                        atype = (byte)11;
1398                    }
1399                    
1400                    addCode(0, Opcode.NEWARRAY, atype);
1401                    return;
1402                }
1403            }
1404
1405            ConstantInfo info = mCp.addConstantClass(componentType);
1406            addCode(0, Opcode.ANEWARRAY, info);
1407            return;
1408        }
1409
1410        // multidimensional
1411
int stackAdjust = -(dim - 1);
1412        
1413        ConstantInfo info = mCp.addConstantClass(componentType);
1414        
1415        byte[] bytes = new byte[4];
1416        
1417        bytes[0] = Opcode.MULTIANEWARRAY;
1418        bytes[1] = (byte)0;
1419        bytes[2] = (byte)0;
1420        bytes[3] = (byte)dim;
1421        
1422        mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info);
1423    }
1424
1425    // stack operation style instructions
1426

1427    /**
1428     * Generates code for the dup instruction.
1429     */

1430    public void dup() {
1431        addCode(1, Opcode.DUP);
1432    }
1433
1434    /**
1435     * Generates code for the dup_x1 instruction.
1436     */

1437    public void dupX1() {
1438        addCode(1, Opcode.DUP_X1);
1439    }
1440
1441    /**
1442     * Generates code for the dup_x2 instruction.
1443     */

1444    public void dupX2() {
1445        addCode(1, Opcode.DUP_X2);
1446    }
1447
1448    /**
1449     * Generates code for the dup2 instruction.
1450     */

1451    public void dup2() {
1452        addCode(2, Opcode.DUP2);
1453    }
1454
1455    /**
1456     * Generates code for the dup2_x1 instruction.
1457     */

1458    public void dup2X1() {
1459        addCode(2, Opcode.DUP2_X1);
1460    }
1461
1462    /**
1463     * Generates code for the dup2_x2 instruction.
1464     */

1465    public void dup2X2() {
1466        addCode(2, Opcode.DUP2_X2);
1467    }
1468
1469    /**
1470     * Generates code for the pop instruction.
1471     */

1472    public void pop() {
1473        addCode(-1, Opcode.POP);
1474    }
1475
1476    /**
1477     * Generates code for the pop2 instruction.
1478     */

1479    public void pop2() {
1480        addCode(-2, Opcode.POP2);
1481    }
1482
1483    /**
1484     * Generates code for the swap instruction.
1485     */

1486    public void swap() {
1487        addCode(0, Opcode.SWAP);
1488    }
1489
1490    /**
1491     * Generates code for a swap2 instruction.
1492     */

1493    public void swap2() {
1494        dup2X2();
1495        pop2();
1496    }
1497
1498    // flow control instructions
1499

1500    private void branch(int stackAdjust, Location location, byte opcode) {
1501        mInstructions.new BranchInstruction(stackAdjust, opcode, location);
1502    }
1503
1504    /**
1505     * Generates code that performs an unconditional branch to the specified
1506     * location or label.
1507     *
1508     * @param location The location or label to branch to
1509     */

1510    public void branch(Location location) {
1511        branch(0, location, Opcode.GOTO);
1512    }
1513
1514    /**
1515     * Generates code that performs a conditional branch based on the
1516     * value of an object on the stack. A branch is performed based on whether
1517     * the object reference on the stack is null or not.
1518     *
1519     * @param location The location or label to branch to
1520     * @param choice If true, do branch when null, else branch when not null
1521     */

1522    public void ifNullBranch(Location location, boolean choice) {
1523        branch(-1, location, choice ? Opcode.IFNULL : Opcode.IFNONNULL);
1524    }
1525
1526
1527    /**
1528     * Generates code that performs a conditional branch based on the value of
1529     * two object references on the stack. A branch is performed based on
1530     * whether the two objects are equal.
1531     *
1532     * @param location The location or label to branch to
1533     * @param choice If true, branch when equal, else branch when not equal
1534     */

1535    public void ifEqualBranch(Location location, boolean choice) {
1536        branch(-2, location, choice ? Opcode.IF_ACMPEQ : Opcode.IF_ACMPNE);
1537    }
1538
1539    /**
1540     * Generates code the performs a conditional branch based on a comparison
1541     * between an int value on the stack and zero. The int value on the
1542     * stack is on the left side of the comparison expression.
1543     *
1544     * @param location The location or label to branch to
1545     * @param choice One of "==", "!=", "<", ">=", ">" or "<="
1546     * @exception IllegalArgumentException When the choice is not valid
1547     */

1548    public void ifZeroComparisonBranch(Location location, String JavaDoc choice)
1549        throws IllegalArgumentException JavaDoc {
1550
1551        choice = choice.intern();
1552
1553        byte opcode;
1554        if (choice == "==") {
1555            opcode = Opcode.IFEQ;
1556        }
1557        else if (choice == "!=") {
1558            opcode = Opcode.IFNE;
1559        }
1560        else if (choice == "<") {
1561            opcode = Opcode.IFLT;
1562        }
1563        else if (choice == ">=") {
1564            opcode = Opcode.IFGE;
1565        }
1566        else if (choice == ">") {
1567            opcode = Opcode.IFGT;
1568        }
1569        else if (choice == "<=") {
1570            opcode = Opcode.IFLE;
1571        }
1572        else {
1573            throw new IllegalArgumentException JavaDoc
1574                ("Invalid comparision choice: " + choice);
1575        }
1576        
1577        branch(-1, location, opcode);
1578    }
1579
1580    /**
1581     * Generates code the performs a conditional branch based on a comparison
1582     * between two int values on the stack. The first int value on the stack
1583     * is on the left side of the comparison expression.
1584     *
1585     * @param location The location or label to branch to
1586     * @param choice One of "==", "!=", "<", ">=", ">" or "<="
1587     * @exception IllegalArgumentException When the choice is not valid
1588     */

1589    public void ifComparisonBranch(Location location, String JavaDoc choice)
1590        throws IllegalArgumentException JavaDoc {
1591
1592        choice = choice.intern();
1593
1594        byte opcode;
1595        if (choice == "==") {
1596            opcode = Opcode.IF_ICMPEQ;
1597        }
1598        else if (choice == "!=") {
1599            opcode = Opcode.IF_ICMPNE;
1600        }
1601        else if (choice == "<") {
1602            opcode = Opcode.IF_ICMPLT;
1603        }
1604        else if (choice == ">=") {
1605            opcode = Opcode.IF_ICMPGE;
1606        }
1607        else if (choice == ">") {
1608            opcode = Opcode.IF_ICMPGT;
1609        }
1610        else if (choice == "<=") {
1611            opcode = Opcode.IF_ICMPLE;
1612        }
1613        else {
1614            throw new IllegalArgumentException JavaDoc
1615                ("Invalid comparision choice: " + choice);
1616        }
1617
1618        branch(-2, location, opcode);
1619    }
1620
1621    /**
1622     * Generates code for a switch statement. The generated code is either a
1623     * lookupswitch or tableswitch. The choice of which switch type to generate
1624     * is made based on the amount of bytes to be generated. A tableswitch
1625     * is usually smaller, unless the cases are sparse.
1626     *
1627     * <p>The key value to switch on must already be on the stack when this
1628     * instruction executes.
1629     *
1630     * @param cases The values to match on. The array length must be the same
1631     * as for locations.
1632     * @param locations The locations or labels to branch to for each case.
1633     * The array length must be the same as for cases.
1634     * @param defaultLocation The location or label to branch to if the key on
1635     * the stack was not matched.
1636     */

1637    public void switchBranch(int[] cases,
1638                             Location[] locations, Location defaultLocation) {
1639
1640        mInstructions.new SwitchInstruction(cases, locations, defaultLocation);
1641    }
1642
1643    /**
1644     * Generates code that performs a subroutine branch to the specified
1645     * location. The instruction generated is either jsr or jsr_w. It is most
1646     * often used for implementing a finally block.
1647     *
1648     * @param location The location or label to branch to
1649     */

1650    public void jsr(Location location) {
1651        // Adjust the stack by one to make room for the return address.
1652
branch(1, location, Opcode.JSR);
1653    }
1654
1655    /**
1656     * Generates code that returns from a subroutine invoked by jsr.
1657     *
1658     * @param local The local variable reference that contains the return
1659     * address. The local variable must be of an object type.
1660     */

1661    public void ret(LocalVariable local) {
1662        if (local == null) {
1663            throw new NullPointerException JavaDoc("No local variable specified");
1664        }
1665
1666        mInstructions.new RetInstruction(local);
1667    }
1668
1669    // math instructions
1670

1671    /**
1672     * Generates code for either a unary or binary math operation on one
1673     * or two values pushed on the stack.
1674     *
1675     * <p>Pass in an opcode from the the Opcode class. The only valid math
1676     * opcodes are:
1677     *
1678     * <pre>
1679     * IADD, ISUB, IMUL, IDIV, IREM, INEG, IAND, IOR, IXOR, ISHL, ISHR, IUSHR
1680     * LADD, LSUB, LMUL, LDIV, LREM, LNEG, LAND, LOR, LXOR, LSHL, LSHR, LUSHR
1681     * FADD, FSUB, FMUL, FDIV, FREM, FNEG
1682     * DADD, DSUB, DMUL, DDIV, DREM, DNEG
1683     *
1684     * LCMP
1685     * FCMPG, FCMPL
1686     * DCMPG, DCMPL
1687     * </pre>
1688     *
1689     * A not operation (~) is performed by doing a loadConstant with either
1690     * -1 or -1L followed by math(Opcode.IXOR) or math(Opcode.LXOR).
1691     *
1692     * @param opcode An opcode from the Opcode class.
1693     * @exception IllegalArgumentException When the opcode selected is not
1694     * a math operation.
1695     * @see Opcode
1696     */

1697    public void math(byte opcode) {
1698        int stackAdjust;
1699        
1700        switch(opcode) {
1701        case Opcode.INEG:
1702        case Opcode.LNEG:
1703        case Opcode.FNEG:
1704        case Opcode.DNEG:
1705            stackAdjust = 0;
1706            break;
1707        case Opcode.IADD:
1708        case Opcode.ISUB:
1709        case Opcode.IMUL:
1710        case Opcode.IDIV:
1711        case Opcode.IREM:
1712        case Opcode.IAND:
1713        case Opcode.IOR:
1714        case Opcode.IXOR:
1715        case Opcode.ISHL:
1716        case Opcode.ISHR:
1717        case Opcode.IUSHR:
1718        case Opcode.FADD:
1719        case Opcode.FSUB:
1720        case Opcode.FMUL:
1721        case Opcode.FDIV:
1722        case Opcode.FREM:
1723        case Opcode.FCMPG:
1724        case Opcode.FCMPL:
1725            stackAdjust = -1;
1726            break;
1727        case Opcode.LADD:
1728        case Opcode.LSUB:
1729        case Opcode.LMUL:
1730        case Opcode.LDIV:
1731        case Opcode.LREM:
1732        case Opcode.LAND:
1733        case Opcode.LOR:
1734        case Opcode.LXOR:
1735        case Opcode.LSHL:
1736        case Opcode.LSHR:
1737        case Opcode.LUSHR:
1738        case Opcode.DADD:
1739        case Opcode.DSUB:
1740        case Opcode.DMUL:
1741        case Opcode.DDIV:
1742        case Opcode.DREM:
1743            stackAdjust = -2;
1744            break;
1745        case Opcode.LCMP:
1746        case Opcode.DCMPG:
1747        case Opcode.DCMPL:
1748            stackAdjust = -3;
1749            break;
1750        default:
1751            throw new IllegalArgumentException JavaDoc
1752                ("Not a math opcode: " + Opcode.getMnemonic(opcode));
1753        }
1754
1755        addCode(stackAdjust, opcode);
1756    }
1757
1758    // miscellaneous instructions
1759

1760    /**
1761     * Generates code for an arraylength instruction. The object to get the
1762     * length from must already be on the stack.
1763     */

1764    public void arrayLength() {
1765        addCode(0, Opcode.ARRAYLENGTH);
1766    }
1767
1768    /**
1769     * Generates code that throws an exception. The object to throw must
1770     * already be on the stack.
1771     */

1772    public void throwObject() {
1773        addCode(-1, Opcode.ATHROW);
1774    }
1775
1776    /**
1777     * Generates code that performs an object cast operation. The object
1778     * to check must already be on the stack.
1779     */

1780    public void checkCast(TypeDescriptor type) {
1781        ConstantInfo info = mCp.addConstantClass(type);
1782        addCode(0, Opcode.CHECKCAST, info);
1783    }
1784
1785    /**
1786     * Generates code that performs an instanceof operation. The object to
1787     * check must already be on the stack.
1788     */

1789    public void instanceOf(TypeDescriptor type) {
1790        ConstantInfo info = mCp.addConstantClass(type);
1791        addCode(0, Opcode.INSTANCEOF, info);
1792    }
1793
1794    /**
1795     * Generates code that increments a local integer variable by a signed
1796     * constant amount.
1797     */

1798    public void integerIncrement(LocalVariable local, int amount) {
1799        if (local == null) {
1800            throw new NullPointerException JavaDoc("No local variable specified");
1801        }
1802
1803        if (-32768 <= amount && amount <= 32767) {
1804            mInstructions.new ShortIncrementInstruction(local, (short)amount);
1805        }
1806        else {
1807            // Amount can't possibly fit in a 16-bit value, so use regular
1808
// instructions instead.
1809

1810            loadLocal(local);
1811            loadConstant(amount);
1812            math(Opcode.IADD);
1813            storeLocal(local);
1814        }
1815    }
1816
1817    /**
1818     * Generates code to enter the monitor on an object loaded on the stack.
1819     */

1820    public void monitorEnter() {
1821        addCode(-1, Opcode.MONITORENTER);
1822    }
1823
1824    /**
1825     * Generates code to exit the monitor on an object loaded on the stack.
1826     */

1827    public void monitorExit() {
1828        addCode(-1, Opcode.MONITOREXIT);
1829    }
1830
1831    /**
1832     * Generates an instruction that does nothing. (No-OPeration)
1833     */

1834    public void nop() {
1835        addCode(0, Opcode.NOP);
1836    }
1837
1838    /**
1839     * Generates a breakpoint instruction for use in a debugging environment.
1840     */

1841    public void breakpoint() {
1842        addCode(0, Opcode.BREAKPOINT);
1843    }
1844}
1845
Popular Tags