Add support invoke-polymorphic to dexdump

o Update bytecode.txt with codepoints for invoke-polymorphic
  instructions and run opcode-gen/regen-all.

o Update dexdump to support invoke-polymorphic with output equivalent to
  dexdump2.

o Add format classes to dexgen and dx.

Bug: 30550796
Test: manually tested with DEX files generated from ART run-tests.
Change-Id: I986a896747d73e11418ba1876cce86087b4a9e68
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index b186bbd..fd7542e 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -81,6 +81,13 @@
     const char* signature;
 };
 
+
+/* basic info about a prototype */
+struct ProtoInfo {
+    char* parameterTypes;  // dynamically allocated with malloc
+    const char* returnType;
+};
+
 /*
  * Get 2 little-endian bytes.
  */
@@ -691,6 +698,63 @@
     return true;
 }
 
+/*
+ * Get information about a ProtoId.
+ */
+bool getProtoInfo(DexFile* pDexFile, u4 protoIdx, ProtoInfo* pProtoInfo)
+{
+    if (protoIdx >= pDexFile->pHeader->protoIdsSize) {
+        return false;
+    }
+
+    const DexProtoId* protoId = dexGetProtoId(pDexFile, protoIdx);
+
+    // Get string for return type.
+    if (protoId->returnTypeIdx >= pDexFile->pHeader->typeIdsSize) {
+        return false;
+    }
+    pProtoInfo->returnType = dexStringByTypeIdx(pDexFile, protoId->returnTypeIdx);
+
+    // Build string for parameter types.
+    size_t bufSize = 1;
+    char* buf = (char*)malloc(bufSize);
+    if (buf == NULL) {
+        return false;
+    }
+
+    buf[0] = '\0';
+    size_t bufUsed = 1;
+
+    const DexTypeList* paramTypes = dexGetProtoParameters(pDexFile, protoId);
+    if (paramTypes == NULL) {
+        // No parameters.
+        pProtoInfo->parameterTypes = buf;
+        return true;
+    }
+
+    for (u4 i = 0; i < paramTypes->size; ++i) {
+        if (paramTypes->list[i].typeIdx >= pDexFile->pHeader->typeIdsSize) {
+            free(buf);
+            return false;
+        }
+        const char* param = dexStringByTypeIdx(pDexFile, paramTypes->list[i].typeIdx);
+        size_t newUsed = bufUsed + strlen(param);
+        if (newUsed > bufSize) {
+            char* newBuf = (char*)realloc(buf, newUsed);
+            if (newBuf == NULL) {
+                free(buf);
+                return false;
+            }
+            buf = newBuf;
+            bufSize = newUsed;
+        }
+        strncat(buf + bufUsed - 1, param, bufSize - (bufUsed - 1));
+        bufUsed = newUsed;
+    }
+
+    pProtoInfo->parameterTypes = buf;
+    return true;
+}
 
 /*
  * Look up a class' descriptor.
@@ -718,6 +782,7 @@
 
     int outSize;
     u4 index;
+    u4 secondaryIndex = 0;
     u4 width;
 
     /* TODO: Make the index *always* be in field B, to simplify this code. */
@@ -742,6 +807,12 @@
         index = pDecInsn->vC;
         width = 4;
         break;
+    case kFmt45cc:
+    case kFmt4rcc:
+        index = pDecInsn->vB;  // method index
+        secondaryIndex = pDecInsn->arg[4];  // proto index
+        width = 4;
+        break;
     default:
         index = 0;
         width = 4;
@@ -826,6 +897,24 @@
     case kIndexFieldOffset:
         outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
         break;
+    case kIndexMethodAndProtoRef:
+        {
+            FieldMethodInfo methInfo;
+            ProtoInfo protoInfo;
+            protoInfo.parameterTypes = NULL;
+            if (getMethodInfo(pDexFile, index, &methInfo) &&
+                getProtoInfo(pDexFile, secondaryIndex, &protoInfo)) {
+                outSize = snprintf(buf, bufSize, "%s.%s:%s, (%s)%s // method@%0*x, proto@%0*x",
+                                   methInfo.classDescriptor, methInfo.name, methInfo.signature,
+                                   protoInfo.parameterTypes, protoInfo.returnType,
+                                   width, index, width, secondaryIndex);
+            } else {
+                outSize = snprintf(buf, bufSize, "<method?>, <proto?> // method@%0*x, proto@%0*x",
+                                   width, index, width, secondaryIndex);
+            }
+            free(protoInfo.parameterTypes);
+        }
+        break;
     default:
         outSize = snprintf(buf, bufSize, "<?>");
         break;
@@ -1042,6 +1131,26 @@
         break;
     case kFmt00x:        // unknown op or breakpoint
         break;
+    case kFmt45cc:
+        {
+            fputs("  {", stdout);
+            printf("v%d", pDecInsn->vC);
+            for (int i = 0; i < (int) pDecInsn->vA - 1; ++i) {
+                printf(", v%d", pDecInsn->arg[i]);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
+    case kFmt4rcc:
+        {
+            fputs("  {", stdout);
+            printf("v%d", pDecInsn->vC);
+            for (int i = 1; i < (int) pDecInsn->vA; ++i) {
+                printf(", v%d", pDecInsn->vC + i);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
     default:
         printf(" ???");
         break;
diff --git a/dexgen/src/com/android/dexgen/dex/code/DalvOps.java b/dexgen/src/com/android/dexgen/dex/code/DalvOps.java
index 1d051ea..732420f 100644
--- a/dexgen/src/com/android/dexgen/dex/code/DalvOps.java
+++ b/dexgen/src/com/android/dexgen/dex/code/DalvOps.java
@@ -281,8 +281,8 @@
     public static final int UNUSED_F7 = 0xf7;
     public static final int UNUSED_F8 = 0xf8;
     public static final int UNUSED_F9 = 0xf9;
-    public static final int UNUSED_FA = 0xfa;
-    public static final int UNUSED_FB = 0xfb;
+    public static final int INVOKE_POLYMORPHIC = 0xfa;
+    public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb;
     public static final int UNUSED_FC = 0xfc;
     public static final int UNUSED_FD = 0xfd;
     public static final int UNUSED_FE = 0xfe;
diff --git a/dexgen/src/com/android/dexgen/dex/code/Dops.java b/dexgen/src/com/android/dexgen/dex/code/Dops.java
index afd21e3..0a2a6db 100644
--- a/dexgen/src/com/android/dexgen/dex/code/Dops.java
+++ b/dexgen/src/com/android/dexgen/dex/code/Dops.java
@@ -39,6 +39,8 @@
 import com.android.dexgen.dex.code.form.Form32x;
 import com.android.dexgen.dex.code.form.Form35c;
 import com.android.dexgen.dex.code.form.Form3rc;
+import com.android.dexgen.dex.code.form.Form45cc;
+import com.android.dexgen.dex.code.form.Form4rcc;
 import com.android.dexgen.dex.code.form.Form51l;
 import com.android.dexgen.dex.code.form.SpecialFormat;
 
@@ -496,6 +498,10 @@
         new Dop(DalvOps.INVOKE_INTERFACE, DalvOps.INVOKE_INTERFACE,
             Form35c.THE_ONE, false, "invoke-interface");
 
+    public static final Dop INVOKE_POLYMORPHIC =
+        new Dop(DalvOps.INVOKE_POLYMORPHIC, DalvOps.INVOKE_POLYMORPHIC,
+            Form45cc.THE_ONE, false, "invoke-polymorphic");
+
     public static final Dop INVOKE_VIRTUAL_RANGE =
         new Dop(DalvOps.INVOKE_VIRTUAL_RANGE, DalvOps.INVOKE_VIRTUAL,
             Form3rc.THE_ONE, false, "invoke-virtual/range");
@@ -516,6 +522,10 @@
         new Dop(DalvOps.INVOKE_INTERFACE_RANGE, DalvOps.INVOKE_INTERFACE,
             Form3rc.THE_ONE, false, "invoke-interface/range");
 
+    public static final Dop INVOKE_POLYMORPHIC_RANGE =
+        new Dop(DalvOps.INVOKE_POLYMORPHIC_RANGE, DalvOps.INVOKE_POLYMORPHIC,
+            Form4rcc.THE_ONE, false, "invoke-polymorphic/range");
+
     public static final Dop NEG_INT =
         new Dop(DalvOps.NEG_INT, DalvOps.NEG_INT,
             Form12x.THE_ONE, true, "neg-int");
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form45cc.java b/dexgen/src/com/android/dexgen/dex/code/form/Form45cc.java
new file mode 100644
index 0000000..9a37ba3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form45cc.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2017 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.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 45cc}. See the instruction format spec
+ * for details.
+ */
+public final class Form45cc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form45cc();
+
+    /** Maximal number of operands */
+    private static final int MAX_NUM_OPS = 5;
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form45cc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        return regListString(regs) + ", " + 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;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        return (wordCount(regs) >= 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form4rcc.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int cpi = ((CstInsn) insn).getIndex();
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        int sz = regs.size();
+        int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
+        int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
+        int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
+        int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
+        int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(r4, sz)), // encode the fifth operand here
+              (short) cpi,
+              codeUnit(r0, r1, r2, r3));
+    }
+
+    /**
+     * Gets the number of words required for the given register list, where
+     * category-2 values count as two words. Return {@code -1} if the
+     * list requires more than five words or contains registers that need
+     * more than a nibble to identify them.
+     *
+     * @param regs {@code non-null;} the register list in question
+     * @return {@code >= -1;} the number of words required, or {@code -1}
+     * if the list couldn't possibly fit in this format
+     */
+    private static int wordCount(RegisterSpecList regs) {
+        int sz = regs.size();
+
+        if (sz > MAX_NUM_OPS) {
+            // It can't possibly fit.
+            return -1;
+        }
+
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = regs.get(i);
+            result += one.getCategory();
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
+                return -1;
+            }
+        }
+
+        return (result <= MAX_NUM_OPS) ? result : -1;
+    }
+
+    /**
+     * Returns a register list which is equivalent to the given one,
+     * except that it splits category-2 registers into two explicit
+     * entries. This returns the original list if no modification is
+     * required
+     *
+     * @param orig {@code non-null;} the original list
+     * @return {@code non-null;} the list with the described transformation
+     */
+    private static RegisterSpecList explicitize(RegisterSpecList orig) {
+        int wordCount = wordCount(orig);
+        int sz = orig.size();
+
+        if (wordCount == sz) {
+            return orig;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(wordCount);
+        int wordAt = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = orig.get(i);
+            result.set(wordAt, one);
+            if (one.getCategory() == 2) {
+                result.set(wordAt + 1,
+                           RegisterSpec.make(one.getReg() + 1, Type.VOID));
+                wordAt += 2;
+            } else {
+                wordAt++;
+            }
+        }
+
+        result.setImmutable();
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form4rcc.java b/dexgen/src/com/android/dexgen/dex/code/form/Form4rcc.java
new file mode 100644
index 0000000..3c43de3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form4rcc.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 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.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 4rcc}. See the instruction format spec
+ * for details.
+ */
+public final class Form4rcc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form4rcc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form4rcc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@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();
+    }
+
+    /** {@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;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        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);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@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;
+
+        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);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index a84ddc0..f3c2b49 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -40,6 +40,8 @@
 import com.android.dx.dex.code.form.Form32x;
 import com.android.dx.dex.code.form.Form35c;
 import com.android.dx.dex.code.form.Form3rc;
+import com.android.dx.dex.code.form.Form45cc;
+import com.android.dx.dex.code.form.Form4rcc;
 import com.android.dx.dex.code.form.Form51l;
 import com.android.dx.dex.code.form.SpecialFormat;
 import com.android.dx.io.Opcodes;
@@ -499,6 +501,10 @@
         new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE,
             Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false);
 
+    public static final Dop INVOKE_POLYMORPHIC =
+        new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC,
+            Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, false);
+
     public static final Dop INVOKE_VIRTUAL_RANGE =
         new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL,
             Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
@@ -519,6 +525,10 @@
         new Dop(Opcodes.INVOKE_INTERFACE_RANGE, Opcodes.INVOKE_INTERFACE,
             Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
 
+    public static final Dop INVOKE_POLYMORPHIC_RANGE =
+        new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC,
+            Opcodes.NO_NEXT, Form4rcc.THE_ONE, false);
+
     public static final Dop NEG_INT =
         new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT,
             Opcodes.NO_NEXT, Form12x.THE_ONE, true);
@@ -1162,6 +1172,8 @@
         set(SHL_INT_LIT8);
         set(SHR_INT_LIT8);
         set(USHR_INT_LIT8);
+        set(INVOKE_POLYMORPHIC);
+        set(INVOKE_POLYMORPHIC_RANGE);
         // END(dops-init)
     }
 
diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java
index fbfb0db..affa9eb 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -213,6 +213,7 @@
     //     Opcodes.SHL_INT_LIT8
     //     Opcodes.SHR_INT_LIT8
     //     Opcodes.USHR_INT_LIT8
+    //     Opcodes.INVOKE_POLYMORPHIC
     // END(first-opcodes)
 
     static {
diff --git a/dx/src/com/android/dx/dex/code/form/Form45cc.java b/dx/src/com/android/dx/dex/code/form/Form45cc.java
new file mode 100644
index 0000000..4fe38f9
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form45cc.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 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.rop.type.Type;
+import com.android.dx.util.AnnotatedOutput;
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 45cc}. See the instruction format spec
+ * for details.
+ */
+public final class Form45cc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form45cc();
+
+    /** Maximal number of operands */
+    private static final int MAX_NUM_OPS = 5;
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form45cc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        return regListString(regs) + ", " + 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;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        return (wordCount(regs) >= 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        BitSet bits = new BitSet(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec reg = regs.get(i);
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            bits.set(i, unsignedFitsInNibble(reg.getReg() +
+                                             reg.getCategory() - 1));
+        }
+
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int cpi = ((CstInsn) insn).getIndex();
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        int sz = regs.size();
+        int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
+        int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
+        int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
+        int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
+        int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(r4, sz)), // encode the fifth operand here
+              (short) cpi,
+              codeUnit(r0, r1, r2, r3));
+    }
+
+    /**
+     * Gets the number of words required for the given register list, where
+     * category-2 values count as two words. Return {@code -1} if the
+     * list requires more than five words or contains registers that need
+     * more than a nibble to identify them.
+     *
+     * @param regs {@code non-null;} the register list in question
+     * @return {@code >= -1;} the number of words required, or {@code -1}
+     * if the list couldn't possibly fit in this format
+     */
+    private static int wordCount(RegisterSpecList regs) {
+        int sz = regs.size();
+
+        if (sz > MAX_NUM_OPS) {
+            // It can't possibly fit.
+            return -1;
+        }
+
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = regs.get(i);
+            result += one.getCategory();
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
+                return -1;
+            }
+        }
+
+        return (result <= MAX_NUM_OPS) ? result : -1;
+    }
+
+    /**
+     * Returns a register list which is equivalent to the given one,
+     * except that it splits category-2 registers into two explicit
+     * entries. This returns the original list if no modification is
+     * required
+     *
+     * @param orig {@code non-null;} the original list
+     * @return {@code non-null;} the list with the described transformation
+     */
+    private static RegisterSpecList explicitize(RegisterSpecList orig) {
+        int wordCount = wordCount(orig);
+        int sz = orig.size();
+
+        if (wordCount == sz) {
+            return orig;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(wordCount);
+        int wordAt = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = orig.get(i);
+            result.set(wordAt, one);
+            if (one.getCategory() == 2) {
+                result.set(wordAt + 1,
+                           RegisterSpec.make(one.getReg() + 1, Type.VOID));
+                wordAt += 2;
+            } else {
+                wordAt++;
+            }
+        }
+
+        result.setImmutable();
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form4rcc.java b/dx/src/com/android/dx/dex/code/form/Form4rcc.java
new file mode 100644
index 0000000..d4eca55
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form4rcc.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 4rcc}. See the instruction format spec
+ * for details.
+ */
+public final class Form4rcc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form4rcc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form4rcc() {
+        // 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 4;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+        Constant cst = ci.getConstant();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        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()) &&
+             unsignedFitsInByte(regs.getWordCount()));
+    }
+
+    /** {@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, count), (short) cpi, (short) firstReg);
+    }
+}
diff --git a/dx/src/com/android/dx/io/IndexType.java b/dx/src/com/android/dx/io/IndexType.java
index bbddfa8..d873894 100644
--- a/dx/src/com/android/dx/io/IndexType.java
+++ b/dx/src/com/android/dx/io/IndexType.java
@@ -41,6 +41,9 @@
     /** field reference index */
     FIELD_REF,
 
+    /** method index and a proto index */
+    METHOD_AND_PROTO_REF,
+
     /** inline method index (for inline linked method invocations) */
     INLINE_METHOD,
 
diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java
index 756d267..60225f1 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -931,6 +931,14 @@
         new Info(Opcodes.USHR_INT_LIT8, "ushr-int/lit8",
             InstructionCodec.FORMAT_22B, IndexType.NONE);
 
+    public static final Info INVOKE_POLYMORPHIC =
+        new Info(Opcodes.INVOKE_POLYMORPHIC, "invoke-polymorphic",
+            InstructionCodec.FORMAT_45CC, IndexType.METHOD_AND_PROTO_REF);
+
+    public static final Info INVOKE_POLYMORPHIC_RANGE =
+        new Info(Opcodes.INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range",
+            InstructionCodec.FORMAT_4RCC, IndexType.METHOD_AND_PROTO_REF);
+
     // END(opcode-info-defs)
 
     // Static initialization.
@@ -1164,6 +1172,8 @@
         set(SHL_INT_LIT8);
         set(SHR_INT_LIT8);
         set(USHR_INT_LIT8);
+        set(INVOKE_POLYMORPHIC);
+        set(INVOKE_POLYMORPHIC_RANGE);
         // END(opcode-info-init)
     }
 
diff --git a/dx/src/com/android/dx/io/Opcodes.java b/dx/src/com/android/dx/io/Opcodes.java
index 611dbda..6f135de 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -259,6 +259,8 @@
     public static final int SHL_INT_LIT8 = 0xe0;
     public static final int SHR_INT_LIT8 = 0xe1;
     public static final int USHR_INT_LIT8 = 0xe2;
+    public static final int INVOKE_POLYMORPHIC = 0xfa;
+    public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb;
     // END(opcodes)
 
     // TODO: Generate these payload opcodes with opcode-gen.
diff --git a/dx/src/com/android/dx/io/instructions/InstructionCodec.java b/dx/src/com/android/dx/io/instructions/InstructionCodec.java
index 228352f..9c30575 100644
--- a/dx/src/com/android/dx/io/instructions/InstructionCodec.java
+++ b/dx/src/com/android/dx/io/instructions/InstructionCodec.java
@@ -604,6 +604,28 @@
         }
     },
 
+    FORMAT_45CC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterList(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterList(insn, out);
+        }
+    },
+
+    FORMAT_4RCC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterList(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterList(insn, out);
+        }
+    },
+
     FORMAT_PACKED_SWITCH_PAYLOAD() {
         @Override public DecodedInstruction decode(int opcodeUnit,
                 CodeInput in) throws EOFException {
diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp
index bdcc558..d8f850e 100644
--- a/libdex/DexOpcodes.cpp
+++ b/libdex/DexOpcodes.cpp
@@ -280,8 +280,8 @@
     "+iput-object-quick",
     "+invoke-virtual-quick",
     "+invoke-virtual-quick/range",
-    "+invoke-super-quick",
-    "+invoke-super-quick/range",
+    "invoke-polymorphic",
+    "invoke-polymorphic/range",
     "+iput-object-volatile",
     "+sget-object-volatile",
     "+sput-object-volatile",
diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h
index c2b9b80..09fdcdb 100644
--- a/libdex/DexOpcodes.h
+++ b/libdex/DexOpcodes.h
@@ -318,8 +318,8 @@
     OP_IPUT_OBJECT_QUICK            = 0xf7,
     OP_INVOKE_VIRTUAL_QUICK         = 0xf8,
     OP_INVOKE_VIRTUAL_QUICK_RANGE   = 0xf9,
-    OP_INVOKE_SUPER_QUICK           = 0xfa,
-    OP_INVOKE_SUPER_QUICK_RANGE     = 0xfb,
+    OP_INVOKE_POLYMORPHIC           = 0xfa,
+    OP_INVOKE_POLYMORPHIC_RANGE     = 0xfb,
     OP_IPUT_OBJECT_VOLATILE         = 0xfc,
     OP_SGET_OBJECT_VOLATILE         = 0xfd,
     OP_SPUT_OBJECT_VOLATILE         = 0xfe,
@@ -584,8 +584,8 @@
         H(OP_IPUT_OBJECT_QUICK),                                              \
         H(OP_INVOKE_VIRTUAL_QUICK),                                           \
         H(OP_INVOKE_VIRTUAL_QUICK_RANGE),                                     \
-        H(OP_INVOKE_SUPER_QUICK),                                             \
-        H(OP_INVOKE_SUPER_QUICK_RANGE),                                       \
+        H(OP_INVOKE_POLYMORPHIC),                                             \
+        H(OP_INVOKE_POLYMORPHIC_RANGE),                                       \
         H(OP_IPUT_OBJECT_VOLATILE),                                           \
         H(OP_SGET_OBJECT_VOLATILE),                                           \
         H(OP_SPUT_OBJECT_VOLATILE),                                           \
diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp
index be343f0..3b7d552 100644
--- a/libdex/InstrUtils.cpp
+++ b/libdex/InstrUtils.cpp
@@ -47,7 +47,7 @@
     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3,
-    3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0,
+    3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 2, 2, 2, 0,
     // END(libdex-widths)
 };
 
@@ -357,7 +357,7 @@
     kFmt22b,  kFmt22b,  kFmt22b,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,
     kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,  kFmt20bc,
     kFmt35mi, kFmt3rmi, kFmt35c,  kFmt10x,  kFmt22cs, kFmt22cs, kFmt22cs,
-    kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt35ms, kFmt3rms,
+    kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt45cc, kFmt4rcc,
     kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,
     // END(libdex-formats)
 };
@@ -451,7 +451,7 @@
     kIndexMethodRef,    kIndexNone,         kIndexFieldOffset,
     kIndexFieldOffset,  kIndexFieldOffset,  kIndexFieldOffset,
     kIndexFieldOffset,  kIndexFieldOffset,  kIndexVtableOffset,
-    kIndexVtableOffset, kIndexVtableOffset, kIndexVtableOffset,
+    kIndexVtableOffset, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef,
     kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
     kIndexUnknown,
     // END(libdex-index-types)
@@ -642,6 +642,29 @@
         pDec->vA = INST_AA(inst);
         pDec->vB_wide = FETCH_u4(1) | ((u8) FETCH_u4(3) << 32);
         break;
+    case kFmt45cc:
+        {
+            // AG op BBBB FEDC HHHH
+            pDec->vA = INST_B(inst);  // This is labelled A in the spec.
+            pDec->vB = FETCH(1);  // vB meth@BBBB
+            u2 fedc  = FETCH(2);
+            pDec->vC = fedc & 0xf;
+            pDec->arg[0] = (fedc >> 4) & 0xf;  // vD
+            pDec->arg[1] = (fedc >> 8) & 0xf;  // vE
+            pDec->arg[2] = (fedc >> 12);       // vF
+            pDec->arg[3] = INST_A(inst);       // vG
+            pDec->arg[4] = FETCH(3);           // vH proto@HHHH
+        }
+        break;
+    case kFmt4rcc:
+        {
+            // AA op BBBB CCCC HHHH
+            pDec->vA = INST_AA(inst);
+            pDec->vB = FETCH(1);
+            pDec->vC = FETCH(2);
+            pDec->arg[4] = FETCH(3);  // vH proto@HHHH
+        }
+        break;
     default:
         ALOGW("Can't decode unexpected format %d (op=%d)", format, opcode);
         assert(false);
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
index 76993a5..2f34bd9 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -61,6 +61,8 @@
     kFmt51l,        // op vAA, #+BBBBBBBBBBBBBBBB
     kFmt35mi,       // [opt] inline invoke
     kFmt3rmi,       // [opt] inline invoke/range
+    kFmt45cc,       // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
+    kFmt4rcc,       // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
 };
 
 /*
@@ -69,15 +71,16 @@
  */
 enum InstructionIndexType {
     kIndexUnknown = 0,
-    kIndexNone,         // has no index
-    kIndexVaries,       // "It depends." Used for throw-verification-error
-    kIndexTypeRef,      // type reference index
-    kIndexStringRef,    // string reference index
-    kIndexMethodRef,    // method reference index
-    kIndexFieldRef,     // field reference index
-    kIndexInlineMethod, // inline method index (for inline linked methods)
-    kIndexVtableOffset, // vtable offset (for static linked methods)
-    kIndexFieldOffset   // field offset (for static linked fields)
+    kIndexNone,              // has no index
+    kIndexVaries,            // "It depends." Used for throw-verification-error
+    kIndexTypeRef,           // type reference index
+    kIndexStringRef,         // string reference index
+    kIndexMethodRef,         // method reference index
+    kIndexFieldRef,          // field reference index
+    kIndexInlineMethod,      // inline method index (for inline linked methods)
+    kIndexVtableOffset,      // vtable offset (for static linked methods)
+    kIndexFieldOffset,       // field offset (for static linked fields)
+    kIndexMethodAndProtoRef  // method index and proto index
 };
 
 /*
diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt
index 6b7b9b1..dc0778d 100644
--- a/opcode-gen/bytecode.txt
+++ b/opcode-gen/bytecode.txt
@@ -39,9 +39,10 @@
 format 22c
 format 22t
 format 35c 3rc
+format 45cc 4rcc
 
 # Optimized formats
-format 00x 
+format 00x
 format 20bc
 format 22cs
 format 35mi
@@ -67,6 +68,7 @@
 #     inline-method
 #     vtable-offset
 #     field-offset
+#     method-and-proto-ref
 #   flags; pipe-combined combo of one or more of:
 #     optimized     -- optimized; not to be included in unoptimized dex files
 #     branch        -- might branch to an address
@@ -337,8 +339,13 @@
 op   f7 +iput-object-quick          22cs n field-offset  optimized|continue|throw
 op   f8 +invoke-virtual-quick       35ms n vtable-offset optimized|continue|throw|invoke
 op   f9 +invoke-virtual-quick/range 3rms n vtable-offset optimized|continue|throw|invoke
-op   fa +invoke-super-quick         35ms n vtable-offset optimized|continue|throw|invoke
-op   fb +invoke-super-quick/range   3rms n vtable-offset optimized|continue|throw|invoke
+
+# Invoke-polymorphic
+op   fa invoke-polymorphic          45cc y method-and-proto-ref continue|throw|invoke
+op   fb invoke-polymorphic/range    4rcc y method-and-proto-ref continue|throw|invoke
+
+# More optimized opcodes (not valid in an unoptimized dex file)
+
 op   fc +iput-object-volatile       22c  n field-ref     optimized|continue|throw
 op   fd +sget-object-volatile       21c  y field-ref     optimized|continue|throw
 op   fe +sput-object-volatile       21c  n field-ref     optimized|continue|throw
diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk
index e26a60c..d1e9a08 100644
--- a/opcode-gen/opcode-gen.awk
+++ b/opcode-gen/opcode-gen.awk
@@ -474,16 +474,17 @@
 
 # Initialize the indexTypes data.
 function initIndexTypes() {
-    indexTypeValues["unknown"]       = "kIndexUnknown";
-    indexTypeValues["none"]          = "kIndexNone";
-    indexTypeValues["varies"]        = "kIndexVaries";
-    indexTypeValues["type-ref"]      = "kIndexTypeRef";
-    indexTypeValues["string-ref"]    = "kIndexStringRef";
-    indexTypeValues["method-ref"]    = "kIndexMethodRef";
-    indexTypeValues["field-ref"]     = "kIndexFieldRef";
-    indexTypeValues["inline-method"] = "kIndexInlineMethod";
-    indexTypeValues["vtable-offset"] = "kIndexVtableOffset";
-    indexTypeValues["field-offset"]  = "kIndexFieldOffset";
+    indexTypeValues["unknown"]              = "kIndexUnknown";
+    indexTypeValues["none"]                 = "kIndexNone";
+    indexTypeValues["varies"]               = "kIndexVaries";
+    indexTypeValues["type-ref"]             = "kIndexTypeRef";
+    indexTypeValues["string-ref"]           = "kIndexStringRef";
+    indexTypeValues["method-ref"]           = "kIndexMethodRef";
+    indexTypeValues["field-ref"]            = "kIndexFieldRef";
+    indexTypeValues["inline-method"]        = "kIndexInlineMethod";
+    indexTypeValues["vtable-offset"]        = "kIndexVtableOffset";
+    indexTypeValues["field-offset"]         = "kIndexFieldOffset";
+    indexTypeValues["method-and-proto-ref"] = "kIndexMethodAndProtoRef";
 }
 
 # Initialize the flags data.