diff src/com/go/trove/classfile/CodeDisassembler.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/go/trove/classfile/CodeDisassembler.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,1584 @@
+/* ====================================================================
+ * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
+ * ====================================================================
+ * The Tea Software License, Version 1.1
+ *
+ * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Walt Disney Internet Group (http://opensource.go.com/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact opensource@dig.com.
+ *
+ * 5. Products derived from this software may not be called "Tea",
+ *    "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
+ *    "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
+ *    written permission of the Walt Disney Internet Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * For more information about Tea, please see http://opensource.go.com/.
+ */
+
+package com.go.trove.classfile;
+
+import java.util.*;
+
+/******************************************************************************
+ * 
+ * @author Brian S O'Neill
+ * @version
+ * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/27 <!-- $-->
+ */
+public class CodeDisassembler {
+    private final MethodInfo mMethod;
+    private final String mEnclosingClassName;
+    private final String mSuperClassName;
+    private final CodeAttr mCode;
+    private final ConstantPool mCp;
+    private final byte[] mByteCodes;
+    private final ExceptionHandler[] mExceptionHandlers;
+
+    // Current CodeAssembler in use for disassembly.
+    private CodeAssembler mAssembler;
+
+    // List of all the LocalVariable objects in use.
+    private Vector mLocals;
+
+    // True if the method being decompiled still has a "this" reference.
+    private boolean mHasThis;
+
+    // Maps Integer address keys to itself, but to Label objects after first
+    // needed.
+    private Map mLabels;
+
+    // Maps Integer catch locations to Lists of ExceptionHandler objects.
+    private Map mCatchLocations;
+
+    // Current address being decompiled.
+    private int mAddress;
+
+    public CodeDisassembler(MethodInfo method) {
+        mMethod = method;
+        mEnclosingClassName = method.getClassFile().getClassName();
+        mSuperClassName = method.getClassFile().getSuperClassName();
+        mCode = method.getCodeAttr();
+        mCp = mCode.getConstantPool();
+        CodeBuffer buffer = mCode.getCodeBuffer();
+        mByteCodes = buffer.getByteCodes();
+        mExceptionHandlers = buffer.getExceptionHandlers();
+    }
+
+    /**
+     * Disassemble the MethodInfo into the given assembler.
+     *
+     * @see CodeAssemblerPrinter
+     */
+    public synchronized void disassemble(CodeAssembler assembler) {
+        mAssembler = assembler;
+        mLocals = new Vector();
+        mHasThis = !mMethod.getAccessFlags().isStatic();
+
+        gatherLabels();
+
+        // Gather the local variables of the parameters.
+        LocalVariable[] paramVars = assembler.getParameters();
+        for (int i=0; i<paramVars.length; i++) {
+            LocalVariable paramVar = paramVars[i];
+            int number = paramVar.getNumber();
+            if (number >= mLocals.size()) {
+                mLocals.setSize(number + 1);
+            }
+            mLocals.setElementAt(paramVar, number);
+        }
+
+        Location currentLoc = new Location() {
+            public int getLocation() {
+                return mAddress;
+            }
+
+            public int compareTo(Object obj) {
+                if (this == obj) {
+                    return 0;
+                }
+                Location other = (Location)obj;
+                
+                int loca = getLocation();
+                int locb = other.getLocation();
+                
+                if (loca < locb) {
+                    return -1;
+                }
+                else if (loca > locb) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        };
+
+        int currentLine = -1;
+
+        for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
+            int nextLine = mCode.getLineNumber(currentLoc);
+            if (nextLine != currentLine) {
+                if ((currentLine = nextLine) >= 0) {
+                    mAssembler.mapLineNumber(currentLine);
+                }
+            }
+
+            // Check if a label needs to be created and/or located.
+            locateLabel();
+
+            byte opcode = mByteCodes[mAddress];
+
+            int index;
+            Location loc;
+            Class clazz;
+            ConstantInfo ci;
+
+            switch (opcode) {
+
+            default:
+                // TODO: raise an error.
+                break;
+
+                // Opcodes with no operands...
+
+            case Opcode.NOP:
+                assembler.nop();
+                break;
+            case Opcode.BREAKPOINT:
+                assembler.breakpoint();
+                break;
+
+            case Opcode.ACONST_NULL:
+                assembler.loadConstant(null);
+                break;
+            case Opcode.ICONST_M1:
+                assembler.loadConstant(-1);
+                break;
+            case Opcode.ICONST_0:
+                assembler.loadConstant(0);
+                break;
+            case Opcode.ICONST_1:
+                assembler.loadConstant(1);
+                break;
+            case Opcode.ICONST_2:
+                assembler.loadConstant(2);
+                break;
+            case Opcode.ICONST_3:
+                assembler.loadConstant(3);
+                break;
+            case Opcode.ICONST_4:
+                assembler.loadConstant(4);
+                break;
+            case Opcode.ICONST_5:
+                assembler.loadConstant(5);
+                break;
+            case Opcode.LCONST_0:
+                assembler.loadConstant(0L);
+                break;
+            case Opcode.LCONST_1:
+                assembler.loadConstant(1L);
+                break;
+            case Opcode.FCONST_0:
+                assembler.loadConstant(0f);
+                break;
+            case Opcode.FCONST_1:
+                assembler.loadConstant(1f);
+                break;
+            case Opcode.FCONST_2:
+                assembler.loadConstant(2f);
+                break;
+            case Opcode.DCONST_0:
+                assembler.loadConstant(0d);
+                break;
+            case Opcode.DCONST_1:
+                assembler.loadConstant(1d);
+                break;
+
+            case Opcode.POP:
+                assembler.pop();
+                break;
+            case Opcode.POP2:
+                assembler.pop2();
+                break;
+            case Opcode.DUP:
+                assembler.dup();
+                break;
+            case Opcode.DUP_X1:
+                assembler.dupX1();
+                break;
+            case Opcode.DUP_X2:
+                assembler.dupX2();
+                break;
+            case Opcode.DUP2:
+                assembler.dup2();
+                break;
+            case Opcode.DUP2_X1:
+                assembler.dup2X2();
+                break;
+            case Opcode.DUP2_X2:
+                assembler.dup2X2();
+                break;
+            case Opcode.SWAP:
+                assembler.swap();
+                break;
+
+            case Opcode.IADD:  case Opcode.LADD: 
+            case Opcode.FADD:  case Opcode.DADD:
+            case Opcode.ISUB:  case Opcode.LSUB:
+            case Opcode.FSUB:  case Opcode.DSUB:
+            case Opcode.IMUL:  case Opcode.LMUL:
+            case Opcode.FMUL:  case Opcode.DMUL:
+            case Opcode.IDIV:  case Opcode.LDIV:
+            case Opcode.FDIV:  case Opcode.DDIV:
+            case Opcode.IREM:  case Opcode.LREM:
+            case Opcode.FREM:  case Opcode.DREM:
+            case Opcode.INEG:  case Opcode.LNEG:
+            case Opcode.FNEG:  case Opcode.DNEG:
+            case Opcode.ISHL:  case Opcode.LSHL:
+            case Opcode.ISHR:  case Opcode.LSHR:
+            case Opcode.IUSHR: case Opcode.LUSHR:
+            case Opcode.IAND:  case Opcode.LAND:
+            case Opcode.IOR:   case Opcode.LOR:
+            case Opcode.IXOR:  case Opcode.LXOR:
+            case Opcode.FCMPL: case Opcode.DCMPL:
+            case Opcode.FCMPG: case Opcode.DCMPG:
+            case Opcode.LCMP: 
+                assembler.math(opcode);
+                break;
+
+            case Opcode.I2L:
+                assembler.convert(int.class, long.class);
+                break;
+            case Opcode.I2F:
+                assembler.convert(int.class, float.class);
+                break;
+            case Opcode.I2D:
+                assembler.convert(int.class, double.class);
+                break;
+            case Opcode.L2I:
+                assembler.convert(long.class, int.class);
+                break;
+            case Opcode.L2F:
+                assembler.convert(long.class, float.class);
+                break;
+            case Opcode.L2D:
+                assembler.convert(long.class, double.class);
+                break;
+            case Opcode.F2I:
+                assembler.convert(float.class, int.class);
+                break;
+            case Opcode.F2L:
+                assembler.convert(float.class, long.class);
+                break;
+            case Opcode.F2D:
+                assembler.convert(float.class, double.class);
+                break;
+            case Opcode.D2I:
+                assembler.convert(double.class, int.class);
+                break;
+            case Opcode.D2L:
+                assembler.convert(double.class, long.class);
+                break;
+            case Opcode.D2F:
+                assembler.convert(double.class, float.class);
+                break;
+            case Opcode.I2B:
+                assembler.convert(int.class, byte.class);
+                break;
+            case Opcode.I2C:
+                assembler.convert(int.class, char.class);
+                break;
+            case Opcode.I2S:
+                assembler.convert(int.class, short.class);
+                break;
+
+            case Opcode.IRETURN:
+                assembler.returnValue(int.class);
+                break;
+            case Opcode.LRETURN:
+                assembler.returnValue(long.class);
+                break;
+            case Opcode.FRETURN:
+                assembler.returnValue(float.class);
+                break;
+            case Opcode.DRETURN:
+                assembler.returnValue(double.class);
+                break;
+            case Opcode.ARETURN:
+                assembler.returnValue(Object.class);
+                break;
+            case Opcode.RETURN:
+                assembler.returnVoid();
+                break;
+
+            case Opcode.IALOAD:
+                assembler.loadFromArray(int.class);
+                break;
+            case Opcode.LALOAD:
+                assembler.loadFromArray(long.class);
+                break;
+            case Opcode.FALOAD:
+                assembler.loadFromArray(float.class);
+                break;
+            case Opcode.DALOAD:
+                assembler.loadFromArray(double.class);
+                break;
+            case Opcode.AALOAD:
+                assembler.loadFromArray(Object.class);
+                break;
+            case Opcode.BALOAD:
+                assembler.loadFromArray(byte.class);
+                break;
+            case Opcode.CALOAD:
+                assembler.loadFromArray(char.class);
+                break;
+            case Opcode.SALOAD:
+                assembler.loadFromArray(short.class);
+                break;
+
+            case Opcode.IASTORE:
+                assembler.storeToArray(int.class);
+                break;
+            case Opcode.LASTORE:
+                assembler.storeToArray(long.class);
+                break;
+            case Opcode.FASTORE:
+                assembler.storeToArray(float.class);
+                break;
+            case Opcode.DASTORE:
+                assembler.storeToArray(double.class);
+                break;
+            case Opcode.AASTORE:
+                assembler.storeToArray(Object.class);
+                break;
+            case Opcode.BASTORE:
+                assembler.storeToArray(byte.class);
+                break;
+            case Opcode.CASTORE:
+                assembler.storeToArray(char.class);
+                break;
+            case Opcode.SASTORE:
+                assembler.storeToArray(short.class);
+                break;
+
+            case Opcode.ARRAYLENGTH:
+                assembler.arrayLength();
+                break;
+            case Opcode.ATHROW:
+                assembler.throwObject();
+                break;
+            case Opcode.MONITORENTER:
+                assembler.monitorEnter();
+                break;
+            case Opcode.MONITOREXIT:
+                assembler.monitorExit();
+                break;
+
+                // End opcodes with no operands.
+
+                // Opcodes that load a constant from the constant pool...
+                
+            case Opcode.LDC:
+            case Opcode.LDC_W:
+            case Opcode.LDC2_W:
+                switch (opcode) {
+                case Opcode.LDC:
+                    index = readUnsignedByte();
+                    break;
+                case Opcode.LDC_W:
+                case Opcode.LDC2_W:
+                    index = readUnsignedShort();
+                    break;
+                default:
+                    index = 0;
+                    break;
+                }
+
+                ci = mCp.getConstant(index);
+
+                if (ci instanceof ConstantStringInfo) {
+                    assembler.loadConstant
+                        (((ConstantStringInfo)ci).getValue());
+                }
+                else if (ci instanceof ConstantIntegerInfo) {
+                    assembler.loadConstant
+                        (((ConstantIntegerInfo)ci).getValue().intValue());
+                }
+                else if (ci instanceof ConstantLongInfo) {
+                    assembler.loadConstant
+                        (((ConstantLongInfo)ci).getValue().longValue());
+                }
+                else if (ci instanceof ConstantFloatInfo) {
+                    assembler.loadConstant
+                        (((ConstantFloatInfo)ci).getValue().floatValue());
+                }
+                else if (ci instanceof ConstantDoubleInfo) {
+                    assembler.loadConstant
+                        (((ConstantDoubleInfo)ci).getValue().doubleValue());
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+
+            case Opcode.NEW:
+                ci = mCp.getConstant(readUnsignedShort());
+
+                if (ci instanceof ConstantClassInfo) {
+                    assembler.newObject
+                        (((ConstantClassInfo)ci).getTypeDescriptor());
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+            case Opcode.ANEWARRAY:
+                ci = mCp.getConstant(readUnsignedShort());
+
+                if (ci instanceof ConstantClassInfo) {
+                    TypeDescriptor type = 
+                        ((ConstantClassInfo)ci).getTypeDescriptor();
+                    type = new TypeDescriptor(type, 1);
+                    assembler.newObject(type);
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+            case Opcode.MULTIANEWARRAY:
+                ci = mCp.getConstant(readUnsignedShort());
+                int dims = readUnsignedByte();
+
+                if (ci instanceof ConstantClassInfo) {
+                    assembler.newObject
+                        (((ConstantClassInfo)ci).getTypeDescriptor());
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+
+            case Opcode.CHECKCAST:
+                ci = mCp.getConstant(readUnsignedShort());
+
+                if (ci instanceof ConstantClassInfo) {
+                    assembler.checkCast
+                        (((ConstantClassInfo)ci).getTypeDescriptor());
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+            case Opcode.INSTANCEOF:
+                ci = mCp.getConstant(readUnsignedShort());
+
+                if (ci instanceof ConstantClassInfo) {
+                    assembler.instanceOf
+                        (((ConstantClassInfo)ci).getTypeDescriptor());
+                }
+                else {
+                    // TODO: raise an error.
+                }
+                break;
+
+            case Opcode.GETSTATIC:
+            case Opcode.PUTSTATIC:
+            case Opcode.GETFIELD:
+            case Opcode.PUTFIELD:
+                ci = mCp.getConstant(readUnsignedShort());
+                if (!(ci instanceof ConstantFieldInfo)) {
+                    // TODO: raise an error.
+                    break;
+                }
+                ConstantFieldInfo field = (ConstantFieldInfo)ci;
+                String className = field.getParentClass().getClassName();
+                if (mEnclosingClassName.equals(className)) {
+                    className = null;
+                }
+                String fieldName = field.getNameAndType().getName();
+                Descriptor type = field.getNameAndType().getType();
+                if (!(type instanceof TypeDescriptor)) {
+                    // TODO: raise an error.
+                    break;
+                }
+
+                // Implementation note: Although it may seem convenient if the
+                // CodeAssembler had methods that accepted ConstantFieldInfo
+                // objects as parameters, it would cause problems because
+                // ConstantPools are not portable between ClassFiles.
+                
+                switch (opcode) {
+                case Opcode.GETSTATIC:
+                    if (className == null) {
+                        assembler.loadStaticField
+                            (fieldName, (TypeDescriptor)type);
+                    }
+                    else {
+                        assembler.loadStaticField
+                            (className, fieldName, (TypeDescriptor)type);
+                    }
+                    break;
+                case Opcode.PUTSTATIC:
+                    if (className == null) {
+                        assembler.storeStaticField
+                            (fieldName, (TypeDescriptor)type);
+                    }
+                    else {
+                        assembler.storeStaticField
+                            (className, fieldName, (TypeDescriptor)type);
+                    }
+                    break;
+                case Opcode.GETFIELD:
+                    if (className == null) {
+                        assembler.loadField
+                            (fieldName, (TypeDescriptor)type);
+                    }
+                    else {
+                        assembler.loadField
+                            (className, fieldName, (TypeDescriptor)type);
+                    }
+                    break;
+                case Opcode.PUTFIELD:
+                    if (className == null) {
+                        assembler.storeField
+                            (fieldName, (TypeDescriptor)type);
+                    }
+                    else {
+                        assembler.storeField
+                            (className, fieldName, (TypeDescriptor)type);
+                    }
+                    break;
+                }
+                break;
+
+            case Opcode.INVOKEVIRTUAL:
+            case Opcode.INVOKESPECIAL:
+            case Opcode.INVOKESTATIC:
+            case Opcode.INVOKEINTERFACE:
+                ci = mCp.getConstant(readUnsignedShort());
+
+                ConstantNameAndTypeInfo nameAndType;
+
+                if (opcode == Opcode.INVOKEINTERFACE) {
+                    // Read and ignore nargs and padding byte.
+                    readShort();
+                    if (!(ci instanceof ConstantInterfaceMethodInfo)) {
+                        // TODO: raise an error.
+                        break;
+                    }
+                    ConstantInterfaceMethodInfo method = 
+                        (ConstantInterfaceMethodInfo)ci;
+                    className = method.getParentClass().getClassName();
+                    nameAndType = method.getNameAndType();
+                }
+                else {
+                    if (!(ci instanceof ConstantMethodInfo)) {
+                        // TODO: raise an error.
+                        break;
+                    }
+                    ConstantMethodInfo method = 
+                        (ConstantMethodInfo)ci;
+                    className = method.getParentClass().getClassName();
+                    if (mEnclosingClassName.equals(className)) {
+                        className = null;
+                    }
+                    nameAndType = method.getNameAndType();
+                }
+
+                String methodName = nameAndType.getName();
+                type = nameAndType.getType();
+                if (!(type instanceof MethodDescriptor)) {
+                    // TODO: raise an error.
+                    break;
+                }
+                TypeDescriptor ret = ((MethodDescriptor)type).getReturnType();
+                if (ret.getClassArg() == void.class) {
+                    ret = null;
+                }
+                TypeDescriptor[] params = 
+                    ((MethodDescriptor)type).getParameterTypes();
+                if (params.length == 0) {
+                    params = null;
+                }
+
+                switch (opcode) {
+                case Opcode.INVOKEVIRTUAL:
+                    if (className == null) {
+                        assembler.invokeVirtual(methodName, ret, params);
+                    }
+                    else {
+                        assembler.invokeVirtual
+                            (className, methodName, ret, params);
+                    }
+                    break;
+                case Opcode.INVOKESPECIAL:
+                    if ("<init>".equals(methodName)) {
+                        if (className == null) {
+                            assembler.invokeConstructor(params);
+                        }
+                        else {
+                            if (className.equals(mSuperClassName)) {
+                                assembler.invokeSuperConstructor(params);
+                            }
+                            else {
+                                assembler.invokeConstructor(className, params);
+                            }
+                        }
+                    }
+                    else {
+                        if (className == null) {
+                            assembler.invokePrivate(methodName, ret, params);
+                        }
+                        else {
+                            assembler.invokeSuper
+                                (className, methodName, ret, params);
+                        }
+                    }
+                    break;
+                case Opcode.INVOKESTATIC:
+                    if (className == null) {
+                        assembler.invokeStatic(methodName, ret, params);
+                    }
+                    else {
+                        assembler.invokeStatic
+                            (className, methodName, ret, params);
+                    }
+                    break;
+                case Opcode.INVOKEINTERFACE:
+                    assembler.invokeInterface
+                        (className, methodName, ret, params);
+                    break;
+                }
+                break;
+
+                // End opcodes that load a constant from the constant pool.
+
+                // Opcodes that load or store local variables...
+
+            case Opcode.ILOAD: case Opcode.ISTORE:
+            case Opcode.LLOAD: case Opcode.LSTORE:
+            case Opcode.FLOAD: case Opcode.FSTORE:
+            case Opcode.DLOAD: case Opcode.DSTORE:
+            case Opcode.ALOAD: case Opcode.ASTORE:
+            case Opcode.ILOAD_0: case Opcode.ISTORE_0:
+            case Opcode.ILOAD_1: case Opcode.ISTORE_1:
+            case Opcode.ILOAD_2: case Opcode.ISTORE_2:
+            case Opcode.ILOAD_3: case Opcode.ISTORE_3:
+            case Opcode.LLOAD_0: case Opcode.LSTORE_0:
+            case Opcode.LLOAD_1: case Opcode.LSTORE_1:
+            case Opcode.LLOAD_2: case Opcode.LSTORE_2:
+            case Opcode.LLOAD_3: case Opcode.LSTORE_3:
+            case Opcode.FLOAD_0: case Opcode.FSTORE_0:
+            case Opcode.FLOAD_1: case Opcode.FSTORE_1:
+            case Opcode.FLOAD_2: case Opcode.FSTORE_2:
+            case Opcode.FLOAD_3: case Opcode.FSTORE_3:
+            case Opcode.DLOAD_0: case Opcode.DSTORE_0:
+            case Opcode.DLOAD_1: case Opcode.DSTORE_1:
+            case Opcode.DLOAD_2: case Opcode.DSTORE_2:
+            case Opcode.DLOAD_3: case Opcode.DSTORE_3:
+            case Opcode.ALOAD_0: case Opcode.ASTORE_0:
+            case Opcode.ALOAD_1: case Opcode.ASTORE_1:
+            case Opcode.ALOAD_2: case Opcode.ASTORE_2:
+            case Opcode.ALOAD_3: case Opcode.ASTORE_3:
+                switch (opcode) {
+                case Opcode.ILOAD: case Opcode.ISTORE:
+                    index = readUnsignedByte();
+                    clazz = int.class;
+                    break;
+                case Opcode.LLOAD: case Opcode.LSTORE:
+                    index = readUnsignedByte();
+                    clazz = long.class;
+                    break;
+                case Opcode.FLOAD: case Opcode.FSTORE:
+                    index = readUnsignedByte();
+                    clazz = float.class;
+                    break;
+                case Opcode.DLOAD: case Opcode.DSTORE:
+                    index = readUnsignedByte();
+                    clazz = double.class;
+                    break;
+                case Opcode.ALOAD: case Opcode.ASTORE:
+                    index = readUnsignedByte();
+                    clazz = Object.class;
+                    break;
+                case Opcode.ILOAD_0: case Opcode.ISTORE_0:
+                    index = 0;
+                    clazz = int.class;
+                    break;
+                case Opcode.ILOAD_1: case Opcode.ISTORE_1:
+                    index = 1;
+                    clazz = int.class;
+                    break;
+                case Opcode.ILOAD_2: case Opcode.ISTORE_2:
+                    index = 2;
+                    clazz = int.class;
+                    break;
+                case Opcode.ILOAD_3: case Opcode.ISTORE_3:
+                    index = 3;
+                    clazz = int.class;
+                    break;
+                case Opcode.LLOAD_0: case Opcode.LSTORE_0:
+                    index = 0;
+                    clazz = long.class;
+                    break;
+                case Opcode.LLOAD_1: case Opcode.LSTORE_1:
+                    index = 1;
+                    clazz = long.class;
+                    break;
+                case Opcode.LLOAD_2: case Opcode.LSTORE_2:
+                    index = 2;
+                    clazz = long.class;
+                    break;
+                case Opcode.LLOAD_3: case Opcode.LSTORE_3:
+                    index = 3;
+                    clazz = long.class;
+                    break;
+                case Opcode.FLOAD_0: case Opcode.FSTORE_0:
+                    index = 0;
+                    clazz = float.class;
+                    break;
+                case Opcode.FLOAD_1: case Opcode.FSTORE_1:
+                    index = 1;
+                    clazz = float.class;
+                    break;
+                case Opcode.FLOAD_2: case Opcode.FSTORE_2:
+                    index = 2;
+                    clazz = float.class;
+                    break;
+                case Opcode.FLOAD_3: case Opcode.FSTORE_3:
+                    index = 3;
+                    clazz = float.class;
+                    break;
+                case Opcode.DLOAD_0: case Opcode.DSTORE_0:
+                    index = 0;
+                    clazz = double.class;
+                    break;
+                case Opcode.DLOAD_1: case Opcode.DSTORE_1:
+                    index = 1;
+                    clazz = double.class;
+                    break;
+                case Opcode.DLOAD_2: case Opcode.DSTORE_2:
+                    index = 2;
+                    clazz = double.class;
+                    break;
+                case Opcode.DLOAD_3: case Opcode.DSTORE_3:
+                    index = 3;
+                    clazz = double.class;
+                    break;
+                case Opcode.ALOAD_0: case Opcode.ASTORE_0:
+                    index = 0;
+                    clazz = Object.class;
+                    break;
+                case Opcode.ALOAD_1: case Opcode.ASTORE_1:
+                    index = 1;
+                    clazz = Object.class;
+                    break;
+                case Opcode.ALOAD_2: case Opcode.ASTORE_2:
+                    index = 2;
+                    clazz = Object.class;
+                    break;
+                case Opcode.ALOAD_3: case Opcode.ASTORE_3:
+                    index = 3;
+                    clazz = Object.class;
+                    break;
+                default:
+                    index = 0;
+                    clazz = null;
+                    break;
+                }
+
+                switch (opcode) {
+                case Opcode.ILOAD:
+                case Opcode.LLOAD:
+                case Opcode.FLOAD:
+                case Opcode.DLOAD:
+                case Opcode.ALOAD:
+                case Opcode.ILOAD_0:
+                case Opcode.ILOAD_1:
+                case Opcode.ILOAD_2:
+                case Opcode.ILOAD_3:
+                case Opcode.LLOAD_0:
+                case Opcode.LLOAD_1:
+                case Opcode.LLOAD_2:
+                case Opcode.LLOAD_3:
+                case Opcode.FLOAD_0:
+                case Opcode.FLOAD_1:
+                case Opcode.FLOAD_2:
+                case Opcode.FLOAD_3:
+                case Opcode.DLOAD_0:
+                case Opcode.DLOAD_1:
+                case Opcode.DLOAD_2:
+                case Opcode.DLOAD_3:
+                case Opcode.ALOAD_0:
+                case Opcode.ALOAD_1:
+                case Opcode.ALOAD_2:
+                case Opcode.ALOAD_3:
+                    if (index == 0 && mHasThis) {
+                        assembler.loadThis();
+                    }
+                    else {
+                        assembler.loadLocal(getLocalVariable(index, clazz));
+                    }
+                    break;
+                case Opcode.ISTORE:
+                case Opcode.LSTORE:
+                case Opcode.FSTORE:
+                case Opcode.DSTORE:
+                case Opcode.ASTORE:
+                case Opcode.ISTORE_0:
+                case Opcode.ISTORE_1:
+                case Opcode.ISTORE_2:
+                case Opcode.ISTORE_3:
+                case Opcode.LSTORE_0:
+                case Opcode.LSTORE_1:
+                case Opcode.LSTORE_2:
+                case Opcode.LSTORE_3:
+                case Opcode.FSTORE_0:
+                case Opcode.FSTORE_1:
+                case Opcode.FSTORE_2:
+                case Opcode.FSTORE_3:
+                case Opcode.DSTORE_0:
+                case Opcode.DSTORE_1:
+                case Opcode.DSTORE_2:
+                case Opcode.DSTORE_3:
+                case Opcode.ASTORE_0:
+                case Opcode.ASTORE_1:
+                case Opcode.ASTORE_2:
+                case Opcode.ASTORE_3:
+                    if (index == 0 && mHasThis) {
+                        // The "this" reference just got blown away.
+                        mHasThis = false;
+                    }
+                    assembler.storeLocal(getLocalVariable(index, clazz));
+                    break;
+                }
+                break;
+
+            case Opcode.RET:
+                LocalVariable local = getLocalVariable
+                    (readUnsignedByte(), Object.class);
+                assembler.ret(local);
+                break;
+
+            case Opcode.IINC:
+                local = getLocalVariable(readUnsignedByte(), int.class);
+                assembler.integerIncrement(local, readByte());
+                break;
+
+                // End opcodes that load or store local variables.
+
+                // Opcodes that branch to another address.
+
+            case Opcode.GOTO:
+                loc = getLabel(mAddress + readShort());
+                assembler.branch(loc);
+                break;
+            case Opcode.JSR:
+                loc = getLabel(mAddress + readShort());
+                assembler.jsr(loc);
+                break;
+            case Opcode.GOTO_W:
+                loc = getLabel(mAddress + readInt());
+                assembler.branch(loc);
+                break;
+            case Opcode.JSR_W:
+                loc = getLabel(mAddress + readInt());
+                assembler.jsr(loc);
+                break;
+
+            case Opcode.IFNULL:
+                loc = getLabel(mAddress + readShort());
+                assembler.ifNullBranch(loc, true);
+                break;
+            case Opcode.IFNONNULL:
+                loc = getLabel(mAddress + readShort());
+                assembler.ifNullBranch(loc, false);
+                break;
+
+            case Opcode.IF_ACMPEQ:
+                loc = getLabel(mAddress + readShort());
+                assembler.ifEqualBranch(loc, true);
+                break;
+            case Opcode.IF_ACMPNE:
+                loc = getLabel(mAddress + readShort());
+                assembler.ifEqualBranch(loc, false);
+                break;
+
+            case Opcode.IFEQ:
+            case Opcode.IFNE:
+            case Opcode.IFLT:
+            case Opcode.IFGE:
+            case Opcode.IFGT:
+            case Opcode.IFLE:
+                loc = getLabel(mAddress + readShort());
+                String choice;
+                switch (opcode) {
+                case Opcode.IFEQ:
+                    choice = "==";
+                    break;
+                case Opcode.IFNE:
+                    choice = "!=";
+                    break;
+                case Opcode.IFLT:
+                    choice = "<";
+                    break;
+                case Opcode.IFGE:
+                    choice = ">=";
+                    break;
+                case Opcode.IFGT:
+                    choice = ">";
+                    break;
+                case Opcode.IFLE:
+                    choice = "<=";
+                    break;
+                default:
+                    choice = null;
+                    break;
+                }
+                assembler.ifZeroComparisonBranch(loc, choice);
+                break;
+
+            case Opcode.IF_ICMPEQ:
+            case Opcode.IF_ICMPNE:
+            case Opcode.IF_ICMPLT:
+            case Opcode.IF_ICMPGE:
+            case Opcode.IF_ICMPGT:
+            case Opcode.IF_ICMPLE:
+                loc = getLabel(mAddress + readShort());
+                switch (opcode) {
+                case Opcode.IF_ICMPEQ:
+                    choice = "==";
+                    break;
+                case Opcode.IF_ICMPNE:
+                    choice = "!=";
+                    break;
+                case Opcode.IF_ICMPLT:
+                    choice = "<";
+                    break;
+                case Opcode.IF_ICMPGE:
+                    choice = ">=";
+                    break;
+                case Opcode.IF_ICMPGT:
+                    choice = ">";
+                    break;
+                case Opcode.IF_ICMPLE:
+                    choice = "<=";
+                    break;
+                default:
+                    choice = null;
+                    break;
+                }
+                assembler.ifComparisonBranch(loc, choice);
+                break;
+
+                // End opcodes that branch to another address.
+
+                // Miscellaneous opcodes...
+
+            case Opcode.BIPUSH:
+                assembler.loadConstant(readByte());
+                break;
+            case Opcode.SIPUSH:
+                assembler.loadConstant(readShort());
+                break;
+
+            case Opcode.NEWARRAY:
+                int atype = readByte();
+                clazz = null;
+                switch (atype) {
+                case 4: // T_BOOLEAN
+                    clazz = boolean.class;
+                    break;
+                case 5: // T_CHAR
+                    clazz = char.class;
+                    break;
+                case 6: // T_FLOAT
+                    clazz = float.class;
+                    break;
+                case 7: // T_DOUBLE
+                    clazz = double.class;
+                    break;
+                case 8: // T_BYTE
+                    clazz = byte.class;
+                    break;
+                case 9: // T_SHORT
+                    clazz = short.class;
+                    break;
+                case 10: // T_INT
+                    clazz = int.class;
+                    break;
+                case 11: // T_LONG
+                    clazz = long.class;
+                    break;
+                }
+
+                if (clazz == null) {
+                    // TODO: raise an error.
+                    break;
+                }
+
+                assembler.newObject
+                    (new TypeDescriptor(new TypeDescriptor(clazz), 1));
+                break;
+
+            case Opcode.TABLESWITCH:
+            case Opcode.LOOKUPSWITCH:
+                int opcodeAddress = mAddress;
+                // Read padding until address is 32 bit word aligned.
+                while (((mAddress + 1) & 3) != 0) {
+                    ++mAddress;
+                }
+                Location defaultLocation = getLabel(opcodeAddress + readInt());
+                int[] cases;
+                Location[] locations;
+                
+                if (opcode == Opcode.TABLESWITCH) {
+                    int lowValue = readInt();
+                    int highValue = readInt();
+                    int caseCount = highValue - lowValue + 1;
+                    try {
+                        cases = new int[caseCount];
+                    }
+                    catch (NegativeArraySizeException e) {
+                        // TODO: raise an error.
+                        break;
+                    }
+                    locations = new Location[caseCount];
+                    for (int i=0; i<caseCount; i++) {
+                        cases[i] = lowValue + i;
+                        locations[i] = getLabel(opcodeAddress + readInt());
+                    }
+                }
+                else {
+                    int caseCount = readInt();
+                    try {
+                        cases = new int[caseCount];
+                    }
+                    catch (NegativeArraySizeException e) {
+                        // TODO: raise an error.
+                        break;
+                    }
+                    locations = new Location[caseCount];
+                    for (int i=0; i<caseCount; i++) {
+                        cases[i] = readInt();
+                        locations[i] = getLabel(opcodeAddress + readInt());
+                    }
+                }
+
+                assembler.switchBranch(cases, locations, defaultLocation);
+                break;
+
+            case Opcode.WIDE:
+                opcode = mByteCodes[++mAddress];
+                switch (opcode) {
+
+                default:
+                    // TODO: raise an error.
+                    break;
+
+                case Opcode.ILOAD: case Opcode.ISTORE:
+                case Opcode.LLOAD: case Opcode.LSTORE:
+                case Opcode.FLOAD: case Opcode.FSTORE:
+                case Opcode.DLOAD: case Opcode.DSTORE:
+                case Opcode.ALOAD: case Opcode.ASTORE:
+
+                    switch (opcode) {
+                    case Opcode.ILOAD: case Opcode.ISTORE:
+                        clazz = int.class;
+                        break;
+                    case Opcode.LLOAD: case Opcode.LSTORE:
+                        clazz = long.class;
+                        break;
+                    case Opcode.FLOAD: case Opcode.FSTORE:
+                        clazz = float.class;
+                        break;
+                    case Opcode.DLOAD: case Opcode.DSTORE:
+                        clazz = double.class;
+                        break;
+                    case Opcode.ALOAD: case Opcode.ASTORE:
+                        clazz = Object.class;
+                        break;
+                    default:
+                        clazz = null;
+                        break;
+                    }
+                    
+                    index = readUnsignedShort();
+
+                    switch (opcode) {
+                    case Opcode.ILOAD:
+                    case Opcode.LLOAD:
+                    case Opcode.FLOAD:
+                    case Opcode.DLOAD:
+                    case Opcode.ALOAD:
+                        if (index == 0 && mHasThis) {
+                            assembler.loadThis();
+                        }
+                        else {
+                            assembler.loadLocal
+                                (getLocalVariable(index, clazz));
+                        }
+                        break;
+                    case Opcode.ISTORE:
+                    case Opcode.LSTORE:
+                    case Opcode.FSTORE:
+                    case Opcode.DSTORE:
+                    case Opcode.ASTORE:
+                        if (index == 0 && mHasThis) {
+                            // The "this" reference just got blown away.
+                            mHasThis = false;
+                        }
+                        assembler.storeLocal(getLocalVariable(index, clazz));
+                        break;
+                    }
+                    break;
+
+                case Opcode.RET:
+                    local = getLocalVariable
+                        (readUnsignedShort(), Object.class);
+                    assembler.ret(local);
+                    break;
+                    
+                case Opcode.IINC:
+                    local = getLocalVariable(readUnsignedShort(), int.class);
+                    assembler.integerIncrement(local, readShort());
+                    break;
+                }
+
+                break;
+            } // end huge switch
+        } // end for loop
+    }
+
+    private void gatherLabels() {
+        mLabels = new HashMap();
+        mCatchLocations = new HashMap(mExceptionHandlers.length * 2 + 1);
+        Integer labelKey;
+
+        // Gather labels for any exception handlers.
+        for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
+            ExceptionHandler handler = mExceptionHandlers[i];
+            labelKey = new Integer(handler.getStartLocation().getLocation());
+            mLabels.put(labelKey, labelKey);
+            labelKey = new Integer(handler.getEndLocation().getLocation());
+            mLabels.put(labelKey, labelKey);
+            labelKey = new Integer(handler.getCatchLocation().getLocation());
+            List list = (List)mCatchLocations.get(labelKey);
+            if (list == null) {
+                list = new ArrayList(2);
+                mCatchLocations.put(labelKey, list);
+            }
+            list.add(handler);
+        }
+
+        // Now gather labels that occur within byte code.
+        for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
+            byte opcode = mByteCodes[mAddress];
+
+            switch (opcode) {
+
+            default:
+                // TODO: raise an error.
+                break;
+
+                // Opcodes that use labels.
+
+            case Opcode.GOTO:
+            case Opcode.JSR:
+            case Opcode.IFNULL:
+            case Opcode.IFNONNULL:
+            case Opcode.IF_ACMPEQ:
+            case Opcode.IF_ACMPNE:
+            case Opcode.IFEQ:
+            case Opcode.IFNE:
+            case Opcode.IFLT:
+            case Opcode.IFGE:
+            case Opcode.IFGT:
+            case Opcode.IFLE:
+            case Opcode.IF_ICMPEQ:
+            case Opcode.IF_ICMPNE:
+            case Opcode.IF_ICMPLT:
+            case Opcode.IF_ICMPGE:
+            case Opcode.IF_ICMPGT:
+            case Opcode.IF_ICMPLE:
+                labelKey = new Integer(mAddress + readShort());
+                mLabels.put(labelKey, labelKey);
+                break;
+
+            case Opcode.GOTO_W:
+            case Opcode.JSR_W:
+                labelKey = new Integer(mAddress + readInt());
+                mLabels.put(labelKey, labelKey);
+                break;
+
+            case Opcode.TABLESWITCH:
+            case Opcode.LOOKUPSWITCH:
+                int opcodeAddress = mAddress;
+                // Read padding until address is 32 bit word aligned.
+                while (((mAddress + 1) & 3) != 0) {
+                    ++mAddress;
+                }
+                
+                // Read the default location.
+                labelKey = new Integer(opcodeAddress + readInt());
+                mLabels.put(labelKey, labelKey);
+                
+                if (opcode == Opcode.TABLESWITCH) {
+                    int lowValue = readInt();
+                    int highValue = readInt();
+                    int caseCount = highValue - lowValue + 1;
+
+                    for (int i=0; i<caseCount; i++) {
+                        // Read the branch location.
+                        labelKey = new Integer(opcodeAddress + readInt());
+                        mLabels.put(labelKey, labelKey);
+                    }
+                }
+                else {
+                    int caseCount = readInt();
+
+                    for (int i=0; i<caseCount; i++) {
+                        // Skip the case value.
+                        mAddress += 4;
+                        // Read the branch location.
+                        labelKey = new Integer(opcodeAddress + readInt());
+                        mLabels.put(labelKey, labelKey);
+                    }
+                }
+                break;
+
+                // All other operations are skipped. The amount to skip
+                // depends on the operand size.
+
+                // Opcodes with no operands...
+
+            case Opcode.NOP:
+            case Opcode.BREAKPOINT:
+            case Opcode.ACONST_NULL:
+            case Opcode.ICONST_M1:
+            case Opcode.ICONST_0:
+            case Opcode.ICONST_1:
+            case Opcode.ICONST_2:
+            case Opcode.ICONST_3:
+            case Opcode.ICONST_4:
+            case Opcode.ICONST_5:
+            case Opcode.LCONST_0:
+            case Opcode.LCONST_1:
+            case Opcode.FCONST_0:
+            case Opcode.FCONST_1:
+            case Opcode.FCONST_2:
+            case Opcode.DCONST_0:
+            case Opcode.DCONST_1:
+            case Opcode.POP:
+            case Opcode.POP2:
+            case Opcode.DUP:
+            case Opcode.DUP_X1:
+            case Opcode.DUP_X2:
+            case Opcode.DUP2:
+            case Opcode.DUP2_X1:
+            case Opcode.DUP2_X2:
+            case Opcode.SWAP:
+            case Opcode.IADD:  case Opcode.LADD: 
+            case Opcode.FADD:  case Opcode.DADD:
+            case Opcode.ISUB:  case Opcode.LSUB:
+            case Opcode.FSUB:  case Opcode.DSUB:
+            case Opcode.IMUL:  case Opcode.LMUL:
+            case Opcode.FMUL:  case Opcode.DMUL:
+            case Opcode.IDIV:  case Opcode.LDIV:
+            case Opcode.FDIV:  case Opcode.DDIV:
+            case Opcode.IREM:  case Opcode.LREM:
+            case Opcode.FREM:  case Opcode.DREM:
+            case Opcode.INEG:  case Opcode.LNEG:
+            case Opcode.FNEG:  case Opcode.DNEG:
+            case Opcode.ISHL:  case Opcode.LSHL:
+            case Opcode.ISHR:  case Opcode.LSHR:
+            case Opcode.IUSHR: case Opcode.LUSHR:
+            case Opcode.IAND:  case Opcode.LAND:
+            case Opcode.IOR:   case Opcode.LOR:
+            case Opcode.IXOR:  case Opcode.LXOR:
+            case Opcode.FCMPL: case Opcode.DCMPL:
+            case Opcode.FCMPG: case Opcode.DCMPG:
+            case Opcode.LCMP: 
+            case Opcode.I2L:
+            case Opcode.I2F:
+            case Opcode.I2D:
+            case Opcode.L2I:
+            case Opcode.L2F:
+            case Opcode.L2D:
+            case Opcode.F2I:
+            case Opcode.F2L:
+            case Opcode.F2D:
+            case Opcode.D2I:
+            case Opcode.D2L:
+            case Opcode.D2F:
+            case Opcode.I2B:
+            case Opcode.I2C:
+            case Opcode.I2S:
+            case Opcode.IRETURN:
+            case Opcode.LRETURN:
+            case Opcode.FRETURN:
+            case Opcode.DRETURN:
+            case Opcode.ARETURN:
+            case Opcode.RETURN:
+            case Opcode.IALOAD:
+            case Opcode.LALOAD:
+            case Opcode.FALOAD:
+            case Opcode.DALOAD:
+            case Opcode.AALOAD:
+            case Opcode.BALOAD:
+            case Opcode.CALOAD:
+            case Opcode.SALOAD:
+            case Opcode.IASTORE:
+            case Opcode.LASTORE:
+            case Opcode.FASTORE:
+            case Opcode.DASTORE:
+            case Opcode.AASTORE:
+            case Opcode.BASTORE:
+            case Opcode.CASTORE:
+            case Opcode.SASTORE:
+            case Opcode.ARRAYLENGTH:
+            case Opcode.ATHROW:
+            case Opcode.MONITORENTER:
+            case Opcode.MONITOREXIT:
+            case Opcode.ILOAD_0: case Opcode.ISTORE_0:
+            case Opcode.ILOAD_1: case Opcode.ISTORE_1:
+            case Opcode.ILOAD_2: case Opcode.ISTORE_2:
+            case Opcode.ILOAD_3: case Opcode.ISTORE_3:
+            case Opcode.LLOAD_0: case Opcode.LSTORE_0:
+            case Opcode.LLOAD_1: case Opcode.LSTORE_1:
+            case Opcode.LLOAD_2: case Opcode.LSTORE_2:
+            case Opcode.LLOAD_3: case Opcode.LSTORE_3:
+            case Opcode.FLOAD_0: case Opcode.FSTORE_0:
+            case Opcode.FLOAD_1: case Opcode.FSTORE_1:
+            case Opcode.FLOAD_2: case Opcode.FSTORE_2:
+            case Opcode.FLOAD_3: case Opcode.FSTORE_3:
+            case Opcode.DLOAD_0: case Opcode.DSTORE_0:
+            case Opcode.DLOAD_1: case Opcode.DSTORE_1:
+            case Opcode.DLOAD_2: case Opcode.DSTORE_2:
+            case Opcode.DLOAD_3: case Opcode.DSTORE_3:
+            case Opcode.ALOAD_0: case Opcode.ASTORE_0:
+            case Opcode.ALOAD_1: case Opcode.ASTORE_1:
+            case Opcode.ALOAD_2: case Opcode.ASTORE_2:
+            case Opcode.ALOAD_3: case Opcode.ASTORE_3:
+                break;
+
+                // Opcodes with one operand byte...
+
+            case Opcode.LDC:
+            case Opcode.ILOAD: case Opcode.ISTORE:
+            case Opcode.LLOAD: case Opcode.LSTORE:
+            case Opcode.FLOAD: case Opcode.FSTORE:
+            case Opcode.DLOAD: case Opcode.DSTORE:
+            case Opcode.ALOAD: case Opcode.ASTORE:
+            case Opcode.RET:
+            case Opcode.IINC:
+            case Opcode.BIPUSH:
+            case Opcode.NEWARRAY:
+                mAddress += 1;
+                break;
+
+                // Opcodes with two operand bytes...
+
+            case Opcode.LDC_W:
+            case Opcode.LDC2_W:
+            case Opcode.NEW:
+            case Opcode.ANEWARRAY:
+            case Opcode.CHECKCAST:
+            case Opcode.INSTANCEOF:
+            case Opcode.GETSTATIC:
+            case Opcode.PUTSTATIC:
+            case Opcode.GETFIELD:
+            case Opcode.PUTFIELD:
+            case Opcode.INVOKEVIRTUAL:
+            case Opcode.INVOKESPECIAL:
+            case Opcode.INVOKESTATIC:
+            case Opcode.SIPUSH:
+                mAddress += 2;
+                break;
+
+                // Opcodes with three operand bytes...
+
+            case Opcode.MULTIANEWARRAY:
+                mAddress += 3;
+                break;
+
+                // Opcodes with four operand bytes...
+
+            case Opcode.INVOKEINTERFACE:
+                mAddress += 4;
+                break;
+
+                // Wide opcode has a variable sized operand.
+
+            case Opcode.WIDE:
+                opcode = mByteCodes[++mAddress];
+                mAddress += 2;
+                if (opcode == Opcode.IINC) {
+                    mAddress += 2;
+                }
+                break;
+            } // end huge switch
+        } // end for loop
+    }
+
+    private int readByte() {
+        return mByteCodes[++mAddress];
+    }
+
+    private int readUnsignedByte() {
+        return mByteCodes[++mAddress] & 0xff;
+    }
+
+    private int readShort() {
+        return (mByteCodes[++mAddress] << 8) | (mByteCodes[++mAddress] & 0xff);
+    }
+
+    private int readUnsignedShort() {
+        return 
+            ((mByteCodes[++mAddress] & 0xff) << 8) | 
+            ((mByteCodes[++mAddress] & 0xff) << 0);
+    }
+
+    private int readInt() {
+        return
+            (mByteCodes[++mAddress] << 24) | 
+            ((mByteCodes[++mAddress] & 0xff) << 16) |
+            ((mByteCodes[++mAddress] & 0xff) << 8) |
+            ((mByteCodes[++mAddress] & 0xff) << 0);
+    }
+
+    private LocalVariable getLocalVariable(int index, Class typeHint) {
+        TypeDescriptor type = new TypeDescriptor(typeHint);
+        LocalVariable local;
+
+        if (index >= mLocals.size()) {
+            mLocals.setSize(index + 1);
+            local = null;
+        }
+        else {
+            local = (LocalVariable)mLocals.elementAt(index);
+            if (local != null) {
+                TypeDescriptor localType = local.getType();
+                Class typeClass = type.getClassArg();
+                Class localTypeClass = localType.getClassArg();
+
+                if (typeClass != null && !typeClass.isPrimitive()) {
+                    typeClass = null;
+                }
+
+                if (localTypeClass != null && !localTypeClass.isPrimitive()) {
+                    localTypeClass = null;
+                }
+
+                if (typeClass == null) {
+                    if (localTypeClass == null) {
+                        // Both types must represent objects. This is ok.
+                    }
+                    else {
+                        // Requesting object type, but existing is primitive.
+                        local = null;
+                    }
+                }
+                else {
+                    if (localTypeClass == null) {
+                        // Requesting primitive type, but existing is object.
+                        local = null;
+                    }
+                    else {
+                        // Primitive types must exactly match.
+                        if (typeClass != localTypeClass) {
+                            local = null;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (local == null) {
+            local = mAssembler.createLocalVariable(null, type);
+            mLocals.setElementAt(local, index);
+        }
+
+        return local;
+    }
+
+    private void locateLabel() {
+        Integer labelKey = new Integer(mAddress);
+        Object labelValue = mLabels.get(labelKey);
+        if (labelValue != null) {
+            if (labelValue instanceof Label) {
+                ((Label)labelValue).setLocation();
+            }
+            else {
+                labelValue = mAssembler.createLabel().setLocation();
+                mLabels.put(labelKey, labelValue);
+            }
+        }
+
+        List handlers = (List)mCatchLocations.get(labelKey);
+
+        if (handlers != null) {
+            for (int i=0; i<handlers.size(); i++) {
+                ExceptionHandler handler = (ExceptionHandler)handlers.get(i);
+                Label start =
+                    getLabel(handler.getStartLocation().getLocation());
+                Label end =
+                    getLabel(handler.getEndLocation().getLocation());
+                String catchClassName;
+                if (handler.getCatchType() == null) {
+                    catchClassName = null;
+                }
+                else {
+                    catchClassName = handler.getCatchType().getClassName();
+                }
+                mAssembler.exceptionHandler(start, end, catchClassName);
+            }
+        }
+    }
+
+    private Label getLabel(int address) {
+        Integer labelKey = new Integer(address);
+        Object labelValue = mLabels.get(labelKey);
+        // labelValue will never be null unless gatherLabels is broken.
+        if (!(labelValue instanceof Label)) {
+            labelValue = mAssembler.createLabel();
+            mLabels.put(labelKey, labelValue);
+        }
+        return (Label)labelValue;
+    }
+}