==== Patch <wide-branches> level 1
Source: 1adc4bfb-2c32-0410-81b9-bf0f0eac59bd:/wide-branch:74430
Target: 737f8f2c-97f8-0310-ac9b-cfac8cc1a2f5:/eng/third-party/janino/trunk:72599
        (svn+ssh://svn.streambase.com/repos/sb)
Log:
 r74429@spiceweasel:  fowles | 2008-05-22 14:13:25 -0400
 creating a branch to pull out the 32K vs 64K branch work
 
 r74430@spiceweasel:  fowles | 2008-05-22 14:24:56 -0400
 implement branching across >16K
 

=== tests/src/EvaluatorTests.java
==================================================================
--- tests/src/EvaluatorTests.java	(revision 72599)
+++ tests/src/EvaluatorTests.java	(patch wide-branches level 1)
@@ -54,6 +54,7 @@
         s.addTest(new EvaluatorTests("testAssertNotCooked"));
         s.addTest(new EvaluatorTests("testAccessingCompilingClass"));
         s.addTest(new EvaluatorTests("testProtectedAccessToParentSuperClassVar"));
+        s.addTest(new EvaluatorTests("test32kBranchLimit"));
         return s;
     }
 
@@ -264,4 +265,42 @@
                 "}"
         );
     }
+    
+    public void test32kBranchLimit() throws Exception {
+        String preamble =
+            "package test;\n" +
+            "public class Test {\n" +
+            "    public int run() {\n" +
+            "        int res = 0;\n" +
+            "        for(int i = 0; i < 2; ++i) {\n";
+        String middle =
+            "            ++res;\n";
+        String postamble =
+            "        }\n" +
+            "        return res;\n" +
+            "    }\n" +
+            "}";
+        
+        int[] tests = new int[] { 1, 10, 100, Short.MAX_VALUE/5, Short.MAX_VALUE/4, Short.MAX_VALUE/2 };
+        for(int i = 0; i < tests.length; ++i) {
+            int repititions = tests[i];
+            
+            StringBuilder sb = new StringBuilder();
+            sb.append(preamble);
+            for(int j = 0; j < repititions; ++j) {
+                sb.append(middle);
+            }
+            sb.append(postamble);
+            
+            SimpleCompiler sc = new SimpleCompiler();
+            sc.cook(sb.toString());
+            
+            Class c = sc.getClassLoader().loadClass("test.Test");
+            Method m = c.getDeclaredMethod("run", null);
+            Object o = c.newInstance();
+            Object res = m.invoke(o, null);
+            assertEquals(Integer.valueOf(2*repititions), res);
+        }
+        
+    }
 }
=== src/org/codehaus/janino/UnitCompiler.java
==================================================================
--- src/org/codehaus/janino/UnitCompiler.java	(revision 72599)
+++ src/org/codehaus/janino/UnitCompiler.java	(patch wide-branches level 1)
@@ -1691,12 +1691,8 @@
         // Don't continue code attribute generation if we had compile errors.
         if (this.compileErrorCount > 0) return;
 
-        // Fix up.
-        codeContext.fixUp();
+        codeContext.fixUpAndRelocate();
 
-        // Relocate.
-        codeContext.relocate();
-
         // Do flow analysis.
         if (UnitCompiler.DEBUG) {
             try {
=== src/org/codehaus/janino/CodeContext.java
==================================================================
--- src/org/codehaus/janino/CodeContext.java	(revision 72599)
+++ src/org/codehaus/janino/CodeContext.java	(patch wide-branches level 1)
@@ -34,8 +34,15 @@
 
 package org.codehaus.janino;
 
-import java.io.*;
-import java.util.*;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
 
 import org.codehaus.janino.util.ClassFile;
 
@@ -137,8 +144,8 @@
     ) throws IOException {
         dos.writeShort(this.maxStack);                     // max_stack
         dos.writeShort(this.maxLocals);                    // max_locals
-        dos.writeInt(0xffff & this.end.offset);            // code_length
-        dos.write(this.code, 0, 0xffff & this.end.offset); // code
+        dos.writeInt(this.end.offset);            // code_length
+        dos.write(this.code, 0, this.end.offset); // code
         dos.writeShort(this.exceptionTableEntries.size());        // exception_table_length
         for (int i = 0; i < this.exceptionTableEntries.size(); ++i) { // exception_table
             ExceptionTableEntry exceptionTableEntry = (ExceptionTableEntry) this.exceptionTableEntries.get(i);
@@ -178,14 +185,18 @@
      * Notice: On inconsistencies, a "RuntimeException" is thrown (KLUDGE).
      */
     public void flowAnalysis(String functionName) {
-        byte[] stackSizes = new byte[0xffff & this.end.offset];
+        if(CodeContext.DEBUG) { 
+            System.err.println("flowAnalysis(" + functionName + ")"); 
+        }
+        
+        byte[] stackSizes = new byte[this.end.offset];
         Arrays.fill(stackSizes, CodeContext.UNEXAMINED);
 
         // Analyze flow from offset zero.
         this.flowAnalysis(
             functionName,
             this.code,                // code
-            0xffff & this.end.offset, // codeSize
+            this.end.offset, // codeSize
             0,                        // offset
             0,                        // stackSize
             stackSizes                // stackSizes
@@ -196,13 +207,13 @@
         while (analyzedExceptionHandlers != this.exceptionTableEntries.size()) {
             for (int i = 0; i < this.exceptionTableEntries.size(); ++i) {
                 ExceptionTableEntry exceptionTableEntry = (ExceptionTableEntry) this.exceptionTableEntries.get(i);
-                if (stackSizes[0xffff & exceptionTableEntry.startPC.offset] != CodeContext.UNEXAMINED) {
+                if (stackSizes[exceptionTableEntry.startPC.offset] != CodeContext.UNEXAMINED) {
                     this.flowAnalysis(
                         functionName,         
                         this.code,                                                   // code
-                        0xffff & this.end.offset,                                    // codeSize
-                        0xffff & exceptionTableEntry.handlerPC.offset,               // offset
-                        stackSizes[0xffff & exceptionTableEntry.startPC.offset] + 1, // stackSize
+                        this.end.offset,                                    // codeSize
+                        exceptionTableEntry.handlerPC.offset,               // offset
+                        stackSizes[exceptionTableEntry.startPC.offset] + 1, // stackSize
                         stackSizes                                                   // stackSizes
                     );
                     ++analyzedExceptionHandlers;
@@ -287,7 +298,7 @@
                 /* FALL THROUGH */
             case Opcode.SD_GETSTATIC:
                 stackSize += this.determineFieldSize((short) (
-                    (code[operandOffset] << 8) + (0xff & code[operandOffset + 1])
+                    extract16BitValue(0, operandOffset, code)
                 ));
                 break;
 
@@ -296,7 +307,7 @@
                 /* FALL THROUGH */
             case Opcode.SD_PUTSTATIC:
                 stackSize -= this.determineFieldSize((short) (
-                    (code[operandOffset] << 8) + (0xff & code[operandOffset + 1])
+                    extract16BitValue(0, operandOffset, code)
                 ));
                 break;
 
@@ -307,7 +318,7 @@
                 /* FALL THROUGH */
             case Opcode.SD_INVOKESTATIC:
                 stackSize -= this.determineArgumentsSize((short) (
-                    (code[operandOffset] << 8) + (0xff & code[operandOffset + 1])
+                    extract16BitValue(0, operandOffset, code)
                 ));
                 break;
 
@@ -368,13 +379,11 @@
                 this.flowAnalysis(
                     functionName,
                     code, codeSize,
-                    offset + (
-                        ((       code[operandOffset++]) << 8) +
-                        ((0xff & code[operandOffset++])     )
-                    ),
+                    extract16BitValue(offset, operandOffset, code),
                     stackSize,
                     stackSizes
                 );
+                operandOffset += 2;
                 break;
 
             case Opcode.OP1_JSR:
@@ -384,10 +393,8 @@
                     System.out.println(code[operandOffset]);
                     System.out.println(code[operandOffset + 1]);
                 }
-                int targetOffset = offset + (
-                    ((       code[operandOffset++]) << 8) +
-                    ((0xff & code[operandOffset++])     )
-                );
+                int targetOffset = extract16BitValue(offset, operandOffset, code);
+                operandOffset += 2;
                 if (stackSizes[targetOffset] == CodeContext.UNEXAMINED) {
                     this.flowAnalysis(
                         functionName,
@@ -403,14 +410,10 @@
                 this.flowAnalysis(
                     functionName,
                     code, codeSize,
-                    offset + (
-                        ((       code[operandOffset++]) << 24) +
-                        ((0xff & code[operandOffset++]) << 16) +
-                        ((0xff & code[operandOffset++]) <<  8) +
-                        ((0xff & code[operandOffset++])      )
-                    ),
+                    extract32BitValue(offset, operandOffset, code),
                     stackSize, stackSizes
                 );
+                operandOffset += 4;
                 break;
 
             case Opcode.OP1_LOOKUPSWITCH:
@@ -418,33 +421,23 @@
                 this.flowAnalysis(
                     functionName,
                     code, codeSize,
-                    offset + (
-                        ((       code[operandOffset++]) << 24) +
-                        ((0xff & code[operandOffset++]) << 16) +
-                        ((0xff & code[operandOffset++]) <<  8) +
-                        ((0xff & code[operandOffset++])      )
-                    ),
+                    extract32BitValue(offset, operandOffset, code),
                     stackSize, stackSizes
                 );
-                int npairs = (
-                    ((       code[operandOffset++]) << 24) +
-                    ((0xff & code[operandOffset++]) << 16) +
-                    ((0xff & code[operandOffset++]) <<  8) +
-                    ((0xff & code[operandOffset++])      )
-                );
+                operandOffset += 4;
+                
+                int npairs = extract32BitValue(0, operandOffset, code);
+                operandOffset += 4;
+                
                 for (int i = 0; i < npairs; ++i) {
-                    operandOffset += 4;
+                    operandOffset += 4; //skip match value
                     this.flowAnalysis(
                         functionName,
                         code, codeSize,
-                        offset + (
-                            ((       code[operandOffset++]) << 24) +
-                            ((0xff & code[operandOffset++]) << 16) +
-                            ((0xff & code[operandOffset++]) <<  8) +
-                            ((0xff & code[operandOffset++])      )
-                        ),
+                        extract32BitValue(offset, operandOffset, code),
                         stackSize, stackSizes
                     );
+                    operandOffset += 4; //advance over offset
                 }
                 break;
 
@@ -453,38 +446,22 @@
                 this.flowAnalysis(
                     functionName,
                     code, codeSize,
-                    offset + (
-                        ((       code[operandOffset++]) << 24) +
-                        ((0xff & code[operandOffset++]) << 16) +
-                        ((0xff & code[operandOffset++]) <<  8) +
-                        ((0xff & code[operandOffset++])      )
-                    ),
+                    extract32BitValue(offset, operandOffset, code),
                     stackSize, stackSizes
                 );
-                int low = (
-                    ((       code[operandOffset++]) << 24) +
-                    ((0xff & code[operandOffset++]) << 16) +
-                    ((0xff & code[operandOffset++]) <<  8) +
-                    ((0xff & code[operandOffset++])      )
-                );
-                int hi = (
-                    ((       code[operandOffset++]) << 24) +
-                    ((0xff & code[operandOffset++]) << 16) +
-                    ((0xff & code[operandOffset++]) <<  8) +
-                    ((0xff & code[operandOffset++])      )
-                );
+                operandOffset += 4;
+                int low = extract32BitValue(offset, operandOffset, code);
+                operandOffset += 4;
+                int hi = extract32BitValue(offset, operandOffset, code);
+                operandOffset += 4;
                 for (int i = low; i <= hi; ++i) {
                     this.flowAnalysis(
                         functionName,
                         code, codeSize,
-                        offset + (
-                            ((       code[operandOffset++]) << 24) +
-                            ((0xff & code[operandOffset++]) << 16) +
-                            ((0xff & code[operandOffset++]) <<  8) +
-                            ((0xff & code[operandOffset++])      )
-                        ),
+                        extract32BitValue(offset, operandOffset, code),
                         stackSize, stackSizes
                     );
+                    operandOffset += 4;
                 }
                 break;
 
@@ -530,20 +507,93 @@
             offset = operandOffset;
         }
     }
+    
+    /**
+     * Extract a 16 bit value at offset in code and add bias to it
+     * @param bias    an int to skew the final result by (useful for calculating relative offsets)
+     * @param offset  the position in the code array to extract the bytes from
+     * @param code    the array of bytes
+     * @return an integer that treats the two bytes at position offset as an UNSIGNED SHORT
+     */
+    private int extract16BitValue(int bias, int offset, byte[] code) {
+        int res = bias + (
+                ((       code[offset  ]) << 8) +
+                ((0xff & code[offset+1])     )
+        );
+        if (CodeContext.DEBUG) {
+            System.out.println("extract16BitValue(bias, offset) = (" + bias +", " + offset + ")");
+            System.out.println("bytes = {" + code[offset] + ", " + code[offset+1] + "}");
+            System.out.println("result = " + res);
+        }
+        return res;
+    }
+    
+    /**
+     * Extract a 32 bit value at offset in code and add bias to it
+     * @param bias    an int to skew the final result by (useful for calculating relative offsets)
+     * @param offset  the position in the code array to extract the bytes from
+     * @param code    the array of bytes
+     * @return the 4 bytes at position offset + bias
+     */
+    private int extract32BitValue(int bias, int offset, byte[] code) {
+        int res = bias + (
+                ((       code[offset  ]) << 24) +
+                ((0xff & code[offset+1]) << 16) +
+                ((0xff & code[offset+2]) <<  8) +
+                ((0xff & code[offset+3])      )
+        );
+        if (CodeContext.DEBUG) {
+            System.out.println("extract32BitValue(bias, offset) = (" + bias +", " + offset + ")");
+            System.out.println(
+                    "bytes = {" + 
+                    code[offset  ] + ", " + 
+                    code[offset+1] + ", " + 
+                    code[offset+2] + ", " + 
+                    code[offset+3] + "}"
+            );
+            System.out.println("result = " + res);
+        }
+        return res;
+    }
+    
+    /**
+     * fixUp() all of the offsets and relocate() all relocatables
+     */
+    public void fixUpAndRelocate() {
+        //we do this in a loop to allow relocatables to adjust the size
+        //of things in the byte stream.  It is extremely unlikely, but possible
+        //that a late relocatable will grow the size of the bytecode, and require
+        //an earlier relocatable to switch from 32K mode to 64K mode branching
+        boolean finished = false;
+        while(!finished) {
+            fixUp();
+            finished = relocate();
+        }
+    }
 
     /**
      * Fix up all offsets.
      */
-    public void fixUp() {
+    private void fixUp() {
         for (Offset o = this.beginning; o != this.end; o = o.next) {
             if (o instanceof FixUp) ((FixUp) o).fixUp();
         }
     }
 
-    public void relocate() {
+    /**
+     * Relocate all relocatables and aggregate their response into a single one
+     * @return true if all of them relocated successfully
+     *         false if any of them needed to change size
+     */
+    private boolean relocate() {
+        boolean finished = true;
         for (int i = 0; i < this.relocatables.size(); ++i) {
-            ((Relocatable) this.relocatables.get(i)).relocate();
+            //do not terminate earlier so that everything gets a chance to grow in the first pass
+            //changes the common case for this to be O(n) instead of O(n**2)
+            boolean part =  ((Relocatable) this.relocatables.get(i)).relocate();
+            finished = finished && part;
         }
+        return finished;
     }
 
     /**
@@ -627,15 +677,15 @@
             this.currentInserter.prev = lno;
         }
 
-        int ico = 0xffff & this.currentInserter.offset;
-        if ((0xffff & this.end.offset) + b.length <= this.code.length) {
-            System.arraycopy(this.code, ico, this.code, ico + b.length, (0xffff & this.end.offset) - ico);
+        int ico = this.currentInserter.offset;
+        if (this.end.offset + b.length <= this.code.length) {
+            System.arraycopy(this.code, ico, this.code, ico + b.length, this.end.offset - ico);
         } else {
             byte[] oldCode = this.code;
             this.code = new byte[this.code.length + CodeContext.SIZE_INCREMENT];
             if (this.code.length >= 0xffff) throw new RuntimeException("Code attribute in class \"" + this.classFile.getThisClassName() + "\" grows beyond 64 KB");
             System.arraycopy(oldCode, 0, this.code, 0, ico);
-            System.arraycopy(oldCode, ico, this.code, ico + b.length, (0xffff & this.end.offset) - ico);
+            System.arraycopy(oldCode, ico, this.code, ico + b.length, this.end.offset - ico);
         }
         System.arraycopy(b, 0, this.code, ico, b.length);
         for (Offset o = this.currentInserter; o != null; o = o.next) o.offset += b.length;
@@ -652,23 +702,123 @@
      * @param lineNumber The line number that corresponds to the byte code, or -1
      */
     public void writeBranch(short lineNumber, int opcode, final Offset dst) {
-        this.relocatables.add(new Branch(this.newOffset(), dst));
+        this.relocatables.add(new Branch(opcode, dst));
         this.write(lineNumber, new byte[] { (byte) opcode, -1, -1 });
     }
 
+    private static final Map EXPANDED_BRANCH_OPS = new HashMap(); // Map<Byte, Byte>
+    static {
+        //comparisons expand by doing a negated jump as follows:
+        //  [if cond offset]
+        //expands to 
+        //  [if !cond skip_goto]
+        //  [GOTO_W offset]
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ACMPEQ), Byte.valueOf(Opcode.IF_ACMPNE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ACMPNE), Byte.valueOf(Opcode.IF_ACMPEQ)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPEQ), Byte.valueOf(Opcode.IF_ICMPNE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPNE), Byte.valueOf(Opcode.IF_ICMPEQ)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPGE), Byte.valueOf(Opcode.IF_ICMPLT)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPLT), Byte.valueOf(Opcode.IF_ICMPGE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPGT), Byte.valueOf(Opcode.IF_ICMPLE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IF_ICMPLE), Byte.valueOf(Opcode.IF_ICMPGT)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFEQ), Byte.valueOf(Opcode.IFNE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFNE), Byte.valueOf(Opcode.IFEQ)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFGE), Byte.valueOf(Opcode.IFLT)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFLT), Byte.valueOf(Opcode.IFGE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFGT), Byte.valueOf(Opcode.IFLE)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFLE), Byte.valueOf(Opcode.IFGT)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFNULL), Byte.valueOf(Opcode.IFNONNULL)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.IFNONNULL), Byte.valueOf(Opcode.IFNULL));
+        
+        // these merely expand to their wide version
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.GOTO), Byte.valueOf(Opcode.GOTO_W)); 
+        EXPANDED_BRANCH_OPS.put(Byte.valueOf(Opcode.JSR), Byte.valueOf(Opcode.JSR_W)); 
+    }
+
     private class Branch extends Relocatable {
-        public Branch(Offset source, Offset destination) {
-            this.source = source;
+        public Branch(int opcode, Offset destination) {
+            this.opcode = opcode;
+            this.source = CodeContext.this.newInserter();
             this.destination = destination;
+            if(opcode == Opcode.JSR_W || opcode == Opcode.GOTO_W) {
+                //no need to expand wide opcodes
+                this.expanded = true;
+            } else { 
+                this.expanded = false;
         }
-        public void relocate() {
+        }
+        
+        public boolean relocate() {
             if (this.destination.offset == Offset.UNSET) throw new RuntimeException("Cannot relocate branch to unset destination offset");
             int offset = this.destination.offset - this.source.offset;
-            if (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE) throw new RuntimeException("Branch offset out of range");
-            byte[] ba = new byte[] { (byte) (offset >> 8), (byte) offset };
-            System.arraycopy(ba, 0, CodeContext.this.code, (0xffff & this.source.offset) + 1, 2);
+            
+            if (!expanded && (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)) {
+                //we want to insert the data without skewing our source position,
+                //so we will cache it and then restore it later.
+                int pos = this.source.offset; 
+                CodeContext.this.pushInserter(source); {
+                    // promotion to a wide instruction only requires 2 extra bytes 
+                    // everything else requires a new GOTO_W instruction after a negated if
+                    CodeContext.this.write(
+                            (short) -1, 
+                            new byte[opcode == Opcode.GOTO ? 2 : 
+                                     opcode == Opcode.JSR ? 2 :
+                                     5]
+                    );
+                } CodeContext.this.popInserter();
+                this.source.offset = pos;
+                expanded = true;
+                return false;
+            }
+            
+            final byte[] ba;
+            if(!expanded) {
+                //we fit in a 16-bit jump
+                ba = new byte[] { (byte)opcode, (byte) (offset >> 8), (byte) offset };
+            } else {
+                byte inverted = ((Byte)CodeContext.EXPANDED_BRANCH_OPS.get(
+                        Byte.valueOf((byte)opcode))
+                ).byteValue();
+                if(opcode == Opcode.GOTO || opcode == Opcode.JSR) {
+                    //  [GOTO offset]
+                    //expands to 
+                    //  [GOTO_W offset]
+                    ba = new byte[] { 
+                            (byte) inverted,
+                            (byte) (offset >> 24), 
+                            (byte) (offset >> 16), 
+                            (byte) (offset >> 8), 
+                            (byte) offset 
+                    };
+                } else {
+                    //exclude the if-statement from jump target
+                    //if jumping backwards this will increase the jump to go over it
+                    //if jumping forwards this will decrease the jump by it
+                    offset -= 3;
+                            
+                    //  [if cond offset]
+                    //expands to 
+                    //  [if !cond skip_goto]
+                    //  [GOTO_W offset]
+                    ba = new byte[] { 
+                            (byte) inverted,
+                            (byte) 0,
+                            (byte) 8, //jump from this instruction past the GOTO_W
+                            (byte) Opcode.GOTO_W, 
+                            (byte) (offset >> 24), 
+                            (byte) (offset >> 16), 
+                            (byte) (offset >> 8), 
+                            (byte) offset 
+                    };
+                }
+            }
+            System.arraycopy(ba, 0, CodeContext.this.code, this.source.offset, ba.length);
+            return true;
         }
-        private final Offset source;
+        
+        private boolean expanded; //marks whether this has been expanded to account for a wide branch
+        private final int opcode;
+        private final Inserter source;
         private final Offset destination;
     }
 
@@ -683,7 +833,7 @@
             this.source      = source;
             this.destination = destination;
         }
-        public void relocate() {
+        public boolean relocate() {
             if (
                 this.source.offset == Offset.UNSET ||
                 this.destination.offset == Offset.UNSET
@@ -695,7 +845,8 @@
                 (byte) (offset >> 8),
                 (byte) offset
             };
-            System.arraycopy(ba, 0, CodeContext.this.code, 0xffff & this.where.offset, 4);
+            System.arraycopy(ba, 0, CodeContext.this.code, this.where.offset, 4);
+            return true;
         }
         private final Offset where, source, destination;
     }
@@ -755,9 +906,9 @@
      * automatically shifted.
      */
     public class Offset {
-        short              offset = Offset.UNSET;
+        int              offset = Offset.UNSET;
         Offset             prev = null, next = null;
-        final static short UNSET = -1;
+        final static int UNSET = -1;
 
         /**
          * Set this "Offset" to the offset of the current inserter; insert
@@ -776,7 +927,7 @@
         public final CodeContext getCodeContext() { return CodeContext.this; }
 
         public String toString() {
-            return CodeContext.this.classFile.getThisClassName() + ": " + (0xffff & this.offset);
+            return CodeContext.this.classFile.getThisClassName() + ": " + this.offset;
         }
     }
 
@@ -830,15 +981,20 @@
     }
 
     public class LineNumberOffset extends Offset {
-        private final short lineNumber;
-        public LineNumberOffset(short offset, short lineNumber) {
+        private final int lineNumber;
+        public LineNumberOffset(int offset, int lineNumber) {
             this.lineNumber = lineNumber;
             this.offset = offset;
         }
     }
 
     private abstract class Relocatable {
-        public abstract void relocate();
+        /**
+         * Relocate this object.
+         * @return true if the relocation succeeded in place
+         *         false if the relocation grew the number of bytes required
+         */
+        public abstract boolean relocate();
     }
 
     private short       localVariableArrayLength = 0;
=== src/org/codehaus/janino/util/ClassFile.java
==================================================================
--- src/org/codehaus/janino/util/ClassFile.java	(revision 72599)
+++ src/org/codehaus/janino/util/ClassFile.java	(patch wide-branches level 1)
@@ -1334,8 +1334,8 @@
         }
 
         public static class Entry {
-            public final short startPC, lineNumber;
-            public Entry(short startPC, short lineNumber) {
+            public final int startPC, lineNumber;
+            public Entry(int startPC, int lineNumber) {
                 this.startPC    = startPC;
                 this.lineNumber = lineNumber;
             }

==== BEGIN SVK PATCH BLOCK ====
Version: svk v2.0.2 (linux)

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
==== END SVK PATCH BLOCK ====

