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
16package javassist.bytecode;
17
18import 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 */
34public 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
41    protected CodeIterator(CodeAttribute ca) {
42        codeAttr = ca;
43        bytecode = ca.getCode();
44        begin();
45    }
46
47    /**
48     * Moves to the first instruction.
49     */
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     */
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     */
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     */
93    public int getMark() { return mark; }
94
95    /**
96     * Returns a Code attribute read with this iterator.
97     */
98    public CodeAttribute get() {
99        return codeAttr;
100    }
101
102    /**
103     * Returns <code>code_length</code> of <code>Code_attribute</code>.
104     */
105    public int getCodeLength() {
106        return bytecode.length;
107    }
108
109    /**
110     * Returns the unsigned 8bit value at the given index.
111     */
112    public int byteAt(int index) { return bytecode[index] & 0xff; }
113
114    /**
115     * Writes an 8bit value at the given index.
116     */
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     */
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     */
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     */
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     */
145    public int s32bitAt(int index) {
146        return ByteArray.read32bit(bytecode, index);
147    }
148
149    /**
150     * Writes a 32bit integer at the index.
151     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
262    public int skipThisConstructor() throws BadBytecode {
263        return skipSuperConstructor0(1);
264    }
265
266    /* skipSuper        1: this(), 0: super(), -1: both.
267     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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
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
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
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
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
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     */
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
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     */
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
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
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
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;
1269        Branch(int p) { pos = orgPos = p; }
1270        void shift(int where, int gapLength, boolean exclusive) {
1271            if (where < pos || (where == pos && exclusive))
1272                pos += gapLength;
1273        }
1274
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
1297        boolean expanded() { return false; }
1298        int gapChanged() { return 0; }
1299        int deltaSize() { return 0; }   // newSize - oldSize
1300
1301        // This returns the original instruction size.
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;
1310        LdcW(int p, int i) {
1311            super(p);
1312            index = i;
1313            state = true;
1314        }
1315
1316        boolean expanded() {
1317            if (state) {
1318                state = false;
1319                return true;
1320            }
1321            else
1322                return false;
1323        }
1324
1325        int deltaSize() { return 1; }
1326
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
1341        Branch16(int p, int off) {
1342            super(p);
1343            offset = off;
1344            state = BIT16;
1345        }
1346
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
1355        boolean expanded() {
1356            if (state == EXPAND) {
1357                state = BIT32;
1358                return true;
1359            }
1360            else
1361                return false;
1362        }
1363
1364        abstract int deltaSize();
1365        abstract void write32(int src, byte[] code, int dest, byte[] newcode);
1366
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 {
1381        Jump16(int p, int off) {
1382            super(p, off);
1383        }
1384
1385        int deltaSize() {
1386            return state == BIT32 ? 2 : 0;
1387        }
1388
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 {
1397        If16(int p, int off) {
1398            super(p, off);
1399        }
1400
1401        int deltaSize() {
1402            return state == BIT32 ? 5 : 0;
1403        }
1404
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
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
1430        Jump32(int p, int off) {
1431            super(p);
1432            offset = off;
1433        }
1434
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
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
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
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
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
1479        int deltaSize() {
1480            return gap - (3 - (orgPos & 3));
1481        }
1482
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
1501        abstract int write2(int dest, byte[] newcode);
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         */
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
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
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
1545        int tableSize() { return 8 + 4 * offsets.length; }
1546    }
1547
1548    static class Lookup extends Switcher {
1549        int[] matches;
1550
1551        Lookup(int pos, int defaultByte, int[] matches, int[] offsets) {
1552            super(pos, defaultByte, offsets);
1553            this.matches = matches;
1554        }
1555
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
1569        int tableSize() { return 4 + 8 * matches.length; }
1570    }
1571}
1572