Implement the new instruction formats.

I also refactored some of the old code in the process, to minimize
duplication, and I also did a minor cleanup of the format spec.

Change-Id: Ib07ea4ade52aa6ec4fa69000798e0cfb8f10c3a9
diff --git a/docs/instruction-formats.html b/docs/instruction-formats.html
index b936698..5db2dfd 100644
--- a/docs/instruction-formats.html
+++ b/docs/instruction-formats.html
@@ -326,7 +326,7 @@
   <td>const-string/jumbo</td>
 </tr>
 <tr>
-  <td>B|A|<i>op</i> CCCC G|F|E|D</td>
+  <td rowspan="2">B|A|<i>op</i> CCCC G|F|E|D</td>
   <td>35c</td>
   <td><i>[<code>B=5</code>] <code>op</code></i> {vD, vE, vF, vG, vA},
     meth@CCCC<br/>
@@ -346,7 +346,6 @@
   <td>&nbsp;</td>
 </tr>
 <tr>
-  <td>B|A|<i>op</i> CCCC G|F|E|D</td>
   <td>35ms</td>
 
   <td><i>[<code>B=5</code>] <code>op</code></i> {vD, vE, vF, vG, vA},
@@ -365,7 +364,7 @@
   </td>
 </tr>
 <tr>
-  <td>AA|<i>op</i> BBBB CCCC</td>
+  <td rowspan="2">AA|<i>op</i> BBBB CCCC</td>
   <td>3rc</td>
   <td><i><code>op</code></i> {vCCCC .. vNNNN}, meth@BBBB<br/>
     <i><code>op</code></i> {vCCCC .. vNNNN}, type@BBBB<br/>
@@ -376,7 +375,6 @@
   <td>&nbsp;</td>
 </tr>
 <tr>
-  <td>AA|<i>op</i> BBBB CCCC</td>
   <td>3rms</td>
   <td><i><code>op</code></i> {vCCCC .. vNNNN}, vtaboff@BBBB<br/>
     <p><i>where <code>NNNN = CCCC+AA-1</code>, that is <code>A</code>
diff --git a/dx/src/com/android/dx/dex/code/InsnFormat.java b/dx/src/com/android/dx/dex/code/InsnFormat.java
index e7171c4..19b2151 100644
--- a/dx/src/com/android/dx/dex/code/InsnFormat.java
+++ b/dx/src/com/android/dx/dex/code/InsnFormat.java
@@ -16,6 +16,7 @@
 
 package com.android.dx.dex.code;
 
+import com.android.dx.rop.code.RegisterSpec;
 import com.android.dx.rop.code.RegisterSpecList;
 import com.android.dx.rop.cst.Constant;
 import com.android.dx.rop.cst.CstInteger;
@@ -182,6 +183,49 @@
     }
 
     /**
+     * Helper method to return a register range string.
+     *
+     * @param list {@code non-null;} the list of registers (which must be
+     * sequential)
+     * @return {@code non-null;} the string form
+     */
+    protected static String regRangeString(RegisterSpecList list) {
+        int size = list.size();
+        StringBuilder sb = new StringBuilder(30);
+
+        sb.append("{");
+
+        switch (size) {
+            case 0: {
+                // Nothing to do.
+                break;
+            }
+            case 1: {
+                sb.append(list.get(0).regString());
+                break;
+            }
+            default: {
+                RegisterSpec lastReg = list.get(size - 1);
+                if (lastReg.getCategory() == 2) {
+                    /*
+                     * Add one to properly represent a list-final
+                     * category-2 register.
+                     */
+                    lastReg = lastReg.withOffset(1);
+                }
+
+                sb.append(list.get(0).regString());
+                sb.append("..");
+                sb.append(lastReg.regString());
+            }
+        }
+
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /**
      * Helper method to return a literal bits argument string.
      *
      * @param value the value
@@ -370,6 +414,34 @@
     }
 
     /**
+     * Helper method to determine if a list of registers are sequential,
+     * including degenerate cases for empty or single-element lists.
+     *
+     * @param list {@code non-null;} the list of registers
+     * @return {@code true} iff the list is sequentially ordered
+     */
+    protected static boolean isRegListSequential(RegisterSpecList list) {
+        int sz = list.size();
+
+        if (sz < 2) {
+            return true;
+        }
+
+        int first = list.get(0).getReg();
+        int next = first;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = list.get(i);
+            if (one.getReg() != next) {
+                return false;
+            }
+            next += one.getCategory();
+        }
+
+        return true;
+    }
+
+    /**
      * Helper method to extract the callout-argument index from an
      * appropriate instruction.
      *
diff --git a/dx/src/com/android/dx/dex/code/form/Form21c.java b/dx/src/com/android/dx/dex/code/form/Form21c.java
index ed1ec3c..55979cd 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21c.java
@@ -103,12 +103,12 @@
 
         CstInsn ci = (CstInsn) insn;
         int cpi = ci.getIndex();
+        Constant cst = ci.getConstant();
 
         if (! unsignedFitsInShort(cpi)) {
             return false;
         }
 
-        Constant cst = ci.getConstant();
         return (cst instanceof CstType) ||
             (cst instanceof CstFieldRef) ||
             (cst instanceof CstString);
diff --git a/dx/src/com/android/dx/dex/code/form/Form22c.java b/dx/src/com/android/dx/dex/code/form/Form22c.java
index 423ccc8..62809bc 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22c.java
@@ -92,7 +92,7 @@
     /** {@inheritDoc} */
     @Override
     public InsnFormat nextUp() {
-        return null;
+        return Form52c.THE_ONE;
     }
 
     /** {@inheritDoc} */
diff --git a/dx/src/com/android/dx/dex/code/form/Form22s.java b/dx/src/com/android/dx/dex/code/form/Form22s.java
index 5964217..15cf70d 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22s.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22s.java
@@ -89,7 +89,7 @@
     /** {@inheritDoc} */
     @Override
     public InsnFormat nextUp() {
-        return null;
+        return Form32s.THE_ONE;
     }
 
     /** {@inheritDoc} */
diff --git a/dx/src/com/android/dx/dex/code/form/Form31c.java b/dx/src/com/android/dx/dex/code/form/Form31c.java
index 60cc1b7..ef4f8dc 100644
--- a/dx/src/com/android/dx/dex/code/form/Form31c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form31c.java
@@ -104,15 +104,15 @@
         CstInsn ci = (CstInsn) insn;
         Constant cst = ci.getConstant();
 
-        return ((cst instanceof CstType) ||
-                (cst instanceof CstFieldRef) ||
-                (cst instanceof CstString));
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef) ||
+            (cst instanceof CstString);
     }
 
     /** {@inheritDoc} */
     @Override
     public InsnFormat nextUp() {
-        return null;
+        return Form41c.THE_ONE;
     }
 
     /** {@inheritDoc} */
diff --git a/dx/src/com/android/dx/dex/code/form/Form32s.java b/dx/src/com/android/dx/dex/code/form/Form32s.java
new file mode 100644
index 0000000..f55922e
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form32s.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 32s}. See the instruction format spec
+ * for details.
+ */
+public final class Form32s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form32s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form32s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString()
+            + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInByte(regs.get(0).getReg()) &&
+              unsignedFitsInByte(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+                opcodeUnit(insn),
+                codeUnit(regs.get(0).getReg(), regs.get(1).getReg()),
+                (short) value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form32x.java b/dx/src/com/android/dx/dex/code/form/Form32x.java
index 4a981ee..0ae6f83 100644
--- a/dx/src/com/android/dx/dex/code/form/Form32x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form32x.java
@@ -71,7 +71,7 @@
     /** {@inheritDoc} */
     @Override
     public InsnFormat nextUp() {
-        return null;
+        return Form33x.THE_ONE;
     }
 
     /** {@inheritDoc} */
diff --git a/dx/src/com/android/dx/dex/code/form/Form33x.java b/dx/src/com/android/dx/dex/code/form/Form33x.java
new file mode 100644
index 0000000..a8ea3af
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form33x.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 33x}. See the instruction format spec
+ * for details.
+ */
+public final class Form33x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form33x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form33x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + regs.get(2).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 3) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInByte(regs.get(1).getReg()) &&
+            unsignedFitsInShort(regs.get(2).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+                opcodeUnit(insn),
+                codeUnit(regs.get(0).getReg(), regs.get(1).getReg()),
+                (short) regs.get(2).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form3rc.java b/dx/src/com/android/dx/dex/code/form/Form3rc.java
index 755ad76..dab3fba 100644
--- a/dx/src/com/android/dx/dex/code/form/Form3rc.java
+++ b/dx/src/com/android/dx/dex/code/form/Form3rc.java
@@ -45,41 +45,8 @@
     /** {@inheritDoc} */
     @Override
     public String insnArgString(DalvInsn insn) {
-        RegisterSpecList regs = insn.getRegisters();
-        int size = regs.size();
-        StringBuilder sb = new StringBuilder(30);
-
-        sb.append("{");
-
-        switch (size) {
-            case 0: {
-                // Nothing to do.
-                break;
-            }
-            case 1: {
-                sb.append(regs.get(0).regString());
-                break;
-            }
-            default: {
-                RegisterSpec lastReg = regs.get(size - 1);
-                if (lastReg.getCategory() == 2) {
-                    /*
-                     * Add one to properly represent a list-final
-                     * category-2 register.
-                     */
-                    lastReg = lastReg.withOffset(1);
-                }
-
-                sb.append(regs.get(0).regString());
-                sb.append("..");
-                sb.append(lastReg.regString());
-            }
-        }
-
-        sb.append("}, ");
-        sb.append(cstString(insn));
-
-        return sb.toString();
+        return regRangeString(insn.getRegisters()) + ", " +
+            cstString(insn);
     }
 
     /** {@inheritDoc} */
@@ -107,12 +74,12 @@
 
         CstInsn ci = (CstInsn) insn;
         int cpi = ci.getIndex();
+        Constant cst = ci.getConstant();
 
         if (! unsignedFitsInShort(cpi)) {
             return false;
         }
 
-        Constant cst = ci.getConstant();
         if (!((cst instanceof CstMethodRef) ||
               (cst instanceof CstType))) {
             return false;
@@ -121,55 +88,26 @@
         RegisterSpecList regs = ci.getRegisters();
         int sz = regs.size();
 
-        if (sz == 0) {
-            return true;
-        }
-
-        int first = regs.get(0).getReg();
-        int next = first;
-
-        if (!unsignedFitsInShort(first)) {
-            return false;
-        }
-
-        for (int i = 0; i < sz; i++) {
-            RegisterSpec one = regs.get(i);
-            if (one.getReg() != next) {
-                return false;
-            }
-            next += one.getCategory();
-        }
-
-        return unsignedFitsInByte(next - first);
+        return (regs.size() == 0) ||
+            (isRegListSequential(regs) &&
+             unsignedFitsInShort(regs.get(0).getReg()) &&
+             unsignedFitsInByte(regs.getWordCount()));
     }
 
     /** {@inheritDoc} */
     @Override
     public InsnFormat nextUp() {
-        return null;
+        return Form5rc.THE_ONE;
     }
 
     /** {@inheritDoc} */
     @Override
     public void writeTo(AnnotatedOutput out, DalvInsn insn) {
         RegisterSpecList regs = insn.getRegisters();
-        int sz = regs.size();
         int cpi = ((CstInsn) insn).getIndex();
-        int firstReg;
-        int count;
+        int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
+        int count = regs.getWordCount();
 
-        if (sz == 0) {
-            firstReg = 0;
-            count = 0;
-        } else {
-            int lastReg = regs.get(sz - 1).getNextReg();
-            firstReg = regs.get(0).getReg();
-            count = lastReg - firstReg;
-        }
-
-        write(out,
-              opcodeUnit(insn, count),
-              (short) cpi,
-              (short) firstReg);
+        write(out, opcodeUnit(insn, count), (short) cpi, (short) firstReg);
     }
 }
diff --git a/dx/src/com/android/dx/dex/code/form/Form41c.java b/dx/src/com/android/dx/dex/code/form/Form41c.java
new file mode 100644
index 0000000..1f02cb2
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form41c.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 41c}. See the instruction format spec
+ * for details.
+ */
+public final class Form41c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form41c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form41c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 4;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInShort(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out, opcodeUnit(insn), cpi, (short) regs.get(0).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form52c.java b/dx/src/com/android/dx/dex/code/form/Form52c.java
new file mode 100644
index 0000000..4fd3e66
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form52c.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 52c}. See the instruction format spec
+ * for details.
+ */
+public final class Form52c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form52c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form52c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInShort(regs.get(0).getReg()) &&
+              unsignedFitsInShort(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+                opcodeUnit(insn),
+                cpi,
+                (short) regs.get(0).getReg(),
+                (short) regs.get(1).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form5rc.java b/dx/src/com/android/dx/dex/code/form/Form5rc.java
new file mode 100644
index 0000000..668ef21
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form5rc.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 5rc}. See the instruction format spec
+ * for details.
+ */
+public final class Form5rc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form5rc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form5rc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return regRangeString(insn.getRegisters()) + ", " +
+            cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        int sz = regs.size();
+
+        return (regs.size() == 0) ||
+            (isRegListSequential(regs) &&
+             unsignedFitsInShort(regs.get(0).getReg()) &&
+             unsignedFitsInShort(regs.getWordCount()));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+        int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
+        int count = regs.getWordCount();
+
+        write(out, opcodeUnit(insn), cpi, (short) firstReg, (short) count);
+    }
+}