1 // Copyright (c) 1997, 1998, 1999, 2001, 2003, 2004, 2008 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;
getAttributes()24   public final Attribute getAttributes () { return attributes; }
setAttributes(Attribute attributes)25   public final void setAttributes (Attribute attributes)
26   { this.attributes = attributes; }
27   LineNumbersAttr lines;
28   public LocalVarsAttr locals;
29   public StackMapTableAttr stackMap;
30 
31   SourceDebugExtAttr sourceDbgExt;
32 
33   public static final int GENERATE_STACK_MAP_TABLE = 1;
34   public static final int DONT_USE_JSR = 2;
35   int flags;
36 
37   public Type[] stack_types;
38   Type[] local_types = new Type[20];
39 
40   /** Previously-defined label. */
41   Label previousLabel;
42   /** Set of vars set in current block (since previousLabel).
43    * This is so we can differentiate variable set locally, versus definitions
44    * that reach us (and that might be invalidated by future flows). */
45   boolean[] varsSetInCurrentBlock;
46 
47   int SP;  // Current stack size (in "words")
48   private int max_stack;
49   private int max_locals;
50   /** Current active length of code array.
51    * Note that processFixups may expand/contract the code array.  */
52   int PC;
53   byte[] code;
54 
useJsr()55   boolean useJsr()
56   {
57     return (flags & DONT_USE_JSR) == 0;
58   }
59 
60   /* The exception handler table, as a vector of quadruples
61      (start_pc, end_pc, handler_pc, catch_type).
62      Only the first exception_table_length quadruples are defined. */
63   short[] exception_table;
64 
65   /* The number of (defined) exception handlers (i.e. quadruples)
66      in exception_table. */
67   int exception_table_length;
68 
69   /** The definition of a label. */
70   static final int FIXUP_DEFINE = 0;
71   static final int FIXUP_DEFINE_UNREACHABLE = 1;
72   // From FIXUP_SWITCH up to FIXUP_TRANSFER2 must be contiguous
73   // - see the jump-to-jump optimization in processFixups.
74   /** The offset points to a tableswitch/lookupswitch - handle padding. */
75   static final int FIXUP_SWITCH = 2;
76   /** The offset contains a label relative to the previous FIXUP_SWITCH. */
77   static final int FIXUP_CASE = 3;
78   /** The offset points to a goto instruction. */
79   static final int FIXUP_GOTO = 4;
80   /** The offset points to a jsr instruction. */
81   static final int FIXUP_JSR = 5;
82   /** The offset points to a conditional transfer (if_xxx) instruction. */
83   static final int FIXUP_TRANSFER = 6;
84   /** A FIXUP_GOTO_, FIXUP_JSR, or FIXUP_TRANSFER that uses a 2-byte offset. */
85   static final int FIXUP_TRANSFER2 = 7;
86   /** The offsets points to 3 bytes that should be deleted. */
87   static final int FIXUP_DELETE3 = 8;
88   /** The following instructions are moved to later in the code stream.
89    * Instead the instructions starting at the fixup label are patched here.
90    * (If the fixup label is null, we're done.)
91    * This allows re-arranging code to avoid unneeded gotos.
92    * The following instruction is the target of a later FIXUP_MOVE,
93    * and we'll insert then when we get to it. */
94   static final int FIXUP_MOVE = 9;
95   /** The following instructions are moved to the end of the code stream.
96    * Same as FIXUP_MOVE, but there is no explicit later FIXUP_MOVE that
97    * refers to the following instructions.  Created by beginFragment.
98    * The fixup_offset points to the end of the fragment.
99    * (The first processFixups patches these to FIXUP_MOVE.) */
100   static final int FIXUP_MOVE_TO_END = 10;
101   /** FIXUP_TRY with the following FIXUP_TRY_END and FIXUP_TRY_HANDLER
102    * marks an exception handler.  The label is the start of the try clause;
103    * the current offset marks the exception handler. */
104   static final int FIXUP_TRY = 11;
105   /** Second part of a FIXUP_TRY/FIXUP_TRY_END/FIXUP_TRY_HANDLER set.
106    * The label is the end of the try clause;
107    * the current offset is the exception type as a constant pool index. */
108   static final int FIXUP_TRY_END = 12;
109   static final int FIXUP_TRY_HANDLER = 13;
110   /** With following FIXUP_LINE_NUMBER associates an offset with a line number.
111    * The fixup_offset is the code location; the fixup_label is null. */
112   static final int FIXUP_LINE_PC = 14;
113   /** With preceding FIXUP_LINE_PC associates an offset with a line number.
114    * The fixup_offset is the line number; the fixup_label is null. */
115   static final int FIXUP_LINE_NUMBER = 15;
116   int[] fixup_offsets;
117   Label[] fixup_labels;
118   /** Active length of fixup_offsets and fixup_labels.
119    * If {@code fixup_count == -1} we're not doing fixups. */
120   int fixup_count;
121 
122   /** This causes a later processFixup to rearrange the code.
123    * The code at target comes here, instead of the following instructions.
124    * Fuctionally equivalent to: <code>goto target; here:</code>,
125    * but implemented by code re-arranging.  Therefore there should be
126    * at some later point a <code>goto here; target:</code>.
127    */
fixupChain(Label here, Label target)128   public final void fixupChain (Label here, Label target)
129   {
130     fixupAdd(CodeAttr.FIXUP_MOVE, -1, target);
131     here.defineRaw(this);
132     setPreviousLabelHere(here);
133   }
134 
135   /** Add a fixup at this location.
136    * @param kind one of the FIXUP_xxx codes.
137    * @param label varies - typically the target of jump. */
fixupAdd(int kind, Label label)138   public final void fixupAdd (int kind, Label label)
139   {
140     fixupAdd(kind, PC, label);
141   }
142 
fixupAdd(int kind, int offset, Label label)143   final void fixupAdd (int kind, int offset, Label label)
144   {
145     if (label != null && kind != FIXUP_DEFINE && kind != FIXUP_DEFINE_UNREACHABLE
146         && kind != FIXUP_SWITCH && kind != FIXUP_TRY)
147       label.needsStackMapEntry = true;
148     int count = fixup_count;
149     if (count == 0)
150       {
151 	fixup_offsets = new int[30];
152 	fixup_labels = new Label[30];
153       }
154     else if (fixup_count == fixup_offsets.length)
155       {
156 	int new_length = 2 * count;
157 	Label[] new_labels = new Label[new_length];
158 	System.arraycopy (fixup_labels, 0, new_labels, 0, count);
159 	fixup_labels = new_labels;
160 	int[] new_offsets = new int[new_length];
161 	System.arraycopy (fixup_offsets, 0, new_offsets, 0, count);
162 	fixup_offsets = new_offsets;
163       }
164     fixupSet(count, kind, offset);
165     fixup_labels[count] = label;
166     fixup_count = count + 1;
167   }
168 
fixupOffset(int index)169   private final int fixupOffset(int index)
170   {
171     return fixup_offsets[index] >> 4;
172   }
173 
fixupKind(int index)174   private final int fixupKind(int index)
175   {
176     return fixup_offsets[index] & 15;
177   }
178 
fixupSet(int index, int kind, int offset)179     private void fixupSet(int index, int kind, int offset) {
180          fixup_offsets[index] = fixupEncode(kind, offset);
181     }
fixupEncode(int kind, int offset)182     private int fixupEncode(int kind, int offset) {
183         return (offset << 4) | kind;
184     }
185 
186   /** If true we get a line number entry for each instruction.
187    * Normally false, but can be a convenient hack to allow instruction-level
188    * stepping/debugging and stacktraces.  In this case {@code LINE==PC}. */
189   public static boolean instructionLineMode = false;
190 
191   /** The stack of currently active conditionals. */
192   IfState if_stack;
193 
194   /** The stack of currently active try statements. */
195   TryState try_stack;
196 
getMethod()197   public final Method getMethod() { return (Method) getContainer(); }
198 
getPC()199   public final int getPC() { return PC; }
200 
getSP()201   public final int getSP() { return SP; }
202 
getConstants()203   public final ConstantPool getConstants ()
204   {
205     return getMethod().classfile.constants;
206   }
207 
208   /* True if we cannot fall through to bytes[PC] -
209      the previous instruction was an uncondition control transfer.  */
210   private boolean unreachable_here;
211   /** True if control could reach here. */
reachableHere()212   public final boolean reachableHere () { return !unreachable_here; }
setReachable(boolean val)213   public final void setReachable(boolean val) { unreachable_here = !val; }
setUnreachable()214   public final void setUnreachable() { unreachable_here = true; }
215 
216   /** Get the maximum number of words on the operand stack in this method. */
getMaxStack()217   public int getMaxStack() { return max_stack; }
218   /** Get the maximum number of local variable words in this method. */
getMaxLocals()219   public int getMaxLocals() { return max_locals; }
220 
221   /** Set the maximum number of words on the operand stack in this method. */
setMaxStack(int n)222   public void setMaxStack(int n) { max_stack = n; }
223   /** Set the maximum number of local variable words in this method. */
setMaxLocals(int n)224   public void setMaxLocals(int n) { max_locals = n; }
225 
226   /** Get the code (instruction bytes) of this method.
227     * Does not make a copy. */
getCode()228   public byte[] getCode() { return code; }
229   /** Set the code (instruction bytes) of this method.
230     * @param code the code bytes (which are not copied).
231     * Implicitly calls setCodeLength(code.length). */
setCode(byte[] code)232   public void setCode(byte[] code) {
233     this.code = code; this.PC = code.length; }
234   /** Set the length the the code (instruction bytes) of this method.
235     * That is the number of current used bytes in getCode().
236     * (Any remaing bytes provide for future growth.) */
setCodeLength(int len)237   public void setCodeLength(int len) { PC = len;}
238   /** Set the current lengthof the code (instruction bytes) of this method. */
getCodeLength()239   public int getCodeLength() { return PC; }
240 
CodeAttr(Method meth)241   public CodeAttr (Method meth)
242   {
243     super ("Code");
244     addToFrontOf(meth);
245     meth.code = this;
246     if (meth.getDeclaringClass().getClassfileMajorVersion() >= 50)
247       flags |= GENERATE_STACK_MAP_TABLE|DONT_USE_JSR;
248   }
249 
reserve(int bytes)250   public final void reserve (int bytes)
251   {
252     if (code == null)
253       code = new byte[100+bytes];
254     else if (PC + bytes > code.length)
255       {
256 	byte[] new_code = new byte[2 * code.length + bytes];
257 	System.arraycopy (code, 0, new_code, 0, PC);
258 	code = new_code;
259       }
260   }
261 
262   /** Get opcode that implements NOT (x OPCODE y). */
invert_opcode(byte opcode)263   byte invert_opcode (byte opcode)
264   {
265     int iopcode = opcode & 0xFF;
266     if ((iopcode >= 153 && iopcode <= 166)
267 	|| (iopcode >= 198 && iopcode <= 199))
268       return (byte) (iopcode ^ 1);
269     throw new Error("unknown opcode to invert_opcode");
270   }
271 
272   /**
273    * Write an 8-bit byte to the current code-stream.
274    * @param i the byte to write
275    */
put1(int i)276   public final void put1(int i)
277   {
278     code[PC++] = (byte) i;
279     unreachable_here = false;
280   }
281 
282   /**
283    * Write a 16-bit short to the current code-stream
284    * @param i the value to write
285    */
put2(int i)286   public final void put2(int i)
287   {
288     code[PC++] = (byte) (i >> 8);
289     code[PC++] = (byte) (i);
290     unreachable_here = false;
291   }
292 
293   /**
294    * Write a 32-bit int to the current code-stream
295    * @param i the value to write
296    */
put4(int i)297   public final void put4(int i)
298   {
299     code[PC++] = (byte) (i >> 24);
300     code[PC++] = (byte) (i >> 16);
301     code[PC++] = (byte) (i >> 8);
302 
303     code[PC++] = (byte) (i);
304     unreachable_here = false;
305   }
306 
putIndex2(CpoolEntry cnst)307   public final void putIndex2 (CpoolEntry cnst)
308   {
309     put2(cnst.index);
310   }
311 
putLineNumber(String filename, int linenumber)312   public final void putLineNumber (String filename, int linenumber)
313   {
314     if (filename != null)
315       getMethod().classfile.setSourceFile(filename);
316     putLineNumber(linenumber);
317   }
318 
putLineNumber(int linenumber)319   public final void putLineNumber (int linenumber)
320   {
321     if (sourceDbgExt != null)
322       linenumber = sourceDbgExt.fixLine(linenumber);
323     fixupAdd(FIXUP_LINE_PC, null);
324     fixupAdd(FIXUP_LINE_NUMBER, linenumber, null);
325   }
326 
327   /** Initialize local_types from parameters. */
noteParamTypes()328   void noteParamTypes ()
329   {
330     Method method = getMethod();
331     int offset = 0;
332     if ((method.access_flags & Access.STATIC) == 0)
333       {
334         Type type = method.classfile;
335         if ("<init>".equals(method.getName())
336             && ! "java.lang.Object".equals(type.getName()))
337           type = UninitializedType.uninitializedThis((ClassType) type);
338         noteVarType(offset++, type);
339       }
340     int arg_count = method.arg_types.length;
341     for (int i = 0;  i < arg_count;  i++)
342       {
343         Type type = method.arg_types[i];
344         noteVarType(offset++, type);
345         for (int size = type.getSizeInWords(); -- size > 0; )
346           offset++;
347       }
348     if ((flags & GENERATE_STACK_MAP_TABLE) != 0)
349       {
350         stackMap = new StackMapTableAttr();
351 
352         int[] encodedLocals = new int[20+offset];
353         int count = 0;
354         for (int i = 0; i < offset;  i++)
355           {
356             int encoded = stackMap.encodeVerificationType(local_types[i], this);
357             encodedLocals[count++] = encoded;
358             int tag = encoded & 0xFF;
359             if (tag == 3 || tag == 4)
360               i++;
361           }
362         stackMap.encodedLocals = encodedLocals;
363         stackMap.countLocals = count;
364         stackMap.encodedStack = new int[10];
365         stackMap.countStack = 0;
366       }
367   }
368 
setPreviousLabelHere(Label here)369     void setPreviousLabelHere(Label here) {
370         previousLabel = here;
371         boolean[] varsSet = varsSetInCurrentBlock;
372         if (varsSet != null)
373             for (int i = varsSet.length;  --i >= 0; ) varsSet[i] = false;
374     }
375 
noteVarType(int offset, Type type)376   public void noteVarType (int offset, Type type)
377   {
378     int size = type.getSizeInWords();
379 
380     if (local_types == null)
381       local_types = new Type[offset + size + 20];
382     else if (offset + size > local_types.length) {
383       Type[] new_array = new Type[2 * (offset + size)];
384       System.arraycopy (local_types, 0, new_array, 0, local_types.length);
385       local_types = new_array;
386     }
387     local_types[offset] = type;
388     if (varsSetInCurrentBlock == null)
389       varsSetInCurrentBlock = new boolean[local_types.length];
390     else if (varsSetInCurrentBlock.length <= offset)
391       {
392         boolean[] tmp = new boolean[local_types.length];
393         System.arraycopy(varsSetInCurrentBlock, 0, tmp, 0, varsSetInCurrentBlock.length);
394         varsSetInCurrentBlock = tmp;
395       }
396     varsSetInCurrentBlock[offset] = true;
397     if (offset > 0)
398       {
399         Type prev = local_types[offset-1];
400         if (prev != null && prev.getSizeInWords() == 2)
401           local_types[offset-1] = null;
402       }
403     while (--size > 0)
404       local_types[++offset] = null;
405   }
406 
407   /** Set the current type state from a label. */
setTypes(Label label)408   public final void setTypes (Label label)
409   {
410     setTypes(label.localTypes, label.stackTypes);
411   }
412 
413   /** Set the current type state from a label. */
setTypes(Type[] labelLocals, Type[] labelStack)414   public final void setTypes (Type[] labelLocals, Type[] labelStack)
415   {
416     int usedStack = labelStack.length;
417     int usedLocals = labelLocals.length;
418     if (local_types != null)
419       {
420         if (usedLocals > 0)
421           System.arraycopy(labelLocals, 0, local_types, 0, usedLocals);
422         for (int i = usedLocals;  i < local_types.length;  i++)
423           local_types[i] = null;
424       }
425     if (stack_types == null || usedStack > stack_types.length)
426       stack_types = new Type[usedStack];
427     else
428       {
429         for (int i = usedStack;  i < stack_types.length;  i++)
430           stack_types[i] = null;
431       }
432     System.arraycopy(labelStack, 0, stack_types, 0, usedStack);
433     SP = usedStack;
434   }
435 
pushType(Type type)436   public final void pushType(Type type)
437   {
438     if (type.size == 0)
439       throw new Error ("pushing void type onto stack");
440     if (stack_types == null || stack_types.length == 0) // ??
441       stack_types = new Type[20];
442     else if (SP + 1 >= stack_types.length) {
443       Type[] new_array = new Type[2 * stack_types.length];
444       System.arraycopy (stack_types, 0, new_array, 0, SP);
445       stack_types = new_array;
446     }
447     if (type.size == 8)
448       stack_types[SP++] = Type.voidType;
449     stack_types[SP++] = type;
450     if (SP > max_stack)
451       max_stack = SP;
452   }
453 
popType()454   public final Type popType ()
455   {
456     if (SP <= 0)
457       throw new Error("popType called with empty stack "+getMethod());
458     Type type = stack_types[--SP];
459     if (type.size == 8)
460       if (! popType().isVoid())
461 	throw new Error("missing void type on stack");
462     return type;
463   }
464 
topType()465   public final Type topType ()
466   {
467     return stack_types[SP - 1];
468   }
469 
470   /** Compile code to pop values off the stack (and ignore them).
471    * @param nvalues the number of values (not words) to pop
472    */
emitPop(int nvalues)473   public void emitPop (int nvalues)
474   {
475     for ( ; nvalues > 0;  --nvalues)
476       {
477         reserve(1);
478 	Type type = popType();
479 	if (type.size > 4)
480 	  put1(88);  // pop2
481 	else if (nvalues > 1)
482 	  { // optimization:  can we pop 2 4-byte words using a pop2
483 	    Type type2 = popType();
484 	    if (type2.size > 4)
485 	      {
486 		put1(87);  // pop
487 		reserve(1);
488 	      }
489 	    put1(88);  // pop2
490 	    --nvalues;
491 	  }
492 	else
493 	  put1(87); // pop
494       }
495   }
496 
497   /** Get a new Label for the current location.
498    * Unlike Label.define, does not change reachableHere().
499    */
getLabel()500   public Label getLabel ()
501   {
502     Label label = new Label();
503     label.defineRaw(this);
504     return label;
505   }
506 
emitSwap()507   public void emitSwap ()
508   {
509     reserve(1);
510     Type type1 = popType();
511     Type type2 = popType();
512 
513     if (type1.size > 4 || type2.size > 4)
514       {
515 	// There is no swap instruction in the JVM for this case.
516 	// Fall back to a more convoluted way.
517 	pushType(type2);
518 	pushType(type1);
519 	emitDupX();
520 	emitPop(1);
521       }
522     else
523       {
524 	pushType(type1);
525 	put1(95);  // swap
526 	pushType(type2);
527       }
528   }
529 
530   /** Emit code to duplicate the top element of the stack. */
emitDup()531   public void emitDup ()
532   {
533     reserve(1);
534 
535     Type type = topType();
536     put1 (type.size <= 4 ? 89 : 92); // dup or dup2
537     pushType (type);
538   }
539 
540   /** Emit code to duplicate the top element of the stack
541       and place the copy before the previous element. */
emitDupX()542   public void emitDupX ()
543   {
544     reserve(1);
545 
546     Type type = popType();
547     Type skipedType = popType();
548 
549     if (skipedType.size <= 4)
550       put1 (type.size <= 4 ? 90 : 93); // dup_x1 or dup2_x1
551     else
552       put1 (type.size <= 4 ? 91 : 94); // dup_x2 or dup2_x2
553 
554     pushType (type);
555     pushType (skipedType);
556     pushType (type);
557   }
558 
559   /** Compile code to duplicate with offset.
560    * @param size the size of the stack item to duplicate (1 or 2)
561    * @param offset where to insert the result (must be 0, 1, or 2)
562    * The new words get inserted at stack[SP-size-offset]
563    */
emitDup(int size, int offset)564   public void emitDup (int size, int offset)
565   {
566     if (size == 0)
567       return;
568     reserve(1);
569     // copied1 and (optionally copied2) are the types of the duplicated words
570     Type copied1 = popType ();
571     Type copied2 = null;
572     if (size == 1)
573       {
574 	if (copied1.size > 4)
575 	  throw new Error ("using dup for 2-word type");
576       }
577     else if (size != 2)
578       throw new Error ("invalid size to emitDup");
579     else if (copied1.size <= 4)
580       {
581 	copied2 = popType();
582 	if (copied2.size > 4)
583 	  throw new Error ("dup will cause invalid types on stack");
584       }
585 
586     int kind;
587     // These are the types of the words (in any) that are "skipped":
588     Type skipped1 = null;
589     Type skipped2 = null;
590     if (offset == 0)
591       {
592 	kind = size == 1 ? 89 : 92;  // dup or dup2
593       }
594     else if (offset == 1)
595       {
596 	kind = size == 1 ? 90 : 93; // dup_x1 or dup2_x1
597 	skipped1 = popType ();
598 	if (skipped1.size > 4)
599 	  throw new Error ("dup will cause invalid types on stack");
600       }
601     else if (offset == 2)
602       {
603 	kind = size == 1 ? 91 : 94; // dup_x2 or dup2_x2
604 	skipped1 = popType();
605 	if (skipped1.size <= 4)
606 	  {
607 	    skipped2 = popType();
608 	    if (skipped2.size > 4)
609 	      throw new Error ("dup will cause invalid types on stack");
610 	  }
611       }
612     else
613       throw new Error ("emitDup:  invalid offset");
614 
615     put1(kind);
616     if (copied2 != null)
617       pushType(copied2);
618     pushType(copied1);
619     if (skipped2 != null)
620       pushType(skipped2);
621     if (skipped1 != null)
622       pushType(skipped1);
623     if (copied2 != null)
624       pushType(copied2);
625     pushType(copied1);
626   }
627 
628   /**
629    * Compile code to duplicate the top 1 or 2 words.
630    * @param size number of words to duplicate
631    */
emitDup(int size)632   public void emitDup (int size)
633   {
634     emitDup(size, 0);
635   }
636 
emitDup(Type type)637   public void emitDup (Type type)
638   {
639     emitDup(type.size > 4 ? 2 : 1, 0);
640   }
641 
enterScope(Scope scope)642   public void enterScope (Scope scope)
643   {
644     scope.setStartPC(this);
645     locals.enterScope(scope);
646   }
647 
pushScope()648   public Scope pushScope ()
649   {
650     Scope scope = new Scope ();
651     if (locals == null)
652       locals = new LocalVarsAttr(getMethod());
653     enterScope(scope);
654     if (locals.parameter_scope == null)
655       locals.parameter_scope = scope;
656     return scope;
657   }
658 
659     /** Create a Scope that is automatically popped.
660      * I.e. the next popScope will keep popping autoPop scopes until
661      * it gets to a non-autoPop scope.  An autoPop Scope is useful for
662      * variables that are assigned and set in the middle of a managed Scope.
663      */
pushAutoPoppableScope()664     public Scope pushAutoPoppableScope() {
665         Scope scope = pushScope();
666         scope.autoPop = true;
667         return scope;
668     }
669 
getCurrentScope()670   public Scope getCurrentScope()
671   {
672     return locals.current_scope;
673   }
674 
popScope()675     public Scope popScope () {
676         Label end = getLabel();
677         for (;;) {
678             Scope scope = locals.current_scope;
679             locals.current_scope = scope.parent;
680             scope.freeLocals(this);
681             scope.end = end;
682             if (! scope.autoPop)
683                 return scope;
684         }
685     }
686 
687   /** Get the index'th parameter. */
getArg(int index)688   public Variable getArg (int index)
689   {
690     return locals.parameter_scope.getVariable(index);
691   }
692 
693   /**
694    * Search by name for a Variable
695    * @param name name to search for
696    * @return the Variable, or null if not found (in any scope of this Method).
697    */
lookup(String name)698   public Variable lookup (String name)
699   {
700     Scope scope = locals.current_scope;
701     for (; scope != null;  scope = scope.parent)
702       {
703 	Variable var = scope.lookup (name);
704 	if (var != null)
705 	  return var;
706       }
707     return null;
708   }
709 
710   /** Add a new local variable (in the current scope).
711    * @param type type of the new Variable.
712    * @return the new Variable. */
addLocal(Type type)713   public Variable addLocal (Type type)
714   {
715     return locals.current_scope.addVariable(this, type, null);
716   }
717 
718   /** Add a new local variable (in the current scope).
719    * @param type type of the new Variable.
720    * @param name name of the new Variable.
721    * @return the new Variable. */
addLocal(Type type, String name)722   public Variable addLocal (Type type, String name)
723   {
724     return locals.current_scope.addVariable (this, type, name);
725   }
726 
727   /** Call addLocal for parameters (as implied by method type). */
addParamLocals()728   public void addParamLocals()
729   {
730     Method method = getMethod();
731     if ((method.access_flags & Access.STATIC) == 0)
732       addLocal(method.classfile).setParameter(true);
733     int arg_count = method.arg_types.length;
734     for (int i = 0;  i < arg_count;  i++)
735       addLocal(method.arg_types[i]).setParameter(true);
736   }
737 
emitPushConstant(int val, Type type)738   public final void emitPushConstant(int val, Type type)
739   {
740     switch (type.getSignature().charAt(0))
741       {
742       case 'B':  case 'C':  case 'I':  case 'Z':  case 'S':
743 	emitPushInt(val);  break;
744       case 'J':
745 	emitPushLong((long)val);  break;
746       case 'F':
747 	emitPushFloat((float)val);  break;
748       case 'D':
749 	emitPushDouble((double)val);  break;
750       default:
751 	throw new Error("bad type to emitPushConstant");
752       }
753   }
754 
755   /* Low-level method to pust a ConstantPool entry.
756    * Does not do the appropriatre <code>pushType</code>. */
emitPushConstant(CpoolEntry cnst)757   public final void emitPushConstant (CpoolEntry cnst)
758   {
759     reserve(3);
760     int index = cnst.index;
761     if (cnst instanceof CpoolValue2)
762       {
763       	put1 (20); // ldc2_w
764 	put2 (index);
765       }
766     else if (index < 256)
767       {
768 	put1(18); // ldc
769 	put1(index);
770       }
771     else
772       {
773 	put1(19); // ldc_w
774 	put2(index);
775       }
776   }
777 
emitPushInt(int i)778   public final void emitPushInt(int i)
779   {
780     reserve(3);
781     if (i >= -1 && i <= 5)
782       put1(i + 3);  // iconst_m1 .. iconst_5
783     else if (i >= -128 && i < 128)
784       {
785 	put1(16); // bipush
786 	put1(i);
787       }
788     else if (i >= -32768 && i < 32768)
789       {
790 	put1(17); // sipush
791 	put2(i);
792       }
793     else
794       {
795 	emitPushConstant(getConstants().addInt(i));
796       }
797     pushType(Type.intType);
798   }
799 
emitPushLong(long i)800   public void emitPushLong (long i)
801   {
802     if (i == 0 || i == 1)
803       {
804 	reserve(1);
805 	put1 (9 + (int) i);  // lconst_0 .. lconst_1
806       }
807     else if ((long) (int) i == i)
808       {
809 	emitPushInt ((int) i);
810 	reserve(1);
811 	popType();
812 	put1 (133); // i2l
813       }
814     else
815       {
816 	emitPushConstant(getConstants().addLong(i));
817       }
818     pushType(Type.longType);
819   }
820 
emitPushFloat(float x)821   public void emitPushFloat (float x)
822   {
823     int xi = (int) x;
824     if ((float) xi == x && xi >= -128 && xi < 128)
825       {
826 	if (xi >= 0 && xi <= 2)
827 	  {
828 	    reserve(1);
829 	    put1(11 + xi);  // fconst_0 .. fconst_2
830 	    if (xi == 0 && Float.floatToIntBits(x) != 0) // x == -0.0
831 	      {
832 		reserve(1);
833 		put1(118);  // fneg
834 	      }
835 	  }
836 	else
837 	  {
838 	    // Saves space in the constant pool
839 	    // Probably faster, at least on modern CPUs.
840 	    emitPushInt (xi);
841 	    reserve(1);
842 	    popType();
843 	    put1 (134); // i2f
844 	  }
845       }
846     else
847       {
848 	emitPushConstant(getConstants().addFloat(x));
849       }
850     pushType(Type.floatType);
851   }
852 
emitPushDouble(double x)853   public void emitPushDouble (double x)
854   {
855     int xi = (int) x;
856     if ((double) xi == x && xi >= -128 && xi < 128)
857       {
858 	if (xi == 0 || xi == 1)
859 	  {
860 	    reserve(1);
861 	    put1(14+xi);  // dconst_0 or dconst_1
862 	    if (xi == 0 && Double.doubleToLongBits(x) != 0L) // x == -0.0
863 	      {
864 		reserve(1);
865 		put1(119);  // dneg
866 	      }
867 	  }
868 	else
869 	  {
870 	    // Saves space in the constant pool
871 	    // Probably faster, at least on modern CPUs.
872 	    emitPushInt (xi);
873 	    reserve(1);
874 	    popType();
875 	    put1 (135); // i2d
876 	  }
877       }
878     else
879       {
880 	emitPushConstant(getConstants().addDouble(x));
881       }
882     pushType(Type.doubleType);
883   }
884 
885   /** Calculate how many CONSTANT_String constants we need for a string.
886    * Each CONSTANT_String can be at most 0xFFFF bytes (as a UTF8 string).
887    * Returns a String, where each char, coerced to an int, is the length
888    * of a substring of the input that is at most 0xFFFF bytes.
889    */
calculateSplit(String str)890   public static final String calculateSplit (String str)
891   {
892     int strLength = str.length();
893     StringBuffer sbuf = new StringBuffer(20);
894     // Where the current segments starts, as an index in 'str':
895     int segmentStart = 0;
896     int byteLength = 0; // Length in bytes of current segment so far.
897     for (int i = 0;  i < strLength; i++)
898       {
899 	char ch = str.charAt(i);
900 	int bytes = ch >= 0x0800 ? 3 : ch >= 0x0080 || ch == 0 ? 2 : 1;
901 	if (byteLength + bytes > 0xFFFF)
902 	  {
903 	    sbuf.append((char) (i - segmentStart));
904 	    segmentStart = i;
905 	    byteLength = 0;
906 	  }
907 	byteLength += bytes;
908       }
909     sbuf.append((char) (strLength - segmentStart));
910     return sbuf.toString();
911   }
912 
913   /** Emit code to push the value of a constant String.
914    * Uses CONSTANT_String and CONSTANT_Utf8 constant pool entries as needed.
915    * Can handle Strings whose UTF8 length is greates than 0xFFFF bytes
916    * (the limit of a CONSTANT_Utf8) by generating String concatenation.
917    */
emitPushString(String str)918   public final void emitPushString (String str)
919   {
920     if (str == null)
921       emitPushNull();
922     else
923       {
924 	int length = str.length();
925 	String segments = calculateSplit(str);
926 	int numSegments = segments.length();
927 	if (numSegments <= 1)
928 	  emitPushConstant(getConstants().addString(str));
929 	else
930 	  {
931 	    if (numSegments == 2)
932 	      {
933 		int firstSegment = (int) segments.charAt(0);
934 		emitPushString(str.substring(0, firstSegment));
935 		emitPushString(str.substring(firstSegment));
936 		Method concatMethod
937 		  = Type.javalangStringType.getDeclaredMethod("concat", 1);
938 		emitInvokeVirtual(concatMethod);
939 	      }
940 	    else
941 	      {
942 		ClassType sbufType = ClassType.make("java.lang.StringBuffer");
943 		emitNew(sbufType);
944 		emitDup(sbufType);
945 		emitPushInt(length);
946 		Type[] args1 = { Type.intType  };
947 		emitInvokeSpecial(sbufType.getDeclaredMethod("<init>", args1));
948 		Type[] args2 = { Type.javalangStringType    };
949 		Method appendMethod
950 		  = sbufType.getDeclaredMethod("append", args2);
951 		int segStart = 0;
952 		for (int seg = 0;  seg < numSegments;  seg++)
953 		  {
954 		    emitDup(sbufType);
955 		    int segEnd = segStart + (int) segments.charAt(seg);
956 		    emitPushString(str.substring(segStart, segEnd));
957 		    emitInvokeVirtual(appendMethod);
958 		    segStart = segEnd;
959 		  }
960 		emitInvokeVirtual(Type.toString_method);
961 	      }
962 	    if (str == str.intern())
963 	      emitInvokeVirtual(Type.javalangStringType.getDeclaredMethod("intern", 0));
964 	    return;
965 	  }
966 	pushType(Type.javalangStringType);
967       }
968   }
969 
970   /** Push a class constant pool entry.
971    * This is only supported by JDK 1.5 and later. */
emitPushClass(ObjectType ctype)972   public final void emitPushClass (ObjectType ctype)
973   {
974     emitPushConstant(getConstants().addClass(ctype));
975     pushType(Type.javalangClassType);
976   }
977 
978     /** Push a MethodHandle, using an appropriate constant pool entry.
979      * This is only supported by JDK 1.6 and later.
980      */
emitPushMethodHandle(Method method)981     public final void emitPushMethodHandle(Method method) {
982         emitPushConstant(getConstants().addMethodHandle(method));
983         pushType(Type.javalanginvokeMethodHandleType);
984     }
985 
emitPushNull()986     public void emitPushNull() { emitPushNull(Type.nullType); }
987 
emitPushNull(ObjectType type)988     public void emitPushNull(ObjectType type) {
989         reserve(1);
990         put1(1);  // aconst_null
991         pushType(type);
992     }
993 
994   /** Push zero or null as appropriate for the given type. */
emitPushDefaultValue(Type type)995   public void emitPushDefaultValue (Type type)
996   {
997     type = type.getImplementationType();
998     if (type instanceof PrimType)
999       emitPushConstant(0, type);
1000     else
1001       emitPushNull();
1002   }
1003 
1004   /** Initialize a variable to zero or null, as appropriate. */
emitStoreDefaultValue(Variable var)1005   public void emitStoreDefaultValue (Variable var)
1006   {
1007     emitPushDefaultValue(var.getType());
1008     emitStore(var);
1009   }
1010 
emitPushThis()1011   public final void emitPushThis()
1012   {
1013     emitLoad(locals.used[0]);
1014   }
1015 
emitPushPrimArray(Object value, ArrayType arrayType)1016     public final void emitPushPrimArray(Object value, ArrayType arrayType)
1017     {
1018         int len = java.lang.reflect.Array.getLength(value);
1019         emitPushPrimArray(value, len, len, arrayType);
1020     }
1021 
1022   /** Emit code to push a constant primitive array.
1023    * @param value The array value that we want the emitted code to re-create.
1024    * @param arrayType The ArrayType that matches value.
1025    */
emitPushPrimArray(Object value, int len, int count, ArrayType arrayType)1026   public final void emitPushPrimArray(Object value, int len, int count,
1027                                       ArrayType arrayType)
1028   {
1029     Type elementType = arrayType.getComponentType();
1030     emitPushInt(len);
1031     emitNewArray(elementType);
1032     char sig = elementType.getSignature().charAt(0);
1033     for (int i = 0;  i < count;  i++)
1034       {
1035 	long ival = 0;  float fval = 0;  double dval = 0;
1036 	switch (sig)
1037 	  {
1038 	  case 'J':
1039 	    ival = ((long[]) value)[i];
1040 	    if (ival == 0)
1041 	      continue;
1042 	    break;
1043 	  case 'I':
1044 	    ival = ((int[]) value)[i];
1045 	    if (ival == 0)
1046 	      continue;
1047 	    break;
1048 	  case 'S':
1049 	    ival = ((short[]) value)[i];
1050 	    if (ival == 0)
1051 	      continue;
1052 	    break;
1053 	  case 'C':
1054 	    ival = ((char[]) value)[i];
1055 	    if (ival == 0)
1056 	      continue;
1057 	    break;
1058 	  case 'B':
1059 	    ival = ((byte[]) value)[i];
1060 	    if (ival == 0)
1061 	      continue;
1062 	    break;
1063 	  case 'Z':
1064 	    ival = ((boolean[]) value)[i] ? 1 : 0;
1065 	    if (ival == 0)
1066 	      continue;
1067 	    break;
1068 	  case 'F':
1069 	    fval = ((float[]) value)[i];
1070 	    if (fval == 0.0)
1071 	      continue;
1072 	    break;
1073 	  case 'D':
1074 	    dval = ((double[]) value)[i];
1075 	    if (dval == 0.0)
1076 	      continue;
1077 	    break;
1078 	  }
1079 	emitDup(arrayType);
1080 	emitPushInt(i);
1081 	switch (sig)
1082 	  {
1083 	  case 'Z':
1084 	  case 'C':
1085 	  case 'B':
1086 	  case 'S':
1087 	  case 'I':
1088 	    emitPushInt((int) ival);
1089 	    break;
1090 	  case 'J':
1091 	    emitPushLong(ival);
1092 	    break;
1093 	  case 'F':
1094 	    emitPushFloat(fval);
1095 	    break;
1096 	  case 'D':
1097 	    emitPushDouble(dval);
1098 	    break;
1099 	  }
1100 	emitArrayStore(elementType);
1101       }
1102   }
1103 
1104 
1105 
emitNewArray(int type_code)1106   void emitNewArray (int type_code)
1107   {
1108     reserve(2);
1109     put1(188);  // newarray
1110     put1(type_code);
1111   }
1112 
emitArrayLength()1113   public final void emitArrayLength ()
1114   {
1115     if (! (popType() instanceof ArrayType))
1116       throw new Error( "non-array type in emitArrayLength" );
1117 
1118     reserve(1);
1119     put1(190);  // arraylength
1120     pushType(Type.intType);
1121   }
1122 
1123   /* Returns an integer in the range 0 (for 'int') through 4 (for object
1124      reference) to 7 (for 'short') which matches the pattern of how JVM
1125      opcodes typically depend on the operand type. */
1126 
adjustTypedOp(char sig)1127   private int adjustTypedOp  (char sig)
1128   {
1129     switch (sig)
1130       {
1131       case 'I':  return 0;  // int
1132       case 'J':  return 1;  // long
1133       case 'F':  return 2;  // float
1134       case 'D':  return 3;  // double
1135       default:   return 4;  // object
1136       case 'B':
1137       case 'Z':  return 5;  // byte or boolean
1138       case 'C':  return 6;  // char
1139       case 'S':  return 7;  // short
1140       }
1141   }
1142 
adjustTypedOp(Type type)1143   private int adjustTypedOp  (Type type)
1144   {
1145     return adjustTypedOp(type.getSignature().charAt(0));
1146   }
1147 
emitTypedOp(int op, Type type)1148   private void emitTypedOp (int op, Type type)
1149   {
1150     reserve(1);
1151     put1(op + adjustTypedOp(type));
1152   }
1153 
emitTypedOp(int op, char sig)1154   private void emitTypedOp (int op, char sig)
1155   {
1156     reserve(1);
1157     put1(op + adjustTypedOp(sig));
1158   }
1159 
1160   /** Store into an element of an array.
1161    * Must already have pushed the array reference, the index,
1162    * and the new value (in that order).
1163    * Stack:  {@literal ..., array, index, value => ...}
1164    */
emitArrayStore(Type element_type)1165   public void emitArrayStore (Type element_type)
1166   {
1167     popType();  // Pop new value
1168     popType();  // Pop index
1169     popType();  // Pop array reference
1170     emitTypedOp(79, element_type);
1171   }
1172 
1173   /** Store into an element of an array.
1174    * Must already have pushed the array reference, the index,
1175    * and the new value (in that order).
1176    * Stack: {@literal ..., array, index, value => ...}
1177    */
emitArrayStore()1178   public void emitArrayStore ()
1179   {
1180     popType();  // Pop new value
1181     popType();  // Pop index
1182     Type arrayType = popType().getImplementationType(); // Pop array reference
1183     Type elementType = ((ArrayType) arrayType).getComponentType();
1184     emitTypedOp(79, elementType);
1185   }
1186 
1187   /** Load an element from an array.
1188    * Must already have pushed the array and the index (in that order):
1189    * Stack: {@literal ..., array, index => ..., value}
1190    */
emitArrayLoad(Type element_type)1191   public void emitArrayLoad (Type element_type)
1192   {
1193     popType();  // Pop index
1194     popType();  // Pop array reference
1195     emitTypedOp(46, element_type);
1196     pushType(element_type);
1197   }
1198 
1199   /** Load an element from an array.
1200    * Equivalent to {@code emitArrayLoad(Type)}, but element_type is implied.
1201    * Must already have pushed the array and the index (in that order):
1202    * Stack: {@literal ..., array, index => ..., value}
1203    */
emitArrayLoad()1204   public void emitArrayLoad ()
1205   {
1206     popType();  // Pop index
1207     Type arrayType = popType().getImplementationType();
1208     Type elementType = ((ArrayType) arrayType).getComponentType();
1209     emitTypedOp(46, elementType);
1210     pushType(elementType);
1211   }
1212 
1213   /**
1214    * Invoke new on a class type.
1215    * Does not call the constructor!
1216    * @param type the desired new object type
1217    */
emitNew(ClassType type)1218   public void emitNew (ClassType type)
1219   {
1220     reserve(3);
1221     Label label = new Label(this);
1222     label.defineRaw(this);
1223     put1(187); // new
1224     putIndex2(getConstants().addClass(type));
1225     pushType(new UninitializedType(type, label));
1226   }
1227 
1228   /** Compile code to allocate a new array.
1229    * The size should have been already pushed on the stack.
1230    * @param element_type type of the array elements
1231    * @param dims number of dimensions - more than 1 is untested
1232    */
emitNewArray(Type element_type, int dims)1233   public void emitNewArray (Type element_type, int dims)
1234   {
1235     if (popType ().promote () != Type.intType)
1236       throw new Error ("non-int dim. spec. in emitNewArray");
1237 
1238     if (element_type instanceof PrimType)
1239       {
1240 	int code;
1241 	switch (element_type.getSignature().charAt(0))
1242 	  {
1243 	  case 'B':  code =  8;  break;
1244 	  case 'S':  code =  9;  break;
1245 	  case 'I':  code = 10;  break;
1246 	  case 'J':  code = 11;  break;
1247 	  case 'F':  code =  6;  break;
1248 	  case 'D':  code =  7;  break;
1249 	  case 'Z':  code =  4;  break;
1250 	  case 'C':  code =  5;  break;
1251 	  default:   throw new Error("bad PrimType in emitNewArray");
1252 	  }
1253 	emitNewArray(code);
1254       }
1255     else if (element_type instanceof ArrayType && dims > 1) // untested
1256     {
1257       reserve(4);
1258       put1(197); // multianewarray
1259       putIndex2 (getConstants ().addClass (new ArrayType (element_type)));
1260       if (dims < 1 || dims > 255)
1261 	throw new Error ("dims out of range in emitNewArray");
1262       put1(dims);
1263       while (-- dims > 0) // first dim already popped
1264 	if (popType ().promote () != Type.intType)
1265 	  throw new Error ("non-int dim. spec. in emitNewArray");
1266     }
1267     else if (element_type instanceof ObjectType)
1268       {
1269 	reserve(3);
1270 	put1(189); // anewarray
1271 	putIndex2(getConstants().addClass((ObjectType) element_type));
1272       }
1273     else
1274       throw new Error ("unimplemented type in emitNewArray");
1275 
1276     pushType (new ArrayType (element_type));
1277   }
1278 
emitNewArray(Type element_type)1279   public void emitNewArray (Type element_type)
1280   {
1281     emitNewArray (element_type, 1);
1282   }
1283 
1284   // We may want to deprecate this, because it depends on popType.
emitBinop(int base_code)1285   private void emitBinop (int base_code)
1286   {
1287     Type type2 = popType().promote();
1288     Type type1_raw = popType();
1289     Type type1 = type1_raw.promote();
1290     if (type1 != type2 || ! (type1 instanceof PrimType))
1291       throw new Error ("non-matching or bad types in binary operation");
1292     emitTypedOp(base_code, type1);
1293     pushType(type1_raw);
1294   }
1295 
emitBinop(int base_code, char sig)1296   private void emitBinop (int base_code, char sig)
1297   {
1298     popType();
1299     popType();
1300     emitTypedOp(base_code, sig);
1301     pushType(Type.signatureToPrimitive(sig));
1302   }
1303 
emitBinop(int base_code, Type type)1304   public void emitBinop (int base_code, Type type)
1305   {
1306     popType();
1307     popType();
1308     emitTypedOp(base_code, type);
1309     pushType(type);
1310   }
1311 
1312   // public final void emitIntAdd () { put1(96); popType();}
1313   // public final void emitLongAdd () { put1(97); popType();}
1314   // public final void emitFloatAdd () { put1(98); popType();}
1315   // public final void emitDoubleAdd () { put1(99); popType();}
1316 
emitAdd(char sig)1317   public final void emitAdd(char sig) { emitBinop (96, sig); }
emitAdd(PrimType type)1318   public final void emitAdd(PrimType type) { emitBinop (96, type); }
emitAdd()1319   @Deprecated public final void emitAdd () { emitBinop (96); }
1320 
emitSub(char sig)1321   public final void emitSub(char sig) { emitBinop (100, sig); }
emitSub(PrimType type)1322   public final void emitSub(PrimType type) { emitBinop (100, type); }
emitSub()1323   @Deprecated public final void emitSub () { emitBinop (100); }
1324 
emitMul()1325   public final void emitMul () { emitBinop (104); }
emitDiv()1326   public final void emitDiv () { emitBinop (108); }
emitRem()1327   public final void emitRem () { emitBinop (112); }
emitAnd()1328   public final void emitAnd () { emitBinop (126); }
emitIOr()1329   public final void emitIOr () { emitBinop (128); }
emitXOr()1330   public final void emitXOr () { emitBinop (130); }
1331 
emitShl()1332   public final void emitShl () { emitShift (120); }
emitShr()1333   public final void emitShr () { emitShift (122); }
emitUshr()1334   public final void emitUshr() { emitShift (124); }
1335 
emitShift(int base_code)1336   private void emitShift (int base_code)
1337   {
1338     Type type2 = popType().promote();
1339     Type type1_raw = popType();
1340     Type type1 = type1_raw.promote();
1341 
1342     if (type1 != Type.intType && type1 != Type.longType)
1343       throw new Error ("the value shifted must be an int or a long");
1344 
1345     if (type2 != Type.intType)
1346       throw new Error ("the amount of shift must be an int");
1347 
1348     emitTypedOp(base_code, type1);
1349     pushType(type1_raw);
1350   }
1351 
1352   /** Compile 'not', assuming 0 or 1 is on the JVM stack. */
emitNot(Type type)1353   public final void emitNot(Type type)
1354   {
1355     emitPushConstant(1, type);
1356     emitAdd();
1357     emitPushConstant(1, type);
1358     emitAnd();
1359   }
1360 
emitPrimop(int opcode, int arg_count, Type retType)1361   public void emitPrimop (int opcode, int arg_count, Type retType)
1362   {
1363     reserve(1);
1364     while (-- arg_count >= 0)
1365       popType();
1366     put1(opcode);
1367     pushType(retType);
1368   }
1369 
emitMaybeWide(int opcode, int index)1370   void emitMaybeWide (int opcode, int index)
1371   {
1372     if (index >= 256)
1373       {
1374 	put1(196); // wide
1375 	put1(opcode);
1376 	put2(index);
1377       }
1378     else
1379       {
1380 	put1(opcode);
1381 	put1(index);
1382       }
1383   }
1384 
1385   /**
1386    * Compile code to push the contents of a local variable onto the statck.
1387    * @param var The variable whose contents we want to push.
1388    */
emitLoad(Variable var)1389   public final void emitLoad (Variable var)
1390   {
1391     if (var.dead())
1392       throw new Error("attempting to push dead variable");
1393     int offset = var.offset;
1394     if (offset < 0 || !var.isSimple())
1395       throw new Error ("attempting to load from unassigned variable "+var
1396 		       +" simple:"+var.isSimple()+", offset: "+offset);
1397     Type type = var.getType().promote();
1398     reserve(4);
1399     int kind = adjustTypedOp(type);
1400     if (offset <= 3)
1401       put1(26 + 4 * kind + offset);  // [ilfda]load_[0123]
1402     else
1403       emitMaybeWide(21 + kind, offset); // [ilfda]load
1404     pushType(var.getType());
1405   }
1406 
emitStore(Variable var)1407   public void emitStore (Variable var)
1408   {
1409     if (! reachableHere())
1410       return;
1411     int offset = var.offset;
1412     if (offset < 0 || !var.isSimple ())
1413       throw new Error ("attempting to store in unassigned "+var
1414 		       +" simple:"+var.isSimple()+", offset: "+offset);
1415     Type type = var.getType().promote ();
1416     noteVarType(offset, type);
1417     reserve(4);
1418     popType();
1419     int kind = adjustTypedOp(type);
1420     if (offset <= 3)
1421       put1(59 + 4 * kind + offset);  // [ilfda]store_[0123]
1422     else
1423       emitMaybeWide(54 + kind, offset); // [ilfda]store
1424   }
1425 
1426 
1427   /** Emit an instruction to increment a variable by some amount.
1428    * If the increment is zero, do nothing.
1429    * The variable must contain an integral value - except if increment is zero.
1430    */
emitInc(Variable var, short inc)1431   public void emitInc (Variable var, short inc)
1432   {
1433     if (var.dead ())
1434       throw new Error ("attempting to increment dead variable");
1435     int offset = var.offset;
1436     if (offset < 0 || !var.isSimple ())
1437       throw new Error ("attempting to increment unassigned variable"+var.getName()
1438 		       +" simple:"+var.isSimple()+", offset: "+offset);
1439 
1440     if (inc == 0)
1441       return;
1442 
1443     reserve(6);
1444     if (var.getType().getImplementationType().promote() != Type.intType)
1445       throw new Error("attempting to increment non-int variable");
1446 
1447     boolean wide = offset > 255 || inc > 255 || inc < -256;
1448     if (wide)
1449     {
1450       put1(196); // wide
1451       put1(132); // iinc
1452       put2(offset);
1453       put2(inc);
1454     }
1455     else
1456     {
1457       put1(132); // iinc
1458       put1(offset);
1459       put1(inc);
1460     }
1461   }
1462 
1463 
1464   private final void emitFieldop (Field field, int opcode)
1465   {
1466     reserve(3);
1467     put1(opcode);
1468     putIndex2(getConstants().addFieldRef(field));
1469   }
1470 
1471   /** Compile code to get a static field value.
1472    * Stack: {@code ... => ..., value} */
1473 
1474   public final void emitGetStatic(Field field)
1475   {
1476     pushType(field.getType());
1477     emitFieldop (field, 178);  // getstatic
1478   }
1479 
1480   /** Compile code to get a non-static field value.
1481    * Stack: {@code ..., objectref => ..., value} */
1482 
1483   public final void emitGetField(Field field)
1484   {
1485     popType();
1486     pushType(field.getType());
1487     emitFieldop(field, 180);  // getfield
1488   }
1489 
1490   /** Compile code to put a static field value.
1491    * Stack: {@code ..., value => ...} */
1492 
1493   public final void emitPutStatic (Field field)
1494   {
1495     popType();
1496     emitFieldop(field, 179);  // putstatic
1497   }
1498 
1499   /** Compile code to put a non-static field value.
1500    * Stack:  {@code ..., objectref, value => ...} */
1501 
1502   public final void emitPutField (Field field)
1503   {
1504     popType();
1505     popType();
1506     emitFieldop(field, 181);  // putfield
1507   }
1508 
1509   /** Comptes the number of stack words taken by a list of types. */
1510   private int words(Type[] types)
1511   {
1512     int res = 0;
1513     for (int i=types.length; --i >= 0; )
1514       if (types[i].size > 4)
1515        res+=2;
1516       else
1517        res++;
1518     return res;
1519   }
1520 
emitInvokeMethod(Method method, int opcode)1521   public void emitInvokeMethod (Method method, int opcode)
1522   {
1523     if (! reachableHere())
1524       return;
1525     reserve(opcode == 185 ? 5 : 3);
1526     int arg_count = method.arg_types.length;
1527     boolean is_invokestatic = opcode == 184;
1528     boolean is_init = opcode == 183 && "<init>".equals(method.getName());
1529 
1530     if (is_invokestatic != ((method.access_flags & Access.STATIC) != 0))
1531       throw new Error
1532 	("emitInvokeXxx static flag mis-match method.flags="+method.access_flags);
1533     if (!is_invokestatic && !is_init)
1534       arg_count++;
1535     put1(opcode);  // invokevirtual, invokespecial, or invokestatic
1536     putIndex2(getConstants().addMethodRef(method));
1537     if (opcode == 185)  // invokeinterface
1538       {
1539 	put1(words(method.arg_types)+1); // 1 word for 'this'
1540 	put1(0);
1541       }
1542     while (--arg_count >= 0)
1543       {
1544         Type t = popType();
1545         if (t instanceof UninitializedType)
1546           throw new Error("passing "+t+" as parameter");
1547       }
1548     if (is_init)
1549       {
1550         Type t = popType();
1551         ClassType ctype;
1552         if (! (t instanceof UninitializedType))
1553           throw new Error("calling <init> on already-initialized object");
1554         ctype = ((UninitializedType) t).ctype;
1555         for (int i = 0;  i < SP;  i++)
1556           if (stack_types[i] == t)
1557             stack_types[i] = ctype;
1558         Variable[] used = locals.used;
1559         for (int i = used == null ? 0 : used.length;  --i >= 0; )
1560           {
1561             Variable var = used[i];
1562             if (var != null && var.getType() == t)
1563                 var.setType(ctype);
1564           }
1565         for (int i = local_types == null ? 0 : local_types.length;  --i >= 0; )
1566           {
1567             if (local_types[i] == t)
1568                 local_types[i] = ctype;
1569           }
1570       }
1571    if (method.return_type.size != 0)
1572       pushType(method.return_type);
1573   }
1574 
emitInvoke(Method method)1575   public void emitInvoke (Method method)
1576   {
1577     int opcode;
1578     if ((method.access_flags & Access.STATIC) != 0)
1579       opcode = 184;   // invokestatic
1580     else if (method.classfile.isInterface())
1581       opcode = 185;   // invokeinterface
1582     else if ("<init>".equals(method.getName())
1583              || (method.access_flags & Access.PRIVATE) != 0)
1584       opcode = 183;   // invokespecial
1585     else
1586       opcode = 182;   // invokevirtual
1587     emitInvokeMethod(method, opcode);
1588   }
1589 
1590   /** Compile a virtual method call.
1591    * The stack contains the 'this' object, followed by the arguments in order.
1592    * @param method the method to invoke virtually
1593    */
emitInvokeVirtual(Method method)1594   public void emitInvokeVirtual (Method method)
1595   {
1596     emitInvokeMethod(method, 182);  // invokevirtual
1597   }
1598 
emitInvokeSpecial(Method method)1599   public void emitInvokeSpecial (Method method)
1600   {
1601     emitInvokeMethod(method, 183);  // invokespecial
1602   }
1603 
1604   /** Compile a static method call.
1605    * The stack contains the the arguments in order.
1606    * @param method the static method to invoke
1607    */
emitInvokeStatic(Method method)1608   public void emitInvokeStatic (Method method)
1609   {
1610     emitInvokeMethod(method, 184);  // invokestatic
1611   }
1612 
emitInvokeInterface(Method method)1613   public void emitInvokeInterface (Method method)
1614   {
1615     emitInvokeMethod(method, 185);  // invokeinterface
1616   }
1617 
emitTransfer(Label label, int opcode)1618   final void emitTransfer (Label label, int opcode)
1619   {
1620     label.setTypes(this);
1621     fixupAdd(FIXUP_TRANSFER, label);
1622     put1(opcode);
1623     PC += 2;
1624   }
1625 
1626   /** Compile an unconditional branch (goto).
1627    * @param label target of the branch (must be in this method).
1628    */
emitGoto(Label label)1629   public final void emitGoto (Label label)
1630   {
1631     label.setTypes(this);
1632     fixupAdd(FIXUP_GOTO, label);
1633     reserve(3);
1634     put1(167);
1635     PC += 2;
1636     setUnreachable();
1637   }
1638 
emitJsr(Label label)1639   public final void emitJsr (Label label)
1640   {
1641     fixupAdd(FIXUP_JSR, label);
1642     reserve(3);
1643     put1(168);
1644     PC += 2;
1645   }
1646 
1647   ExitableBlock currentExitableBlock;
1648   int exitableBlockLevel;
1649 
1650   /** Enter a block which can be exited.
1651    * Used to make sure finally-blocks are executed when exiting a block,
1652    * loop, or method.
1653    */
startExitableBlock(Type resultType, boolean runFinallyBlocks)1654   public ExitableBlock startExitableBlock (Type resultType, boolean runFinallyBlocks)
1655   {
1656     ExitableBlock bl = new ExitableBlock(resultType, this, runFinallyBlocks);
1657     bl.outer = currentExitableBlock;
1658     currentExitableBlock = bl;
1659     return bl;
1660   }
1661 
1662   /** End a block entered by a previous startExitableBlock.
1663    */
endExitableBlock()1664   public void endExitableBlock ()
1665   {
1666     ExitableBlock bl = currentExitableBlock;
1667     bl.finish();
1668     currentExitableBlock = bl.outer;
1669   }
1670 
emitGotoIfCompare1(Label label, int opcode)1671   public final void emitGotoIfCompare1 (Label label, int opcode)
1672   {
1673     popType();
1674     reserve(3);
1675     emitTransfer (label, opcode);
1676   }
1677 
emitGotoIfIntEqZero(Label label)1678   public final void emitGotoIfIntEqZero(Label label)
1679   { emitGotoIfCompare1(label, 153); }
emitGotoIfIntNeZero(Label label)1680   public final void emitGotoIfIntNeZero(Label label)
1681   { emitGotoIfCompare1(label, 154); }
emitGotoIfIntLtZero(Label label)1682   public final void emitGotoIfIntLtZero(Label label)
1683   { emitGotoIfCompare1(label, 155); }
emitGotoIfIntGeZero(Label label)1684   public final void emitGotoIfIntGeZero(Label label)
1685   { emitGotoIfCompare1(label, 156); }
emitGotoIfIntGtZero(Label label)1686   public final void emitGotoIfIntGtZero(Label label)
1687   { emitGotoIfCompare1(label, 157); }
emitGotoIfIntLeZero(Label label)1688   public final void emitGotoIfIntLeZero(Label label)
1689   { emitGotoIfCompare1(label, 158); }
emitGotoIfNull(Label label)1690   public final void emitGotoIfNull(Label label)
1691   { emitGotoIfCompare1(label, 198); }
emitGotoIfNonNull(Label label)1692   public final void emitGotoIfNonNull(Label label)
1693   { emitGotoIfCompare1(label, 199); }
1694 
emitGotoIfCompare2(Label label, int logop)1695   public final void emitGotoIfCompare2 (Label label, int logop)
1696   {
1697     Type type2 = popType().promote();
1698     Type type1 = popType().promote();
1699     reserve(4);
1700     char sig1 = type1.getSignature().charAt(0);
1701     char sig2 = type2.getSignature().charAt(0);
1702 
1703     boolean cmpg = (logop == 155 || logop == 158); // iflt,ifle
1704 
1705     if (sig1 == 'I' && sig2 == 'I')
1706       logop += 6;  // iflt -> if_icmplt etc.
1707     else if (sig1 == 'J' && sig2 == 'J')
1708       put1(148);   // lcmp
1709     else if (sig1 == 'F' && sig2 == 'F')
1710       put1(cmpg ? 149 : 150);   // fcmpl/fcmpg
1711     else if (sig1 == 'D' && sig2 == 'D')
1712       put1(cmpg ? 151 : 152);   // dcmpl/dcmpg
1713     else if ((sig1 == 'L' || sig1 == '[')
1714 	     && (sig2 == 'L' || sig2 == '[')
1715 	     && logop <= 154)
1716       logop += 12; // ifeq->if_acmpeq, ifne->if_acmpne
1717     else
1718       throw new Error ("invalid types to emitGotoIfCompare2");
1719 
1720     emitTransfer (label, logop);
1721   }
1722 
1723   // binary comparisons
1724   @Deprecated
emitGotoIfEq(Label label, boolean invert)1725   public final void emitGotoIfEq (Label label, boolean invert)
1726   {
1727     emitGotoIfCompare2(label, invert ? 154 : 153);
1728   }
1729 
1730   /** Compile a conditional transfer if 2 top stack elements are equal. */
emitGotoIfEq(Label label)1731   public final void emitGotoIfEq (Label label)
1732   {
1733     emitGotoIfCompare2(label, 153);
1734   }
1735 
1736   /** Compile conditional transfer if 2 top stack elements are not equal. */
emitGotoIfNE(Label label)1737   public final void emitGotoIfNE (Label label)
1738   {
1739     emitGotoIfCompare2(label, 154);
1740   }
1741 
emitGotoIfLt(Label label)1742   public final void emitGotoIfLt(Label label)
1743   { emitGotoIfCompare2(label, 155); }
emitGotoIfGe(Label label)1744   public final void emitGotoIfGe(Label label)
1745   { emitGotoIfCompare2(label, 156); }
emitGotoIfGt(Label label)1746   public final void emitGotoIfGt(Label label)
1747   { emitGotoIfCompare2(label, 157); }
emitGotoIfLe(Label label)1748   public final void emitGotoIfLe(Label label)
1749   { emitGotoIfCompare2(label, 158); }
1750 
1751 
1752   /** Compile start of a conditional:
1753    *   <tt>if (!(<var>x</var> opcode 0)) ...</tt>.
1754    * The value of <var>x</var> must already have been pushed. */
emitIfCompare1(int opcode)1755   public final void emitIfCompare1 (int opcode)
1756   {
1757     if (popType().promote() != Type.intType)
1758       throw new Error ("non-int type to emitIfCompare1");
1759     reserve(3);
1760     emitTransfer(emitIfRaw(), opcode);
1761   }
1762 
1763   /** Compile start of conditional:  <tt>if (x != 0) ...</tt>.
1764    * Also use this if you have pushed a boolean value:  if (b) ... */
emitIfIntNotZero()1765   public final void emitIfIntNotZero()
1766   {
1767     emitIfCompare1(153); // ifeq
1768   }
1769 
1770   /** Compile start of conditional:  <tt>if (x == 0) ...</tt>.
1771    * Also use this if you have pushed a boolean value:  if (!b) ... */
emitIfIntEqZero()1772   public final void emitIfIntEqZero()
1773   {
1774     emitIfCompare1(154); // ifne
1775   }
1776 
1777   /** Compile start of conditional:  {@code if (x <= 0)}. */
emitIfIntLEqZero()1778   public final void emitIfIntLEqZero()
1779   {
1780     emitIfCompare1(157); // ifgt
1781   }
1782 
1783   /** Compile start of conditional:  {@code if (x >= 0)}. */
emitIfIntGEqZero()1784   public final void emitIfIntGEqZero()
1785   {
1786     emitIfCompare1(155); // iflt
1787   }
1788 
1789   /** Compile start of a conditional:  {@code if (!(x opcode null)) ...}.
1790    * The value of <tt>x</tt> must already have been pushed and must be of
1791    * reference type. */
emitIfRefCompare1(int opcode)1792   public final void emitIfRefCompare1 (int opcode)
1793   {
1794     if (! (popType() instanceof ObjectType))
1795       throw new Error ("non-ref type to emitIfRefCompare1");
1796     reserve(3);
1797     emitTransfer(emitIfRaw(), opcode);
1798   }
1799 
1800   /** Compile start of conditional:  {@code if (x != null) ...}. */
emitIfNotNull()1801   public final void emitIfNotNull()
1802   {
1803     emitIfRefCompare1(198); // ifnull
1804   }
1805 
1806   /** Compile start of conditional:  {@code if (x == null) ...} */
emitIfNull()1807   public final void emitIfNull()
1808   {
1809     emitIfRefCompare1(199); // ifnonnull
1810   }
1811 
1812   /** Compile start of a conditional:  {@code if (!(x OPCODE y)) ...}
1813    * The value of x and y must already have been pushed. */
emitIfIntCompare(int opcode)1814   public final void emitIfIntCompare(int opcode)
1815   {
1816     popType();
1817     popType();
1818     reserve(3);
1819     emitTransfer(emitIfRaw(), opcode);
1820   }
1821 
1822   /* Compile start of a conditional:  {@code if (x < y) ...} */
emitIfIntLt()1823   public final void emitIfIntLt()
1824   {
1825     emitIfIntCompare(162);  // if_icmpge
1826   }
1827 
1828   /* Compile start of a conditional:  {@code if (x >= y) ...} */
emitIfIntGEq()1829   public final void emitIfIntGEq()
1830   {
1831     emitIfIntCompare(161);  // if_icmplt
1832   }
1833 
1834   /** Compile start of a conditional:  if (x != y) ...
1835    * The values of x and y must already have been pushed. */
emitIfNEq()1836   public final void emitIfNEq ()
1837   {
1838     emitGotoIfEq(emitIfRaw());
1839   }
1840 
1841   /** Compile start of a conditional:  {@code if (x == y) ...}
1842    * The values of x and y must already have been pushed. */
emitIfEq()1843   public final void emitIfEq ()
1844   {
1845     emitGotoIfNE(emitIfRaw());
1846   }
1847 
1848   /** Compile start of a conditional:  {@code if (x < y) ...}
1849    * The values of x and y must already have been pushed. */
emitIfLt()1850   public final void emitIfLt ()
1851   {
1852     emitGotoIfGe(emitIfRaw());
1853   }
1854 
1855   /** Compile start of a conditional:  {@code if (x >= y) ...}
1856    * The values of x and y must already have been pushed. */
emitIfGe()1857   public final void emitIfGe ()
1858   {
1859     emitGotoIfLt(emitIfRaw());
1860   }
1861 
1862   /** Compile start of a conditional:  {@code if (x > y) ...}
1863    * The values of x and y must already have been pushed. */
emitIfGt()1864   public final void emitIfGt ()
1865   {
1866     emitGotoIfLe(emitIfRaw());
1867   }
1868 
1869   /** Compile start of a conditional:  {@code if (x <= y) ...}
1870    * The values of x and y must already have been pushed. */
emitIfLe()1871   public final void emitIfLe ()
1872   {
1873     emitGotoIfGt(emitIfRaw());
1874   }
1875 
1876   /** Emit a 'ret' instruction.
1877     * @param var the variable containing the return address */
emitRet(Variable var)1878   public void emitRet (Variable var)
1879   {
1880     int offset = var.offset;
1881     if (offset < 256)
1882       {
1883 	reserve(2);
1884 	put1(169);  // ret
1885 	put1(offset);
1886       }
1887     else
1888       {
1889 	reserve(4);
1890 	put1(196);  // wide
1891 	put1(169);  // ret
1892 	put2(offset);
1893       }
1894   }
1895 
emitThen()1896   public final void emitThen()
1897   {
1898   }
1899 
emitIfThen()1900   public final void emitIfThen ()
1901   {
1902     new IfState(this, null);
1903   }
1904 
1905   /** Compile start of else clause. */
emitElse()1906   public final void emitElse ()
1907   {
1908     Label else_label = if_stack.end_label;
1909     if (reachableHere ())
1910       {
1911         Label end_label = new Label (this);
1912         if_stack.end_label = end_label;
1913 	emitGoto (end_label);
1914       }
1915     else
1916       if_stack.end_label = null;
1917     if (else_label != null)
1918       else_label.define (this);
1919     if_stack.doing_else = true;
1920   }
1921 
1922   /** Compile end of conditional. */
emitFi()1923   public final void emitFi ()
1924   {
1925     if (if_stack.end_label != null)
1926       if_stack.end_label.define (this);
1927     // Pop the if_stack.
1928     if_stack = if_stack.previous;
1929   }
1930 
1931     /** Convenience for compiling {@code if P1 && P2 then S1 else S2}.
1932      * Compile that as:
1933      * <pre>
1934      * compile P1, including an appropriate emitIfXxx
1935      * emitAndThen()
1936      * compile P2, including an appropriate emitIfXxx
1937      * compile S1
1938      * emitElse
1939      * compile S2
1940      * emitFi
1941      * </pre>
1942      */
emitAndThen()1943     public void emitAndThen() {
1944         if (if_stack==null||if_stack.andThenSet) throw new InternalError();
1945         if_stack.andThenSet = true;
1946     }
1947 
1948     /** Start a new if/then/else block.
1949      * The caller is responsible for evaluating the condition,
1950      * and in the "false" case got the returned label.
1951      * In the "true" case just continue inline.
1952      * @return the else/end label to goto if the condition is false.
1953      * A subsequent emitElse or emitFi defines the label.
1954      */
emitIfRaw()1955     public Label emitIfRaw() {
1956         if (if_stack!=null && if_stack.andThenSet) {
1957             if_stack.andThenSet = false;
1958         } else
1959             new IfState(this);
1960         return if_stack.end_label;
1961     }
1962 
fixUnsigned(Type stackType)1963     public final void fixUnsigned(Type stackType) {
1964         if (stackType instanceof PrimType
1965             && ((PrimType) stackType).isUnsigned()) {
1966             char sig1 = stackType.getSignature().charAt(0);
1967             if (sig1 == 'S') {
1968                 reserve(1);
1969                 put1(146); // i2c
1970             } else if (sig1 == 'B') {
1971                 emitPushInt(255);
1972                 emitAnd();
1973             }
1974         }
1975     }
1976 
emitConvert(PrimType from, PrimType to)1977     public final void emitConvert(PrimType from, PrimType to) {
1978         String to_sig = to.getSignature();
1979         String from_sig = from.getSignature();
1980         int op = -1;
1981 	char to_sig0 = to_sig.charAt(0);
1982 	char from_sig0 = from_sig.charAt(0);
1983 	if (from_sig0 == to_sig0)
1984             return;
1985 	if (from.size < 4)
1986 	  from_sig0 = 'I';
1987 	if (to.size < 4) {
1988 	    emitConvert(from, Type.intType);
1989 	    from_sig0 = 'I';
1990             if (to.isUnsigned()) {
1991                 if (to_sig0 == 'S')
1992                     to_sig0 = 'C';
1993                 else if (to_sig0 == 'B') {
1994                     emitPushInt(0xff);
1995                     emitAnd();
1996                     return;
1997                 }
1998             }
1999         }
2000         if (from_sig0 == 'J' && from.isUnsigned()
2001             && (to_sig0 == 'F' || to_sig0 == 'D')) {
2002             emitPushInt(1);
2003             emitUshr();
2004             emitConvert(Type.longType, to);
2005             emitPushConstant(2, to);
2006             emitMul();
2007             return;
2008         }
2009         if (from_sig0 == 'I' && from.isUnsigned()
2010             && (to_sig0 == 'J' || to_sig0 == 'F' || to_sig0 == 'D')) {
2011             emitConvert(Type.intType, Type.longType);
2012             reserve(4);
2013             emitPushLong(0xffffffffL);
2014             emitAnd();
2015             from_sig0 = 'J';
2016         }
2017 	if (from_sig0 == to_sig0)
2018             return;
2019 	switch (from_sig0)
2020 	  {
2021 	  case 'I':
2022 	    switch (to_sig0)
2023 	      {
2024 	        case 'B':  op = 145;  break;  // i2b
2025 	        case 'C':  op = 146;  break;  // i2c
2026 	        case 'S':  op = 147;  break;  // i2s
2027 		case 'J':  op = 133;  break;  // i2l
2028 		case 'F':  op = 134;  break;  // i2f
2029 		case 'D':  op = 135;  break;  // i2d
2030 	      }
2031 	    break;
2032 	  case 'J':
2033 	    switch (to_sig0)
2034 	      {
2035 		case 'I':  op = 136;  break;  // l2i
2036 		case 'F':  op = 137;  break;  // l2f
2037 		case 'D':  op = 138;  break;  // l2d
2038 	      }
2039 	    break;
2040 	  case 'F':
2041 	    switch (to_sig0)
2042 	      {
2043 		case 'I':  op = 139;  break;  // f2i
2044 		case 'J':  op = 140;  break;  // f2l
2045 		case 'D':  op = 141;  break;  // f2d
2046 	      }
2047 	    break;
2048 	  case 'D':
2049 	    switch (to_sig0)
2050 	      {
2051 		case 'I':  op = 142;  break;  // d2i
2052 		case 'J':  op = 143;  break;  // d2l
2053 		case 'F':  op = 144;  break;  // d2f
2054 	      }
2055 	    break;
2056 	  }
2057         if (op < 0)
2058             throw new Error ("unsupported CodeAttr.emitConvert");
2059         reserve(1);
2060         popType();
2061         put1(op);
2062         pushType(to);
2063     }
2064 
emitCheckcast(Type type, int opcode)2065   private void emitCheckcast (Type type, int opcode)
2066   {
2067     reserve(3);
2068     popType();
2069     put1(opcode);
2070     if (type instanceof ObjectType)
2071       {
2072 	putIndex2(getConstants().addClass((ObjectType) type));
2073       }
2074     else
2075       throw new Error ("unimplemented type " + type
2076 		       + " in emitCheckcast/emitInstanceof");
2077   }
2078 
castNeeded(Type top, Type required)2079   public static boolean castNeeded (Type top, Type required)
2080   {
2081     top = top.getRawType();
2082     for (;;)
2083       {
2084         if (top == required)
2085           return false;
2086         if (required instanceof ClassType
2087             && top instanceof ClassType
2088             && ((ClassType) top).isSubclass((ClassType) required))
2089           return false;
2090         else if (required instanceof ArrayType
2091                  && top instanceof ArrayType)
2092           {
2093             required = ((ArrayType) required).getComponentType();
2094             top = ((ArrayType) top).getComponentType();
2095             continue;
2096           }
2097         return true;
2098       }
2099   }
2100 
emitCheckcast(Type type)2101   public void emitCheckcast (Type type)
2102   {
2103     if (castNeeded(topType(), type))
2104       {
2105         emitCheckcast(type, 192);
2106         pushType(type);
2107       }
2108   }
2109 
emitInstanceof(Type type)2110   public void emitInstanceof (Type type)
2111   {
2112     emitCheckcast(type, 193);
2113     pushType(Type.booleanType);
2114   }
2115 
emitThrow()2116   public final void emitThrow ()
2117   {
2118     popType();
2119     reserve(1);
2120     put1 (191);  // athrow
2121     setUnreachable();
2122   }
2123 
emitMonitorEnter()2124   public final void emitMonitorEnter ()
2125   {
2126     popType();
2127     reserve(1);
2128     put1 (194);  // monitorenter
2129   }
2130 
emitMonitorExit()2131   public final void emitMonitorExit ()
2132   {
2133     popType();
2134     reserve(1);
2135     put1 (195);  // monitorexit
2136   }
2137 
2138   /**
2139    * Compile a method return.
2140    * If inside a 'catch' clause, first call 'finally' clauses.
2141    * The return value (unless the return type is void) must be on the stack,
2142    * and have the correct type.
2143    */
emitReturn()2144   public final void emitReturn ()
2145   {
2146     if (try_stack != null)
2147       new Error();
2148     emitRawReturn();
2149   }
2150 
emitRawReturn()2151   final void emitRawReturn ()
2152   {
2153     if (! reachableHere())
2154       return;
2155     if (getMethod().getReturnType().size == 0)
2156       {
2157 	reserve(1);
2158 	put1(177); // return
2159       }
2160     else
2161       emitTypedOp (172, popType().promote());
2162     setUnreachable();
2163   }
2164 
2165 
2166   /** Add an exception handler.
2167     * Low-level routine; {@code #emitCatchStart} is preferred. */
addHandler(int start_pc, int end_pc, int handler_pc, int catch_type)2168   public void addHandler (int start_pc, int end_pc,
2169 			  int handler_pc, int catch_type)
2170   {
2171     int index = 4 * exception_table_length;
2172     if (exception_table == null)
2173       {
2174 	exception_table = new short[20];
2175       }
2176     else if (exception_table.length <= index)
2177       {
2178 	short[] new_table = new short[2 * exception_table.length];
2179 	System.arraycopy(exception_table, 0, new_table, 0, index);
2180 	exception_table = new_table;
2181       }
2182     exception_table[index++] = (short) start_pc;
2183     exception_table[index++] = (short) end_pc;
2184     exception_table[index++] = (short) handler_pc;
2185     exception_table[index++] = (short) catch_type;
2186     exception_table_length++;
2187   }
2188 
2189   /** Add an exception handler.
2190    * Low-level routine; {@link #emitCatchStart} is preferred. */
addHandler(Label start_try, Label end_try, ClassType catch_type)2191   public void addHandler (Label start_try, Label end_try,
2192 			  ClassType catch_type)
2193   {
2194     ConstantPool constants = getConstants();
2195     int catch_type_index;
2196     if (catch_type == null)
2197       catch_type_index = 0;
2198     else
2199       catch_type_index = constants.addClass(catch_type).index;
2200     fixupAdd(FIXUP_TRY, start_try);
2201     fixupAdd(FIXUP_TRY_END, catch_type_index, end_try);
2202     Label handler = new Label();
2203     handler.localTypes = start_try.localTypes;
2204     handler.stackTypes = new Type[1];
2205     Type handler_class = catch_type == null ? Type.javalangThrowableType : catch_type;
2206     handler.stackTypes[0] = handler_class;
2207     setTypes(handler);
2208     fixupAdd(FIXUP_TRY_HANDLER, 0, handler);
2209     setReachable(true);
2210   }
2211 
2212   /** Beginning of code that has a cleanup handler.
2213    * This is similar to a try-finally, but the cleanup is only
2214    * done in the case of an exception.  Alternatively, the try clause
2215    * has to manually do the cleanup with code duplication.
2216    * Equivalent to: <code>try <var>body</var> catch (Throwable ex) { <var>cleanup</var>; throw ex; }</code>
2217    * Call <code>emitWithCleanupStart</code> before the <code><var>body</var></code>.
2218    */
emitWithCleanupStart()2219   public void emitWithCleanupStart ()
2220   {
2221     int savedSP = SP;
2222     SP = 0; // Hack to disable emitTryStart needlessly saving the stack.
2223     emitTryStart(false, null);
2224     SP = savedSP;
2225   }
2226 
2227   /** Called after a <code><var>body</var></code> that has a <code><var>cleanup</var></code> clause.
2228    * Followed by the <code><var>cleanup</var></code> code.
2229    */
emitWithCleanupCatch(Variable catchVar)2230   public void emitWithCleanupCatch (Variable catchVar)
2231   {
2232     emitTryEnd(false);
2233     try_stack.saved_result = catchVar;
2234     emitCatchStart(catchVar);
2235   }
2236 
2237   /** Called after generating a <code><var>cleanup</var></code> handler. */
2238 
emitWithCleanupDone()2239   public void emitWithCleanupDone ()
2240   {
2241     Variable catchVar = try_stack.saved_result;
2242     try_stack.saved_result = null;
2243     if (catchVar != null)
2244       emitLoad(catchVar);
2245     emitThrow();
2246     emitCatchEnd();
2247     emitTryCatchEnd();
2248   }
2249 
2250 
emitTryStart(boolean has_finally, Type result_type)2251   public void emitTryStart(boolean has_finally, Type result_type)
2252   {
2253     if (result_type != null && result_type.isVoid())
2254       result_type = null;
2255     Variable[] savedStack = null;
2256     if (result_type != null || SP > 0)
2257       pushScope();
2258     if (SP > 0)
2259       {
2260 	savedStack = new Variable[SP];
2261 	int i = 0;
2262 	while (SP > 0)
2263 	  {
2264 	    Variable var = addLocal(topType());
2265 	    emitStore(var);
2266 	    savedStack[i++] = var;
2267 	  }
2268       }
2269     TryState try_state = new TryState(this);
2270     try_state.savedStack = savedStack;
2271 
2272     int usedLocals = local_types == null ? 0 : local_types.length;
2273     for (; usedLocals > 0; usedLocals--)
2274       {
2275         Type last = local_types[usedLocals-1];
2276         if (last != null)
2277           break;
2278       }
2279 
2280     Type[] startLocals;
2281     if (usedLocals == 0)
2282       startLocals = Type.typeArray0;
2283     else
2284       {
2285         startLocals = new Type[usedLocals];
2286         System.arraycopy(local_types, 0, startLocals, 0, usedLocals);
2287       }
2288     try_state.start_try.localTypes = startLocals;
2289 
2290     if (result_type != null)
2291       try_state.saved_result = addLocal(result_type);
2292     if (has_finally)
2293       try_state.finally_subr = new Label();
2294   }
2295 
2296     @Deprecated
emitTryEnd()2297     public void emitTryEnd() {
2298     }
2299 
emitTryEnd(boolean fromFinally)2300   private void emitTryEnd (boolean fromFinally)
2301   {
2302     if (try_stack.tryClauseDone)
2303       return;
2304     try_stack.tryClauseDone = true;
2305     if (try_stack.finally_subr != null)
2306       try_stack.exception = addLocal(Type.javalangThrowableType);
2307     gotoFinallyOrEnd(fromFinally);
2308     try_stack.end_try = getLabel();
2309   }
2310 
emitCatchStart(Variable var)2311     public void emitCatchStart(Variable var) {
2312         if (var == null)
2313             emitCatchStart((ClassType) null);
2314         else {
2315             emitCatchStart((ClassType) var.getType());
2316             emitStore(var);
2317         }
2318     }
2319 
emitCatchStart(ClassType type)2320   public void emitCatchStart(ClassType type)
2321   {
2322     emitTryEnd(false);
2323     setTypes(try_stack.start_try.localTypes, Type.typeArray0);
2324     if (try_stack.try_type != null)
2325       emitCatchEnd();
2326     try_stack.try_type = type;
2327     addHandler(try_stack.start_try, try_stack.end_try, type);
2328     setReachable(true);
2329   }
2330 
emitCatchEnd()2331   public void emitCatchEnd()
2332   {
2333     gotoFinallyOrEnd(false);
2334     try_stack.try_type = null;
2335   }
2336 
gotoFinallyOrEnd(boolean fromFinally)2337   private void gotoFinallyOrEnd (boolean fromFinally)
2338   {
2339     if (reachableHere())
2340       {
2341 	if (try_stack.saved_result != null)
2342 	  emitStore(try_stack.saved_result);
2343         if (try_stack.end_label == null)
2344           try_stack.end_label = new Label();
2345 	if (try_stack.finally_subr == null || useJsr())
2346           {
2347             if (try_stack.finally_subr != null)
2348               emitJsr(try_stack.finally_subr);
2349             emitGoto(try_stack.end_label);
2350           }
2351         else
2352           {
2353             if (try_stack.exitCases != null)
2354               emitPushInt(0);
2355             emitPushNull(); // No caught Throwable.
2356             if (! fromFinally)
2357               emitGoto(try_stack.finally_subr);
2358           }
2359       }
2360   }
2361 
emitFinallyStart()2362   public void emitFinallyStart()
2363   {
2364     emitTryEnd(true);
2365     if (try_stack.try_type != null)
2366       emitCatchEnd();
2367     try_stack.end_try = getLabel();
2368 
2369     pushScope();
2370     if (useJsr())
2371       {
2372         SP = 0;
2373         emitCatchStart((ClassType) null);
2374         emitStore(try_stack.exception);
2375         emitJsr(try_stack.finally_subr);
2376         emitLoad(try_stack.exception);
2377         emitThrow();
2378       }
2379     else
2380       {
2381         if (reachableHere())
2382           emitGoto(try_stack.finally_subr);
2383         addHandler(try_stack.start_try, try_stack.end_try, Type.javalangThrowableType);
2384         if (try_stack.saved_result != null)
2385           emitStoreDefaultValue(try_stack.saved_result);
2386         if (try_stack.exitCases != null)
2387           {
2388             emitPushInt(-1);  // Return switch case code.
2389             emitSwap();
2390           }
2391       }
2392     try_stack.finally_subr.define(this);
2393 
2394     if (useJsr())
2395       {
2396         Type ret_addr_type = Type.objectType;
2397         try_stack.finally_ret_addr = addLocal(ret_addr_type);
2398         pushType(ret_addr_type);
2399         emitStore(try_stack.finally_ret_addr);
2400       }
2401     else
2402       {
2403         // Stack contents at the start of the finally block:
2404         // an integer exit code, but only if (exitCases != null).
2405         // a Throwable or null
2406       }
2407   }
2408 
emitFinallyEnd()2409   public void emitFinallyEnd()
2410   {
2411     if (! reachableHere())
2412       try_stack.end_label = null;
2413     else if (useJsr())
2414       emitRet(try_stack.finally_ret_addr);
2415     else if (try_stack.end_label == null && try_stack.exitCases == null)
2416       {
2417         emitThrow();
2418       }
2419     else
2420       {
2421         emitStore(try_stack.exception);
2422         emitLoad(try_stack.exception);
2423         emitIfNotNull();
2424         emitLoad(try_stack.exception);
2425         emitThrow();
2426         emitElse();
2427 
2428         ExitableBlock exit = try_stack.exitCases;
2429 
2430         if (exit != null)
2431           {
2432             SwitchState sw = startSwitch();
2433 
2434             while (exit != null)
2435               {
2436                 ExitableBlock next = exit.nextCase;
2437                 exit.nextCase = null;
2438                 exit.currentTryState = null;
2439                 TryState nextTry = TryState.outerHandler(try_stack.previous,
2440                                                          exit.initialTryState);
2441                 if (nextTry == exit.initialTryState) // Optimization
2442                   {
2443                     sw.addCaseGoto(exit.switchCase, this, exit.endLabel);
2444                   }
2445                 else
2446                   {
2447                     sw.addCase(exit.switchCase, this);
2448                     exit.exit(nextTry);
2449                   }
2450                 exit = next;
2451               }
2452             try_stack.exitCases = null;
2453 
2454             sw.addDefault(this);
2455             sw.finish(this);
2456           }
2457         emitFi();
2458 
2459         setUnreachable();
2460       }
2461     popScope();
2462     try_stack.finally_subr = null;
2463   }
2464 
emitTryCatchEnd()2465   public void emitTryCatchEnd()
2466   {
2467     if (try_stack.finally_subr != null)
2468       emitFinallyEnd();
2469     Variable[] vars = try_stack.savedStack;
2470     if (try_stack.end_label == null)
2471       setUnreachable();
2472     else
2473       {
2474         setTypes(try_stack.start_try.localTypes, Type.typeArray0);
2475         try_stack.end_label.define(this);
2476         if (vars != null)
2477           {
2478             for (int i = vars.length;  --i >= 0; )
2479               {
2480                 Variable v = vars[i];
2481                 if (v != null) {
2482                   emitLoad(v);
2483                 }
2484               }
2485           }
2486         if (try_stack.saved_result != null)
2487           emitLoad(try_stack.saved_result);
2488       }
2489     if (try_stack.saved_result != null || vars != null)
2490 	popScope();
2491     try_stack = try_stack.previous;
2492   }
2493 
getCurrentTry()2494   public final TryState getCurrentTry ()
2495   {
2496     return try_stack;
2497   }
2498 
isInTry()2499   public final boolean isInTry()
2500   {
2501     // This also return true if we're in  a catch clause, but that is
2502     // good enough for now.
2503     return try_stack != null;
2504   }
2505 
2506   /** Start a new switch statment or expression.
2507    * The switch value must have been calculated and left on the stack.
2508    */
startSwitch()2509   public SwitchState startSwitch ()
2510   {
2511     SwitchState sw = new SwitchState(this);
2512     sw.switchValuePushed(this);
2513     return sw;
2514   }
2515 
2516   /** Compile a tail-call to position 0 of the current procedure.
2517    * @param pop_args if true, copy argument registers (except this) from stack.
2518    * @param start the Label to jump back to. */
emitTailCall(boolean pop_args, Label start)2519   public void emitTailCall (boolean pop_args, Label start)
2520   {
2521     if (pop_args)
2522       {
2523 	Method meth = getMethod();
2524 	int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0 : 1;
2525 	for (int i = meth.arg_types.length;  --i >= 0; )
2526 	  arg_slots += meth.arg_types[i].size > 4 ? 2 : 1;
2527 	for (int i = meth.arg_types.length;  --i >= 0; )
2528 	  {
2529 	    arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1;
2530 	    emitStore(locals.used [arg_slots]);
2531 	  }
2532       }
2533     emitGoto(start);
2534   }
2535 
2536   /** Compile a tail-call to position 0 of the current procedure.
2537    * @param pop_args if true, copy argument registers (except this) from stack.
2538    * @param scope Scope whose start we jump back to. */
emitTailCall(boolean pop_args, Scope scope)2539   public void emitTailCall (boolean pop_args, Scope scope)
2540   {
2541     emitTailCall(pop_args, scope.start);
2542   }
2543 
processFixups()2544     public void processFixups() {
2545         if (fixup_count <= 0)
2546             return;
2547 
2548         // For each label, set it to its maximum limit, assuming all
2549         // fixups causes the code to be expanded.  We need a prepass
2550         // for this, since FIXUP_MOVEs can cause code to be reordered.
2551         // Also, convert each FIXUP_MOVE_TO_END to FIXUP_MOVE.
2552 
2553         int delta = 0;
2554         int instruction_tail = fixup_count;
2555         fixupAdd(CodeAttr.FIXUP_MOVE, -1, null);
2556 
2557         /* DEBUGGING
2558         if (false) {
2559             ClassTypeWriter writer =
2560                 new ClassTypeWriter(getMethod().getDeclaringClass(),
2561                                     System.err, 0);
2562             writer.println("processFixups1 for "+getMethod());
2563             disAssembleWithFixups(writer);
2564             writer.flush();
2565         }
2566         */
2567 
2568   loop1:
2569    for (int i = 0;  ;  )
2570       {
2571 	int offset = fixup_offsets[i];
2572 	int kind = offset & 15;
2573 	offset >>= 4;
2574 	Label label = fixup_labels[i];
2575         // Optimize: TRANSFER L1; ...; L1: GOTO L2
2576         // to: TRANSFER L2; ...; L1: GOTO L2
2577         // If L1 is a FIXUP_DEFINE_UNREACHABLE then we can delete the GOTO L2
2578         // (replace it with a DELETE3), since L1 is never reached.
2579         if (kind >= FIXUP_CASE && kind <= FIXUP_TRANSFER2) {
2580             int max = fixup_count;
2581         goto_to_goto:
2582             while (label != null && --max >= 0) {
2583                 int labpc = fixupOffset(label.first_fixup);
2584                 for (int def = label.first_fixup+1; ; def++) {
2585                     if (def >= fixup_count || labpc != fixupOffset(def)) {
2586                         break goto_to_goto;
2587                     } else if (fixupKind(def) == FIXUP_GOTO
2588                                || fixupKind(def) == FIXUP_DELETE3) {
2589                         label = fixup_labels[def];
2590                         fixup_labels[i] = label;
2591                         break;
2592                     }
2593                 }
2594             }
2595         }
2596 	switch (kind)
2597 	  {
2598 	  case FIXUP_TRY:
2599             i+=2;
2600             break;
2601 	  case FIXUP_LINE_PC:
2602 	    i++;
2603 	  case FIXUP_CASE:
2604 	  case FIXUP_DELETE3:
2605 	    break;
2606           case FIXUP_DEFINE_UNREACHABLE:
2607               // If we're currently "unreachable" and we see
2608               //    L0: L1: ... Ln: GOTO Lg
2609               // then we can delete the "GOTO Lg" because we also (separately)
2610               // patch each use of Li to Lg.
2611               while (i + 1 < fixup_count && fixupKind(i+1) == FIXUP_DEFINE
2612                      && fixupOffset(i+1) == offset) {
2613                   i++;
2614                   label.position += delta;
2615                   label = fixup_labels[i];
2616               }
2617               if (i + 1 < fixup_count && fixupKind(i+1) == FIXUP_GOTO
2618                   && fixupOffset(i+1) == offset) {
2619                   for (int j = i; ; j--) {
2620                       fixup_labels[j].needsStackMapEntry = false;
2621                       if (fixupKind(j) == FIXUP_DEFINE_UNREACHABLE)
2622                           break;
2623                   }
2624                   i++;
2625                   fixupSet(i, FIXUP_DELETE3, offset);
2626                   delta -= 3;
2627                   continue;
2628               }
2629               // fall through
2630 	  case FIXUP_DEFINE:
2631 	    label.position += delta;
2632 	    break;
2633 	  case FIXUP_SWITCH:
2634 	    delta += 3;  // May need to add up to 3 padding bytes.
2635 	    break;
2636 	  case FIXUP_GOTO:
2637             if (fixupOffset(label.first_fixup) == offset + 3)
2638 	      {
2639 		// Optimize: GOTO L; L:
2640                 fixupSet(i, FIXUP_DELETE3, offset);
2641 		delta -= 3;
2642 		break;
2643 	      }
2644 	    // ... else fall through ...
2645 	  case FIXUP_JSR:
2646 	    if (PC >= 0x8000)
2647 	      delta += 2;  // May need to convert goto->goto_w, jsr->jsr_w.
2648 	    break;
2649 	  case FIXUP_TRANSFER:
2650 	    if (PC >= 0x8000)
2651 	      delta += 5;  // May need to add a goto_w.
2652 	    break;
2653 	  case FIXUP_MOVE_TO_END:
2654 	    fixup_labels[instruction_tail] = fixup_labels[i+1];
2655 	    instruction_tail = offset;
2656 	    // ... fall through ...
2657 	  case FIXUP_MOVE:
2658             int cur_pc = ((i+1) >= fixup_count ? PC
2659                           : fixupOffset(fixup_labels[i+1].first_fixup));
2660             fixupSet(i, FIXUP_MOVE, cur_pc);
2661 	    if (label == null)
2662 	      break loop1;
2663 	    else
2664 	      {
2665 		i = label.first_fixup;
2666 		int next_pc = fixupOffset(i);
2667 		delta = (cur_pc + delta) - next_pc;
2668 		continue;
2669 	      }
2670 	  default:
2671 	    throw new Error("unexpected fixup");
2672 	  }
2673 	i++;
2674       }
2675     // Next a loop to fix the position of each label, and calculate
2676     // the exact number of code bytes.
2677 
2678     // Number of bytes to be inserted or (if negative) removed, so far.
2679     int new_size = PC;
2680     // Current delta between final PC and offset in generated code array.
2681     delta = 0;
2682   loop2:
2683     for (int i = 0;  i < fixup_count;  )
2684       {
2685 	int offset = fixup_offsets[i];
2686 	int kind = offset & 15;
2687 	Label label = fixup_labels[i];
2688 	if (label != null && label.position < 0)
2689 	  throw new Error ("undefined label "+label);
2690         offset = offset >> 4;
2691 	switch (kind)
2692 	  {
2693 	  case FIXUP_TRY:
2694             i+=2;
2695             fixup_labels[i].position = offset + delta;
2696             break;
2697 	  case FIXUP_LINE_PC:
2698 	    i++;
2699 	  case FIXUP_CASE:
2700 	    break;
2701 	  case FIXUP_DELETE3:
2702 	    delta -= 3;
2703 	    new_size -= 3;
2704 	    break;
2705           case FIXUP_DEFINE_UNREACHABLE:
2706 	  case FIXUP_DEFINE:
2707 	    label.position = offset + delta;
2708 	    break;
2709 	  case FIXUP_SWITCH:
2710 	    int padding = 3 - (offset+delta) & 3;
2711 	    delta += padding;
2712 	    new_size += padding;
2713 	    break;
2714 	  case FIXUP_GOTO:
2715 	  case FIXUP_JSR:
2716 	  case FIXUP_TRANSFER:
2717 	    int rel = label.position - (offset+delta);
2718 	    if ((short) rel == rel)
2719 	      {
2720                 fixupSet(i, FIXUP_TRANSFER2, offset);
2721 	      }
2722 	    else
2723 	      {
2724 		delta += kind == FIXUP_TRANSFER ? 5 : 2;  // need goto_w
2725 		new_size += kind == FIXUP_TRANSFER ? 5 : 2;  // need goto_w
2726 	      }
2727 	    break;
2728 	  case FIXUP_MOVE:
2729 	    if (label == null)
2730 	      break loop2;
2731 	    else
2732 	      {
2733 		i = label.first_fixup;
2734 		int next_pc = fixupOffset(i);
2735 		delta = (offset + delta) - next_pc;
2736 		continue;
2737 	      }
2738 	  default:
2739 	    throw new Error("unexpected fixup");
2740 	  }
2741 	i++;
2742       }
2743 
2744     /* DEBUGGING
2745     if (false) {
2746         ClassTypeWriter writer =
2747             new ClassTypeWriter(getMethod().getDeclaringClass(), System.err, 0);
2748         writer.println("processFixups3 for "+getMethod());
2749         disAssembleWithFixups(writer);
2750         writer.flush();
2751     }
2752     */
2753 
2754     byte[] new_code = new byte[new_size];
2755     int prev_linenumber = -1;
2756     int new_pc = 0;
2757     int next_fixup_index = 0;
2758     int next_fixup_offset = fixupOffset(0);
2759     int oldPC = -1;
2760     Label pendingStackMapLabel = null;
2761   loop3:
2762     for (int old_pc = 0;  ;  )
2763       {
2764 	if (old_pc < next_fixup_offset)
2765           new_code[new_pc++] = code[old_pc++];
2766 	else
2767 	  {
2768 	    int kind = fixup_offsets[next_fixup_index] & 15;
2769 	    Label label = fixup_labels[next_fixup_index];
2770             if (pendingStackMapLabel != null
2771                 && pendingStackMapLabel.position < new_pc)
2772               {
2773                 stackMap.emitStackMapEntry(pendingStackMapLabel, this);
2774                 pendingStackMapLabel = null;
2775               }
2776             if (pendingStackMapLabel != null
2777                 && pendingStackMapLabel.position > new_pc)
2778               throw new Error("labels out of order");
2779 	    switch (kind)
2780 	      {
2781 	      case FIXUP_DEFINE:
2782               case FIXUP_DEFINE_UNREACHABLE:
2783                   if (stackMap != null && label != null && label.isUsed() && label.needsStackMapEntry)
2784                   {
2785                     pendingStackMapLabel
2786                       = mergeLabels(pendingStackMapLabel, label);
2787                   }
2788 		break;
2789 	      case FIXUP_DELETE3:
2790 		old_pc += 3;
2791 		break;
2792 	      case FIXUP_TRANSFER2:
2793 		delta = label.position - new_pc;
2794 		new_code[new_pc++] = code[old_pc];
2795 		new_code[new_pc++] = (byte) (delta >> 8);
2796 		new_code[new_pc++] = (byte) (delta & 0xFF);
2797 		old_pc += 3;
2798 		break;
2799 	      case FIXUP_GOTO:
2800 	      case FIXUP_JSR:
2801 	      case FIXUP_TRANSFER:
2802 		delta = label.position - new_pc;
2803 		byte opcode = code[old_pc];
2804 		if (kind == FIXUP_TRANSFER)
2805 		  {
2806 		    // convert: IF_xxx L to IF_NOT_xxx Lt; GOTO L; Lt:
2807 		    opcode = invert_opcode(opcode);
2808 		    new_code[new_pc++] = opcode;
2809 		    new_code[new_pc++] = 0;
2810 		    new_code[new_pc++] = 8;  // 8 byte offset to Lt.
2811 		    opcode = (byte) 200;  // goto_w
2812 		  }
2813 		else
2814 		  {
2815 		    // Change goto to goto_w; jsr to jsr_w:
2816 		    opcode = (byte) (opcode + (200-167));
2817 		  }
2818 		new_code[new_pc++] = opcode;
2819 		new_code[new_pc++] = (byte) (delta >> 24);
2820 		new_code[new_pc++] = (byte) (delta >> 16);
2821 		new_code[new_pc++] = (byte) (delta >> 8);
2822 		new_code[new_pc++] = (byte) (delta & 0xFF);
2823 		old_pc += 3;
2824 		break;
2825 	      case FIXUP_SWITCH:
2826 		int padding = 3 - new_pc & 3;
2827 		int switch_start = new_pc;
2828 		new_code[new_pc++] = code[old_pc++];
2829 		while (--padding >= 0)
2830 		  new_code[new_pc++] = 0;
2831 		while (next_fixup_index < fixup_count
2832 		       && fixupKind(next_fixup_index + 1) == FIXUP_CASE)
2833 		  {
2834 		    next_fixup_index++;
2835 		    int offset = fixupOffset(next_fixup_index);
2836 		    while (old_pc < offset)
2837 		      new_code[new_pc++] = code[old_pc++];
2838 		    delta = (fixup_labels[next_fixup_index].position
2839 			     - switch_start);
2840 		    new_code[new_pc++] = (byte) (delta >> 24);
2841 		    new_code[new_pc++] = (byte) (delta >> 16);
2842 		    new_code[new_pc++] = (byte) (delta >> 8);
2843 		    new_code[new_pc++] = (byte) (delta & 0xFF);
2844 		    old_pc += 4;
2845 		  }
2846 		break;
2847 	      case FIXUP_TRY:
2848                 label = fixup_labels[next_fixup_index+2];
2849                 int handler_type_index = fixupOffset(next_fixup_index+1);
2850                 if (stackMap != null)
2851                   pendingStackMapLabel
2852                     = mergeLabels(pendingStackMapLabel, label);
2853 		addHandler(fixup_labels[next_fixup_index].position,
2854 			   fixup_labels[next_fixup_index+1].position,
2855 			   new_pc,
2856 			   handler_type_index);
2857 		next_fixup_index+=2;
2858 		break;
2859 	      case FIXUP_LINE_PC:
2860 		if (lines == null)
2861 		  lines = new LineNumbersAttr(this);
2862 		next_fixup_index++;
2863                 int linenumber = fixupOffset(next_fixup_index);
2864                 if (linenumber != prev_linenumber)
2865                   lines.put(linenumber, new_pc);
2866                 prev_linenumber = linenumber;
2867 		break;
2868 	      case FIXUP_MOVE:
2869 		if (label == null)
2870 		  break loop3;
2871 		else
2872 		  {
2873 		    next_fixup_index = label.first_fixup;
2874 		    old_pc = fixupOffset(next_fixup_index);
2875 		    next_fixup_offset = old_pc;
2876 		    if (label.position != new_pc)
2877 		      throw new Error("bad pc");
2878 		    continue;
2879 		  }
2880 	      default:
2881 		throw new Error("unexpected fixup");
2882 	      }
2883 	    next_fixup_index++;
2884 	    next_fixup_offset = fixupOffset(next_fixup_index);
2885 	  }
2886       }
2887     if (new_size != new_pc)
2888       throw new Error("PC confusion new_pc:"+new_pc+" new_size:"+new_size);
2889     PC = new_size;
2890     code = new_code;
2891     fixup_count = 0;
2892     fixup_labels = null;
2893     fixup_offsets = null;
2894   }
2895 
mergeLabels(Label oldLabel, Label newLabel)2896   private Label mergeLabels (Label oldLabel, Label newLabel)
2897   {
2898     if (oldLabel != null)
2899       newLabel.setTypes(oldLabel);
2900     return newLabel;
2901   }
2902 
assignConstants(ClassType cl)2903   public void assignConstants (ClassType cl)
2904   {
2905     if (locals != null && locals.container == null && ! locals.isEmpty())
2906       locals.addToFrontOf(this);
2907     processFixups();
2908     if (stackMap != null && stackMap.numEntries > 0)
2909       stackMap.addToFrontOf(this);
2910     if (instructionLineMode)
2911       {
2912         // A kludge to low-level debugging:
2913         // Define a "line number" for each instrction.
2914         if (lines == null)
2915           lines = new LineNumbersAttr(this);
2916         lines.linenumber_count = 0;
2917         int codeLen = getCodeLength();
2918         for (int i = 0;  i < codeLen;  i++)
2919           lines.put(i, i);
2920       }
2921     super.assignConstants(cl);
2922     Attribute.assignConstants(this, cl);
2923   }
2924 
getLength()2925   public final int getLength()
2926   {
2927     return 12 + getCodeLength() + 8 * exception_table_length
2928       + Attribute.getLengthAll(this);
2929   }
2930 
write(DataOutputStream dstr)2931   public void write (DataOutputStream dstr) throws java.io.IOException
2932   {
2933     dstr.writeShort (max_stack);
2934     dstr.writeShort (max_locals);
2935     dstr.writeInt (PC);
2936     dstr.write (code, 0, PC);
2937 
2938     dstr.writeShort (exception_table_length);
2939     int count = exception_table_length;
2940     for (int i = 0;  --count >= 0;  i += 4)
2941       {
2942 	dstr.writeShort(exception_table[i]);
2943 	dstr.writeShort(exception_table[i+1]);
2944 	dstr.writeShort(exception_table[i+2]);
2945 	dstr.writeShort(exception_table[i+3]);
2946       }
2947 
2948     Attribute.writeAll(this, dstr);
2949   }
2950 
print(ClassTypeWriter dst)2951   public void print (ClassTypeWriter dst)
2952   {
2953     dst.print("Attribute \"");
2954     dst.print(getName());
2955     dst.print("\", length:");
2956     dst.print(getLength());
2957     dst.print(", max_stack:");
2958     dst.print(max_stack);
2959     dst.print(", max_locals:");
2960     dst.print(max_locals);
2961     dst.print(", code_length:");
2962     int length = getCodeLength();
2963     dst.println(length);
2964     disAssemble(dst, 0, length);
2965     if (exception_table_length > 0)
2966       {
2967 	dst.print("Exceptions (count: ");
2968 	dst.print(exception_table_length);
2969 	dst.println("):");
2970 	int count = exception_table_length;
2971 	for (int i = 0;  --count >= 0;  i += 4)
2972 	  {
2973 	    dst.print("  start: ");
2974 	    dst.print(exception_table[i] & 0xffff);
2975 	    dst.print(", end: ");
2976 	    dst.print(exception_table[i+1] & 0xffff);
2977 	    dst.print(", handler: ");
2978 	    dst.print(exception_table[i+2] & 0xffff);
2979 	    dst.print(", type: ");
2980 	    int catch_type_index = exception_table[i+3] & 0xffff;
2981 	    if (catch_type_index == 0)
2982 	      dst.print("0 /* finally */");
2983 	    else
2984 	      {
2985 		dst.printOptionalIndex(catch_type_index);
2986 		dst.printConstantTersely(catch_type_index, ConstantPool.CLASS);
2987 	      }
2988 	    dst.println();
2989 	  }
2990       }
2991     dst.printAttributes(this);
2992   }
2993 
2994     /* DEBUGGING:
2995     public void disAssembleWithFixups(ClassTypeWriter dst) {
2996         if (fixup_count <= 0) {
2997             disAssemble(dst, 0, PC);
2998             return;
2999         }
3000         int prev_pc = 0;
3001         for (int i = 0;  i < fixup_count; ) {
3002             int offset = fixup_offsets[i];
3003             int kind = offset & 15;
3004             Label label = fixup_labels[i];
3005             offset = offset >> 4;
3006             int pc = offset;
3007             if (kind == FIXUP_MOVE || kind == FIXUP_MOVE_TO_END)
3008                 pc = (i+1 >= fixup_count) ? PC : fixup_offsets[i+1] >> 4;
3009             else if (kind == FIXUP_CASE)
3010                 pc = prev_pc;
3011             disAssemble(dst, prev_pc, pc);
3012 
3013             dst.print("fixup#");  dst.print(i);
3014             dst.print(" @");  dst.print(offset);
3015             prev_pc = pc;
3016             switch (kind) {
3017             case FIXUP_DEFINE:
3018             case FIXUP_DEFINE_UNREACHABLE:
3019                 dst.print(" DEFINE ");
3020                 if (kind == FIXUP_DEFINE_UNREACHABLE)
3021                     dst.print("(unreachable) ");
3022                 dst.println(label);
3023                 break;
3024             case FIXUP_SWITCH:
3025                 dst.println(" SWITCH");
3026                 break;
3027             case FIXUP_CASE:
3028                 dst.print(" CASE ");
3029                 dst.println(label);
3030                 break;
3031             case FIXUP_GOTO:
3032                 dst.print(" GOTO ");
3033                 dst.println(label);
3034                 break;
3035             case FIXUP_TRANSFER:
3036                 dst.print(" TRANSFER ");
3037                 dst.println(label);
3038                 break;
3039             case FIXUP_TRANSFER2:
3040                 dst.print(" TRANSFER2 ");
3041                 dst.println(label);
3042                 break;
3043             case FIXUP_DELETE3:
3044                 dst.println(" DELETE3");
3045                 break;
3046             case FIXUP_MOVE:
3047                 dst.print(" MOVE ");
3048                 dst.println(label);
3049                 break;
3050             case FIXUP_MOVE_TO_END:
3051                 dst.print(" MOVE_TO_END ");
3052                 dst.println(label);
3053                 break;
3054             case FIXUP_TRY:
3055                 dst.print(" TRY start: ");
3056                 dst.println(label);
3057                 i++;
3058                 dst.print(" - end: ");
3059                 dst.print(fixup_labels[i]);
3060                 dst.print(" type: ");
3061                 dst.println(fixup_offsets[i] >> 4);
3062                 i++;
3063                 dst.print(" - handler: ");
3064                 dst.println(fixup_labels[i]);
3065                 break;
3066             case FIXUP_LINE_PC:
3067                 dst.print(" LINE ");
3068                 i++;
3069                 dst.println(fixup_offsets[i] >> 4);
3070                 break;
3071             default:
3072                 dst.println(" kind:"+fixupKind(i)+" offset:"+fixupOffset(i)
3073                             +" "+fixup_labels[i]);
3074             }
3075             i++;
3076         }
3077         disAssemble(dst, prev_pc, PC);
3078     }
3079     */
3080 
disAssemble(ClassTypeWriter dst, int start, int limit)3081   public void disAssemble (ClassTypeWriter dst, int start, int limit)
3082   {
3083     boolean wide = false;
3084     for (int i = start;  i < limit; )
3085       {
3086 	int oldpc = i++;
3087 	int op = code[oldpc] & 0xff;
3088 	String str = Integer.toString(oldpc);
3089 	int printConstant = 0;
3090 	int j = str.length();
3091 	while (++j <= 3) dst.print(' ');
3092 	dst.print(str);
3093 	dst.print(": ");
3094 	// We do a rough binary partition of the opcodes.
3095 	if (op < 120)
3096 	  {
3097 	    if (op < 87)
3098 	      {
3099 		if (op < 3)  print("nop;aconst_null;iconst_m1;", op, dst);
3100 		else if (op < 9) { dst.print("iconst_");  dst.print(op-3); }
3101 		else if (op < 16) // op >= 9 [lconst_0] && op <= 15 [dconst_1]
3102 		  {
3103 		    char typ;
3104 		    if (op < 11) { typ = 'l';  op -= 9; }
3105 		    else if (op < 14) { typ = 'f';  op -= 11; }
3106 		    else { typ = 'd';  op -= 14; }
3107 		    dst.print(typ);  dst.print("const_");  dst.print(op);
3108 		  }
3109 		else if (op < 21)
3110 		  {
3111 		    if (op < 18)  // op >= 16 [bipush] && op <= 17 [sipush]
3112 		      {
3113 			print("bipush ;sipush ;", op-16, dst);
3114 			int constant;
3115 			if (op == 16)  constant = code[i++];
3116 			else { constant = (short) readUnsignedShort(i);  i+=2;}
3117 			dst.print(constant);
3118 		      }
3119 		    else // op >= 18 [ldc] && op <= 20 [ldc2_w]
3120 		      {
3121 			printConstant = op == 18 ? 1 : 2;
3122 			print("ldc;ldc_w;ldc2_w;", op-18, dst);
3123 		      }
3124 		  }
3125 		else // op >= 21 && op < 87
3126 		  {
3127 		    String load_or_store;
3128 		    if (op < 54) { load_or_store = "load"; }
3129 		    else { load_or_store = "store"; op -=(54-21); }
3130 		    int index;  // -2 if array op;  -1 if index follows
3131 		    if (op < 26) { index = -1; op -= 21; }
3132 		    else if (op < 46) { op -= 26;  index = op % 4;  op >>= 2; }
3133 		    else { index = -2; op -= 46; }
3134 		    dst.print("ilfdabcs".charAt(op));
3135 		    if (index == -2) dst.write('a');
3136 		    dst.print(load_or_store);
3137 		    if (index >= 0) { dst.write('_');  dst.print(index); }
3138 		    else if (index == -1)
3139 		      {
3140 			if (wide) { index = readUnsignedShort(i); i += 2; }
3141 			else { index = code[i] & 0xff; i++; }
3142 			wide = false;
3143 			dst.print(' ');
3144 			dst.print(index);
3145 		      }
3146 		  }
3147 	      }
3148 	    else // op >= 87 && op < 120
3149 	      {
3150 		if (op < 96)
3151 		  print("pop;pop2;dup;dup_x1;dup_x2;dup2;dup2_x1;dup2_x2;swap;"
3152 			, op-87, dst);
3153 		else // op >= 96 [iadd] && op <= 119 [dneg]
3154 		  {
3155 		    dst.print("ilfda".charAt((op-96) % 4));
3156 		    print("add;sub;mul;div;rem;neg;", (op-96)>>2, dst);
3157 		  }
3158 	      }
3159 	  }
3160 	else // op >= 120
3161 	  {
3162 	    if (op < 170)
3163 	      {
3164 		if (op < 132) // op >= 120 [ishl] && op <= 131 [lxor]
3165 		  {
3166 		    dst.print((op & 1) == 0 ? 'i' : 'l');
3167 		    print("shl;shr;ushr;and;or;xor;", (op-120)>>1, dst);
3168 		  }
3169 		else if (op == 132) // iinc
3170 		  {
3171 		    int var_index;
3172 		    int constant;
3173 		    dst.print("iinc");
3174 		    if (! wide)
3175 		      {
3176 			var_index = 0xff & code[i++];
3177 			constant = code[i++];
3178 		      }
3179 		    else
3180 		      {
3181 			var_index = readUnsignedShort(i);
3182 			i += 2;
3183 			constant = (short) readUnsignedShort(i);
3184 			i += 2;
3185 			wide = false;
3186 		      }
3187 		    dst.print(' ');  dst.print(var_index);
3188 		    dst.print(' ');  dst.print(constant);
3189 		  }
3190 		else if (op < 148) // op >= 133 [i2l] && op <= 147 [i2s]
3191 		  {
3192 		    dst.print("ilfdi".charAt((op-133) / 3));
3193 		    dst.print('2');
3194 		    dst.print("lfdifdildilfbcs".charAt(op-133));
3195 		  }
3196 		else if (op < 153) // op >= 148 [lcmp] && op <= 152 [dcmpg]
3197 		  print("lcmp;fcmpl;fcmpg;dcmpl;dcmpg;", op-148, dst);
3198 		else if (op < 169)
3199 		  {
3200 		    if (op < 159)
3201 		      {
3202 			dst.print("if");
3203 			print("eq;ne;lt;ge;gt;le;", op-153, dst);
3204 		      }
3205 		    else if (op < 167)
3206 		      {
3207 			if (op < 165) { dst.print("if_icmp"); }
3208 			else { dst.print("if_acmp"); op -= 165-159; }
3209 			print("eq;ne;lt;ge;gt;le;", op-159, dst);
3210 		      }
3211 		    else
3212 		      print("goto;jsr;", op-167, dst);
3213 		    int delta = (short) readUnsignedShort(i);
3214 		    i += 2;
3215 		    dst.print(' ');  dst.print(oldpc+delta);
3216 		  }
3217 		else
3218 		  {
3219 		    int index;
3220 		    dst.print("ret ");
3221 		    if (wide) { index = readUnsignedShort(i); i += 2; }
3222 		    else { index = code[i] & 0xff; i++; }
3223 		    wide = false;
3224 		    dst.print(index);
3225 		  }
3226 	      }
3227 	    else
3228 	      {
3229 		if (op < 172) //  [tableswitch] or [lookupswitch]
3230 		  {
3231 		    if (fixup_count <= 0)
3232 		      i = (i + 3) & ~3; // skip 0-3 byte padding.
3233 		    int code_offset = readInt(i);  i += 4;
3234 		    if (op == 170)
3235 		      {
3236 			dst.print("tableswitch");
3237 			int low = readInt(i);  i += 4;
3238 			int high = readInt(i);  i += 4;
3239 			dst.print(" low: "); dst.print(low);
3240 			dst.print(" high: "); dst.print(high);
3241 			dst.print(" default: "); dst.print(oldpc+code_offset);
3242 			for (;  low <= high;  low++)
3243 			  {
3244 			    code_offset = readInt(i);  i += 4;
3245 			    dst.println();
3246 			    dst.print("  ");  dst.print(low);
3247 			    dst.print(": ");  dst.print(oldpc + code_offset);
3248 			  }
3249 		      }
3250 		    else
3251 		      {
3252 			dst.print("lookupswitch");
3253 			int npairs = readInt(i);  i += 4;
3254 			dst.print(" npairs: "); dst.print(npairs);
3255 			dst.print(" default: "); dst.print(oldpc+code_offset);
3256 			while (--npairs >= 0)
3257 			  {
3258 			    int match = readInt(i);  i += 4;
3259 			    code_offset = readInt(i);  i += 4;
3260 			    dst.println();
3261 			    dst.print("  ");  dst.print(match);
3262 			    dst.print(": ");  dst.print(oldpc + code_offset);
3263 			  }
3264 		      }
3265 		  }
3266 		else if (op < 178) // op >= 172 [ireturn] && op <= 177 [return]
3267 		  {
3268 		    if (op < 177) dst.print("ilfda".charAt(op-172));
3269 		    dst.print("return");
3270 		  }
3271 		else if (op < 182) // op >= 178 [getstatic] && op <= 181 [putfield]
3272 		  {
3273 		    print("getstatic;putstatic;getfield;putfield;", op-178, dst);
3274 		    printConstant = 2;
3275 		  }
3276 		else if (op < 185) // op >= 182 && op <= 185 [invoke*]
3277 		  {
3278 		    dst.print("invoke");
3279 		    print("virtual;special;static;", op-182, dst);
3280 		    printConstant = 2;
3281 		  }
3282 		else if (op == 185) // invokeinterface
3283 		  {
3284 		    dst.print("invokeinterface (");
3285 		    int index = readUnsignedShort(i);
3286 		    i += 2;
3287 		    int args = 0xff & code[i];
3288 		    i += 2;
3289 		    dst.print(args + " args)");
3290 		    dst.printConstantOperand(index);
3291 		  }
3292 		else if (op == 186) // invokedynamic
3293 		  {
3294 		    dst.print("invokedynamic");
3295 		    int index = readUnsignedShort(i);
3296 		    i += 4;
3297 		    dst.printConstantOperand(index);
3298 		  }
3299 		else if (op < 196)
3300 		  {
3301 		    print("186;new;newarray;anewarray;arraylength;athrow;checkcast;instanceof;monitorenter;monitorexit;", op-186, dst);
3302 		    if (op == 187 || op == 189 || op == 192 || op == 193)
3303 		      printConstant = 2;
3304 		    else if (op == 188)  // newarray
3305 		      {
3306 			int type = code[i++];
3307 			dst.print(' ');
3308 			if (type >= 4 && type <= 11)
3309 			  print("boolean;char;float;double;byte;short;int;long;",
3310 				type-4, dst);
3311 			else
3312 			  dst.print(type);
3313 		      }
3314 
3315 		  }
3316 		else if (op == 196) // wide
3317 		  {
3318 		    dst.print("wide");
3319 		    wide = true;
3320 		  }
3321 		else if (op == 197)
3322 		  {
3323 		    dst.print("multianewarray");
3324 		    int index = readUnsignedShort(i);
3325 		    i += 2;
3326 		    dst.printConstantOperand(index);
3327 		    int dims = 0xff & code[i++];
3328 		    dst.print(' ');
3329 		    dst.print(dims);
3330 		  }
3331 		else if (op < 200)
3332 		  {
3333 		    print("ifnull;ifnonnull;", op-198, dst);
3334 		    int delta = (short) readUnsignedShort(i);
3335 		    i += 2;
3336 		    dst.print(' ');  dst.print(oldpc+delta);
3337 		  }
3338 		else if (op < 202)
3339 		  {
3340 		    print("goto_w;jsr_w;", op-200, dst);
3341 		    int delta = readInt(i);
3342 		    i += 4;
3343 		    dst.print(' ');  dst.print(oldpc+delta);
3344 		  }
3345 		else
3346 		  dst.print(op);
3347 	      }
3348 	  }
3349 	if (printConstant > 0)
3350 	  {
3351 	    int index;
3352 	    if (printConstant == 1) index = 0xff & code[i++];
3353 	    else { index = readUnsignedShort(i);  i += 2; }
3354 	    dst.printConstantOperand(index);
3355 	  }
3356 	dst.println();
3357       }
3358   }
3359 
readUnsignedShort(int offset)3360   private int readUnsignedShort(int offset)
3361   {
3362     return ((0xff & code[offset]) << 8) | (0xff & code[offset+1]);
3363   }
3364 
readInt(int offset)3365   private int readInt(int offset)
3366   {
3367     return (readUnsignedShort(offset) << 16) | readUnsignedShort(offset+2);
3368   }
3369 
3370   /*
3371   public saveStack (ClassType into)
3372   {
3373     Field[] flds = new Field[SP];
3374     while (SP > 0)
3375       {
3376 	Field fld = ?;
3377 	emitStore(fld);
3378 	flds[SP...]
3379       }
3380   }
3381   */
3382 
3383   /* Print the i'th ';'-delimited substring of str on dst. */
print(String str, int i, PrintWriter dst)3384   private void print (String str, int i, PrintWriter dst)
3385   {
3386     int last = 0;
3387     int pos = -1;
3388     for (; i >= 0; i--)
3389       {
3390 	last = ++pos;
3391 	pos = str.indexOf(';', last);
3392       }
3393     dst.write(str, last, pos-last);
3394   }
3395 
beginFragment(Label after)3396   public int beginFragment (Label after)
3397   {
3398     return beginFragment(new Label(), after);
3399   }
3400 
beginFragment(Label start, Label after)3401   public int beginFragment (Label start, Label after)
3402   {
3403     int i = fixup_count;
3404     fixupAdd(FIXUP_MOVE_TO_END, after);
3405     start.define(this);
3406     return i;
3407   }
3408 
3409   /** End a fragment.
3410    * @param cookie the return value from the previous beginFragment.
3411    */
endFragment(int cookie)3412   public void endFragment (int cookie)
3413   {
3414     fixupSet(cookie, FIXUP_MOVE_TO_END, fixup_count);
3415     Label after = fixup_labels[cookie];
3416     fixupAdd(FIXUP_MOVE, -1, null);
3417     after.define(this);
3418     int fx = fixup_count - 1;
3419     fixupSet(fx, FIXUP_DEFINE, fixupOffset(fx));
3420   }
3421 }
3422