KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > bytecode > CodeIterator


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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 /**
19  * An iterator for editing a code attribute.
20  *
21  * <p>This iterator does not provide <code>remove()</code>.
22  * If a piece of code in a <code>Code_attribute</code> is unnecessary,
23  * it should be overwritten with <code>NOP</code>.
24  *
25  * @see CodeAttribute#iterator()
26  */

27 public class CodeIterator implements Opcode {
28     protected CodeAttribute codeAttr;
29     protected byte[] bytecode;
30     protected int endPos;
31     protected int currentPos;
32
33     CodeIterator(CodeAttribute ca) {
34         codeAttr = ca;
35         bytecode = ca.getCode();
36         begin();
37     }
38
39     /**
40      * Moves to the first instruction.
41      */

42     public void begin() {
43         currentPos = 0;
44         endPos = getCodeLength();
45     }
46
47     /**
48      * Moves to the given index.
49      *
50      * <p>The index of the next instruction is set to the given index.
51      * The successive call to <code>next()</code>
52      * returns the index that has been given to <code>move()</code>.
53      *
54      * <p>Note that the index is into the byte array returned by
55      * <code>get().getCode()</code>.
56      *
57      * @see CodeAttribute#getCode()
58      */

59     public void move(int index) {
60         currentPos = index;
61     }
62
63     /**
64      * Returns a Code attribute read with this iterator.
65      */

66     public CodeAttribute get() {
67         return codeAttr;
68     }
69
70     /**
71      * Returns <code>code_length</code> of <code>Code_attribute</code>.
72      */

73     public int getCodeLength() {
74         return bytecode.length;
75     }
76
77     /**
78      * Returns the unsigned 8bit value at the given index.
79      */

80     public int byteAt(int index) { return bytecode[index] & 0xff; }
81
82     /**
83      * Writes an 8bit value at the given index.
84      */

85     public void writeByte(int value, int index) {
86         bytecode[index] = (byte)value;
87     }
88
89     /**
90      * Returns the unsigned 16bit value at the given index.
91      */

92     public int u16bitAt(int index) {
93         return ByteArray.readU16bit(bytecode, index);
94     }
95
96     /**
97      * Returns the signed 16bit value at the given index.
98      */

99     public int s16bitAt(int index) {
100         return ByteArray.readS16bit(bytecode, index);
101     }
102
103     /**
104      * Writes a 16 bit integer at the index.
105      */

106     public void write16bit(int value, int index) {
107         ByteArray.write16bit(value, bytecode, index);
108     }
109
110     /**
111      * Returns the signed 32bit value at the given index.
112      */

113     public int s32bitAt(int index) {
114         return ByteArray.read32bit(bytecode, index);
115     }
116
117     /**
118      * Writes a 32bit integer at the index.
119      */

120     public void write32bit(int value, int index) {
121         ByteArray.write32bit(value, bytecode, index);
122     }
123
124     /**
125      * Writes a byte array at the index.
126      *
127      * @param code may be a zero-length array.
128      */

129     public void write(byte[] code, int index) {
130         int len = code.length;
131         for (int j = 0; j < len; ++j)
132             bytecode[index++] = code[j];
133     }
134
135     /**
136      * Returns true if there is more instructions.
137      */

138     public boolean hasNext() { return currentPos < endPos; }
139
140     /**
141      * Returns the index of the next instruction
142      * (not the operand following the current opcode).
143      *
144      * <p>Note that the index is into the byte array returned by
145      * <code>get().getCode()</code>.
146      *
147      * @see CodeAttribute#getCode()
148      * @see CodeIterator#byteAt(int)
149      */

150     public int next() throws BadBytecode {
151         int pos = currentPos;
152         currentPos = nextOpcode(bytecode, pos);
153         return pos;
154     }
155
156     /**
157      * Moves to the first instruction following
158      * constructor invocation <code>super()</code> or <code>this()</code>.
159      *
160      * <p>This method skips all the instructions for executing
161      * <code>super()</code> or <code>this()</code>, which should be
162      * placed at the beginning of a constructor body.
163      *
164      * <p>This method returns the index of INVOKESPECIAL instruction
165      * executing <code>super()</code> or <code>this()</code>.
166      * A successive call to <code>next()</code> returns the
167      * index of the next instruction following that INVOKESPECIAL.
168      *
169      * <p>This method works only for a constructor.
170      *
171      * @return the index of the INVOKESPECIAL instruction, or -1
172      * if a constructor invocation is not found.
173      */

174     public int skipConstructor() throws BadBytecode {
175         return skipSuperConstructor0(-1);
176     }
177
178     /**
179      * Moves to the first instruction following super
180      * constructor invocation <code>super()</code>.
181      *
182      * <p>This method skips all the instructions for executing
183      * <code>super()</code>, which should be
184      * placed at the beginning of a constructor body.
185      *
186      * <p>This method returns the index of INVOKESPECIAL instruction
187      * executing <code>super()</code>.
188      * A successive call to <code>next()</code> returns the
189      * index of the next instruction following that INVOKESPECIAL.
190      *
191      * <p>This method works only for a constructor.
192      *
193      * @return the index of the INVOKESPECIAL instruction, or -1
194      * if a super constructor invocation is not found
195      * but <code>this()</code> is found.
196      */

197     public int skipSuperConstructor() throws BadBytecode {
198         return skipSuperConstructor0(0);
199     }
200
201     /**
202      * Moves to the first instruction following explicit
203      * constructor invocation <code>this()</code>.
204      *
205      * <p>This method skips all the instructions for executing
206      * <code>this()</code>, which should be
207      * placed at the beginning of a constructor body.
208      *
209      * <p>This method returns the index of INVOKESPECIAL instruction
210      * executing <code>this()</code>.
211      * A successive call to <code>next()</code> returns the
212      * index of the next instruction following that INVOKESPECIAL.
213      *
214      * <p>This method works only for a constructor.
215      *
216      * @return the index of the INVOKESPECIAL instruction, or -1
217      * if a explicit constructor invocation is not found
218      * but <code>super()</code> is found.
219      */

220     public int skipThisConstructor() throws BadBytecode {
221         return skipSuperConstructor0(1);
222     }
223
224     /* skipSuper 1: this(), 0: super(), -1: both.
225      */

226     private int skipSuperConstructor0(int skipThis) throws BadBytecode {
227         begin();
228         ConstPool cp = codeAttr.getConstPool();
229         String JavaDoc thisClassName = codeAttr.getDeclaringClass();
230         int nested = 0;
231         while (hasNext()) {
232             int index = next();
233             int c = byteAt(index);
234             if (c == NEW)
235                 ++nested;
236             else if (c == INVOKESPECIAL) {
237                 int mref = ByteArray.readU16bit(bytecode, index + 1);
238                 if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit))
239                     if (--nested < 0) {
240                         if (skipThis < 0)
241                             return index;
242
243                         String JavaDoc cname = cp.getMethodrefClassName(mref);
244                         if (cname.equals(thisClassName) == (skipThis > 0))
245                             return index;
246                         else
247                             break;
248                     }
249             }
250         }
251
252         begin();
253         return -1;
254     }
255
256     /**
257      * Inserts the given bytecode sequence
258      * before the next instruction that would be returned by
259      * <code>next()</code> (not before the instruction returned
260      * by tha last call to <code>next()</code>).
261      * Branch offsets and the exception table are also updated.
262      *
263      * <p>If the next instruction is at the beginning of a block statement,
264      * then the bytecode is inserted within that block.
265      *
266      * <p>An extra gap may be inserted at the end of the inserted
267      * bytecode sequence for adjusting alignment if the code attribute
268      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
269      *
270      * @param code inserted bytecode sequence.
271      * @return the index indicating the first byte of the
272      * inserted byte sequence.
273      */

274     public int insert(byte[] code)
275         throws BadBytecode
276     {
277         int pos = currentPos;
278         insert0(currentPos, code, false);
279         return pos;
280     }
281
282     /**
283      * Inserts the given bytecode sequence
284      * before the instruction at the given index <code>pos</code>.
285      * Branch offsets and the exception table are also updated.
286      *
287      * <p>If the instruction at the given index is at the beginning
288      * of a block statement,
289      * then the bytecode is inserted within that block.
290      *
291      * <p>An extra gap may be inserted at the end of the inserted
292      * bytecode sequence for adjusting alignment if the code attribute
293      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
294      *
295      * @param pos the index at which a byte sequence is inserted.
296      * @param code inserted bytecode sequence.
297      */

298     public void insert(int pos, byte[] code) throws BadBytecode {
299         insert0(pos, code, false);
300     }
301
302     /**
303      * Inserts the given bytecode sequence exclusively
304      * before the next instruction that would be returned by
305      * <code>next()</code> (not before the instruction returned
306      * by tha last call to <code>next()</code>).
307      * Branch offsets and the exception table are also updated.
308      *
309      * <p>If the next instruction is at the beginning of a block statement,
310      * then the bytecode is excluded from that block.
311      *
312      * <p>An extra gap may be inserted at the end of the inserted
313      * bytecode sequence for adjusting alignment if the code attribute
314      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
315      *
316      * @param code inserted bytecode sequence.
317      * @return the index indicating the first byte of the
318      * inserted byte sequence.
319      */

320     public int insertEx(byte[] code)
321         throws BadBytecode
322     {
323         int pos = currentPos;
324         insert0(currentPos, code, true);
325         return pos;
326     }
327
328     /**
329      * Inserts the given bytecode sequence exclusively
330      * before the instruction at the given index <code>pos</code>.
331      * Branch offsets and the exception table are also updated.
332      *
333      * <p>If the instruction at the given index is at the beginning
334      * of a block statement,
335      * then the bytecode is excluded from that block.
336      *
337      * <p>An extra gap may be inserted at the end of the inserted
338      * bytecode sequence for adjusting alignment if the code attribute
339      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
340      *
341      * @param pos the index at which a byte sequence is inserted.
342      * @param code inserted bytecode sequence.
343      */

344     public void insertEx(int pos, byte[] code) throws BadBytecode {
345         insert0(pos, code, true);
346     }
347
348     private void insert0(int pos, byte[] code, boolean exclusive)
349         throws BadBytecode
350     {
351         int len = code.length;
352         if (len <= 0)
353             return;
354
355         insertGapCore(pos, len, exclusive); // currentPos will change.
356
for (int j = 0; j < len; ++j)
357             bytecode[pos++] = code[j];
358     }
359
360     /**
361      * Inserts a gap
362      * before the next instruction that would be returned by
363      * <code>next()</code> (not before the instruction returned
364      * by tha last call to <code>next()</code>).
365      * Branch offsets and the exception table are also updated.
366      * The inserted gap is filled with NOP. The gap length may be
367      * extended to a multiple of 4.
368      *
369      * <p>If the next instruction is at the beginning of a block statement,
370      * then the gap is inserted within that block.
371      *
372      * @param length gap length
373      * @return the index indicating the first byte of the inserted gap.
374      */

375     public int insertGap(int length) throws BadBytecode {
376         int pos = currentPos;
377         insertGapCore(currentPos, length, false);
378         return pos;
379     }
380
381     /**
382      * Inserts a gap in front of the instruction at the given
383      * index <code>pos</code>.
384      * Branch offsets and the exception table are also updated.
385      * The inserted gap is filled with NOP. The gap length may be
386      * extended to a multiple of 4.
387      *
388      * <p>If the instruction at the given index is at the beginning
389      * of a block statement,
390      * then the gap is inserted within that block.
391      *
392      * @param pos the index at which a gap is inserted.
393      * @param length gap length.
394      * @return the length of the inserted gap.
395      * It might be bigger than <code>length</code>.
396      */

397     public int insertGap(int pos, int length) throws BadBytecode {
398         return insertGapCore(pos, length, false);
399     }
400
401     /**
402      * Inserts an exclusive gap
403      * before the next instruction that would be returned by
404      * <code>next()</code> (not before the instruction returned
405      * by tha last call to <code>next()</code>).
406      * Branch offsets and the exception table are also updated.
407      * The inserted gap is filled with NOP. The gap length may be
408      * extended to a multiple of 4.
409      *
410      * <p>If the next instruction is at the beginning of a block statement,
411      * then the gap is excluded from that block.
412      *
413      * @param length gap length
414      * @return the index indicating the first byte of the inserted gap.
415      */

416     public int insertExGap(int length) throws BadBytecode {
417         int pos = currentPos;
418         insertGapCore(currentPos, length, true);
419         return pos;
420     }
421
422     /**
423      * Inserts an exclusive gap in front of the instruction at the given
424      * index <code>pos</code>.
425      * Branch offsets and the exception table are also updated.
426      * The inserted gap is filled with NOP. The gap length may be
427      * extended to a multiple of 4.
428      *
429      * <p>If the instruction at the given index is at the beginning
430      * of a block statement,
431      * then the gap is excluded from that block.
432      *
433      * @param pos the index at which a gap is inserted.
434      * @param length gap length.
435      * @return the length of the inserted gap.
436      * It might be bigger than <code>length</code>.
437      */

438     public int insertExGap(int pos, int length) throws BadBytecode {
439         return insertGapCore(pos, length, true);
440     }
441
442     /**
443      * @return the length of the really inserted gap.
444      */

445     private int insertGapCore(int pos, int length, boolean exclusive)
446         throws BadBytecode
447     {
448         if (length <= 0)
449             return 0;
450
451         int cur = currentPos;
452         byte[] c = insertGap(bytecode, pos, length, exclusive,
453                              get().getExceptionTable(), codeAttr);
454         int length2 = c.length - bytecode.length;
455         if (cur >= pos)
456             currentPos = cur + length2;
457
458         codeAttr.setCode(c);
459         bytecode = c;
460         endPos = getCodeLength();
461         return length2;
462     }
463
464     /**
465      * Copies and inserts the entries in the given exception table
466      * at the beginning of the exception table in the code attribute
467      * edited by this object.
468      *
469      * @param offset the value added to the code positions included
470      * in the entries.
471      */

472     public void insert(ExceptionTable et, int offset) {
473         codeAttr.getExceptionTable().add(0, et, offset);
474     }
475
476     /**
477      * Appends the given bytecode sequence at the end.
478      *
479      * @param code the bytecode appended.
480      * @return the position of the first byte of the appended bytecode.
481      */

482     public int append(byte[] code) {
483         int size = getCodeLength();
484         int len = code.length;
485         if (len <= 0)
486             return size;
487
488         appendGap(len);
489         byte[] dest = bytecode;
490         for (int i = 0; i < len; ++i)
491             dest[i + size] = code[i];
492
493         return size;
494     }
495
496     /**
497      * Appends a gap at the end of the bytecode sequence.
498      *
499      * @param gapLength gap length
500      */

501     public void appendGap(int gapLength) {
502         byte[] code = bytecode;
503         int codeLength = code.length;
504         byte[] newcode = new byte[codeLength + gapLength];
505
506         int i;
507         for (i = 0; i < codeLength; ++i)
508             newcode[i] = code[i];
509
510         for (i = codeLength; i < codeLength + gapLength; ++i)
511             newcode[i] = NOP;
512
513         codeAttr.setCode(newcode);
514         bytecode = newcode;
515         endPos = getCodeLength();
516     }
517
518     /**
519      * Copies and appends the entries in the given exception table
520      * at the end of the exception table in the code attribute
521      * edited by this object.
522      *
523      * @param offset the value added to the code positions included
524      * in the entries.
525      */

526     public void append(ExceptionTable et, int offset) {
527         ExceptionTable table = codeAttr.getExceptionTable();
528         table.add(table.size(), et, offset);
529     }
530
531     /* opcodeLegth is used for implementing nextOpcode().
532      */

533     private static final int opcodeLength[] = {
534         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3,
535         3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
536         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1,
537         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
538         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
539         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
540         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
541         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
542         3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
543         3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
544         5, 5
545     };
546     // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE
547

548     /**
549      * Calculates the index of the next opcode.
550      */

551     static int nextOpcode(byte[] code, int index)
552         throws BadBytecode
553     {
554         int opcode;
555         try {
556             opcode = code[index] & 0xff;
557         }
558         catch (IndexOutOfBoundsException JavaDoc e) {
559             throw new BadBytecode("invalid opcode address");
560         }
561
562         try {
563             int len = opcodeLength[opcode];
564             if (len > 0)
565                 return index + len;
566             else if (opcode == WIDE)
567                 if (code[index + 1] == (byte)IINC) // WIDE IINC
568
return index + 6;
569                 else
570                     return index + 4; // WIDE ...
571
else {
572                 int index2 = (index & ~3) + 8;
573                 if (opcode == LOOKUPSWITCH) {
574                     int npairs = ByteArray.read32bit(code, index2);
575                     return index2 + npairs * 8 + 4;
576                 }
577                 else if (opcode == TABLESWITCH) {
578                     int low = ByteArray.read32bit(code, index2);
579                     int high = ByteArray.read32bit(code, index2 + 4);
580                     return index2 + (high - low + 1) * 4 + 8;
581                 }
582                 // else
583
// throw new BadBytecode(opcode);
584
}
585         }
586         catch (IndexOutOfBoundsException JavaDoc e) {
587         }
588
589         // opcode is UNUSED or an IndexOutOfBoundsException was thrown.
590
throw new BadBytecode(opcode);
591     }
592
593     // methods for implementing insertGap().
594

595     /* If "where" is the beginning of a block statement, then the inserted
596      * gap is also included in the block statement.
597      * "where" must indicate the first byte of an opcode.
598      * The inserted gap is filled with NOP. gapLength may be extended to
599      * a multiple of 4.
600      */

601     static byte[] insertGap(byte[] code, int where, int gapLength,
602                 boolean exclusive, ExceptionTable etable, CodeAttribute ca)
603         throws BadBytecode
604     {
605         if (gapLength <= 0)
606             return code;
607
608         try {
609             return insertGap0(code, where, gapLength, exclusive, etable, ca);
610         }
611         catch (AlignmentException e) {
612             try {
613                 return insertGap0(code, where, (gapLength + 3) & ~3,
614                                   exclusive, etable, ca);
615             }
616             catch (AlignmentException e2) {
617                 throw new RuntimeException JavaDoc("fatal error?");
618             }
619         }
620     }
621
622     private static byte[] insertGap0(byte[] code, int where, int gapLength,
623                                 boolean exclusive, ExceptionTable etable,
624                                 CodeAttribute ca)
625         throws BadBytecode, AlignmentException
626     {
627         int codeLength = code.length;
628         byte[] newcode = new byte[codeLength + gapLength];
629         insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
630         etable.shiftPc(where, gapLength, exclusive);
631         LineNumberAttribute na
632             = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
633         if (na != null)
634             na.shiftPc(where, gapLength, exclusive);
635
636         LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
637                                                 LocalVariableAttribute.tag);
638         if (va != null)
639             va.shiftPc(where, gapLength, exclusive);
640
641         LocalVariableAttribute vta
642             = (LocalVariableAttribute)ca.getAttribute(
643                                               LocalVariableAttribute.typeTag);
644         if (vta != null)
645             vta.shiftPc(where, gapLength, exclusive);
646
647         return newcode;
648     }
649
650     private static void insertGap2(byte[] code, int where, int gapLength,
651                         int endPos, byte[] newcode, boolean exclusive)
652         throws BadBytecode, AlignmentException
653     {
654         int nextPos;
655         int i = 0;
656         int j = 0;
657         for (; i < endPos; i = nextPos) {
658             if (i == where) {
659                 int j2 = j + gapLength;
660                 while (j < j2)
661                     newcode[j++] = NOP;
662             }
663
664             nextPos = nextOpcode(code, i);
665             int inst = code[i] & 0xff;
666             // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
667
if ((153 <= inst && inst <= 168)
668                 || inst == IFNULL || inst == IFNONNULL) {
669                 /* 2bytes *signed* offset */
670                 int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
671                 offset = newOffset(i, offset, where, gapLength, exclusive);
672                 newcode[j] = code[i];
673                 ByteArray.write16bit(offset, newcode, j + 1);
674                 j += 3;
675             }
676             else if (inst == GOTO_W || inst == JSR_W) {
677                 /* 4bytes offset */
678                 int offset = ByteArray.read32bit(code, i + 1);
679                 offset = newOffset(i, offset, where, gapLength, exclusive);
680                 newcode[j++] = code[i];
681                 ByteArray.write32bit(offset, newcode, j);
682                 j += 4;
683             }
684             else if (inst == TABLESWITCH) {
685                 if (i != j && (gapLength & 3) != 0)
686                     throw new AlignmentException();
687
688                 int i0 = i;
689                 int i2 = (i & ~3) + 4; // 0-3 byte padding
690
while (i0 < i2)
691                     newcode[j++] = code[i0++];
692
693                 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
694                                             where, gapLength, exclusive);
695                 ByteArray.write32bit(defaultbyte, newcode, j);
696                 int lowbyte = ByteArray.read32bit(code, i2 + 4);
697                 ByteArray.write32bit(lowbyte, newcode, j + 4);
698                 int highbyte = ByteArray.read32bit(code, i2 + 8);
699                 ByteArray.write32bit(highbyte, newcode, j + 8);
700                 j += 12;
701                 i0 = i2 + 12;
702                 i2 = i0 + (highbyte - lowbyte + 1) * 4;
703                 while (i0 < i2) {
704                     int offset = newOffset(i, ByteArray.read32bit(code, i0),
705                                            where, gapLength, exclusive);
706                     ByteArray.write32bit(offset, newcode, j);
707                     j += 4;
708                     i0 += 4;
709                 }
710             }
711             else if (inst == LOOKUPSWITCH) {
712                 if (i != j && (gapLength & 3) != 0)
713                     throw new AlignmentException();
714
715                 int i0 = i;
716                 int i2 = (i & ~3) + 4; // 0-3 byte padding
717
while (i0 < i2)
718                     newcode[j++] = code[i0++];
719
720                 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
721                                             where, gapLength, exclusive);
722                 ByteArray.write32bit(defaultbyte, newcode, j);
723                 int npairs = ByteArray.read32bit(code, i2 + 4);
724                 ByteArray.write32bit(npairs, newcode, j + 4);
725                 j += 8;
726                 i0 = i2 + 8;
727                 i2 = i0 + npairs * 8;
728                 while (i0 < i2) {
729                     ByteArray.copy32bit(code, i0, newcode, j);
730                     int offset = newOffset(i,
731                                         ByteArray.read32bit(code, i0 + 4),
732                                         where, gapLength, exclusive);
733                     ByteArray.write32bit(offset, newcode, j + 4);
734                     j += 8;
735                     i0 += 8;
736                 }
737             }
738             else
739                 while (i < nextPos)
740                     newcode[j++] = code[i++];
741             }
742     }
743
744     private static int newOffset(int i, int offset, int where,
745                                  int gapLength, boolean exclusive) {
746         int target = i + offset;
747         if (i < where) {
748             if (where < target || (exclusive && where == target))
749                 offset += gapLength;
750         }
751         else
752             if (target < where || (!exclusive && where == target))
753                 offset -= gapLength;
754
755         return offset;
756     }
757 }
758
759
760 class AlignmentException extends Exception JavaDoc {
761 }
762
Popular Tags