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