KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > bytecode > CodeAttr


1 // Copyright (c) 1997, 1998, 1999, 2001, 2003, 2004 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.bytecode;
5 import java.io.*;
6
7 /**
8   * Represents the contents of a standard "Code" attribute.
9   * <p>
10   * Most of the actual methods that generate bytecode operation
11   * are in this class (typically with names starting with <code>emit</code>),
12   * though there are also some in <code>Method</code>.
13   * <p>
14   * Note that a <code>CodeAttr</code> is an <code>Attribute</code>
15   * of a <code>Method</code>, and can in turn contain other
16   * <code>Attribute</code>s, such as a <code>LineNumbersAttr</code>.
17   *
18   * @author Per Bothner
19   */

20
21 public class CodeAttr extends Attribute implements AttrContainer
22 {
23   Attribute attributes;
24   public final Attribute getAttributes () { return attributes; }
25   public final void setAttributes (Attribute attributes)
26   { this.attributes = attributes; }
27   LineNumbersAttr lines;
28   public LocalVarsAttr locals;
29
30   SourceDebugExtAttr sourceDbgExt;
31
32   // In hindsight, maintaining stack_types is more hassle than it is worth.
33
// Instead, better to just keep track of SP, which should catch most
34
// stack errors, while being more general and less hassle. FIXME.
35
Type[] stack_types;
36
37   int SP; // Current stack size (in "words")
38
private int max_stack;
39   private int max_locals;
40   /** Current active length of code array.
41    * Note that processFixups may expand/contract the code array. */

42   int PC;
43   byte[] code;
44
45   /* The exception handler table, as a vector of quadruples
46      (start_pc, end_pc, handler_pc, catch_type).
47      Only the first exception_table_length quadruples are defined. */

48   short[] exception_table;
49
50   /* The number of (defined) exception handlers (i.e. quadruples)
51      in exception_table. */

52   int exception_table_length;
53
54   /** Not a fixup - a no-op. */
55   static final int FIXUP_NONE = 0;
56   /** The definition of a label. */
57   static final int FIXUP_DEFINE = 1;
58   /** The offset points to a tableswitch/lookupswitch - handle padding. */
59   static final int FIXUP_SWITCH = 2;
60   /** The offset contains a label relative to the previous FIXUP_SWITCH. */
61   static final int FIXUP_CASE = 3;
62   /** The offset points to a goto instruction.
63    * This case up to FIXUP_TRANSFER2 must be contiguous
64    * - see the jump-to-jump optimization in processFixups. */

65   static final int FIXUP_GOTO = 4;
66   /** The offset points to a jsr instruction. */
67   static final int FIXUP_JSR = 5;
68   /** The offset points to a conditional transfer (if_xxx) instruction. */
69   static final int FIXUP_TRANSFER = 6;
70   /** A FIXUP_GOTO_, FIXUP_JSR, or FIXUP_TRANSFER that uses a 2-byte offset. */
71   static final int FIXUP_TRANSFER2 = 7;
72   /** The offsets points to 3 bytes that should be deleted. */
73   static final int FIXUP_DELETE3 = 8;
74   /** The following instructions are moved to later in the code stream.
75    * Instead the instructions starting at the fixup label are patched here.
76    * (If the fixup label is null, we're done.)
77    * This allows re-arranging code to avoid unneeded gotos.
78    * The following instruction is the target of a later FIXUP_MOVE,
79    * and we'll insert then when we get to it. */

80   static final int FIXUP_MOVE = 9;
81   /** The following instructions are moved to the end of the code stream.
82    * Same as FIXUP_MOVE, but there is no explicit later FIXUP_MOVE that
83    * refers to the following instructions. Created by beginFragment.
84    * The fixup_offset points to the end of the fragment.
85    * (The first processFixups patches these to FIXUP_MOVE.) */

86   static final int FIXUP_MOVE_TO_END = 10;
87   /** FIXUP_TRY with the following FIXUP_CATCH marks an exception handler.
88    * The label is the start of the try clause;
89    * the current offset marks the exception handler. */

90   static final int FIXUP_TRY = 11;
91   /** Second half of a FIXUP_TRY/FIXUP_CATCH pair.
92    * The label is the ed of the try clause;
93    * the current offset is the exception type as a constant pool index. */

94   static final int FIXUP_CATCH = 12;
95   /** With following FIXUP_LINE_NUMBER associates an offset with a line number.
96    * The fixup_offset is the code location; the fixup_label is null. */

97   static final int FIXUP_LINE_PC = 13;
98   /** With preceding FIXUP_LINE_PC associates an offset with a line number.
99    * The fixup_offset is the line number; the fixup_label is null. */

100   static final int FIXUP_LINE_NUMBER = 14;
101   int[] fixup_offsets;
102   Label[] fixup_labels;
103   int fixup_count;
104
105   /** This causes a later processFixup to rearrange the code.
106    * The code at target comes here, instead of the following instructions.
107    * Fuctionally equivalent to: <code>goto target; here:</code>,
108    * but implemented by code re-arranging. Therefore there should be
109    * at some later point a <code>goto here; target:</code>.
110    */

111   public final void fixupChain (Label here, Label target)
112   {
113     fixupAdd(CodeAttr.FIXUP_MOVE, 0, target);
114     here.define(this);
115   }
116
117   /** Add a fixup at this location.
118    * @param kind one of the FIXUP_xxx codes.
119    * @param label varies - typically the target of jump. */

120   public final void fixupAdd (int kind, Label label)
121   {
122     fixupAdd(kind, PC, label);
123   }
124
125   final void fixupAdd (int kind, int offset, Label label)
126   {
127     int count = fixup_count;
128     if (count == 0)
129       {
130     fixup_offsets = new int[30];
131     fixup_labels = new Label[30];
132       }
133     else if (fixup_count == fixup_offsets.length)
134       {
135     int new_length = 2 * count;
136     Label[] new_labels = new Label[new_length];
137     System.arraycopy (fixup_labels, 0, new_labels, 0, count);
138     fixup_labels = new_labels;
139     int[] new_offsets = new int[new_length];
140     System.arraycopy (fixup_offsets, 0, new_offsets, 0, count);
141     fixup_offsets = new_offsets;
142       }
143     fixup_offsets[count] = (offset << 4) | kind;
144     fixup_labels[count] = label;
145     fixup_count = count + 1;
146   }
147
148   private final int fixupOffset(int index)
149   {
150     return fixup_offsets[index] >> 4;
151   }
152
153   private final int fixupKind(int index)
154   {
155     return fixup_offsets[index] & 15;
156   }
157
158   /** If true we get a line number entry for each instruction.
159    * Normally false, but can be a convenient hack to allow instruction-level
160    * stepping/debugging and stacktraces. In this case {@code LINE==PC}. */

161   public static boolean instructionLineMode = false;
162
163   /** The stack of currently active conditionals. */
164   IfState if_stack;
165
166   /** The stack of currently active try statements. */
167   TryState try_stack;
168
169   public final Method getMethod() { return (Method) getContainer(); }
170
171   public final int getPC() { return PC; }
172
173   public final int getSP() { return SP; }
174
175   public final ConstantPool getConstants ()
176   {
177     return getMethod().classfile.constants;
178   }
179
180   /* True if we cannot fall through to bytes[PC] -
181      the previous instruction was an uncondition control transfer. */

182   private boolean unreachable_here;
183   /** True if control could reach here. */
184   public final boolean reachableHere () { return !unreachable_here; }
185   public final void setReachable(boolean val) { unreachable_here = !val; }
186   public final void setUnreachable() { unreachable_here = true; }
187
188   /** Get the maximum number of words on the operand stack in this method. */
189   public int getMaxStack() { return max_stack; }
190   /** Get the maximum number of local variable words in this method. */
191   public int getMaxLocals() { return max_locals; }
192
193   /** Set the maximum number of words on the operand stack in this method. */
194   public void setMaxStack(int n) { max_stack = n; }
195   /** Set the maximum number of local variable words in this method. */
196   public void setMaxLocals(int n) { max_locals = n; }
197
198   /** Get the code (instruction bytes) of this method.
199     * Does not make a copy. */

200   public byte[] getCode() { return code; }
201   /** Set the code (instruction bytes) of this method.
202     * @param code the code bytes (which are not copied).
203     * Implicitly calls setCodeLength(code.length). */

204   public void setCode(byte[] code) {
205     this.code = code; this.PC = code.length; }
206   /** Set the length the the code (instruction bytes) of this method.
207     * That is the number of current used bytes in getCode().
208     * (Any remaing bytes provide for future growth.) */

209   public void setCodeLength(int len) { PC = len;}
210   /** Set the current lengthof the code (instruction bytes) of this method. */
211   public int getCodeLength() { return PC; }
212
213   public CodeAttr (Method meth)
214   {
215     super ("Code");
216     addToFrontOf(meth);
217     meth.code = this;
218   }
219
220   public final void reserve (int bytes)
221   {
222     if (code == null)
223       code = new byte[100+bytes];
224     else if (PC + bytes > code.length)
225       {
226     byte[] new_code = new byte[2 * code.length + bytes];
227     System.arraycopy (code, 0, new_code, 0, PC);
228     code = new_code;
229       }
230   }
231
232   /** Get opcode that implements NOT (x OPCODE y). */
233   byte invert_opcode (byte opcode)
234   {
235     if ((opcode >= 153 && opcode <= 166)
236     || (opcode >= 198 && opcode <= 199))
237       return (byte) (opcode ^ 1);
238     throw new Error JavaDoc("unknown opcode to invert_opcode");
239   }
240
241   /**
242    * Write an 8-bit byte to the current code-stream.
243    * @param i the byte to write
244    */

245   public final void put1(int i)
246   {
247     code[PC++] = (byte) i;
248     unreachable_here = false;
249   }
250
251   /**
252    * Write a 16-bit short to the current code-stream
253    * @param i the value to write
254    */

255   public final void put2(int i)
256   {
257     code[PC++] = (byte) (i >> 8);
258     code[PC++] = (byte) (i);
259     unreachable_here = false;
260   }
261
262   /**
263    * Write a 32-bit int to the current code-stream
264    * @param i the value to write
265    */

266   public final void put4(int i)
267   {
268     code[PC++] = (byte) (i >> 24);
269     code[PC++] = (byte) (i >> 16);
270     code[PC++] = (byte) (i >> 8);
271
272     code[PC++] = (byte) (i);
273     unreachable_here = false;
274   }
275
276   public final void putIndex2 (CpoolEntry cnst)
277   {
278     put2(cnst.index);
279   }
280
281   public final void putLineNumber (String JavaDoc filename, int linenumber)
282   {
283     getMethod().classfile.setSourceFile(filename);
284     putLineNumber(linenumber);
285   }
286
287   public final void putLineNumber (int linenumber)
288   {
289     if (sourceDbgExt != null)
290       linenumber = sourceDbgExt.fixLine(linenumber);
291     fixupAdd(FIXUP_LINE_PC, null);
292     fixupAdd(FIXUP_LINE_NUMBER, linenumber, null);
293   }
294
295   public final void pushType(Type type)
296   {
297     if (type.size == 0)
298       throw new Error JavaDoc ("pushing void type onto stack");
299     if (stack_types == null)
300       stack_types = new Type[20];
301     else if (SP + 1 >= stack_types.length) {
302       Type[] new_array = new Type[2 * stack_types.length];
303       System.arraycopy (stack_types, 0, new_array, 0, SP);
304       stack_types = new_array;
305     }
306     if (type.size == 8)
307       stack_types[SP++] = Type.void_type;
308     stack_types[SP++] = type;
309     if (SP > max_stack)
310       max_stack = SP;
311   }
312
313   public final Type popType ()
314   {
315     if (SP <= 0)
316       throw new Error JavaDoc("popType called with empty stack "+getMethod());
317     Type type = stack_types[--SP];
318     if (type.size == 8)
319       if (! popType().isVoid())
320     throw new Error JavaDoc("missing void type on stack");
321     return type;
322   }
323
324   public final Type topType ()
325   {
326     return stack_types[SP - 1];
327   }
328
329   /** Compile code to pop values off the stack (and ignore them).
330    * @param nvalues the number of values (not words) to pop
331    */

332   public void emitPop (int nvalues)
333   {
334     for ( ; nvalues > 0; --nvalues)
335       {
336         reserve(1);
337     Type type = popType();
338     if (type.size > 4)
339       put1(88); // pop2
340
else if (nvalues > 1)
341       { // optimization: can we pop 2 4-byte words using a pop2
342
Type type2 = popType();
343         if (type2.size > 4)
344           {
345         put1(87); // pop
346
reserve(1);
347           }
348         put1(88); // pop2
349
--nvalues;
350       }
351     else
352       put1(87); // pop
353
}
354   }
355
356   /** Get a new Label for the current location.
357    * Unlike Label.define, Does not change reachableHere().
358    */

359   public Label getLabel ()
360   {
361     boolean unreachable = unreachable_here;
362     Label label = new Label();
363     label.define(this);
364     unreachable_here = unreachable;
365     return label;
366   }
367
368   public void emitSwap ()
369   {
370     reserve(1);
371     Type type1 = popType();
372     Type type2 = popType();
373
374     if (type1.size > 4 || type2.size > 4)
375       {
376     // There is no swap instruction in the JVM for this case.
377
// Fall back to a more convoluted way.
378
pushType(type2);
379     pushType(type1);
380     emitDupX();
381     emitPop(1);
382       }
383     else
384       {
385     pushType(type1);
386     put1(95); // swap
387
pushType(type2);
388       }
389   }
390
391   /** Emit code to duplicate the top element of the stack. */
392   public void emitDup ()
393   {
394     reserve(1);
395
396     Type type = topType();
397     put1 (type.size <= 4 ? 89 : 92); // dup or dup2
398
pushType (type);
399   }
400
401   /** Emit code to duplicate the top element of the stack
402       and place the copy before the previous element. */

403   public void emitDupX ()
404   {
405     reserve(1);
406
407     Type type = popType();
408     Type skipedType = popType();
409
410     if (skipedType.size <= 4)
411       put1 (type.size <= 4 ? 90 : 93); // dup_x1 or dup2_x1
412
else
413       put1 (type.size <= 4 ? 91 : 94); // dup_x2 or dup2_x2
414

415     pushType (type);
416     pushType (skipedType);
417     pushType (type);
418   }
419
420   /** Compile code to duplicate with offset.
421    * @param size the size of the stack item to duplicate (1 or 2)
422    * @param offset where to insert the result (must be 0, 1, or 2)
423    * The new words get inserted at stack[SP-size-offset]
424    */

425   public void emitDup (int size, int offset)
426   {
427     if (size == 0)
428       return;
429     reserve(1);
430     // copied1 and (optionally copied2) are the types of the duplicated words
431
Type copied1 = popType ();
432     Type copied2 = null;
433     if (size == 1)
434       {
435     if (copied1.size > 4)
436       throw new Error JavaDoc ("using dup for 2-word type");
437       }
438     else if (size != 2)
439       throw new Error JavaDoc ("invalid size to emitDup");
440     else if (copied1.size <= 4)
441       {
442     copied2 = popType();
443     if (copied2.size > 4)
444       throw new Error JavaDoc ("dup will cause invalid types on stack");
445       }
446
447     int kind;
448     // These are the types of the words (in any) that are "skipped":
449
Type skipped1 = null;
450     Type skipped2 = null;
451     if (offset == 0)
452       {
453     kind = size == 1 ? 89 : 92; // dup or dup2
454
}
455     else if (offset == 1)
456       {
457     kind = size == 1 ? 90 : 93; // dup_x1 or dup2_x1
458
skipped1 = popType ();
459     if (skipped1.size > 4)
460       throw new Error JavaDoc ("dup will cause invalid types on stack");
461       }
462     else if (offset == 2)
463       {
464     kind = size == 1 ? 91 : 94; // dup_x2 or dup2_x2
465
skipped1 = popType();
466     if (skipped1.size <= 4)
467       {
468         skipped2 = popType();
469         if (skipped2.size > 4)
470           throw new Error JavaDoc ("dup will cause invalid types on stack");
471       }
472       }
473     else
474       throw new Error JavaDoc ("emitDup: invalid offset");
475
476     put1(kind);
477     if (copied2 != null)
478       pushType(copied2);
479     pushType(copied1);
480     if (skipped2 != null)
481       pushType(skipped2);
482     if (skipped1 != null)
483       pushType(skipped1);
484     if (copied2 != null)
485       pushType(copied2);
486     pushType(copied1);
487   }
488
489   /**
490    * Compile code to duplicate the top 1 or 2 words.
491    * @param size number of words to duplicate
492    */

493   public void emitDup (int size)
494   {
495     emitDup(size, 0);
496   }
497
498   public void emitDup (Type type)
499   {
500     emitDup(type.size > 4 ? 2 : 1, 0);
501   }
502
503   public void enterScope (Scope scope)
504   {
505     scope.setStartPC(this);
506     locals.enterScope(scope);
507   }
508
509   public Scope pushScope () {
510     Scope scope = new Scope ();
511     if (locals == null)
512       locals = new LocalVarsAttr(getMethod());
513     enterScope(scope);
514     if (locals.parameter_scope == null)
515       locals.parameter_scope = scope;
516     return scope;
517   }
518
519   public Scope getCurrentScope()
520   {
521     return locals.current_scope;
522   }
523
524   public Scope popScope () {
525     Scope scope = locals.current_scope;
526     locals.current_scope = scope.parent;
527     scope.freeLocals(this);
528     scope.end = getLabel();
529     return scope;
530   }
531
532   /** Get the index'th parameter. */
533   public Variable getArg (int index)
534   {
535     return locals.parameter_scope.getVariable(index);
536   }
537
538   /**
539    * Search by name for a Variable
540    * @param name name to search for
541    * @return the Variable, or null if not found (in any scope of this Method).
542    */

543   public Variable lookup (String JavaDoc name)
544   {
545     Scope scope = locals.current_scope;
546     for (; scope != null; scope = scope.parent)
547       {
548     Variable var = scope.lookup (name);
549     if (var != null)
550       return var;
551       }
552     return null;
553   }
554
555   /** Add a new local variable (in the current scope).
556    * @param type type of the new Variable.
557    * @return the new Variable. */

558   public Variable addLocal (Type type)
559   {
560     return locals.current_scope.addVariable(this, type, null);
561   }
562
563   /** Add a new local variable (in the current scope).
564    * @param type type of the new Variable.
565    * @param name name of the new Variable.
566    * @return the new Variable. */

567   public Variable addLocal (Type type, String JavaDoc name)
568   {
569     return locals.current_scope.addVariable (this, type, name);
570   }
571
572   /** Call addLocal for parameters (as implied by method type). */
573   public void addParamLocals()
574   {
575     Method method = getMethod();
576     if ((method.access_flags & Access.STATIC) == 0)
577       addLocal(method.classfile).setParameter(true);
578     int arg_count = method.arg_types.length;
579     for (int i = 0; i < arg_count; i++)
580       addLocal(method.arg_types[i]).setParameter(true);
581   }
582
583   public final void emitPushConstant(int val, Type type)
584   {
585     switch (type.getSignature().charAt(0))
586       {
587       case 'B': case 'C': case 'I': case 'Z': case 'S':
588     emitPushInt(val); break;
589       case 'J':
590     emitPushLong((long)val); break;
591       case 'F':
592     emitPushFloat((float)val); break;
593       case 'D':
594     emitPushDouble((double)val); break;
595       default:
596     throw new Error JavaDoc("bad type to emitPushConstant");
597       }
598   }
599
600   /* Low-level method to pust a ConstantPool entry.
601    * Does not do the appropriatre <code>pushType</code>. */

602   public final void emitPushConstant (CpoolEntry cnst)
603   {
604     reserve(3);
605     int index = cnst.index;
606     if (cnst instanceof CpoolValue2)
607       {
608         put1 (20); // ldc2_w
609
put2 (index);
610       }
611     else if (index < 256)
612       {
613     put1(18); // ldc
614
put1(index);
615       }
616     else
617       {
618     put1(19); // ldc_w
619
put2(index);
620       }
621   }
622
623   public final void emitPushInt(int i)
624   {
625     reserve(3);
626     if (i >= -1 && i <= 5)
627       put1(i + 3); // iconst_m1 .. iconst_5
628
else if (i >= -128 && i < 128)
629       {
630     put1(16); // bipush
631
put1(i);
632       }
633     else if (i >= -32768 && i < 32768)
634       {
635     put1(17); // sipush
636
put2(i);
637       }
638     else
639       {
640     emitPushConstant(getConstants().addInt(i));
641       }
642     pushType(Type.int_type);
643   }
644
645   public void emitPushLong (long i)
646   {
647     if (i == 0 || i == 1)
648       {
649     reserve(1);
650     put1 (9 + (int) i); // lconst_0 .. lconst_1
651
}
652     else if ((long) (int) i == i)
653       {
654     emitPushInt ((int) i);
655     reserve(1);
656     popType();
657     put1 (133); // i2l
658
}
659     else
660       {
661     emitPushConstant(getConstants().addLong(i));
662       }
663     pushType(Type.long_type);
664   }
665
666   public void emitPushFloat (float x)
667   {
668     int xi = (int) x;
669     if ((float) xi == x && xi >= -128 && xi < 128)
670       {
671     if (xi >= 0 && xi <= 2)
672       {
673         reserve(1);
674         put1(11 + xi); // fconst_0 .. fconst_2
675
if (xi == 0 && Float.floatToIntBits(x) != 0) // x == -0.0
676
{
677         reserve(1);
678         put1(118); // fneg
679
}
680       }
681     else
682       {
683         // Saves space in the constant pool
684
// Probably faster, at least on modern CPUs.
685
emitPushInt (xi);
686         reserve(1);
687         popType();
688         put1 (134); // i2f
689
}
690       }
691     else
692       {
693     emitPushConstant(getConstants().addFloat(x));
694       }
695     pushType(Type.float_type);
696   }
697
698   public void emitPushDouble (double x)
699   {
700     int xi = (int) x;
701     if ((double) xi == x && xi >= -128 && xi < 128)
702       {
703     if (xi == 0 || xi == 1)
704       {
705         reserve(1);
706         put1(14+xi); // dconst_0 or dconst_1
707
if (xi == 0 && Double.doubleToLongBits(x) != 0L) // x == -0.0
708
{
709         reserve(1);
710         put1(119); // dneg
711
}
712       }
713     else
714       {
715         // Saves space in the constant pool
716
// Probably faster, at least on modern CPUs.
717
emitPushInt (xi);
718         reserve(1);
719         popType();
720         put1 (135); // i2d
721
}
722       }
723     else
724       {
725     emitPushConstant(getConstants().addDouble(x));
726       }
727     pushType(Type.double_type);
728   }
729
730   /** Calculate how many CONSTANT_String constants we need for a string.
731    * Each CONSTANT_String can be at most 0xFFFF bytes (as a UTF8 string).
732    * Returns a String, where each char, coerced to an int, is the length
733    * of a substring of the input that is at most 0xFFFF bytes.
734    */

735   public static final String JavaDoc calculateSplit (String JavaDoc str)
736   {
737     int strLength = str.length();
738     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(20);
739     // Where the current segments starts, as an index in 'str':
740
int segmentStart = 0;
741     int byteLength = 0; // Length in bytes of current segment so far.
742
for (int i = 0; i < strLength; i++)
743       {
744     char ch = str.charAt(i);
745     int bytes = ch >= 0x0800 ? 3 : ch >= 0x0080 || ch == 0 ? 2 : 1;
746     if (byteLength + bytes > 0xFFFF)
747       {
748         sbuf.append((char) (i - segmentStart));
749         segmentStart = i;
750         byteLength = 0;
751       }
752     byteLength += bytes;
753       }
754     sbuf.append((char) (strLength - segmentStart));
755     return sbuf.toString();
756   }
757
758   /** Emit code to push the value of a constant String.
759    * Uses CONSTANT_String and CONSTANT_Utf8 constant pool entries as needed.
760    * Can handle Strings whose UTF8 length is greates than 0xFFFF bytes
761    * (the limit of a CONSTANT_Utf8) by generating String concatenation.
762    */

763   public final void emitPushString (String JavaDoc str)
764   {
765     if (str == null)
766       emitPushNull();
767     else
768       {
769     int length = str.length();
770     String JavaDoc segments = calculateSplit(str);
771     int numSegments = segments.length();
772     if (numSegments <= 1)
773       emitPushConstant(getConstants().addString(str));
774     else
775       {
776         if (numSegments == 2)
777           {
778         int firstSegment = (int) segments.charAt(0);
779         emitPushString(str.substring(0, firstSegment));
780         emitPushString(str.substring(firstSegment));
781         Method concatMethod
782           = Type.string_type.getDeclaredMethod("concat", 1);
783         emitInvokeVirtual(concatMethod);
784           }
785         else
786           {
787         ClassType sbufType = ClassType.make("java.lang.StringBuffer");
788         emitNew(sbufType);
789         emitDup(sbufType);
790         emitPushInt(length);
791         Type[] args1 = { Type.int_type };
792         emitInvokeSpecial(sbufType.getDeclaredMethod("<init>", args1));
793         Type[] args2 = { Type.string_type };
794         Method appendMethod
795           = sbufType.getDeclaredMethod("append", args2);
796         int segStart = 0;
797         for (int seg = 0; seg < numSegments; seg++)
798           {
799             emitDup(sbufType);
800             int segEnd = segStart + (int) segments.charAt(seg);
801             emitPushString(str.substring(segStart, segEnd));
802             emitInvokeVirtual(appendMethod);
803             segStart = segEnd;
804           }
805         emitInvokeVirtual(Type.toString_method);
806           }
807         if (str == str.intern())
808           emitInvokeVirtual(Type.string_type.getDeclaredMethod("intern", 0));
809         return;
810       }
811     pushType(Type.string_type);
812       }
813   }
814
815   /** Push a class constant pool entry.
816    * This is only supported by JDK 1.5 and later. */

817   public final void emitPushClass (String JavaDoc name)
818   {
819     emitPushConstant(getConstants().addClass(name));
820     pushType(Type.java_lang_Class_type);
821   }
822
823   public void emitPushNull ()
824   {
825     reserve(1);
826     put1(1); // aconst_null
827
pushType(Type.pointer_type);
828   }
829
830   public final void emitPushThis()
831   {
832     reserve(1);
833     put1(42); // aload_0
834
pushType(getMethod().getDeclaringClass());
835   }
836
837   /** Emit code to push a constant primitive array.
838    * @param value The array value that we want the emitted code to re-create.
839    * @param arrayType The ArrayType that matches value.
840    */

841   public final void emitPushPrimArray(Object JavaDoc value, ArrayType arrayType)
842   {
843     Type elementType = arrayType.getComponentType();
844     int len = java.lang.reflect.Array.getLength(value);
845     emitPushInt(len);
846     emitNewArray(elementType);
847     char sig = elementType.getSignature().charAt(0);
848     for (int i = 0; i < len; i++)
849       {
850     long ival = 0; float fval = 0; double dval = 0;
851     switch (sig)
852       {
853       case 'J':
854         ival = ((long[]) value)[i];
855         if (ival == 0)
856           continue;
857         break;
858       case 'I':
859         ival = ((int[]) value)[i];
860         if (ival == 0)
861           continue;
862         break;
863       case 'S':
864         ival = ((short[]) value)[i];
865         if (ival == 0)
866           continue;
867         break;
868       case 'C':
869         ival = ((char[]) value)[i];
870         if (ival == 0)
871           continue;
872         break;
873       case 'B':
874         ival = ((byte[]) value)[i];
875         if (ival == 0)
876           continue;
877         break;
878       case 'Z':
879         ival = ((boolean[]) value)[i] ? 1 : 0;
880         if (ival == 0)
881           continue;
882         break;
883       case 'F':
884         fval = ((float[]) value)[i];
885         if (fval == 0.0)
886           continue;
887         break;
888       case 'D':
889         dval = ((double[]) value)[i];
890         if (dval == 0.0)
891           continue;
892         break;
893       }
894     emitDup(arrayType);
895     emitPushInt(i);
896     switch (sig)
897       {
898       case 'Z':
899       case 'C':
900       case 'B':
901       case 'S':
902       case 'I':
903         emitPushInt((int) ival);
904         break;
905       case 'J':
906         emitPushLong(ival);
907         break;
908       case 'F':
909         emitPushFloat(fval);
910         break;
911       case 'D':
912         emitPushDouble(dval);
913         break;
914       }
915     emitArrayStore(elementType);
916       }
917   }
918
919
920
921   void emitNewArray (int type_code)
922   {
923     reserve(2);
924     put1(188); // newarray
925
put1(type_code);
926   }
927
928   public final void emitArrayLength ()
929   {
930     if (! (popType() instanceof ArrayType))
931       throw new Error JavaDoc( "non-array type in emitArrayLength" );
932     
933     reserve(1);
934     put1(190); // arraylength
935
pushType(Type.int_type);
936   }
937
938   /* Returns an integer in the range 0 (for 'int') through 4 (for object
939      reference) to 7 (for 'short') which matches the pattern of how JVM
940      opcodes typically depend on the operand type. */

941
942   private int adjustTypedOp (char sig)
943   {
944     switch (sig)
945       {
946       case 'I': return 0; // int
947
case 'J': return 1; // long
948
case 'F': return 2; // float
949
case 'D': return 3; // double
950
default: return 4; // object
951
case 'B':
952       case 'Z': return 5; // byte or boolean
953
case 'C': return 6; // char
954
case 'S': return 7; // short
955
}
956   }
957
958   private int adjustTypedOp (Type type)
959   {
960     return adjustTypedOp(type.getSignature().charAt(0));
961   }
962
963   private void emitTypedOp (int op, Type type)
964   {
965     reserve(1);
966     put1(op + adjustTypedOp(type));
967   }
968
969   private void emitTypedOp (int op, char sig)
970   {
971     reserve(1);
972     put1(op + adjustTypedOp(sig));
973   }
974
975   /** Store into an element of an array.
976    * Must already have pushed the array reference, the index,
977    * and the new value (in that order).
978    * Stack: ..., array, index, value => ...
979    */

980   public void emitArrayStore (Type element_type)
981   {
982     popType(); // Pop new value
983
popType(); // Pop index
984
popType(); // Pop array reference
985
emitTypedOp(79, element_type);
986   }
987
988   /** Load an element from an array.
989    * Must already have pushed the array and the index (in that order):
990    * Stack: ..., array, index => ..., value */

991   public void emitArrayLoad (Type element_type)
992   {
993     popType(); // Pop index
994
popType(); // Pop array reference
995
emitTypedOp(46, element_type);
996     pushType(element_type);
997   }
998
999   /**
1000   * Invoke new on a class type.
1001   * Does not call the constructor!
1002   * @param type the desired new object type
1003   */

1004  public void emitNew (ClassType type)
1005  {
1006    reserve(3);
1007    put1(187); // new
1008
putIndex2(getConstants().addClass(type));
1009    pushType(type);
1010  }
1011
1012  /** Compile code to allocate a new array.
1013   * The size should have been already pushed on the stack.
1014   * @param element_type type of the array elements
1015   */

1016  public void emitNewArray (Type element_type, int dims)
1017  {
1018    if (popType ().promote () != Type.int_type)
1019      throw new Error JavaDoc ("non-int dim. spec. in emitNewArray");
1020
1021    if (element_type instanceof PrimType)
1022      {
1023    int code;
1024    switch (element_type.getSignature().charAt(0))
1025      {
1026      case 'B': code = 8; break;
1027      case 'S': code = 9; break;
1028      case 'I': code = 10; break;
1029      case 'J': code = 11; break;
1030      case 'F': code = 6; break;
1031      case 'D': code = 7; break;
1032      case 'Z': code = 4; break;
1033      case 'C': code = 5; break;
1034      default: throw new Error JavaDoc("bad PrimType in emitNewArray");
1035      }
1036    emitNewArray(code);
1037      }
1038    else if (element_type instanceof ObjectType)
1039      {
1040    reserve(3);
1041    put1(189); // anewarray
1042
putIndex2(getConstants().addClass((ObjectType) element_type));
1043      }
1044    else if (element_type instanceof ArrayType)
1045    {
1046      reserve(4);
1047      put1(197); // multianewarray
1048
putIndex2 (getConstants ().addClass (new ArrayType (element_type)));
1049      if (dims < 1 || dims > 255)
1050    throw new Error JavaDoc ("dims out of range in emitNewArray");
1051      put1(dims);
1052      while (-- dims > 0) // first dim already popped
1053
if (popType ().promote () != Type.int_type)
1054      throw new Error JavaDoc ("non-int dim. spec. in emitNewArray");
1055    }
1056    else
1057      throw new Error JavaDoc ("unimplemented type in emitNewArray");
1058
1059    pushType (new ArrayType (element_type));
1060  }
1061
1062  public void emitNewArray (Type element_type)
1063  {
1064    emitNewArray (element_type, 1);
1065  }
1066
1067  // We may want to deprecate this, because it depends on popType.
1068
private void emitBinop (int base_code)
1069  {
1070    Type type2 = popType().promote();
1071    Type type1_raw = popType();
1072    Type type1 = type1_raw.promote();
1073    if (type1 != type2 || ! (type1 instanceof PrimType))
1074      throw new Error JavaDoc ("non-matching or bad types in binary operation");
1075    emitTypedOp(base_code, type1);
1076    pushType(type1_raw);
1077  }
1078
1079  private void emitBinop (int base_code, char sig)
1080  {
1081    popType();
1082    popType();
1083    emitTypedOp(base_code, sig);
1084    pushType(Type.signatureToPrimitive(sig));
1085  }
1086
1087  private void emitBinop (int base_code, Type type)
1088  {
1089    popType();
1090    popType();
1091    emitTypedOp(base_code, type);
1092    pushType(type);
1093  }
1094
1095  // public final void emitIntAdd () { put1(96); popType();}
1096
// public final void emitLongAdd () { put1(97); popType();}
1097
// public final void emitFloatAdd () { put1(98); popType();}
1098
// public final void emitDoubleAdd () { put1(99); popType();}
1099

1100  public final void emitAdd(char sig) { emitBinop (96, sig); }
1101  public final void emitAdd(PrimType type) { emitBinop (96, type); }
1102  /** @deprecated */
1103  public final void emitAdd () { emitBinop (96); }
1104
1105  public final void emitSub(char sig) { emitBinop (100, sig); }
1106  public final void emitSub(PrimType type) { emitBinop (100, type); }
1107  /** @deprecated */
1108  public final void emitSub () { emitBinop (100); }
1109
1110  public final void emitMul () { emitBinop (104); }
1111  public final void emitDiv () { emitBinop (108); }
1112  public final void emitRem () { emitBinop (112); }
1113  public final void emitAnd () { emitBinop (126); }
1114  public final void emitIOr () { emitBinop (128); }
1115  public final void emitXOr () { emitBinop (130); }
1116
1117  public final void emitShl () { emitShift (120); }
1118  public final void emitShr () { emitShift (122); }
1119  public final void emitUshr() { emitShift (124); }
1120
1121  private void emitShift (int base_code)
1122  {
1123    Type type2 = popType().promote();
1124    Type type1_raw = popType();
1125    Type type1 = type1_raw.promote();
1126
1127    if (type1 != Type.int_type && type1 != Type.long_type)
1128      throw new Error JavaDoc ("the value shifted must be an int or a long");
1129
1130    if (type2 != Type.int_type)
1131      throw new Error JavaDoc ("the amount of shift must be an int");
1132
1133    emitTypedOp(base_code, type1);
1134    pushType(type1_raw);
1135  }
1136
1137  public final void emitNot(Type type)
1138  {
1139    emitPushConstant(1, type);
1140    emitAdd();
1141    emitPushConstant(1, type);
1142    emitAnd();
1143  }
1144
1145  public void emitPrimop (int opcode, int arg_count, Type retType)
1146  {
1147    reserve(1);
1148    while (-- arg_count >= 0)
1149      popType();
1150    put1(opcode);
1151    pushType(retType);
1152  }
1153
1154  void emitMaybeWide (int opcode, int index)
1155  {
1156    if (index >= 256)
1157      {
1158    put1(196); // wide
1159
put1(opcode);
1160    put2(index);
1161      }
1162    else
1163      {
1164    put1(opcode);
1165    put1(index);
1166      }
1167  }
1168
1169  /**
1170   * Compile code to push the contents of a local variable onto the statck.
1171   * @param var The variable whose contents we want to push.
1172   */

1173  public final void emitLoad (Variable var)
1174  {
1175    if (var.dead())
1176      throw new Error JavaDoc("attempting to push dead variable");
1177    int offset = var.offset;
1178    if (offset < 0 || !var.isSimple())
1179      throw new Error JavaDoc ("attempting to load from unassigned variable "+var
1180               +" simple:"+var.isSimple()+", offset: "+offset);
1181    Type type = var.getType().promote();
1182    reserve(4);
1183    int kind = adjustTypedOp(type);
1184    if (offset <= 3)
1185      put1(26 + 4 * kind + offset); // [ilfda]load_[0123]
1186
else
1187      emitMaybeWide(21 + kind, offset); // [ilfda]load
1188
pushType(var.getType());
1189  }
1190
1191  public void emitStore (Variable var)
1192  {
1193    if (var.dead ())
1194      throw new Error JavaDoc("attempting to push dead variable");
1195    int offset = var.offset;
1196    if (offset < 0 || !var.isSimple ())
1197      throw new Error JavaDoc ("attempting to store in unassigned "+var
1198               +" simple:"+var.isSimple()+", offset: "+offset);
1199    Type type = var.getType().promote ();
1200    reserve(4);
1201    popType();
1202    int kind = adjustTypedOp(type);
1203    if (offset <= 3)
1204      put1(59 + 4 * kind + offset); // [ilfda]store_[0123]
1205
else
1206      emitMaybeWide(54 + kind, offset); // [ilfda]store
1207
}
1208
1209
1210  public void emitInc (Variable var, short inc)
1211  {
1212    if (var.dead ())
1213      throw new Error JavaDoc ("attempting to increment dead variable");
1214    int offset = var.offset;
1215    if (offset < 0 || !var.isSimple ())
1216      throw new Error JavaDoc ("attempting to increment unassigned variable"+var.getName()
1217               +" simple:"+var.isSimple()+", offset: "+offset);
1218    Type type = var.getType().promote ();
1219    reserve(6);
1220    if (type != Type.int_type)
1221      throw new Error JavaDoc("attempting to increment non-int variable");
1222
1223    boolean wide = offset > 255 || inc > 255 || inc < -256;
1224
1225    if (wide)
1226    {
1227      put1(196); // wide
1228
put1(132); // iinc
1229
put2(offset);
1230      put2(inc);
1231    }
1232    else
1233    {
1234      put1(132); // iinc
1235
put1(offset);
1236      put1(inc);
1237    }
1238  }
1239  
1240
1241  private final void emitFieldop (Field field, int opcode)
1242  {
1243    reserve(3);
1244    put1(opcode);
1245    putIndex2(getConstants().addFieldRef(field));
1246  }
1247
1248  /** Compile code to get a static field value.
1249   * Stack: ... => ..., value */

1250
1251  public final void emitGetStatic(Field field)
1252  {
1253    pushType(field.type);
1254    emitFieldop (field, 178); // getstatic
1255
}
1256
1257  /** Compile code to get a non-static field value.
1258   * Stack: ..., objectref => ..., value */

1259
1260  public final void emitGetField(Field field)
1261  {
1262    popType();
1263    pushType(field.type);
1264    emitFieldop(field, 180); // getfield
1265
}
1266
1267  /** Compile code to put a static field value.
1268   * Stack: ..., value => ... */

1269
1270  public final void emitPutStatic (Field field)
1271  {
1272    popType();
1273    emitFieldop(field, 179); // putstatic
1274
}
1275
1276  /** Compile code to put a non-static field value.
1277   * Stack: ..., objectref, value => ... */

1278
1279  public final void emitPutField (Field field)
1280  {
1281    popType();
1282    popType();
1283    emitFieldop(field, 181); // putfield
1284
}
1285
1286  /** Comptes the number of stack words taken by a list of types. */
1287  private int words(Type[] types)
1288  {
1289    int res = 0;
1290    for (int i=types.length; --i >= 0; )
1291      if (types[i].size > 4)
1292       res+=2;
1293      else
1294       res++;
1295    return res;
1296  }
1297
1298  public void emitInvokeMethod (Method method, int opcode)
1299  {
1300    reserve(opcode == 185 ? 5 : 3);
1301    int arg_count = method.arg_types.length;
1302    boolean is_invokestatic = opcode == 184;
1303    if (is_invokestatic != ((method.access_flags & Access.STATIC) != 0))
1304      throw new Error JavaDoc
1305    ("emitInvokeXxx static flag mis-match method.flags="+method.access_flags);
1306    if (!is_invokestatic)
1307      arg_count++;
1308    put1(opcode); // invokevirtual, invokespecial, or invokestatic
1309
putIndex2(getConstants().addMethodRef(method));
1310    if (opcode == 185) // invokeinterface
1311
{
1312    put1(words(method.arg_types)+1); // 1 word for 'this'
1313
put1(0);
1314      }
1315    while (--arg_count >= 0)
1316      popType();
1317    if (method.return_type.size != 0)
1318      pushType(method.return_type);
1319  }
1320
1321  public void emitInvoke (Method method)
1322  {
1323    int opcode;
1324    if ((method.access_flags & Access.STATIC) != 0)
1325      opcode = 184; // invokestatic
1326
else if (method.classfile.isInterface())
1327      opcode = 185; // invokeinterface
1328
else if ("<init>".equals(method.getName()))
1329      opcode = 183; // invokespecial
1330
else
1331      opcode = 182; // invokevirtual
1332
emitInvokeMethod(method, opcode);
1333  }
1334
1335  /** Compile a virtual method call.
1336   * The stack contains the 'this' object, followed by the arguments in order.
1337   * @param method the method to invoke virtually
1338   */

1339  public void emitInvokeVirtual (Method method)
1340  {
1341    emitInvokeMethod(method, 182); // invokevirtual
1342
}
1343
1344  public void emitInvokeSpecial (Method method)
1345  {
1346    emitInvokeMethod(method, 183); // invokespecial
1347
}
1348
1349  /** Compile a static method call.
1350   * The stack contains the the arguments in order.
1351   * @param method the static method to invoke
1352   */

1353  public void emitInvokeStatic (Method method)
1354  {
1355    emitInvokeMethod(method, 184); // invokestatic
1356
}
1357
1358  public void emitInvokeInterface (Method method)
1359  {
1360    emitInvokeMethod(method, 185); // invokeinterface
1361
}
1362  
1363  final void emitTransfer (Label label, int opcode)
1364  {
1365    fixupAdd(FIXUP_TRANSFER, label);
1366    put1(opcode);
1367    PC += 2;
1368  }
1369
1370  /** Compile an unconditional branch (goto).
1371   * @param label target of the branch (must be in this method).
1372   */

1373  public final void emitGoto (Label label)
1374  {
1375    fixupAdd(FIXUP_GOTO, label);
1376    reserve(3);
1377    put1(167);
1378    PC += 2;
1379    setUnreachable();
1380  }
1381
1382  public final void emitJsr (Label label)
1383  {
1384    fixupAdd(FIXUP_JSR, label);
1385    reserve(3);
1386    put1(168);
1387    PC += 2;
1388  }
1389
1390  public final void emitGotoIfCompare1 (Label label, int opcode)
1391  {
1392    popType();
1393    reserve(3);
1394    emitTransfer (label, opcode);
1395  }
1396
1397  public final void emitGotoIfIntEqZero(Label label)
1398  { emitGotoIfCompare1(label, 153); }
1399  public final void emitGotoIfIntNeZero(Label label)
1400  { emitGotoIfCompare1(label, 154); }
1401  public final void emitGotoIfIntLtZero(Label label)
1402  { emitGotoIfCompare1(label, 155); }
1403  public final void emitGotoIfIntGeZero(Label label)
1404  { emitGotoIfCompare1(label, 156); }
1405  public final void emitGotoIfIntGtZero(Label label)
1406  { emitGotoIfCompare1(label, 157); }
1407  public final void emitGotoIfIntLeZero(Label label)
1408  { emitGotoIfCompare1(label, 158); }
1409
1410  public final void emitGotoIfCompare2 (Label label, int logop)
1411  {
1412    if( logop < 153 || logop > 158 )
1413      throw new Error JavaDoc ("emitGotoIfCompare2: logop must be one of ifeq...ifle");
1414    
1415    Type type2 = popType().promote();
1416    Type type1 = popType().promote();
1417    reserve(4);
1418    char sig1 = type1.getSignature().charAt(0);
1419    char sig2 = type2.getSignature().charAt(0);
1420
1421    boolean cmpg = (logop == 155 || logop == 158); // iflt,ifle
1422

1423    if (sig1 == 'I' && sig2 == 'I')
1424      logop += 6; // iflt -> if_icmplt etc.
1425
else if (sig1 == 'J' && sig2 == 'J')
1426      put1(148); // lcmp
1427
else if (sig1 == 'F' && sig2 == 'F')
1428      put1(cmpg ? 149 : 150); // fcmpl/fcmpg
1429
else if (sig1 == 'D' && sig2 == 'D')
1430      put1(cmpg ? 151 : 152); // dcmpl/dcmpg
1431
else if ((sig1 == 'L' || sig1 == '[')
1432         && (sig2 == 'L' || sig2 == '[')
1433         && logop <= 154)
1434      logop += 12; // ifeq->if_acmpeq, ifne->if_acmpne
1435
else
1436      throw new Error JavaDoc ("invalid types to emitGotoIfCompare2");
1437
1438    emitTransfer (label, logop);
1439  }
1440
1441  // binary comparisons
1442
/** @deprecated */
1443  public final void emitGotoIfEq (Label label, boolean invert)
1444  {
1445    emitGotoIfCompare2(label, invert ? 154 : 153);
1446  }
1447
1448  /** Compile a conditional transfer if 2 top stack elements are equal. */
1449  public final void emitGotoIfEq (Label label)
1450  {
1451    emitGotoIfCompare2(label, 153);
1452  }
1453
1454  /** Compile conditional transfer if 2 top stack elements are not equal. */
1455  public final void emitGotoIfNE (Label label)
1456  {
1457    emitGotoIfCompare2(label, 154);
1458  }
1459
1460  public final void emitGotoIfLt(Label label)
1461  { emitGotoIfCompare2(label, 155); }
1462  public final void emitGotoIfGe(Label label)
1463  { emitGotoIfCompare2(label, 156); }
1464  public final void emitGotoIfGt(Label label)
1465  { emitGotoIfCompare2(label, 157); }
1466  public final void emitGotoIfLe(Label label)
1467  { emitGotoIfCompare2(label, 158); }
1468
1469
1470  /** Compile start of a conditional:
1471   * <tt>if (!(<var>x</var> opcode 0)) ...</tt>.
1472   * The value of <var>x</var> must already have been pushed. */

1473  public final void emitIfCompare1 (int opcode)
1474  {
1475    IfState new_if = new IfState(this);
1476    if (popType().promote() != Type.int_type)
1477      throw new Error JavaDoc ("non-int type to emitIfCompare1");
1478    reserve(3);
1479    emitTransfer (new_if.end_label, opcode);
1480    new_if.start_stack_size = SP;
1481  }
1482
1483  /** Compile start of conditional: <tt>if (x != 0) ...</tt>.
1484   * Also use this if you have pushed a boolean value: if (b) ... */

1485  public final void emitIfIntNotZero()
1486  {
1487    emitIfCompare1(153); // ifeq
1488
}
1489
1490  /** Compile start of conditional: <tt>if (x == 0) ...</tt>.
1491   * Also use this if you have pushed a boolean value: if (!b) ... */

1492  public final void emitIfIntEqZero()
1493  {
1494    emitIfCompare1(154); // ifne
1495
}
1496
1497  /** Compile start of conditional: <tt>if (x <= 0)</tt>. */
1498  public final void emitIfIntLEqZero()
1499  {
1500    emitIfCompare1(157); // ifgt
1501
}
1502
1503  /** Compile start of a conditional: <tt>if (!(x opcode null)) ...</tt>.
1504   * The value of <tt>x</tt> must already have been pushed and must be of
1505   * reference type. */

1506  public final void emitIfRefCompare1 (int opcode)
1507  {
1508    IfState new_if = new IfState(this);
1509    if (! (popType() instanceof ObjectType))
1510      throw new Error JavaDoc ("non-ref type to emitIfRefCompare1");
1511    reserve(3);
1512    emitTransfer (new_if.end_label, opcode);
1513    new_if.start_stack_size = SP;
1514  }
1515  
1516  /** Compile start of conditional: if (x != null) */
1517  public final void emitIfNotNull()
1518  {
1519    emitIfRefCompare1(198); // ifnull
1520
}
1521
1522  /** Compile start of conditional: if (x == null) */
1523  public final void emitIfNull()
1524  {
1525    emitIfRefCompare1(199); // ifnonnull
1526
}
1527  
1528  /** Compile start of a conditional: if (!(x OPCODE y)) ...
1529   * The value of x and y must already have been pushed. */

1530  public final void emitIfIntCompare(int opcode)
1531  {
1532    IfState new_if = new IfState(this);
1533    popType();
1534    popType();
1535    reserve(3);
1536    emitTransfer(new_if.end_label, opcode);
1537    new_if.start_stack_size = SP;
1538  }
1539
1540  /* Compile start of a conditional: if (x < y) ... */
1541  public final void emitIfIntLt()
1542  {
1543    emitIfIntCompare(162); // if_icmpge
1544
}
1545
1546  /** Compile start of a conditional: if (x != y) ...
1547   * The values of x and y must already have been pushed. */

1548  public final void emitIfNEq ()
1549  {
1550    IfState new_if = new IfState (this);
1551    emitGotoIfEq(new_if.end_label);
1552    new_if.start_stack_size = SP;
1553  }
1554
1555  /** Compile start of a conditional: if (x == y) ...
1556   * The values of x and y must already have been pushed. */

1557  public final void emitIfEq ()
1558  {
1559    IfState new_if = new IfState (this);
1560    emitGotoIfNE(new_if.end_label);
1561    new_if.start_stack_size = SP;
1562  }
1563
1564  /** Compile start of a conditional: if (x < y) ...
1565   * The values of x and y must already have been pushed. */

1566  public final void emitIfLt ()
1567  {
1568    IfState new_if = new IfState (this);
1569    emitGotoIfGe(new_if.end_label);
1570    new_if.start_stack_size = SP;
1571  }
1572
1573  /** Compile start of a conditional: if (x >= y) ...
1574   * The values of x and y must already have been pushed. */

1575  public final void emitIfGe ()
1576  {
1577    IfState new_if = new IfState (this);
1578    emitGotoIfLt(new_if.end_label);
1579    new_if.start_stack_size = SP;
1580  }
1581
1582  /** Compile start of a conditional: if (x > y) ...
1583   * The values of x and y must already have been pushed. */

1584  public final void emitIfGt ()
1585  {
1586    IfState new_if = new IfState (this);
1587    emitGotoIfLe(new_if.end_label);
1588    new_if.start_stack_size = SP;
1589  }
1590
1591  /** Compile start of a conditional: if (x <= y) ...
1592   * The values of x and y must already have been pushed. */

1593  public final void emitIfLe ()
1594  {
1595    IfState new_if = new IfState (this);
1596    emitGotoIfGt(new_if.end_label);
1597    new_if.start_stack_size = SP;
1598  }
1599
1600  /** Emit a 'ret' instruction.
1601    * @param var the variable containing the return address */

1602  public void emitRet (Variable var)
1603  {
1604    int offset = var.offset;
1605    if (offset < 256)
1606      {
1607    reserve(2);
1608    put1(169); // ret
1609
put1(offset);
1610      }
1611    else
1612      {
1613    reserve(4);
1614    put1(196); // wide
1615
put1(169); // ret
1616
put2(offset);
1617      }
1618  }
1619
1620  public final void emitThen()
1621  {
1622    if_stack.start_stack_size = SP;
1623  }
1624
1625  public final void emitIfThen ()
1626  {
1627    new IfState(this, null);
1628  }
1629
1630  /** Compile start of else clause. */
1631  public final void emitElse ()
1632  {
1633    Label else_label = if_stack.end_label;
1634    Label end_label = new Label (this);
1635    if_stack.end_label = end_label;
1636    if (reachableHere ())
1637      {
1638    int growth = SP-if_stack.start_stack_size;
1639    if_stack.stack_growth = growth;
1640    if (growth > 0)
1641      {
1642        if_stack.then_stacked_types = new Type[growth];
1643        System.arraycopy (stack_types, if_stack.start_stack_size,
1644                  if_stack.then_stacked_types, 0, growth);
1645      }
1646    else
1647      if_stack.then_stacked_types = new Type[0]; // ???
1648
emitGoto (end_label);
1649      }
1650    while (SP > if_stack.start_stack_size)
1651      popType();
1652    SP = if_stack.start_stack_size;
1653    if (else_label != null)
1654      else_label.define (this);
1655    if_stack.doing_else = true;
1656  }
1657
1658  /** Compile end of conditional. */
1659  public final void emitFi ()
1660  {
1661    boolean make_unreachable = false;
1662    if (! if_stack.doing_else)
1663      { // There was no 'else' clause.
1664
if (reachableHere ()
1665        && SP != if_stack.start_stack_size)
1666      throw new Error JavaDoc("at PC "+PC+" then clause grows stack with no else clause");
1667      }
1668    else if (if_stack.then_stacked_types != null)
1669      {
1670    int then_clause_stack_size
1671      = if_stack.start_stack_size + if_stack.stack_growth;
1672    if (! reachableHere ())
1673      {
1674        if (if_stack.stack_growth > 0)
1675          System.arraycopy (if_stack.then_stacked_types, 0,
1676                stack_types, if_stack.start_stack_size,
1677                if_stack.stack_growth);
1678        SP = then_clause_stack_size;
1679      }
1680    else if (SP != then_clause_stack_size)
1681      throw new Error JavaDoc("at PC "+PC+": SP at end of 'then' was " +
1682              then_clause_stack_size
1683              + " while SP at end of 'else' was " + SP);
1684      }
1685    else if (unreachable_here)
1686      make_unreachable = true;
1687
1688    if (if_stack.end_label != null)
1689      if_stack.end_label.define (this);
1690    if (make_unreachable)
1691      setUnreachable();
1692    // Pop the if_stack.
1693
if_stack = if_stack.previous;
1694  }
1695
1696  public final void emitConvert (Type from, Type to)
1697  {
1698    String JavaDoc to_sig = to.getSignature();
1699    String JavaDoc from_sig = from.getSignature();
1700    int op = -1;
1701    if (to_sig.length() == 1 || from_sig.length() == 1)
1702      {
1703    char to_sig0 = to_sig.charAt(0);
1704    char from_sig0 = from_sig.charAt(0);
1705    if (from_sig0 == to_sig0)
1706      return;
1707    if (from.size < 4)
1708      from_sig0 = 'I';
1709    if (to.size < 4)
1710      {
1711        emitConvert(from, Type.int_type);
1712        from_sig0 = 'I';
1713      }
1714    if (from_sig0 == to_sig0)
1715      return;
1716    switch (from_sig0)
1717      {
1718      case 'I':
1719        switch (to_sig0)
1720          {
1721            case 'B': op = 145; break; // i2b
1722
case 'C': op = 146; break; // i2c
1723
case 'S': op = 147; break; // i2s
1724
case 'J': op = 133; break; // i2l
1725
case 'F': op = 134; break; // i2f
1726
case 'D': op = 135; break; // i2d
1727
}
1728        break;
1729      case 'J':
1730        switch (to_sig0)
1731          {
1732        case 'I': op = 136; break; // l2i
1733
case 'F': op = 137; break; // l2f
1734
case 'D': op = 138; break; // l2d
1735
}
1736        break;
1737      case 'F':
1738        switch (to_sig0)
1739          {
1740        case 'I': op = 139; break; // f2i
1741
case 'J': op = 140; break; // f2l
1742
case 'D': op = 141; break; // f2d
1743
}
1744        break;
1745      case 'D':
1746        switch (to_sig0)
1747          {
1748        case 'I': op = 142; break; // d2i
1749
case 'J': op = 143; break; // d2l
1750
case 'F': op = 144; break; // d2f
1751
}
1752        break;
1753      }
1754      }
1755    if (op < 0)
1756      throw new Error JavaDoc ("unsupported CodeAttr.emitConvert");
1757    reserve(1);
1758    popType();
1759    put1(op);
1760    pushType(to);
1761  }
1762
1763  private void emitCheckcast (Type type, int opcode)
1764  {
1765    reserve(3);
1766    popType();
1767    put1(opcode);
1768    if (type instanceof ArrayType)
1769      {
1770    ArrayType atype = (ArrayType) type;
1771    CpoolUtf8 name = getConstants().addUtf8(atype.signature);
1772    putIndex2(getConstants().addClass(name));
1773      }
1774    else if (type instanceof ClassType)
1775      {
1776    putIndex2(getConstants().addClass((ClassType) type));
1777      }
1778    else
1779      throw new Error JavaDoc ("unimplemented type " + type
1780               + " in emitCheckcast/emitInstanceof");
1781  }
1782
1783  public static boolean castNeeded (Type top, Type required)
1784  {
1785    for (;;)
1786      {
1787        if (required instanceof ClassType
1788            && top instanceof ClassType
1789            && ((ClassType) top).isSubclass((ClassType) required))
1790          return false;
1791        else if (required instanceof ArrayType
1792                 && top instanceof ArrayType)
1793          {
1794            required = ((ArrayType) required).getComponentType();
1795            top = ((ArrayType) top).getComponentType();
1796            continue;
1797          }
1798        return true;
1799      }
1800  }
1801
1802  public void emitCheckcast (Type type)
1803  {
1804    if (castNeeded(topType(), type))
1805      {
1806        emitCheckcast(type, 192);
1807        pushType(type);
1808      }
1809  }
1810
1811  public void emitInstanceof (Type type)
1812  {
1813    emitCheckcast(type, 193);
1814    pushType(Type.boolean_type);
1815  }
1816
1817  public final void emitThrow ()
1818  {
1819    popType();
1820    reserve(1);
1821    put1 (191); // athrow
1822
setUnreachable();
1823  }
1824
1825  public final void emitMonitorEnter ()
1826  {
1827    popType();
1828    reserve(1);
1829    put1 (194); // monitorenter
1830
}
1831
1832  public final void emitMonitorExit ()
1833  {
1834    popType();
1835    reserve(1);
1836    put1 (195); // monitorexit
1837
}
1838
1839  /** Call pending finalizer functions.
1840   * @param limit Only call finalizers more recent than this.
1841   */

1842  public void doPendingFinalizers (TryState limit)
1843  {
1844    TryState stack = try_stack;
1845
1846    /* If a value is returned, it must be saved to a local variable,
1847       to prevent a verification error because of inconsistent stack sizes.
1848    */

1849    boolean saveResult = ! getMethod().getReturnType().isVoid();
1850    Variable result = null;
1851
1852    while (stack != limit)
1853      {
1854    if (stack.finally_subr != null // there is a finally block
1855
&& stack.finally_ret_addr == null) // 'return' is not inside it
1856
{
1857        if (saveResult && result == null)
1858          {
1859        result = addLocal(topType());
1860        emitStore(result);
1861          }
1862        emitJsr(stack.finally_subr);
1863      }
1864
1865    stack = stack.previous;
1866      }
1867
1868    if (result != null)
1869      emitLoad(result);
1870    // We'd like to do freeLocal on the result Variable, but then we risk
1871
// it being re-used in a finalizer, which would trash its value. We
1872
// don't have any convenient way to to do that (the pending Scope
1873
// mechanism is over-kill), we for now we just leak the Variable.
1874
}
1875
1876  /**
1877   * Compile a method return.
1878   * If inside a 'catch' clause, first call 'finally' clauses.
1879   * The return value (unless the return type is void) must be on the stack,
1880   * and have the correct type.
1881   */

1882  public final void emitReturn ()
1883  {
1884    doPendingFinalizers(null);
1885    if (getMethod().getReturnType().size == 0)
1886      {
1887    reserve(1);
1888    put1(177); // return
1889
}
1890    else
1891      emitTypedOp (172, popType().promote());
1892    setUnreachable();
1893  }
1894
1895  /** Add an exception handler. */
1896  public void addHandler (int start_pc, int end_pc,
1897              int handler_pc, int catch_type)
1898  {
1899    int index = 4 * exception_table_length;
1900    if (exception_table == null)
1901      {
1902    exception_table = new short[20];
1903      }
1904    else if (exception_table.length <= index)
1905      {
1906    short[] new_table = new short[2 * exception_table.length];
1907    System.arraycopy(exception_table, 0, new_table, 0, index);
1908    exception_table = new_table;
1909      }
1910    exception_table[index++] = (short) start_pc;
1911    exception_table[index++] = (short) end_pc;
1912    exception_table[index++] = (short) handler_pc;
1913    exception_table[index++] = (short) catch_type;
1914    exception_table_length++;
1915  }
1916
1917  /** Add an exception handler. */
1918  public void addHandler (Label start_try, Label end_try,
1919              ClassType catch_type)
1920  {
1921    ConstantPool constants = getConstants();
1922    int catch_type_index;
1923    if (catch_type == null)
1924      catch_type_index = 0;
1925    else
1926      catch_type_index = constants.addClass(catch_type).index;
1927    fixupAdd(FIXUP_TRY, start_try);
1928    fixupAdd(FIXUP_CATCH, catch_type_index, end_try);
1929  }
1930
1931  /** Beginning of code that has a cleanup handler.
1932   * This is similar to a try-finally, but the cleanup is only
1933   * done in the case of an exception. Alternatively, the try clause
1934   * has to manually do the cleanup with code duplication.
1935   * Equivalent to: <code>try <var>body</var> catch (Throwable ex) { <var>cleanup</var>; throw ex; }</code>
1936   * Call <code>emitWithCleanupStart</code> before the <code><var>body</var></code>.
1937   */

1938  public void emitWithCleanupStart ()
1939  {
1940    int savedSP = SP;
1941    SP = 0;
1942    emitTryStart(false, null);
1943    SP = savedSP;
1944  }
1945
1946  /** Called after a <code><var>body</var></code> that has a <code><var>cleanup</var></code> clause.
1947   * Followed by the <code><var>cleanup</var></code> code.
1948   */

1949  public void emitWithCleanupCatch (Variable catchVar)
1950  {
1951    emitTryEnd();
1952    Type[] savedTypes;
1953    if (SP > 0)
1954      {
1955        savedTypes = new Type[SP];
1956        System.arraycopy(stack_types, 0, savedTypes, 0, SP);
1957        SP = 0;
1958      }
1959    else
1960      savedTypes = null;
1961    try_stack.savedTypes = savedTypes;
1962
1963    try_stack.saved_result = catchVar;
1964    int save_SP = SP;
1965    emitCatchStart(catchVar);
1966  }
1967
1968  /** Called after generating a <code><var>cleanup</var></code> handler. */
1969
1970  public void emitWithCleanupDone ()
1971  {
1972    Variable catchVar = try_stack.saved_result;
1973    try_stack.saved_result = null;
1974    if (catchVar != null)
1975      emitLoad(catchVar);
1976    emitThrow();
1977    emitCatchEnd();
1978    Type[] savedTypes = try_stack.savedTypes;
1979    emitTryCatchEnd();
1980    if (savedTypes != null)
1981      {
1982        SP = savedTypes.length;
1983        if (SP >= stack_types.length)
1984          stack_types = savedTypes;
1985        else
1986          System.arraycopy(savedTypes, 0, stack_types, 0, SP);
1987      }
1988    else
1989      SP = 0;
1990  }
1991
1992
1993  public void emitTryStart(boolean has_finally, Type result_type)
1994  {
1995    if (result_type != null && result_type.isVoid())
1996      result_type = null;
1997    Variable[] savedStack = null;
1998    if (result_type != null || SP > 0)
1999      pushScope();
2000    if (SP > 0)
2001      {
2002    savedStack = new Variable[SP];
2003    int i = 0;
2004    while (SP > 0)
2005      {
2006        Variable var = addLocal(topType());
2007        emitStore(var);
2008        savedStack[i++] = var;
2009      }
2010      }
2011    TryState try_state = new TryState(this);
2012    try_state.savedStack = savedStack;
2013    if (result_type != null)
2014      try_state.saved_result = addLocal(result_type);
2015    if (has_finally)
2016      try_state.finally_subr = new Label();
2017  }
2018
2019  public void emitTryEnd()
2020  {
2021    if (try_stack.end_label == null)
2022      {
2023    if (try_stack.saved_result != null && reachableHere())
2024      emitStore(try_stack.saved_result);
2025    try_stack.end_label = new Label();
2026    if (reachableHere())
2027      {
2028        if (try_stack.finally_subr != null)
2029          emitJsr(try_stack.finally_subr);
2030        emitGoto(try_stack.end_label);
2031      }
2032    try_stack.end_try = getLabel();
2033      }
2034  }
2035
2036  public void emitCatchStart(Variable var)
2037  {
2038    emitTryEnd();
2039    SP = 0;
2040    if (try_stack.try_type != null)
2041      emitCatchEnd();
2042    ClassType type = var == null ? null : (ClassType) var.getType();
2043    try_stack.try_type = type;
2044    addHandler(try_stack.start_try, try_stack.end_try, type);
2045    if (var != null)
2046      {
2047    pushType(type);
2048    emitStore(var);
2049      }
2050    else
2051      pushType(Type.throwable_type);
2052  }
2053
2054  public void emitCatchEnd()
2055  {
2056    if (reachableHere())
2057      {
2058    if (try_stack.saved_result != null)
2059      emitStore(try_stack.saved_result);
2060    if (try_stack.finally_subr != null)
2061      emitJsr(try_stack.finally_subr);
2062    emitGoto(try_stack.end_label);
2063      }
2064    try_stack.try_type = null;
2065  }
2066
2067  public void emitFinallyStart()
2068  {
2069    emitTryEnd();
2070    if (try_stack.try_type != null)
2071      emitCatchEnd();
2072    SP = 0;
2073    try_stack.end_try = getLabel();
2074
2075    pushScope();
2076    Type except_type = Type.pointer_type;
2077    Variable except = addLocal(except_type);
2078    emitCatchStart(null);
2079    emitStore(except);
2080    emitJsr(try_stack.finally_subr);
2081    emitLoad(except);
2082    emitThrow();
2083    
2084    try_stack.finally_subr.define(this);
2085    Type ret_addr_type = Type.pointer_type;
2086    try_stack.finally_ret_addr = addLocal(ret_addr_type);
2087    pushType(ret_addr_type);
2088    emitStore(try_stack.finally_ret_addr);
2089  }
2090
2091  public void emitFinallyEnd()
2092  {
2093    emitRet(try_stack.finally_ret_addr);
2094    setUnreachable();
2095    popScope();
2096    try_stack.finally_subr = null;
2097  }
2098
2099  public void emitTryCatchEnd()
2100  {
2101    if (try_stack.finally_subr != null)
2102      emitFinallyEnd();
2103    try_stack.end_label.define(this);
2104    Variable[] vars = try_stack.savedStack;
2105    if (vars != null)
2106      {
2107    for (int i = vars.length; --i >= 0; )
2108      {
2109        Variable v = vars[i];
2110        if (v != null) {
2111          emitLoad(v);
2112        }
2113      }
2114      }
2115    if (try_stack.saved_result != null)
2116    emitLoad(try_stack.saved_result);
2117    if (try_stack.saved_result != null || vars != null)
2118    popScope();
2119    try_stack = try_stack.previous;
2120  }
2121
2122  public final TryState getCurrentTry ()
2123  {
2124    return try_stack;
2125  }
2126
2127  public final boolean isInTry()
2128  {
2129    // This also return true if we're in a catch clause, but that is
2130
// good enough for now.
2131
return try_stack != null;
2132  }
2133
2134  /** Compile a tail-call to position 0 of the current procedure.
2135   * @param pop_args if true, copy argument registers (except this) from stack.
2136   * @param scope Scope whose start we jump back to. */

2137  public void emitTailCall (boolean pop_args, Scope scope)
2138  {
2139    if (pop_args)
2140      {
2141    Method meth = getMethod();
2142    int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0 : 1;
2143    for (int i = meth.arg_types.length; --i >= 0; )
2144      arg_slots += meth.arg_types[i].size > 4 ? 2 : 1;
2145    for (int i = meth.arg_types.length; --i >= 0; )
2146      {
2147        arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1;
2148        emitStore(locals.used [arg_slots]);
2149      }
2150      }
2151    emitGoto(scope.start);
2152  }
2153
2154  public void processFixups ()
2155  {
2156    if (fixup_count == 0)
2157      return;
2158
2159    // For each label, set it to its maximum limit, assuming all
2160
// fixups causes the code the be expanded. We need a prepass
2161
// for this, since FIXUP_MOVEs can cause code to be reordered.
2162
// Also, convert each FIXUP_MOVE_TO_END to FIXUP_MOVE.
2163

2164    int delta = 0;
2165    int instruction_tail = fixup_count;
2166    fixupAdd(CodeAttr.FIXUP_MOVE, 0, null);
2167
2168  loop1:
2169   for (int i = 0; ; )
2170      {
2171    int offset = fixup_offsets[i];
2172    int kind = offset & 15;
2173    offset >>= 4;
2174    Label label = fixup_labels[i];
2175    switch (kind)
2176      {
2177      case FIXUP_TRY:
2178      case FIXUP_LINE_PC:
2179        i++;
2180      case FIXUP_NONE:
2181      case FIXUP_CASE:
2182      case FIXUP_DELETE3:
2183        break;
2184      case FIXUP_DEFINE:
2185        label.position += delta;
2186        break;
2187      case FIXUP_SWITCH:
2188        delta += 3; // May need to add up to 3 padding bytes.
2189
break;
2190      case FIXUP_GOTO:
2191        // The first test fails in this case: GOTO L2; L1: L2: FIXME
2192
if (label.first_fixup == i + 1
2193        && fixupOffset(i+1) == offset + 3)
2194          {
2195        // Optimize: GOTO L; L:
2196
fixup_offsets[i] = (offset << 4) | FIXUP_DELETE3;
2197        fixup_labels[i] = null;
2198        delta -= 3;
2199        break;
2200          }
2201        // ... else fall through ...
2202
case FIXUP_JSR:
2203        if (PC >= 0x8000)
2204          delta += 2; // May need to convert goto->goto_w, jsr->jsr_w.
2205
break;
2206      case FIXUP_TRANSFER:
2207        if (PC >= 0x8000)
2208          delta += 5; // May need to add a goto_w.
2209
break;
2210      case FIXUP_MOVE_TO_END:
2211        fixup_labels[instruction_tail] = fixup_labels[i+1];
2212        instruction_tail = offset;
2213        // ... fall through ...
2214
case FIXUP_MOVE:
2215        int cur_pc = ((i+1) >= fixup_count ? PC
2216              : fixupOffset(fixup_labels[i+1].first_fixup));
2217        fixup_offsets[i] = (cur_pc << 4) | FIXUP_MOVE;
2218        if (label == null)
2219          break loop1;
2220        else
2221          {
2222        i = label.first_fixup;
2223        int next_pc = fixupOffset(i);
2224        delta = (cur_pc + delta) - next_pc;
2225        continue;
2226          }
2227      default:
2228        throw new Error JavaDoc("unexpected fixup");
2229      }
2230    i++;
2231      }
2232    // Next a loop to fix the position of each label, and calculate
2233
// the exact number of code bytes.
2234

2235    // Number of bytes to be inserted or (if negative) removed, so far.
2236
int new_size = PC;
2237    // Current delta between final PC and offset in generate code array.
2238
delta = 0;
2239  loop2:
2240    for (int i = 0; i < fixup_count; )
2241      {
2242    int offset = fixup_offsets[i];
2243    int kind = offset & 15;
2244    Label label = fixup_labels[i];
2245    if (label != null && label.position < 0)
2246      throw new Error JavaDoc ("undefined label "+label);
2247    while (label != null
2248           && kind >= FIXUP_GOTO && kind <= FIXUP_TRANSFER2
2249           && label.first_fixup + 1 < fixup_count
2250           && (fixup_offsets[label.first_fixup + 1]
2251           == ((fixup_offsets[label.first_fixup] & 15) | FIXUP_GOTO)))
2252      {
2253        // Optimize JUMP L; ... L: GOTO X
2254
// (where the JUMP is any GOTO or other transfer)
2255
// by changing the JUMP L to JUMP X.
2256
label = fixup_labels[label.first_fixup + 1];
2257        fixup_labels[i] = label;
2258      }
2259    offset = offset >> 4;
2260    switch (kind)
2261      {
2262      case FIXUP_TRY:
2263      case FIXUP_LINE_PC:
2264        i++;
2265      case FIXUP_NONE:
2266      case FIXUP_CASE:
2267        break;
2268      case FIXUP_DELETE3:
2269        delta -= 3;
2270        new_size -= 3;
2271        break;
2272      case FIXUP_DEFINE:
2273        label.position = offset + delta;
2274        break;
2275      case FIXUP_SWITCH:
2276        int padding = 3 - (offset+delta) & 3;
2277        delta += padding;
2278        new_size += padding;
2279        break;
2280      case FIXUP_GOTO:
2281      case FIXUP_JSR:
2282      case FIXUP_TRANSFER:
2283        int rel = label.position - (offset+delta);
2284        if ((short) rel == rel)
2285          {
2286        fixup_offsets[i] = (offset << 4) | FIXUP_TRANSFER2;
2287          }
2288        else
2289          {
2290        delta += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w
2291
new_size += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w
2292
}
2293        break;
2294      case FIXUP_MOVE:
2295        if (label == null)
2296          break loop2;
2297        else
2298          {
2299        i = label.first_fixup;
2300        int next_pc = fixupOffset(i);
2301        delta = (offset + delta) - next_pc;
2302        continue;
2303          }
2304      default:
2305        throw new Error JavaDoc("unexpected fixup");
2306      }
2307    i++;
2308      }
2309
2310    byte[] new_code = new byte[new_size];
2311    int new_pc = 0;
2312    int next_fixup_index = 0;
2313    int next_fixup_offset = fixupOffset(0);
2314  loop3:
2315    for (int old_pc = 0; ; )
2316      {
2317    if (old_pc < next_fixup_offset)
2318      {
2319      new_code[new_pc++] = code[old_pc++];
2320      }
2321    else
2322      {
2323        int kind = fixup_offsets[next_fixup_index] & 15;
2324        Label label = fixup_labels[next_fixup_index];
2325        switch (kind)
2326          {
2327          case FIXUP_NONE:
2328          case FIXUP_DEFINE:
2329        break;
2330          case FIXUP_DELETE3:
2331        old_pc += 3;
2332        break;
2333          case FIXUP_TRANSFER2:
2334        delta = label.position - new_pc;
2335        new_code[new_pc++] = code[old_pc];
2336        new_code[new_pc++] = (byte) (delta >> 8);
2337        new_code[new_pc++] = (byte) (delta & 0xFF);
2338        old_pc += 3;
2339        break;
2340          case FIXUP_GOTO:
2341          case FIXUP_JSR:
2342          case FIXUP_TRANSFER:
2343        delta = label.position - new_pc;
2344        byte opcode = code[old_pc];
2345        if (kind == FIXUP_TRANSFER)
2346          {
2347            // convert: IF_xxx L to IF_NOT_xxx Lt; GOTO L; Lt:
2348
opcode = invert_opcode(opcode);
2349            new_code[new_pc++] = opcode;
2350            new_code[new_pc++] = 0;
2351            new_code[new_pc++] = 8; // 8 byte offset to Lt.
2352
opcode = (byte) 200; // goto_w
2353
}
2354        else
2355          {
2356            // Change goto to goto_w; jsr to jsr_w:
2357
opcode = (byte) (opcode + (200-167));
2358          }
2359        new_code[new_pc++] = opcode;
2360        new_code[new_pc++] = (byte) (delta >> 24);
2361        new_code[new_pc++] = (byte) (delta >> 16);
2362        new_code[new_pc++] = (byte) (delta >> 8);
2363        new_code[new_pc++] = (byte) (delta & 0xFF);
2364        old_pc += 3;
2365        break;
2366          case FIXUP_SWITCH:
2367        int padding = 3 - new_pc & 3;
2368        int switch_start = new_pc;
2369        new_code[new_pc++] = code[old_pc++];
2370        while (--padding >= 0)
2371          new_code[new_pc++] = 0;
2372        while (next_fixup_index < fixup_count
2373               && fixupKind(next_fixup_index + 1) == FIXUP_CASE)
2374          {
2375            next_fixup_index++;
2376            int offset = fixupOffset(next_fixup_index);
2377            while (old_pc < offset)
2378              new_code[new_pc++] = code[old_pc++];
2379            delta = (fixup_labels[next_fixup_index].position
2380                 - switch_start);
2381            new_code[new_pc++] = (byte) (delta >> 24);
2382            new_code[new_pc++] = (byte) (delta >> 16);
2383            new_code[new_pc++] = (byte) (delta >> 8);
2384            new_code[new_pc++] = (byte) (delta & 0xFF);
2385            old_pc += 4;
2386          }
2387        break;
2388          case FIXUP_TRY:
2389        addHandler(fixup_labels[next_fixup_index].position,
2390               fixup_labels[next_fixup_index+1].position,
2391               new_pc,
2392               fixupOffset(next_fixup_index+1));
2393        next_fixup_index++;
2394        break;
2395          case FIXUP_LINE_PC:
2396        if (lines == null)
2397          lines = new LineNumbersAttr(this);
2398        next_fixup_index++;
2399        lines.put(fixupOffset(next_fixup_index), new_pc);
2400        break;
2401          case FIXUP_MOVE:
2402        if (label == null)
2403          break loop3;
2404        else
2405          {
2406            next_fixup_index = label.first_fixup;
2407            old_pc = fixupOffset(next_fixup_index);
2408            next_fixup_offset = old_pc;
2409            if (label.position != new_pc)
2410              throw new Error JavaDoc("bad pc");
2411            continue;
2412          }
2413          default:
2414        throw new Error JavaDoc("unexpected fixup");
2415          }
2416        next_fixup_index++;
2417        next_fixup_offset = fixupOffset(next_fixup_index);
2418      }
2419      }
2420    if (new_size != new_pc)
2421      throw new Error JavaDoc("PC confusion new_pc:"+new_pc+" new_size:"+new_size);
2422    PC = new_size;
2423    code = new_code;
2424    fixup_count = 0;
2425    fixup_labels = null;
2426    fixup_offsets = null;
2427  }
2428
2429  public void assignConstants (ClassType cl)
2430  {
2431    if (locals != null && locals.container == null && ! locals.isEmpty())
2432      locals.addToFrontOf(this);
2433    processFixups();
2434    if (instructionLineMode)
2435      {
2436        // A kludge to low-level debugging:
2437
// Define a "line number" for each instrction.
2438
if (lines == null)
2439          lines = new LineNumbersAttr(this);
2440        lines.linenumber_count = 0;
2441        int codeLen = getCodeLength();
2442        for (int i = 0; i < codeLen; i++)
2443          lines.put(i, i);
2444      }
2445    super.assignConstants(cl);
2446    Attribute.assignConstants(this, cl);
2447  }
2448
2449  public final int getLength()
2450  {
2451    return 12 + getCodeLength() + 8 * exception_table_length
2452      + Attribute.getLengthAll(this);
2453  }
2454
2455  public void write (DataOutputStream dstr) throws java.io.IOException JavaDoc
2456  {
2457    dstr.writeShort (max_stack);
2458    dstr.writeShort (max_locals);
2459    dstr.writeInt (PC);
2460    dstr.write (code, 0, PC);
2461
2462    dstr.writeShort (exception_table_length);
2463    int count = exception_table_length;
2464    for (int i = 0; --count >= 0; i += 4)
2465      {
2466    dstr.writeShort(exception_table[i]);
2467    dstr.writeShort(exception_table[i+1]);
2468    dstr.writeShort(exception_table[i+2]);
2469    dstr.writeShort(exception_table[i+3]);
2470      }
2471
2472    Attribute.writeAll(this, dstr);
2473  }
2474
2475  public void print (ClassTypeWriter dst)
2476  {
2477    dst.print("Attribute \"");
2478    dst.print(getName());
2479    dst.print("\", length:");
2480    dst.print(getLength());
2481    dst.print(", max_stack:");
2482    dst.print(max_stack);
2483    dst.print(", max_locals:");
2484    dst.print(max_locals);
2485    dst.print(", code_length:");
2486    int length = getCodeLength();
2487    dst.println(length);
2488    disAssemble(dst, 0, length);
2489    if (exception_table_length > 0)
2490      {
2491    dst.print("Exceptions (count: ");
2492    dst.print(exception_table_length);
2493    dst.println("):");
2494    int count = exception_table_length;
2495    for (int i = 0; --count >= 0; i += 4)
2496      {
2497        dst.print(" start: ");
2498        dst.print(exception_table[i] & 0xffff);
2499        dst.print(", end: ");
2500        dst.print(exception_table[i+1] & 0xffff);
2501        dst.print(", handler: ");
2502        dst.print(exception_table[i+2] & 0xffff);
2503        dst.print(", type: ");
2504        int catch_type_index = exception_table[i+3] & 0xffff;
2505        if (catch_type_index == 0)
2506          dst.print("0 /* finally */");
2507        else
2508          {
2509        dst.printOptionalIndex(catch_type_index);
2510        dst.printConstantTersely(catch_type_index, ConstantPool.CLASS);
2511          }
2512        dst.println();
2513      }
2514      }
2515    dst.printAttributes(this);
2516  }
2517
2518  /* DEBUGGING:
2519  public void disAssembleWithFixups (ClassTypeWriter dst)
2520  {
2521    if (fixup_count == 0)
2522      {
2523    disAssemble(dst, 0, PC);
2524    return;
2525      }
2526    int prev_pc = 0;
2527    for (int i = 0; i < fixup_count; )
2528      {
2529    int offset = fixup_offsets[i];
2530    int kind = offset & 15;
2531    Label label = fixup_labels[i];
2532    offset = offset >> 4;
2533    int pc = offset;
2534    if (kind == FIXUP_MOVE || kind == FIXUP_MOVE_TO_END)
2535      pc = (i+1 >= fixup_count) ? PC : fixup_offsets[i+1] >> 4;
2536    disAssemble(dst, prev_pc, offset);
2537    prev_pc = pc;
2538    dst.print("fixup#"); dst.print(i);
2539    dst.print(" @"); dst.print(offset);
2540    switch (kind)
2541      {
2542      case FIXUP_NONE:
2543        dst.println(" NONE");
2544        break;
2545      case FIXUP_DEFINE:
2546        dst.print(" DEFINE ");
2547        dst.println(label);
2548        break;
2549      case FIXUP_SWITCH:
2550        dst.println(" SWITCH");
2551        break;
2552      case FIXUP_CASE:
2553        dst.println(" CASE");
2554        break;
2555      case FIXUP_GOTO:
2556        dst.print(" GOTO ");
2557        dst.println(label);
2558        break;
2559      case FIXUP_TRANSFER:
2560        dst.print(" TRANSFER ");
2561        dst.println(label);
2562        break;
2563      case FIXUP_TRANSFER2:
2564        dst.print(" TRANSFER2 ");
2565        dst.println(label);
2566        break;
2567      case FIXUP_DELETE3:
2568        dst.println(" DELETE3");
2569        break;
2570      case FIXUP_MOVE:
2571        dst.print(" MOVE ");
2572        dst.println(label);
2573        break;
2574      case FIXUP_MOVE_TO_END:
2575        dst.print(" MOVE_TO_END ");
2576        dst.println(label);
2577        break;
2578      case FIXUP_TRY:
2579        dst.print(" TRY start: ");
2580        dst.println(label);
2581        i++;
2582        dst.print(" - end: ");
2583        dst.print(fixup_labels[i]);
2584        dst.print(" type: ");
2585        dst.println(fixup_offsets[i] >> 4);
2586        break;
2587      case FIXUP_LINE_PC:
2588        dst.print(" LINE ");
2589        i++;
2590        dst.println(fixup_offsets[i] >> 4);
2591        break;
2592      default:
2593        dst.println(" kind:"+fixupKind(i)+" offset:"+fixupOffset(i)+" "+fixup_labels[i]);
2594      }
2595    i++;
2596      }
2597  }
2598  */

2599
2600  public void disAssemble (ClassTypeWriter dst, int start, int limit)
2601  {
2602    boolean wide = false;
2603    for (int i = start; i < limit; )
2604      {
2605    int oldpc = i++;
2606    int op = code[oldpc] & 0xff;
2607    String JavaDoc str = Integer.toString(oldpc);
2608    int printConstant = 0;
2609    int j = str.length();
2610    while (++j <= 3) dst.print(' ');
2611    dst.print(str);
2612    dst.print(": ");
2613    // We do a rough binary partition of the opcodes.
2614
if (op < 120)
2615      {
2616        if (op < 87)
2617          {
2618        if (op < 3) print("nop;aconst_null;iconst_m1;", op, dst);
2619        else if (op < 9) { dst.print("iconst_"); dst.print(op-3); }
2620        else if (op < 16) // op >= 9 [lconst_0] && op <= 15 [dconst_1]
2621
{
2622            char typ;
2623            if (op < 11) { typ = 'l'; op -= 9; }
2624            else if (op < 14) { typ = 'f'; op -= 11; }
2625            else { typ = 'd'; op -= 14; }
2626            dst.print(typ); dst.print("const_"); dst.print(op);
2627          }
2628        else if (op < 21)
2629          {
2630            if (op < 18) // op >= 16 [bipush] && op <= 17 [sipush]
2631
{
2632            print("bipush ;sipush ;", op-16, dst);
2633            int constant;
2634            if (op == 16) constant = code[i++];
2635            else { constant = (short) readUnsignedShort(i); i+=2;}
2636            dst.print(constant);
2637              }
2638            else // op >= 18 [ldc] && op <= 20 [ldc2_w]
2639
{
2640            printConstant = op == 18 ? 1 : 2;
2641            print("ldc;ldc_w;ldc2_w;", op-18, dst);
2642              }
2643          }
2644        else // op >= 21 && op < 87
2645
{
2646            String JavaDoc load_or_store;
2647            if (op < 54) { load_or_store = "load"; }
2648            else { load_or_store = "store"; op -=(54-21); }
2649            int index; // -2 if array op; -1 if index follows
2650
if (op < 26) { index = -1; op -= 21; }
2651            else if (op < 46) { op -= 26; index = op % 4; op >>= 2; }
2652            else { index = -2; op -= 46; }
2653            dst.print("ilfdabcs".charAt(op));
2654            if (index == -2) dst.write('a');
2655            dst.print(load_or_store);
2656            if (index >= 0) { dst.write('_'); dst.print(index); }
2657            else if (index == -1)
2658              {
2659            if (wide) { index = readUnsignedShort(i); i += 2; }
2660            else { index = code[i] & 0xff; i++; }
2661            wide = false;
2662            dst.print(' ');
2663            dst.print(index);
2664              }
2665          }
2666          }
2667        else // op >= 87 && op < 120
2668
{
2669        if (op < 96)
2670          print("pop;pop2;dup;dup_x1;dup_x2;dup2;dup2_x1;dup2_x2;swap;"
2671            , op-87, dst);
2672        else // op >= 96 [iadd] && op <= 119 [dneg]
2673
{
2674            dst.print("ilfda".charAt((op-96) % 4));
2675            print("add;sub;mul;div;rem;neg;", (op-96)>>2, dst);
2676          }
2677          }
2678      }
2679    else // op >= 120
2680
{
2681        if (op < 170)
2682          {
2683        if (op < 132) // op >= 120 [ishl] && op <= 131 [lxor]
2684
{
2685            dst.print((op & 1) == 0 ? 'i' : 'l');
2686            print("shl;shr;ushr;and;or;xor;", (op-120)>>1, dst);
2687          }
2688        else if (op == 132) // iinc
2689
{
2690            int var_index;
2691            int constant;
2692            dst.print("iinc");
2693            if (! wide)
2694              {
2695            var_index = 0xff & code[i++];
2696            constant = code[i++];
2697              }
2698            else
2699              {
2700            var_index = readUnsignedShort(i);
2701            i += 2;
2702            constant = (short) readUnsignedShort(i);
2703            i += 2;
2704            wide = false;
2705              }
2706            dst.print(' '); dst.print(var_index);
2707            dst.print(' '); dst.print(constant);
2708          }
2709        else if (op < 148) // op >= 133 [i2l] && op <= 147 [i2s]
2710
{
2711            dst.print("ilfdi".charAt((op-133) / 3));
2712            dst.print('2');
2713            dst.print("lfdifdildilfbcs".charAt(op-133));
2714          }
2715        else if (op < 153) // op >= 148 [lcmp] && op <= 152 [dcmpg]
2716
print("lcmp;fcmpl;fcmpg;dcmpl;dcmpg;", op-148, dst);
2717        else if (op < 169)
2718          {
2719            if (op < 159)
2720              {
2721            dst.print("if");
2722            print("eq;ne;lt;ge;gt;le;", op-153, dst);
2723              }
2724            else if (op < 167)
2725              {
2726            if (op < 165) { dst.print("if_icmp"); }
2727            else { dst.print("if_acmp"); op -= 165-159; }
2728            print("eq;ne;lt;ge;gt;le;", op-159, dst);
2729              }
2730            else
2731              print("goto;jsr;", op-167, dst);
2732            int delta = (short) readUnsignedShort(i);
2733            i += 2;
2734            dst.print(' '); dst.print(oldpc+delta);
2735          }
2736        else
2737          {
2738            int index;
2739            dst.print("ret ");
2740            if (wide) { index = readUnsignedShort(i); index += 2; }
2741            else { index = code[i] & 0xff; i++; }
2742            wide = false;
2743            dst.print(index);
2744          }
2745          }
2746        else
2747          {
2748        if (op < 172) // [tableswitch] or [lookupswitch]
2749
{
2750            if (fixup_count == 0)
2751              i = (i + 3) & ~3; // skip 0-3 byte padding.
2752
int code_offset = readInt(i); i += 4;
2753            if (op == 170)
2754              {
2755            dst.print("tableswitch");
2756            int low = readInt(i); i += 4;
2757            int high = readInt(i); i += 4;
2758            dst.print(" low: "); dst.print(low);
2759            dst.print(" high: "); dst.print(high);
2760            dst.print(" default: "); dst.print(oldpc+code_offset);
2761            for (; low <= high; low++)
2762              {
2763                code_offset = readInt(i); i += 4;
2764                dst.println();
2765                dst.print(" "); dst.print(low);
2766                dst.print(": "); dst.print(oldpc + code_offset);
2767              }
2768              }
2769            else
2770              {
2771            dst.print("lookupswitch");
2772            int npairs = readInt(i); i += 4;
2773            dst.print(" npairs: "); dst.print(npairs);
2774            dst.print(" default: "); dst.print(oldpc+code_offset);
2775            while (--npairs >= 0)
2776              {
2777                int match = readInt(i); i += 4;
2778                code_offset = readInt(i); i += 4;
2779                dst.println();
2780                dst.print(" "); dst.print(match);
2781                dst.print(": "); dst.print(oldpc + code_offset);
2782              }
2783              }
2784          }
2785        else if (op < 178) // op >= 172 [ireturn] && op <= 177 [return]
2786
{
2787            if (op < 177) dst.print("ilfda".charAt(op-172));
2788            dst.print("return");
2789          }
2790        else if (op < 182) // op >= 178 [getstatic] && op <= 181 [putfield]
2791
{
2792            print("getstatic;putstatic;getfield;putfield;", op-178, dst);
2793            printConstant = 2;
2794          }
2795        else if (op < 185) // op >= 182 && op <= 185 [invoke*]
2796
{
2797            dst.print("invoke");
2798            print("virtual;special;static;", op-182, dst);
2799            printConstant = 2;
2800          }
2801        else if (op == 185) // invokeinterface
2802
{
2803            dst.print("invokeinterface (");
2804            int index = readUnsignedShort(i);
2805            i += 2;
2806            int args = 0xff & code[i];
2807            i += 2;
2808            dst.print(args + " args)");
2809            dst.printConstantOperand(index);
2810          }
2811        else if (op < 196)
2812          {
2813            print("186;new;newarray;anewarray;arraylength;athrow;checkcast;instanceof;monitorenter;monitorexit;", op-186, dst);
2814            if (op == 187 || op == 189 || op == 192 || op == 193)
2815              printConstant = 2;
2816            else if (op == 188) // newarray
2817
{
2818            int type = code[i++];
2819            dst.print(' ');
2820            if (type >= 4 && type <= 11)
2821              print("boolean;char;float;double;byte;short;int;long;",
2822                type-4, dst);
2823            else
2824              dst.print(type);
2825              }
2826            
2827          }
2828        else if (op == 196) // wide
2829
{
2830            dst.print("wide");
2831            wide = true;
2832          }
2833        else if (op == 197)
2834          {
2835            dst.print("multianewarray");
2836            int index = readUnsignedShort(i);
2837            i += 2;
2838            dst.printConstantOperand(index);
2839            int dims = 0xff & code[i++];
2840            dst.print(' ');
2841            dst.print(dims);
2842          }
2843        else if (op < 200)
2844          {
2845            print("ifnull;ifnonnull;", op-198, dst);
2846            int delta = (short) readUnsignedShort(i);
2847            i += 2;
2848            dst.print(' '); dst.print(oldpc+delta);
2849          }
2850        else if (op < 202)
2851          {
2852            print("goto_w;jsr_w;", op-200, dst);
2853            int delta = readInt(i);
2854            i += 4;
2855            dst.print(' '); dst.print(oldpc+delta);
2856          }
2857        else
2858          dst.print(op);
2859          }
2860      }
2861    if (printConstant > 0)
2862      {
2863        int index;
2864        if (printConstant == 1) index = 0xff & code[i++];
2865        else { index = readUnsignedShort(i); i += 2; }
2866        dst.printConstantOperand(index);
2867      }
2868    dst.println();
2869      }
2870  }
2871
2872  private int readUnsignedShort(int offset)
2873  {
2874    return ((0xff & code[offset]) << 8) | (0xff & code[offset+1]);
2875  }
2876
2877  private int readInt(int offset)
2878  {
2879    return (readUnsignedShort(offset) << 16) | readUnsignedShort(offset+2);
2880  }
2881
2882  /*
2883  public saveStack (ClassType into)
2884  {
2885    Field[] flds = new Field[SP];
2886    while (SP > 0)
2887      {
2888    Field fld = ?;
2889    emitStore(fld);
2890    flds[SP...]
2891      }
2892  }
2893  */

2894
2895  /* Print the i'th ';'-delimited substring of str on dst. */
2896  private void print (String JavaDoc str, int i, PrintWriter dst)
2897  {
2898    int last = 0;
2899    int pos = -1;
2900    for (; i >= 0; i--)
2901      {
2902    last = ++pos;
2903    pos = str.indexOf(';', last);
2904      }
2905    dst.write(str, last, pos-last);
2906  }
2907
2908  /** Return an object encapsulating the type state of the JVM stack. */
2909  public Type[] saveStackTypeState(boolean clear)
2910  {
2911    if (SP == 0)
2912      return null;
2913    Type[] typeState = new Type[SP];
2914    System.arraycopy(stack_types, 0, typeState, 0, SP);
2915    if (clear)
2916      SP = 0;
2917    return typeState;
2918  }
2919
2920  /** Restore a type state as saved by saveStackTypeState. */
2921  public void restoreStackTypeState (Type[] save)
2922  {
2923    if (save == null)
2924      SP = 0;
2925    else
2926      {
2927    SP = save.length;
2928    System.arraycopy(save, 0, stack_types, 0, SP);
2929      }
2930  }
2931
2932  public int beginFragment (Label start, Label after)
2933  {
2934    int i = fixup_count;
2935    fixupAdd(FIXUP_MOVE_TO_END, after);
2936    start.define(this);
2937    return i;
2938  }
2939
2940  /** End a fragment.
2941   * @param cookie the return value from the previous beginFragment.
2942   */

2943  public void endFragment (int cookie)
2944  {
2945    fixup_offsets[cookie] = (fixup_count << 4) | FIXUP_MOVE_TO_END;
2946    Label after = fixup_labels[cookie];
2947    fixupAdd(FIXUP_MOVE, 0, null);
2948    after.define(this);
2949  }
2950}
2951
Popular Tags