• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 
22 /**
23  * An iterator for editing a code attribute.
24  *
25  * <p>To directly read or edit a bytecode sequence, call {@link #byteAt(int)}, {@link #s16bitAt(int)},
26  * {@link #writeByte(int, int)}, {@link #write16bit(int, int)}, and other methods.
27  * For example, if <code>method</code> refers to a <code>CtMethod</code> object,
28  * the following code substitutes the <code>NOP</code> instruction for the first
29  * instruction of the method:
30  *
31  * <pre>
32  * CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
33  * CodeIterator ci = ca.iterator();
34  * ci.writeByte(Opcode.NOP, 0);</pre>
35  *
36  * <p>To visit every instruction, call {@link #next()} on a <code>CodeIterator</code>.
37  * It returns the index of the first byte of the next instruction.
38  *
39  * <p>If there are multiple <code>CodeIterator</code>s referring to the
40  * same <code>Code_attribute</code>, then inserting a gap by one
41  * <code>CodeIterator</code> will break the other
42  * <code>CodeIterator</code>.
43  *
44  * <p>This iterator does not provide <code>remove()</code>.
45  * If a piece of code in a <code>Code_attribute</code> is unnecessary,
46  * it should be overwritten with <code>NOP</code>.
47  *
48  * @see CodeAttribute#iterator()
49  */
50 public class CodeIterator implements Opcode {
51     protected CodeAttribute codeAttr;
52     protected byte[] bytecode;
53     protected int endPos;
54     protected int currentPos;
55     protected int mark;
56 
CodeIterator(CodeAttribute ca)57     protected CodeIterator(CodeAttribute ca) {
58         codeAttr = ca;
59         bytecode = ca.getCode();
60         begin();
61     }
62 
63     /**
64      * Moves to the first instruction.
65      */
begin()66     public void begin() {
67         currentPos = mark = 0;
68         endPos = getCodeLength();
69     }
70 
71     /**
72      * Moves to the given index.
73      *
74      * <p>The index of the next instruction is set to the given index.
75      * The successive call to <code>next()</code>
76      * returns the index that has been given to <code>move()</code>.
77      *
78      * <p>Note that the index is into the byte array returned by
79      * <code>get().getCode()</code>.
80      *
81      * @see CodeAttribute#getCode()
82      */
move(int index)83     public void move(int index) {
84         currentPos = index;
85     }
86 
87     /**
88      * Sets a mark to the bytecode at the given index.
89      * The mark can be used to track the position of that bytecode
90      * when code blocks are inserted.
91      * If a code block is inclusively inserted at the position of the
92      * bytecode, the mark is set to the inserted code block.
93      *
94      * @see #getMark()
95      * @since 3.11
96      */
setMark(int index)97     public void setMark(int index) {
98         mark = index;
99     }
100 
101     /**
102      * Gets the index of the position of the mark set by
103      * <code>setMark</code>.
104      *
105      * @return the index of the position.
106      * @see #setMark(int)
107      * @since 3.11
108      */
getMark()109     public int getMark() { return mark; }
110 
111     /**
112      * Returns a Code attribute read with this iterator.
113      */
get()114     public CodeAttribute get() {
115         return codeAttr;
116     }
117 
118     /**
119      * Returns <code>code_length</code> of <code>Code_attribute</code>.
120      */
getCodeLength()121     public int getCodeLength() {
122         return bytecode.length;
123     }
124 
125     /**
126      * Returns the unsigned 8bit value at the given index.
127      */
byteAt(int index)128     public int byteAt(int index) { return bytecode[index] & 0xff; }
129 
130     /**
131      * Returns the signed 8bit value at the given index.
132      */
signedByteAt(int index)133     public int signedByteAt(int index) { return bytecode[index]; }
134 
135     /**
136      * Writes an 8bit value at the given index.
137      */
writeByte(int value, int index)138     public void writeByte(int value, int index) {
139         bytecode[index] = (byte)value;
140     }
141 
142     /**
143      * Returns the unsigned 16bit value at the given index.
144      */
u16bitAt(int index)145     public int u16bitAt(int index) {
146         return ByteArray.readU16bit(bytecode, index);
147     }
148 
149     /**
150      * Returns the signed 16bit value at the given index.
151      */
s16bitAt(int index)152     public int s16bitAt(int index) {
153         return ByteArray.readS16bit(bytecode, index);
154     }
155 
156     /**
157      * Writes a 16 bit integer at the index.
158      */
write16bit(int value, int index)159     public void write16bit(int value, int index) {
160         ByteArray.write16bit(value, bytecode, index);
161     }
162 
163     /**
164      * Returns the signed 32bit value at the given index.
165      */
s32bitAt(int index)166     public int s32bitAt(int index) {
167         return ByteArray.read32bit(bytecode, index);
168     }
169 
170     /**
171      * Writes a 32bit integer at the index.
172      */
write32bit(int value, int index)173     public void write32bit(int value, int index) {
174         ByteArray.write32bit(value, bytecode, index);
175     }
176 
177     /**
178      * Writes a byte array at the index.
179      *
180      * @param code	may be a zero-length array.
181      */
write(byte[] code, int index)182     public void write(byte[] code, int index) {
183         int len = code.length;
184         for (int j = 0; j < len; ++j)
185             bytecode[index++] = code[j];
186     }
187 
188     /**
189      * Returns true if there is more instructions.
190      */
hasNext()191     public boolean hasNext() { return currentPos < endPos; }
192 
193     /**
194      * Returns the index of the next instruction
195      * (not the operand following the current opcode).
196      *
197      * <p>Note that the index is into the byte array returned by
198      * <code>get().getCode()</code>.
199      *
200      * @see CodeAttribute#getCode()
201      * @see CodeIterator#byteAt(int)
202      */
next()203     public int next() throws BadBytecode {
204         int pos = currentPos;
205         currentPos = nextOpcode(bytecode, pos);
206         return pos;
207     }
208 
209     /**
210      * Obtains the value that the next call
211      * to <code>next()</code> will return.
212      *
213      * <p>This method is side-effects free.
214      * Successive calls to <code>lookAhead()</code> return the
215      * same value until <code>next()</code> is called.
216      */
lookAhead()217     public int lookAhead() {
218         return currentPos;
219     }
220 
221     /**
222      * Moves to the instruction for
223      * either <code>super()</code> or <code>this()</code>.
224      *
225      * <p>This method skips all the instructions for computing arguments
226      * to <code>super()</code> or <code>this()</code>, which should be
227      * placed at the beginning of a constructor body.
228      *
229      * <p>This method returns the index of INVOKESPECIAL instruction
230      * executing <code>super()</code> or <code>this()</code>.
231      * A successive call to <code>next()</code> returns the
232      * index of the next instruction following that INVOKESPECIAL.
233      *
234      * <p>This method works only for a constructor.
235      *
236      * @return  the index of the INVOKESPECIAL instruction, or -1
237      *          if a constructor invocation is not found.
238      */
skipConstructor()239     public int skipConstructor() throws BadBytecode {
240         return skipSuperConstructor0(-1);
241     }
242 
243     /**
244      * Moves to the instruction for <code>super()</code>.
245      *
246      * <p>This method skips all the instructions for computing arguments to
247      * <code>super()</code>, which should be
248      * placed at the beginning of a constructor body.
249      *
250      * <p>This method returns the index of INVOKESPECIAL instruction
251      * executing <code>super()</code>.
252      * A successive call to <code>next()</code> returns the
253      * index of the next instruction following that INVOKESPECIAL.
254      *
255      * <p>This method works only for a constructor.
256      *
257      * @return  the index of the INVOKESPECIAL instruction, or -1
258      *          if a super constructor invocation is not found
259      *          but <code>this()</code> is found.
260      */
skipSuperConstructor()261     public int skipSuperConstructor() throws BadBytecode {
262         return skipSuperConstructor0(0);
263     }
264 
265     /**
266      * Moves to the instruction for <code>this()</code>.
267      *
268      * <p>This method skips all the instructions for computing arguments to
269      * <code>this()</code>, which should be
270      * placed at the beginning of a constructor body.
271      *
272      * <p>This method returns the index of INVOKESPECIAL instruction
273      * executing <code>this()</code>.
274      * A successive call to <code>next()</code> returns the
275      * index of the next instruction following that INVOKESPECIAL.
276      *
277      * <p>This method works only for a constructor.
278      *
279      * @return  the index of the INVOKESPECIAL instruction, or -1
280      *          if a explicit constructor invocation is not found
281      *          but <code>super()</code> is found.
282      */
skipThisConstructor()283     public int skipThisConstructor() throws BadBytecode {
284         return skipSuperConstructor0(1);
285     }
286 
287     /* skipSuper        1: this(), 0: super(), -1: both.
288      */
skipSuperConstructor0(int skipThis)289     private int skipSuperConstructor0(int skipThis) throws BadBytecode {
290         begin();
291         ConstPool cp = codeAttr.getConstPool();
292         String thisClassName = codeAttr.getDeclaringClass();
293         int nested = 0;
294         while (hasNext()) {
295             int index = next();
296             int c = byteAt(index);
297             if (c == NEW)
298                 ++nested;
299             else if (c == INVOKESPECIAL) {
300                 int mref = ByteArray.readU16bit(bytecode, index + 1);
301                 if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit))
302                     if (--nested < 0) {
303                         if (skipThis < 0)
304                             return index;
305 
306                         String cname = cp.getMethodrefClassName(mref);
307                         if (cname.equals(thisClassName) == (skipThis > 0))
308                             return index;
309 
310                         break;
311                     }
312             }
313         }
314 
315         begin();
316         return -1;
317     }
318 
319     /**
320      * Inserts the given bytecode sequence
321      * before the next instruction that would be returned by
322      * <code>next()</code> (not before the instruction returned
323      * by the last call to <code>next()</code>).
324      * Branch offsets and the exception table are also updated.
325      *
326      * <p>If the next instruction is at the beginning of a block statement,
327      * then the bytecode is inserted within that block.
328      *
329      * <p>An extra gap may be inserted at the end of the inserted
330      * bytecode sequence for adjusting alignment if the code attribute
331      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
332      *
333      * @param code      inserted bytecode sequence.
334      * @return          the index indicating the first byte of the
335      *                  inserted byte sequence.
336      */
insert(byte[] code)337     public int insert(byte[] code)
338         throws BadBytecode
339     {
340         return insert0(currentPos, code, false);
341     }
342 
343     /**
344      * Inserts the given bytecode sequence
345      * before the instruction at the given index <code>pos</code>.
346      * Branch offsets and the exception table are also updated.
347      *
348      * <p>If the instruction at the given index is at the beginning
349      * of a block statement,
350      * then the bytecode is inserted within that block.
351      *
352      * <p>An extra gap may be inserted at the end of the inserted
353      * bytecode sequence for adjusting alignment if the code attribute
354      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
355      *
356      * <p>The index at which the byte sequence is actually inserted
357      * might be different from pos since some other bytes might be
358      * inserted at other positions (e.g. to change <code>GOTO</code>
359      * to <code>GOTO_W</code>).
360      *
361      * @param pos       the index at which a byte sequence is inserted.
362      * @param code      inserted bytecode sequence.
363      */
insert(int pos, byte[] code)364     public void insert(int pos, byte[] code) throws BadBytecode {
365         insert0(pos, code, false);
366     }
367 
368     /**
369      * Inserts the given bytecode sequence
370      * before the instruction at the given index <code>pos</code>.
371      * Branch offsets and the exception table are also updated.
372      *
373      * <p>If the instruction at the given index is at the beginning
374      * of a block statement,
375      * then the bytecode is inserted within that block.
376      *
377      * <p>An extra gap may be inserted at the end of the inserted
378      * bytecode sequence for adjusting alignment if the code attribute
379      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
380      *
381      * @param pos       the index at which a byte sequence is inserted.
382      * @param code      inserted bytecode sequence.
383      * @return          the index indicating the first byte of the
384      *                  inserted byte sequence, which might be
385      *                  different from pos.
386      * @since 3.11
387      */
insertAt(int pos, byte[] code)388     public int insertAt(int pos, byte[] code) throws BadBytecode {
389         return insert0(pos, code, false);
390     }
391 
392     /**
393      * Inserts the given bytecode sequence exclusively
394      * before the next instruction that would be returned by
395      * <code>next()</code> (not before the instruction returned
396      * by tha last call to <code>next()</code>).
397      * Branch offsets and the exception table are also updated.
398      *
399      * <p>If the next instruction is at the beginning of a block statement,
400      * then the bytecode is excluded from that block.
401      *
402      * <p>An extra gap may be inserted at the end of the inserted
403      * bytecode sequence for adjusting alignment if the code attribute
404      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
405      *
406      * @param code      inserted bytecode sequence.
407      * @return          the index indicating the first byte of the
408      *                  inserted byte sequence.
409      */
insertEx(byte[] code)410     public int insertEx(byte[] code)
411         throws BadBytecode
412     {
413         return insert0(currentPos, code, true);
414     }
415 
416     /**
417      * Inserts the given bytecode sequence exclusively
418      * before the instruction at the given index <code>pos</code>.
419      * Branch offsets and the exception table are also updated.
420      *
421      * <p>If the instruction at the given index is at the beginning
422      * of a block statement,
423      * then the bytecode is excluded from that block.
424      *
425      * <p>An extra gap may be inserted at the end of the inserted
426      * bytecode sequence for adjusting alignment if the code attribute
427      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
428      *
429      * <p>The index at which the byte sequence is actually inserted
430      * might be different from pos since some other bytes might be
431      * inserted at other positions (e.g. to change <code>GOTO</code>
432      * to <code>GOTO_W</code>).
433      *
434      * @param pos       the index at which a byte sequence is inserted.
435      * @param code      inserted bytecode sequence.
436      */
insertEx(int pos, byte[] code)437     public void insertEx(int pos, byte[] code) throws BadBytecode {
438         insert0(pos, code, true);
439     }
440 
441     /**
442      * Inserts the given bytecode sequence exclusively
443      * before the instruction at the given index <code>pos</code>.
444      * Branch offsets and the exception table are also updated.
445      *
446      * <p>If the instruction at the given index is at the beginning
447      * of a block statement,
448      * then the bytecode is excluded from that block.
449      *
450      * <p>An extra gap may be inserted at the end of the inserted
451      * bytecode sequence for adjusting alignment if the code attribute
452      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
453      *
454      * @param pos       the index at which a byte sequence is inserted.
455      * @param code      inserted bytecode sequence.
456      * @return          the index indicating the first byte of the
457      *                  inserted byte sequence, which might be
458      *                  different from pos.
459      * @since 3.11
460      */
insertExAt(int pos, byte[] code)461     public int insertExAt(int pos, byte[] code) throws BadBytecode {
462         return insert0(pos, code, true);
463     }
464 
465     /**
466      * @return          the index indicating the first byte of the
467      *                  inserted byte sequence.
468      */
insert0(int pos, byte[] code, boolean exclusive)469     private int insert0(int pos, byte[] code, boolean exclusive)
470         throws BadBytecode
471     {
472         int len = code.length;
473         if (len <= 0)
474             return pos;
475 
476         // currentPos will change.
477         pos = insertGapAt(pos, len, exclusive).position;
478 
479         int p = pos;
480         for (int j = 0; j < len; ++j)
481             bytecode[p++] = code[j];
482 
483         return pos;
484     }
485 
486     /**
487      * Inserts a gap
488      * before the next instruction that would be returned by
489      * <code>next()</code> (not before the instruction returned
490      * by the last call to <code>next()</code>).
491      * Branch offsets and the exception table are also updated.
492      * The inserted gap is filled with NOP.  The gap length may be
493      * extended to a multiple of 4.
494      *
495      * <p>If the next instruction is at the beginning of a block statement,
496      * then the gap is inserted within that block.
497      *
498      * @param length            gap length
499      * @return  the index indicating the first byte of the inserted gap.
500      */
insertGap(int length)501     public int insertGap(int length) throws BadBytecode {
502         return insertGapAt(currentPos, length, false).position;
503     }
504 
505     /**
506      * Inserts a gap in front of the instruction at the given
507      * index <code>pos</code>.
508      * Branch offsets and the exception table are also updated.
509      * The inserted gap is filled with NOP.  The gap length may be
510      * extended to a multiple of 4.
511      *
512      * <p>If the instruction at the given index is at the beginning
513      * of a block statement,
514      * then the gap is inserted within that block.
515      *
516      * @param pos               the index at which a gap is inserted.
517      * @param length            gap length.
518      * @return the length of the inserted gap.
519      *          It might be bigger than <code>length</code>.
520      */
insertGap(int pos, int length)521     public int insertGap(int pos, int length) throws BadBytecode {
522         return insertGapAt(pos, length, false).length;
523     }
524 
525     /**
526      * Inserts an exclusive gap
527      * before the next instruction that would be returned by
528      * <code>next()</code> (not before the instruction returned
529      * by the last call to <code>next()</code>).
530      * Branch offsets and the exception table are also updated.
531      * The inserted gap is filled with NOP.  The gap length may be
532      * extended to a multiple of 4.
533      *
534      * <p>If the next instruction is at the beginning of a block statement,
535      * then the gap is excluded from that block.
536      *
537      * @param length            gap length
538      * @return  the index indicating the first byte of the inserted gap.
539      */
insertExGap(int length)540     public int insertExGap(int length) throws BadBytecode {
541         return insertGapAt(currentPos, length, true).position;
542     }
543 
544     /**
545      * Inserts an exclusive gap in front of the instruction at the given
546      * index <code>pos</code>.
547      * Branch offsets and the exception table are also updated.
548      * The inserted gap is filled with NOP.  The gap length may be
549      * extended to a multiple of 4.
550      *
551      * <p>If the instruction at the given index is at the beginning
552      * of a block statement,
553      * then the gap is excluded from that block.
554      *
555      * @param pos               the index at which a gap is inserted.
556      * @param length            gap length.
557      * @return the length of the inserted gap.
558      *          It might be bigger than <code>length</code>.
559      */
insertExGap(int pos, int length)560     public int insertExGap(int pos, int length) throws BadBytecode {
561         return insertGapAt(pos, length, true).length;
562     }
563 
564     /**
565      * An inserted gap.
566      *
567      * @since 3.11
568      */
569     public static class Gap {
570         /**
571          * The position of the gap.
572          */
573         public int position;
574 
575         /**
576          * The length of the gap.
577          */
578         public int length;
579     }
580 
581     /**
582      * Inserts an inclusive or exclusive gap in front of the instruction
583      * at the given index <code>pos</code>.
584      * Branch offsets and the exception table in the method body
585      * are also updated.  The inserted gap is filled with NOP.
586      * The gap length may be extended to a multiple of 4.
587      *
588      * <p>Suppose that the instruction at the given index is at the
589      * beginning of a block statement.  If the gap is inclusive,
590      * then it is included within that block.  If the gap is exclusive,
591      * then it is excluded from that block.
592      *
593      * <p>The index at which the gap is actually inserted
594      * might be different from pos since some other bytes might be
595      * inserted at other positions (e.g. to change <code>GOTO</code>
596      * to <code>GOTO_W</code>).  The index is available from the <code>Gap</code>
597      * object returned by this method.
598      *
599      * <p>Suppose that the gap is inserted at the position of
600      * the next instruction that would be returned by
601      * <code>next()</code> (not the last instruction returned
602      * by the last call to <code>next()</code>).  The next
603      * instruction returned by <code>next()</code> after the gap is
604      * inserted is still the same instruction.  It is not <code>NOP</code>
605      * at the first byte of the inserted gap.
606      *
607      * @param pos               the index at which a gap is inserted.
608      * @param length            gap length.
609      * @param exclusive         true if exclusive, otherwise false.
610      * @return the position and the length of the inserted gap.
611      * @since 3.11
612      */
insertGapAt(int pos, int length, boolean exclusive)613     public Gap insertGapAt(int pos, int length, boolean exclusive)
614         throws BadBytecode
615     {
616         /**
617          * cursorPos indicates the next bytecode whichever exclusive is
618          * true or false.
619          */
620         Gap gap = new Gap();
621         if (length <= 0) {
622             gap.position = pos;
623             gap.length = 0;
624             return gap;
625         }
626 
627         byte[] c;
628         int length2;
629         if (bytecode.length + length > Short.MAX_VALUE) {
630             // currentPos might change after calling insertGapCore0w().
631             c = insertGapCore0w(bytecode, pos, length, exclusive,
632                                 get().getExceptionTable(), codeAttr, gap);
633             pos = gap.position;
634             length2 = length; // == gap.length
635         }
636         else {
637             int cur = currentPos;
638             c = insertGapCore0(bytecode, pos, length, exclusive,
639                                       get().getExceptionTable(), codeAttr);
640             // insertGapCore0() never changes pos.
641             length2 = c.length - bytecode.length;
642             gap.position = pos;
643             gap.length = length2;
644             if (cur >= pos)
645                 currentPos = cur + length2;
646 
647             if (mark > pos || (mark == pos && exclusive))
648                 mark += length2;
649         }
650 
651         codeAttr.setCode(c);
652         bytecode = c;
653         endPos = getCodeLength();
654         updateCursors(pos, length2);
655         return gap;
656     }
657 
658     /**
659      * Is called when a gap is inserted.  The default implementation is empty.
660      * A subclass can override this method so that cursors will be updated.
661      *
662      * @param pos           the position where a gap is inserted.
663      * @param length        the length of the gap.
664      */
updateCursors(int pos, int length)665     protected void updateCursors(int pos, int length) {
666         // empty
667     }
668 
669     /**
670      * Copies and inserts the entries in the given exception table
671      * at the beginning of the exception table in the code attribute
672      * edited by this object.
673      *
674      * @param offset    the value added to the code positions included
675      *                          in the entries.
676      */
insert(ExceptionTable et, int offset)677     public void insert(ExceptionTable et, int offset) {
678         codeAttr.getExceptionTable().add(0, et, offset);
679     }
680 
681     /**
682      * Appends the given bytecode sequence at the end.
683      *
684      * @param code      the bytecode appended.
685      * @return  the position of the first byte of the appended bytecode.
686      */
append(byte[] code)687     public int append(byte[] code) {
688         int size = getCodeLength();
689         int len = code.length;
690         if (len <= 0)
691             return size;
692 
693         appendGap(len);
694         byte[] dest = bytecode;
695         for (int i = 0; i < len; ++i)
696             dest[i + size] = code[i];
697 
698         return size;
699     }
700 
701     /**
702      * Appends a gap at the end of the bytecode sequence.
703      *
704      * @param gapLength            gap length
705      */
appendGap(int gapLength)706     public void appendGap(int gapLength) {
707         byte[] code = bytecode;
708         int codeLength = code.length;
709         byte[] newcode = new byte[codeLength + gapLength];
710 
711         int i;
712         for (i = 0; i < codeLength; ++i)
713             newcode[i] = code[i];
714 
715         for (i = codeLength; i < codeLength + gapLength; ++i)
716             newcode[i] = NOP;
717 
718         codeAttr.setCode(newcode);
719         bytecode = newcode;
720         endPos = getCodeLength();
721     }
722 
723     /**
724      * Copies and appends the entries in the given exception table
725      * at the end of the exception table in the code attribute
726      * edited by this object.
727      *
728      * @param offset    the value added to the code positions included
729      *                          in the entries.
730      */
append(ExceptionTable et, int offset)731     public void append(ExceptionTable et, int offset) {
732         ExceptionTable table = codeAttr.getExceptionTable();
733         table.add(table.size(), et, offset);
734     }
735 
736     /* opcodeLegth is used for implementing nextOpcode().
737      */
738     private static final int opcodeLength[] = {
739         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3,
740         3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
741         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1,
742         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
743         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
744         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
745         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
746         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
747         3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
748         3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
749         5, 5
750     };
751     // 0 .. LOOKUPSWITCH, TABLESWITCH, WIDE
752 
753     /**
754      * Calculates the index of the next opcode.
755      */
nextOpcode(byte[] code, int index)756     static int nextOpcode(byte[] code, int index)
757         throws BadBytecode
758     {
759         int opcode;
760         try {
761             opcode = code[index] & 0xff;
762         }
763         catch (IndexOutOfBoundsException e) {
764             throw new BadBytecode("invalid opcode address");
765         }
766 
767         try {
768             int len = opcodeLength[opcode];
769             if (len > 0)
770                 return index + len;
771             else if (opcode == WIDE)
772                 if (code[index + 1] == (byte)IINC)      // WIDE IINC
773                     return index + 6;
774                 else
775                     return index + 4;           // WIDE ...
776             int index2 = (index & ~3) + 8;
777             if (opcode == LOOKUPSWITCH) {
778                 int npairs = ByteArray.read32bit(code, index2);
779                 return index2 + npairs * 8 + 4;
780             }
781             else if (opcode == TABLESWITCH) {
782                 int low = ByteArray.read32bit(code, index2);
783                 int high = ByteArray.read32bit(code, index2 + 4);
784                 return index2 + (high - low + 1) * 4 + 8;
785             }
786         }
787         catch (IndexOutOfBoundsException e) {
788         }
789 
790         // opcode is UNUSED or an IndexOutOfBoundsException was thrown.
791         throw new BadBytecode(opcode);
792     }
793 
794     // methods for implementing insertGap().
795 
796     static class AlignmentException extends Exception {
797 
798         /** default serialVersionUID */
799         private static final long serialVersionUID = 1L;}
800 
801     /**
802      * insertGapCore0() inserts a gap (some NOPs).
803      * It cannot handle a long code sequence more than 32K.  All branch offsets must be
804      * signed 16bits.
805      *
806      * If "where" is the beginning of a block statement and exclusive is false,
807      * then the inserted gap is also included in the block statement.
808      * "where" must indicate the first byte of an opcode.
809      * The inserted gap is filled with NOP.  gapLength may be extended to
810      * a multiple of 4.
811      *
812      * This method was also called from CodeAttribute.LdcEntry.doit().
813      *
814      * @param where       It must indicate the first byte of an opcode.
815      */
insertGapCore0(byte[] code, int where, int gapLength, boolean exclusive, ExceptionTable etable, CodeAttribute ca)816     static byte[] insertGapCore0(byte[] code, int where, int gapLength,
817                                  boolean exclusive, ExceptionTable etable, CodeAttribute ca)
818         throws BadBytecode
819     {
820         if (gapLength <= 0)
821             return code;
822 
823         try {
824             return insertGapCore1(code, where, gapLength, exclusive, etable, ca);
825         }
826         catch (AlignmentException e) {
827             try {
828                 return insertGapCore1(code, where, (gapLength + 3) & ~3,
829                                   exclusive, etable, ca);
830             }
831             catch (AlignmentException e2) {
832                 throw new RuntimeException("fatal error?");
833             }
834         }
835     }
836 
insertGapCore1(byte[] code, int where, int gapLength, boolean exclusive, ExceptionTable etable, CodeAttribute ca)837     private static byte[] insertGapCore1(byte[] code, int where, int gapLength,
838                                          boolean exclusive, ExceptionTable etable,
839                                          CodeAttribute ca)
840         throws BadBytecode, AlignmentException
841     {
842         int codeLength = code.length;
843         byte[] newcode = new byte[codeLength + gapLength];
844         insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
845         etable.shiftPc(where, gapLength, exclusive);
846         LineNumberAttribute na
847             = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
848         if (na != null)
849             na.shiftPc(where, gapLength, exclusive);
850 
851         LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
852                                                 LocalVariableAttribute.tag);
853         if (va != null)
854             va.shiftPc(where, gapLength, exclusive);
855 
856         LocalVariableAttribute vta
857             = (LocalVariableAttribute)ca.getAttribute(
858                                               LocalVariableAttribute.typeTag);
859         if (vta != null)
860             vta.shiftPc(where, gapLength, exclusive);
861 
862         StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
863         if (smt != null)
864             smt.shiftPc(where, gapLength, exclusive);
865 
866         StackMap sm = (StackMap)ca.getAttribute(StackMap.tag);
867         if (sm != null)
868             sm.shiftPc(where, gapLength, exclusive);
869 
870         return newcode;
871     }
872 
insertGap2(byte[] code, int where, int gapLength, int endPos, byte[] newcode, boolean exclusive)873     private static void insertGap2(byte[] code, int where, int gapLength,
874                         int endPos, byte[] newcode, boolean exclusive)
875         throws BadBytecode, AlignmentException
876     {
877         int nextPos;
878         int i = 0;
879         int j = 0;
880         for (; i < endPos; i = nextPos) {
881             if (i == where) {
882                 int j2 = j + gapLength;
883                 while (j < j2)
884                     newcode[j++] = NOP;
885             }
886 
887             nextPos = nextOpcode(code, i);
888             int inst = code[i] & 0xff;
889             // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
890             if ((153 <= inst && inst <= 168)
891                 || inst == IFNULL || inst == IFNONNULL) {
892                 /* 2bytes *signed* offset */
893                 int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
894                 offset = newOffset(i, offset, where, gapLength, exclusive);
895                 newcode[j] = code[i];
896                 ByteArray.write16bit(offset, newcode, j + 1);
897                 j += 3;
898             }
899             else if (inst == GOTO_W || inst == JSR_W) {
900                 /* 4bytes offset */
901                 int offset = ByteArray.read32bit(code, i + 1);
902                 offset = newOffset(i, offset, where, gapLength, exclusive);
903                 newcode[j++] = code[i];
904                 ByteArray.write32bit(offset, newcode, j);
905                 j += 4;
906             }
907             else if (inst == TABLESWITCH) {
908                 if (i != j && (gapLength & 3) != 0)
909                     throw new AlignmentException();
910 
911                 int i2 = (i & ~3) + 4;  // 0-3 byte padding
912                 // IBM JVM 1.4.2 cannot run the following code:
913                 // int i0 = i;
914                 // while (i0 < i2)
915                 //    newcode[j++] = code[i0++];
916                 // So extracting this code into an external method.
917                 // see JIRA JASSIST-74.
918                 j = copyGapBytes(newcode, j, code, i, i2);
919 
920                 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
921                                             where, gapLength, exclusive);
922                 ByteArray.write32bit(defaultbyte, newcode, j);
923                 int lowbyte = ByteArray.read32bit(code, i2 + 4);
924                 ByteArray.write32bit(lowbyte, newcode, j + 4);
925                 int highbyte = ByteArray.read32bit(code, i2 + 8);
926                 ByteArray.write32bit(highbyte, newcode, j + 8);
927                 j += 12;
928                 int i0 = i2 + 12;
929                 i2 = i0 + (highbyte - lowbyte + 1) * 4;
930                 while (i0 < i2) {
931                     int offset = newOffset(i, ByteArray.read32bit(code, i0),
932                                            where, gapLength, exclusive);
933                     ByteArray.write32bit(offset, newcode, j);
934                     j += 4;
935                     i0 += 4;
936                 }
937             }
938             else if (inst == LOOKUPSWITCH) {
939                 if (i != j && (gapLength & 3) != 0)
940                     throw new AlignmentException();
941 
942                 int i2 = (i & ~3) + 4;  // 0-3 byte padding
943 
944                 // IBM JVM 1.4.2 cannot run the following code:
945                 // int i0 = i;
946                 // while (i0 < i2)
947                 //    newcode[j++] = code[i0++];
948                 // So extracting this code into an external method.
949                 // see JIRA JASSIST-74.
950                 j = copyGapBytes(newcode, j, code, i, i2);
951 
952                 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
953                                             where, gapLength, exclusive);
954                 ByteArray.write32bit(defaultbyte, newcode, j);
955                 int npairs = ByteArray.read32bit(code, i2 + 4);
956                 ByteArray.write32bit(npairs, newcode, j + 4);
957                 j += 8;
958                 int i0 = i2 + 8;
959                 i2 = i0 + npairs * 8;
960                 while (i0 < i2) {
961                     ByteArray.copy32bit(code, i0, newcode, j);
962                     int offset = newOffset(i,
963                                         ByteArray.read32bit(code, i0 + 4),
964                                         where, gapLength, exclusive);
965                     ByteArray.write32bit(offset, newcode, j + 4);
966                     j += 8;
967                     i0 += 8;
968                 }
969             }
970             else
971                 while (i < nextPos)
972                     newcode[j++] = code[i++];
973             }
974     }
975 
976 
copyGapBytes(byte[] newcode, int j, byte[] code, int i, int iEnd)977     private static int copyGapBytes(byte[] newcode, int j, byte[] code, int i, int iEnd) {
978         switch (iEnd - i) {
979         case 4:
980             newcode[j++] = code[i++];
981         case 3:
982             newcode[j++] = code[i++];
983         case 2:
984             newcode[j++] = code[i++];
985         case 1:
986             newcode[j++] = code[i++];
987         default:
988         }
989 
990         return j;
991     }
992 
newOffset(int i, int offset, int where, int gapLength, boolean exclusive)993     private static int newOffset(int i, int offset, int where,
994                                  int gapLength, boolean exclusive) {
995         int target = i + offset;
996         if (i < where) {
997             if (where < target || (exclusive && where == target))
998                 offset += gapLength;
999         }
1000         else if (i == where) {
1001             // This code is different from the code in Branch#shiftOffset().
1002             // see JASSIST-124.
1003             if (target < where)
1004                 offset -= gapLength;
1005         }
1006         else
1007             if (target < where || (!exclusive && where == target))
1008                 offset -= gapLength;
1009 
1010         return offset;
1011     }
1012 
1013     static class Pointers {
1014         int cursor;
1015         int mark0, mark;
1016         ExceptionTable etable;
1017         LineNumberAttribute line;
1018         LocalVariableAttribute vars, types;
1019         StackMapTable stack;
1020         StackMap stack2;
1021 
Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca)1022         Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) {
1023             cursor = cur;
1024             mark = m;
1025             mark0 = m0;
1026             etable = et;    // non null
1027             line = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
1028             vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag);
1029             types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag);
1030             stack = (StackMapTable)ca.getAttribute(StackMapTable.tag);
1031             stack2 = (StackMap)ca.getAttribute(StackMap.tag);
1032         }
1033 
shiftPc(int where, int gapLength, boolean exclusive)1034         void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode {
1035             if (where < cursor || (where == cursor && exclusive))
1036                 cursor += gapLength;
1037 
1038             if (where < mark || (where == mark && exclusive))
1039                 mark += gapLength;
1040 
1041             if (where < mark0 || (where == mark0 && exclusive))
1042                 mark0 += gapLength;
1043 
1044             etable.shiftPc(where, gapLength, exclusive);
1045             if (line != null)
1046                 line.shiftPc(where, gapLength, exclusive);
1047 
1048             if (vars != null)
1049                 vars.shiftPc(where, gapLength, exclusive);
1050 
1051             if (types != null)
1052                 types.shiftPc(where, gapLength, exclusive);
1053 
1054             if (stack != null)
1055                 stack.shiftPc(where, gapLength, exclusive);
1056 
1057             if (stack2 != null)
1058                 stack2.shiftPc(where, gapLength, exclusive);
1059         }
1060 
shiftForSwitch(int where, int gapLength)1061         void shiftForSwitch(int where, int gapLength) throws BadBytecode {
1062             if (stack != null)
1063                 stack.shiftForSwitch(where, gapLength);
1064 
1065             if (stack2 != null)
1066                 stack2.shiftForSwitch(where, gapLength);
1067         }
1068     }
1069 
1070     /*
1071      * This method is called from CodeAttribute.LdcEntry.doit().
1072      */
changeLdcToLdcW(byte[] code, ExceptionTable etable, CodeAttribute ca, CodeAttribute.LdcEntry ldcs)1073     static byte[] changeLdcToLdcW(byte[] code, ExceptionTable etable,
1074                                   CodeAttribute ca, CodeAttribute.LdcEntry ldcs)
1075         throws BadBytecode
1076     {
1077         Pointers pointers = new Pointers(0, 0, 0, etable, ca);
1078         List<Branch> jumps = makeJumpList(code, code.length, pointers);
1079         while (ldcs != null) {
1080             addLdcW(ldcs, jumps);
1081             ldcs = ldcs.next;
1082         }
1083 
1084         byte[] r = insertGap2w(code, 0, 0, false, jumps, pointers);
1085         return r;
1086     }
1087 
addLdcW(CodeAttribute.LdcEntry ldcs, List<Branch> jumps)1088     private static void addLdcW(CodeAttribute.LdcEntry ldcs, List<Branch> jumps) {
1089         int where = ldcs.where;
1090         LdcW ldcw = new LdcW(where, ldcs.index);
1091         int s = jumps.size();
1092         for (int i = 0; i < s; i++)
1093             if (where < jumps.get(i).orgPos) {
1094                 jumps.add(i, ldcw);
1095                 return;
1096             }
1097 
1098         jumps.add(ldcw);
1099     }
1100 
1101     /*
1102      * insertGapCore0w() can handle a long code sequence more than 32K.
1103      * It guarantees that the length of the inserted gap (NOPs) is equal to
1104      * gapLength.  No other NOPs except some NOPs following TABLESWITCH or
1105      * LOOKUPSWITCH will not be inserted.
1106      *
1107      * Note: currentPos might be moved.
1108      *
1109      * @param where       It must indicate the first byte of an opcode.
1110      * @param newWhere    It contains the updated index of the position where a gap
1111      *                    is inserted and the length of the gap.
1112      *                    It must not be null.
1113      */
insertGapCore0w(byte[] code, int where, int gapLength, boolean exclusive, ExceptionTable etable, CodeAttribute ca, Gap newWhere)1114     private byte[] insertGapCore0w(byte[] code, int where, int gapLength, boolean exclusive,
1115                                    ExceptionTable etable, CodeAttribute ca, Gap newWhere)
1116         throws BadBytecode
1117     {
1118         if (gapLength <= 0)
1119             return code;
1120 
1121         Pointers pointers = new Pointers(currentPos, mark, where, etable, ca);
1122         List<Branch> jumps = makeJumpList(code, code.length, pointers);
1123         byte[] r = insertGap2w(code, where, gapLength, exclusive, jumps, pointers);
1124         currentPos = pointers.cursor;
1125         mark = pointers.mark;
1126         int where2 = pointers.mark0;
1127         if (where2 == currentPos && !exclusive)
1128             currentPos += gapLength;
1129 
1130         if (exclusive)
1131             where2 -= gapLength;
1132 
1133         newWhere.position = where2;
1134         newWhere.length = gapLength;
1135         return r;
1136     }
1137 
insertGap2w(byte[] code, int where, int gapLength, boolean exclusive, List<Branch> jumps, Pointers ptrs)1138     private static byte[] insertGap2w(byte[] code, int where, int gapLength,
1139                                       boolean exclusive, List<Branch> jumps, Pointers ptrs)
1140         throws BadBytecode
1141     {
1142         if (gapLength > 0) {
1143             ptrs.shiftPc(where, gapLength, exclusive);
1144             for (Branch b:jumps)
1145                 b.shift(where, gapLength, exclusive);
1146         }
1147 
1148         boolean unstable = true;
1149         do {
1150             while (unstable) {
1151                 unstable = false;
1152                 for (Branch b:jumps) {
1153                     if (b.expanded()) {
1154                         unstable = true;
1155                         int p = b.pos;
1156                         int delta = b.deltaSize();
1157                         ptrs.shiftPc(p, delta, false);
1158                         for (Branch bb:jumps)
1159                             bb.shift(p, delta, false);
1160                     }
1161                 }
1162             }
1163 
1164             for (Branch b:jumps) {
1165                 int diff = b.gapChanged();
1166                 if (diff > 0) {
1167                     unstable = true;
1168                     int p = b.pos;
1169                     ptrs.shiftPc(p, diff, false);
1170                     for (Branch bb:jumps)
1171                         bb.shift(p, diff, false);
1172                 }
1173             }
1174         } while (unstable);
1175 
1176         return makeExapndedCode(code, jumps, where, gapLength);
1177     }
1178 
makeJumpList(byte[] code, int endPos, Pointers ptrs)1179     private static List<Branch> makeJumpList(byte[] code, int endPos, Pointers ptrs)
1180         throws BadBytecode
1181     {
1182         List<Branch> jumps = new ArrayList<Branch>();
1183         int nextPos;
1184         for (int i = 0; i < endPos; i = nextPos) {
1185             nextPos = nextOpcode(code, i);
1186             int inst = code[i] & 0xff;
1187             // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
1188             if ((153 <= inst && inst <= 168)
1189                     || inst == IFNULL || inst == IFNONNULL) {
1190                 /* 2bytes *signed* offset */
1191                 int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
1192                 Branch b;
1193                 if (inst == GOTO || inst == JSR)
1194                     b = new Jump16(i, offset);
1195                 else
1196                     b = new If16(i, offset);
1197 
1198                 jumps.add(b);
1199             }
1200             else if (inst == GOTO_W || inst == JSR_W) {
1201                 /* 4bytes offset */
1202                 int offset = ByteArray.read32bit(code, i + 1);
1203                 jumps.add(new Jump32(i, offset));
1204             }
1205             else if (inst == TABLESWITCH) {
1206                 int i2 = (i & ~3) + 4;  // 0-3 byte padding
1207                 int defaultbyte = ByteArray.read32bit(code, i2);
1208                 int lowbyte = ByteArray.read32bit(code, i2 + 4);
1209                 int highbyte = ByteArray.read32bit(code, i2 + 8);
1210                 int i0 = i2 + 12;
1211                 int size = highbyte - lowbyte + 1;
1212                 int[] offsets = new int[size];
1213                 for (int j = 0; j < size; j++) {
1214                     offsets[j] = ByteArray.read32bit(code, i0);
1215                     i0 += 4;
1216                 }
1217 
1218                 jumps.add(new Table(i, defaultbyte, lowbyte, highbyte, offsets, ptrs));
1219             }
1220             else if (inst == LOOKUPSWITCH) {
1221                 int i2 = (i & ~3) + 4;  // 0-3 byte padding
1222                 int defaultbyte = ByteArray.read32bit(code, i2);
1223                 int npairs = ByteArray.read32bit(code, i2 + 4);
1224                 int i0 = i2 + 8;
1225                 int[] matches = new int[npairs];
1226                 int[] offsets = new int[npairs];
1227                 for (int j = 0; j < npairs; j++) {
1228                     matches[j] = ByteArray.read32bit(code, i0);
1229                     offsets[j] = ByteArray.read32bit(code, i0 + 4);
1230                     i0 += 8;
1231                 }
1232 
1233                 jumps.add(new Lookup(i, defaultbyte, matches, offsets, ptrs));
1234             }
1235         }
1236 
1237         return jumps;
1238     }
1239 
makeExapndedCode(byte[] code, List<Branch> jumps, int where, int gapLength)1240     private static byte[] makeExapndedCode(byte[] code, List<Branch> jumps,
1241                                            int where, int gapLength)
1242         throws BadBytecode
1243     {
1244         int n = jumps.size();
1245         int size = code.length + gapLength;
1246         for (Branch b:jumps)
1247             size += b.deltaSize();
1248 
1249         byte[] newcode = new byte[size];
1250         int src = 0, dest = 0, bindex = 0;
1251         int len = code.length;
1252         Branch b;
1253         int bpos;
1254         if (0 < n) {
1255             b = jumps.get(0);
1256             bpos = b.orgPos;
1257         }
1258         else {
1259             b = null;
1260             bpos = len;  // src will be never equal to bpos
1261         }
1262 
1263         while (src < len) {
1264             if (src == where) {
1265                 int pos2 = dest + gapLength;
1266                 while (dest < pos2)
1267                     newcode[dest++] = NOP;
1268             }
1269 
1270             if (src != bpos)
1271                 newcode[dest++] = code[src++];
1272             else {
1273                 int s = b.write(src, code, dest, newcode);
1274                 src += s;
1275                 dest += s + b.deltaSize();
1276                 if (++bindex < n) {
1277                     b = jumps.get(bindex);
1278                     bpos = b.orgPos;
1279                 }
1280                 else  {
1281                     b = null;
1282                     bpos = len;
1283                 }
1284             }
1285         }
1286 
1287         return newcode;
1288     }
1289 
1290     static abstract class Branch {
1291         int pos, orgPos;
Branch(int p)1292         Branch(int p) { pos = orgPos = p; }
shift(int where, int gapLength, boolean exclusive)1293         void shift(int where, int gapLength, boolean exclusive) {
1294             if (where < pos || (where == pos && exclusive))
1295                 pos += gapLength;
1296         }
1297 
shiftOffset(int i, int offset, int where, int gapLength, boolean exclusive)1298         static int shiftOffset(int i, int offset, int where,
1299                                int gapLength, boolean exclusive) {
1300             int target = i + offset;
1301             if (i < where) {
1302                 if (where < target || (exclusive && where == target))
1303                     offset += gapLength;
1304             }
1305             else if (i == where) {
1306                 // This code is different from the code in CodeIterator#newOffset().
1307                 // see JASSIST-124.
1308                 if (target < where && exclusive)
1309                     offset -= gapLength;
1310                 else if (where < target && !exclusive)
1311                     offset += gapLength;
1312             }
1313             else
1314                 if (target < where || (!exclusive && where == target))
1315                     offset -= gapLength;
1316 
1317             return offset;
1318         }
1319 
expanded()1320         boolean expanded() { return false; }
gapChanged()1321         int gapChanged() { return 0; }
deltaSize()1322         int deltaSize() { return 0; }   // newSize - oldSize
1323 
1324         // This returns the original instruction size.
write(int srcPos, byte[] code, int destPos, byte[] newcode)1325         abstract int write(int srcPos, byte[] code, int destPos, byte[] newcode) throws BadBytecode;
1326     }
1327 
1328     /* used by changeLdcToLdcW() and CodeAttribute.LdcEntry.
1329      */
1330     static class LdcW extends Branch {
1331         int index;
1332         boolean state;
LdcW(int p, int i)1333         LdcW(int p, int i) {
1334             super(p);
1335             index = i;
1336             state = true;
1337         }
1338 
1339         @Override
expanded()1340         boolean expanded() {
1341             if (state) {
1342                 state = false;
1343                 return true;
1344             }
1345             return false;
1346         }
1347 
1348         @Override
deltaSize()1349         int deltaSize() { return 1; }
1350 
1351         @Override
write(int srcPos, byte[] code, int destPos, byte[] newcode)1352         int write(int srcPos, byte[] code, int destPos, byte[] newcode) {
1353             newcode[destPos] = LDC_W;
1354             ByteArray.write16bit(index, newcode, destPos + 1);
1355             return 2;
1356         }
1357     }
1358 
1359     static abstract class Branch16 extends Branch {
1360         int offset;
1361         int state;
1362         static final int BIT16 = 0;
1363         static final int EXPAND = 1;
1364         static final int BIT32 = 2;
1365 
Branch16(int p, int off)1366         Branch16(int p, int off) {
1367             super(p);
1368             offset = off;
1369             state = BIT16;
1370         }
1371 
1372         @Override
shift(int where, int gapLength, boolean exclusive)1373         void shift(int where, int gapLength, boolean exclusive) {
1374             offset = shiftOffset(pos, offset, where, gapLength, exclusive);
1375             super.shift(where, gapLength, exclusive);
1376             if (state == BIT16)
1377                 if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset)
1378                     state = EXPAND;
1379         }
1380 
1381         @Override
expanded()1382         boolean expanded() {
1383             if (state == EXPAND) {
1384                 state = BIT32;
1385                 return true;
1386             }
1387             return false;
1388         }
1389 
1390         @Override
deltaSize()1391         abstract int deltaSize();
write32(int src, byte[] code, int dest, byte[] newcode)1392         abstract void write32(int src, byte[] code, int dest, byte[] newcode);
1393 
1394         @Override
write(int src, byte[] code, int dest, byte[] newcode)1395         int write(int src, byte[] code, int dest, byte[] newcode) {
1396             if (state == BIT32)
1397                 write32(src, code, dest, newcode);
1398             else {
1399                 newcode[dest] = code[src];
1400                 ByteArray.write16bit(offset, newcode, dest + 1);
1401             }
1402 
1403             return 3;
1404         }
1405     }
1406 
1407     // GOTO or JSR
1408     static class Jump16 extends Branch16 {
Jump16(int p, int off)1409         Jump16(int p, int off) {
1410             super(p, off);
1411         }
1412 
1413         @Override
deltaSize()1414         int deltaSize() {
1415             return state == BIT32 ? 2 : 0;
1416         }
1417 
1418         @Override
write32(int src, byte[] code, int dest, byte[] newcode)1419         void write32(int src, byte[] code, int dest, byte[] newcode) {
1420             newcode[dest] = (byte)(((code[src] & 0xff) == GOTO) ? GOTO_W : JSR_W);
1421             ByteArray.write32bit(offset, newcode, dest + 1);
1422         }
1423     }
1424 
1425     // if<cond>, if_icmp<cond>, or if_acmp<cond>
1426     static class If16 extends Branch16 {
If16(int p, int off)1427         If16(int p, int off) {
1428             super(p, off);
1429         }
1430 
1431         @Override
deltaSize()1432         int deltaSize() {
1433             return state == BIT32 ? 5 : 0;
1434         }
1435 
1436         @Override
write32(int src, byte[] code, int dest, byte[] newcode)1437         void write32(int src, byte[] code, int dest, byte[] newcode) {
1438             newcode[dest] = (byte)opcode(code[src] & 0xff);
1439             newcode[dest + 1] = 0;
1440             newcode[dest + 2] = 8;  // branch_offset = 8
1441             newcode[dest + 3] = (byte)GOTO_W;
1442             ByteArray.write32bit(offset - 3, newcode, dest + 4);
1443         }
1444 
opcode(int op)1445         int opcode(int op) {
1446             if (op == IFNULL)
1447                 return IFNONNULL;
1448             else if (op == IFNONNULL)
1449                 return IFNULL;
1450             if (((op - IFEQ) & 1) == 0)
1451                 return op + 1;
1452             return op - 1;
1453         }
1454     }
1455 
1456     static class Jump32 extends Branch {
1457         int offset;
1458 
Jump32(int p, int off)1459         Jump32(int p, int off) {
1460             super(p);
1461             offset = off;
1462         }
1463 
1464         @Override
shift(int where, int gapLength, boolean exclusive)1465         void shift(int where, int gapLength, boolean exclusive) {
1466             offset = shiftOffset(pos, offset, where, gapLength, exclusive);
1467             super.shift(where, gapLength, exclusive);
1468         }
1469 
1470         @Override
write(int src, byte[] code, int dest, byte[] newcode)1471         int write(int src, byte[] code, int dest, byte[] newcode) {
1472             newcode[dest] = code[src];
1473             ByteArray.write32bit(offset, newcode, dest + 1);
1474             return 5;
1475         }
1476     }
1477 
1478     static abstract class Switcher extends Branch {
1479         int gap, defaultByte;
1480         int[] offsets;
1481         Pointers pointers;
1482 
Switcher(int pos, int defaultByte, int[] offsets, Pointers ptrs)1483         Switcher(int pos, int defaultByte, int[] offsets, Pointers ptrs) {
1484             super(pos);
1485             this.gap = 3 - (pos & 3);
1486             this.defaultByte = defaultByte;
1487             this.offsets = offsets;
1488             this.pointers = ptrs;
1489         }
1490 
1491         @Override
shift(int where, int gapLength, boolean exclusive)1492         void shift(int where, int gapLength, boolean exclusive) {
1493             int p = pos;
1494             defaultByte = shiftOffset(p, defaultByte, where, gapLength, exclusive);
1495             int num = offsets.length;
1496             for (int i = 0; i < num; i++)
1497                 offsets[i] = shiftOffset(p, offsets[i], where, gapLength, exclusive);
1498 
1499             super.shift(where, gapLength, exclusive);
1500         }
1501 
1502         @Override
gapChanged()1503         int gapChanged() {
1504             int newGap = 3 - (pos & 3);
1505             if (newGap > gap) {
1506                 int diff = newGap - gap;
1507                 gap = newGap;
1508                 return diff;
1509             }
1510 
1511             return 0;
1512         }
1513 
1514         @Override
deltaSize()1515         int deltaSize() {
1516             return gap - (3 - (orgPos & 3));
1517         }
1518 
1519         @Override
write(int src, byte[] code, int dest, byte[] newcode)1520         int write(int src, byte[] code, int dest, byte[] newcode) throws BadBytecode {
1521             int padding = 3 - (pos & 3);
1522             int nops = gap - padding;
1523             int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize();
1524             if (nops > 0)
1525                 adjustOffsets(bytecodeSize, nops);
1526 
1527             newcode[dest++] = code[src];
1528             while (padding-- > 0)
1529                 newcode[dest++] = 0;
1530 
1531             ByteArray.write32bit(defaultByte, newcode, dest);
1532             int size = write2(dest + 4, newcode);
1533             dest += size + 4;
1534             while (nops-- > 0)
1535                 newcode[dest++] = NOP;
1536 
1537             return 5 + (3 - (orgPos & 3)) + size;
1538         }
1539 
write2(int dest, byte[] newcode)1540         abstract int write2(int dest, byte[] newcode);
tableSize()1541         abstract int tableSize();
1542 
1543         /* If the new bytecode size is shorter than the original, some NOPs
1544          * are appended after this branch instruction (tableswitch or
1545          * lookupswitch) to fill the gap.
1546          * This method changes a branch offset to point to the first NOP
1547          * if the offset originally points to the bytecode next to this
1548          * branch instruction.  Otherwise, the bytecode would contain
1549          * dead code.  It complicates the generation of StackMap and
1550          * StackMapTable.
1551          */
adjustOffsets(int size, int nops)1552         void adjustOffsets(int size, int nops) throws BadBytecode {
1553             pointers.shiftForSwitch(pos + size, nops);
1554             if (defaultByte == size)
1555                 defaultByte -= nops;
1556 
1557             for (int i = 0; i < offsets.length; i++)
1558                 if (offsets[i] == size)
1559                     offsets[i] -= nops;
1560         }
1561     }
1562 
1563     static class Table extends Switcher {
1564         int low, high;
1565 
Table(int pos, int defaultByte, int low, int high, int[] offsets, Pointers ptrs)1566         Table(int pos, int defaultByte, int low, int high, int[] offsets, Pointers ptrs) {
1567             super(pos, defaultByte, offsets, ptrs);
1568             this.low = low;
1569             this.high = high;
1570         }
1571 
1572         @Override
write2(int dest, byte[] newcode)1573         int write2(int dest, byte[] newcode) {
1574             ByteArray.write32bit(low, newcode, dest);
1575             ByteArray.write32bit(high, newcode, dest + 4);
1576             int n = offsets.length;
1577             dest += 8;
1578             for (int i = 0; i < n; i++) {
1579                 ByteArray.write32bit(offsets[i], newcode, dest);
1580                 dest += 4;
1581             }
1582 
1583             return 8 + 4 * n;
1584         }
1585 
1586         @Override
tableSize()1587         int tableSize() { return 8 + 4 * offsets.length; }
1588     }
1589 
1590     static class Lookup extends Switcher {
1591         int[] matches;
1592 
Lookup(int pos, int defaultByte, int[] matches, int[] offsets, Pointers ptrs)1593         Lookup(int pos, int defaultByte, int[] matches, int[] offsets, Pointers ptrs) {
1594             super(pos, defaultByte, offsets, ptrs);
1595             this.matches = matches;
1596         }
1597 
1598         @Override
write2(int dest, byte[] newcode)1599         int write2(int dest, byte[] newcode) {
1600             int n = matches.length;
1601             ByteArray.write32bit(n, newcode, dest);
1602             dest += 4;
1603             for (int i = 0; i < n; i++) {
1604                 ByteArray.write32bit(matches[i], newcode, dest);
1605                 ByteArray.write32bit(offsets[i], newcode, dest + 4);
1606                 dest += 8;
1607             }
1608 
1609             return 4 + 8 * n;
1610         }
1611 
1612         @Override
tableSize()1613         int tableSize() { return 4 + 8 * matches.length; }
1614     }
1615 }
1616