Add support invoke-custom to dexdump

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

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

Bug: 30550796,33191717,33231751
Test: manually tested with DEX files generated from ART run-tests.
Change-Id: If2cedea21875e93525c4850005d335901897484a
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index fd7542e..157b661 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -915,6 +915,9 @@
             free(protoInfo.parameterTypes);
         }
         break;
+    case kCallSiteRef:
+        outSize = snprintf(buf, bufSize, "call_site@%0*x", width, index);
+        break;
     default:
         outSize = snprintf(buf, bufSize, "<?>");
         break;
@@ -1842,6 +1845,219 @@
     }
 }
 
+static const DexMapItem* findMapItem(const DexFile* pDexFile, u4 type)
+{
+    u4 offset = pDexFile->pHeader->mapOff;
+    const DexMapList* list = (const DexMapList*)(pDexFile->baseAddr + offset);
+    for (u4 i = 0; i < list->size; ++i) {
+        if (list->list[i].type == type) {
+            return &list->list[i];
+        }
+    }
+    return nullptr;
+}
+
+static void dumpMethodHandles(DexFile* pDexFile)
+{
+    const DexMapItem* item = findMapItem(pDexFile, kDexTypeMethodHandleItem);
+    if (item == nullptr) return;
+    const DexMethodHandleItem* method_handles =
+            (const DexMethodHandleItem*)(pDexFile->baseAddr + item->offset);
+    for (u4 i = 0; i < item->size; ++i) {
+        const DexMethodHandleItem& mh = method_handles[i];
+        bool is_invoke = false;
+        const char* type;
+        switch (mh.methodHandleType) {
+            case 0:
+                type = "put-static";
+                break;
+            case 1:
+                type = "get-static";
+                break;
+            case 2:
+                type = "put-instance";
+                break;
+            case 3:
+                type = "get-instance";
+                break;
+            case 4:
+                type = "invoke-static";
+                is_invoke = true;
+                break;
+            case 5:
+                type = "invoke-instance";
+                is_invoke = true;
+                break;
+            case 6:
+                type = "invoke-constructor";
+                is_invoke = true;
+                break;
+        }
+
+        FieldMethodInfo info;
+        memset(&info, 0, sizeof(info));
+        if (is_invoke) {
+            getMethodInfo(pDexFile, mh.fieldOrMethodIdx, &info);
+        } else {
+            getFieldInfo(pDexFile, mh.fieldOrMethodIdx, &info);
+        }
+
+        if (gOptions.outputFormat == OUTPUT_XML) {
+            printf("<method_handle index index=\"%u\"\n", i);
+            printf(" type=\"%s\"\n", type);
+            printf(" target_class=\"%s\"\n", info.classDescriptor);
+            printf(" target_member=\"%s\"\n", info.name);
+            printf(" target_member_type=\"%s\"\n", info.signature);
+            printf("</method_handle>\n");
+        } else {
+            printf("Method Handle #%u:\n", i);
+            printf("  type        : %s\n", type);
+            printf("  target      : %s %s\n", info.classDescriptor, info.name);
+            printf("  target_type : %s\n", info.signature);
+        }
+    }
+}
+
+/* Helper for dumpCallSites(), which reads a 1- to 8- byte signed
+ * little endian value. */
+static u8 readSignedLittleEndian(const u1** pData, u4 size) {
+    const u1* data = *pData;
+    u8 result = 0;
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        result = (result >> 8) | (((int64_t)*data++) << 56);
+    }
+
+    result >>= (8 - size) * 8;
+    *pData = data;
+    return result;
+}
+
+/* Helper for dumpCallSites(), which reads a 1- to 8- byte unsigned
+ * little endian value. */
+static u8 readUnsignedLittleEndian(const u1** pData, u4 size, bool fillOnRight = false) {
+    const u1* data = *pData;
+    u8 result = 0;
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        result = (result >> 8) | (((u8)*data++) << 56);
+    }
+
+    u8 oldResult = result;
+    if (!fillOnRight) {
+        result >>= (8u - size) * 8;
+    }
+
+    *pData = data;
+    return result;
+}
+
+static void dumpCallSites(DexFile* pDexFile)
+{
+    const DexMapItem* item = findMapItem(pDexFile, kDexTypeCallSiteIdItem);
+    if (item == nullptr) return;
+    const DexCallSiteId* ids = (const DexCallSiteId*)(pDexFile->baseAddr + item->offset);
+    for (u4 index = 0; index < item->size; ++index) {
+        bool doXml = (gOptions.outputFormat == OUTPUT_XML);
+        printf(doXml ? "<call_site index=\"%u\">\n" : "Call Site #%u\n", index);
+        const u1* data = pDexFile->baseAddr + ids[index].callSiteOff;
+        u4 count = readUnsignedLeb128(&data);
+        for (u4 i = 0; i < count; ++i) {
+            printf(doXml ? "<link_argument index=\"%u\" " : "  link_argument[%u] : ", i);
+            u1 headerByte = *data++;
+            u4 valueType = headerByte & kDexAnnotationValueTypeMask;
+            u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
+            switch (valueType) {
+                case kDexAnnotationByte: {
+                    printf(doXml ? "type=\"byte\" value=\"%d\"/>" : "%d (byte)", (int)*data++);
+                    break;
+                }
+                case kDexAnnotationShort: {
+                    printf(doXml ? "type=\"short\" value=\"%d\"/>" : "%d (short)",
+                           (int)readSignedLittleEndian(&data, valueArg + 1));
+                    break;
+                }
+                case kDexAnnotationChar: {
+                    printf(doXml ? "type=\"short\" value=\"%u\"/>" : "%u (char)",
+                           (u2)readUnsignedLittleEndian(&data, valueArg + 1));
+                    break;
+                }
+                case kDexAnnotationInt: {
+                    printf(doXml ? "type=\"int\" value=\"%d\"/>" : "%d (int)",
+                           (int)readSignedLittleEndian(&data, valueArg + 1));
+                    break;
+                }
+                case kDexAnnotationLong: {
+                    printf(doXml ? "type=\"long\" value=\"%" PRId64 "\"/>" : "%" PRId64 " (long)",
+                           (int64_t)readSignedLittleEndian(&data, valueArg + 1));
+                    break;
+                }
+                case kDexAnnotationFloat: {
+                    u4 rawValue = (u4)(readUnsignedLittleEndian(&data, valueArg + 1, true) >> 32);
+                    printf(doXml ? "type=\"float\" value=\"%g\"/>" : "%g (float)",
+                           *((float*)&rawValue));
+                    break;
+                }
+                case kDexAnnotationDouble: {
+                    u8 rawValue = readUnsignedLittleEndian(&data, valueArg + 1, true);
+                    printf(doXml ? "type=\"double\" value=\"%g\"/>" : "%g (double)",
+                           *((double*)&rawValue));
+                    break;
+                }
+                case kDexAnnotationMethodType: {
+                    u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
+                    ProtoInfo protoInfo;
+                    memset(&protoInfo, 0, sizeof(protoInfo));
+                    getProtoInfo(pDexFile, idx, &protoInfo);
+                    printf(doXml ? "type=\"MethodType\" value=\"(%s)%s\"/>" : "(%s)%s (MethodType)",
+                           protoInfo.parameterTypes, protoInfo.returnType);
+                    free(protoInfo.parameterTypes);
+                    break;
+                }
+                case kDexAnnotationMethodHandle: {
+                    u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
+                    printf(doXml ? "type=\"MethodHandle\" value=\"%u\"/>" : "%u (MethodHandle)",
+                           idx);
+                    break;
+                }
+                case kDexAnnotationString: {
+                    u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
+                    printf(doXml ? "type=\"String\" value=\"%s\"/>" : "%s (String)",
+                           dexStringById(pDexFile, idx));
+                    break;
+                }
+                case kDexAnnotationType: {
+                    u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
+                    printf(doXml ? "type=\"Class\" value=\"%s\"/>" : "%s (Class)",
+                           dexStringByTypeIdx(pDexFile, idx));
+                    break;
+                }
+                case kDexAnnotationNull: {
+                    printf(doXml ? "type=\"null\" value=\"null\"/>" : "null (null)");
+                    break;
+                }
+                case kDexAnnotationBoolean: {
+                    printf(doXml ? "type=\"boolean\" value=\"%s\"/>" : "%s (boolean)",
+                           (valueArg & 1) == 0 ? "false" : "true");
+                    break;
+                }
+                default:
+                    // Other types are not anticipated being reached here.
+                    printf("Unexpected type found, bailing on call site info.\n");
+                    i = count;
+                    break;
+            }
+            printf("\n");
+        }
+
+        if (doXml) {
+            printf("</callsite>\n");
+        }
+    }
+}
+
 /*
  * Dump the requested sections of the file.
  */
@@ -1875,6 +2091,9 @@
         dumpClass(pDexFile, i, &package);
     }
 
+    dumpMethodHandles(pDexFile);
+    dumpCallSites(pDexFile);
+
     /* free the last one allocated */
     if (package != NULL) {
         printf("</package>\n");
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index f3c2b49..cc87695 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -501,10 +501,6 @@
         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);
@@ -525,10 +521,6 @@
         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);
@@ -945,6 +937,22 @@
         new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT,
             Opcodes.NO_NEXT, Form22b.THE_ONE, true);
 
+    public static final Dop INVOKE_POLYMORPHIC =
+        new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC,
+            Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, true);
+
+    public static final Dop INVOKE_POLYMORPHIC_RANGE =
+        new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC,
+            Opcodes.NO_NEXT, Form4rcc.THE_ONE, true);
+
+    public static final Dop INVOKE_CUSTOM =
+        new Dop(Opcodes.INVOKE_CUSTOM, Opcodes.INVOKE_CUSTOM,
+            Opcodes.INVOKE_CUSTOM_RANGE, Form35c.THE_ONE, true);
+
+    public static final Dop INVOKE_CUSTOM_RANGE =
+        new Dop(Opcodes.INVOKE_CUSTOM_RANGE, Opcodes.INVOKE_CUSTOM,
+            Opcodes.NO_NEXT, Form3rc.THE_ONE, true);
+
     // END(dops)
 
     // Static initialization.
@@ -1174,6 +1182,8 @@
         set(USHR_INT_LIT8);
         set(INVOKE_POLYMORPHIC);
         set(INVOKE_POLYMORPHIC_RANGE);
+        set(INVOKE_CUSTOM);
+        set(INVOKE_CUSTOM_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 affa9eb..927db3e 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -214,6 +214,7 @@
     //     Opcodes.SHR_INT_LIT8
     //     Opcodes.USHR_INT_LIT8
     //     Opcodes.INVOKE_POLYMORPHIC
+    //     Opcodes.INVOKE_CUSTOM
     // END(first-opcodes)
 
     static {
diff --git a/dx/src/com/android/dx/io/IndexType.java b/dx/src/com/android/dx/io/IndexType.java
index d873894..0bd142a 100644
--- a/dx/src/com/android/dx/io/IndexType.java
+++ b/dx/src/com/android/dx/io/IndexType.java
@@ -44,6 +44,9 @@
     /** method index and a proto index */
     METHOD_AND_PROTO_REF,
 
+    /** call site reference index */
+    CALL_SITE_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 60225f1..500abf7 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -939,6 +939,14 @@
         new Info(Opcodes.INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range",
             InstructionCodec.FORMAT_4RCC, IndexType.METHOD_AND_PROTO_REF);
 
+    public static final Info INVOKE_CUSTOM =
+        new Info(Opcodes.INVOKE_CUSTOM, "invoke-custom",
+            InstructionCodec.FORMAT_35C, IndexType.CALL_SITE_REF);
+
+    public static final Info INVOKE_CUSTOM_RANGE =
+        new Info(Opcodes.INVOKE_CUSTOM_RANGE, "invoke-custom/range",
+            InstructionCodec.FORMAT_3RC, IndexType.CALL_SITE_REF);
+
     // END(opcode-info-defs)
 
     // Static initialization.
@@ -1174,6 +1182,8 @@
         set(USHR_INT_LIT8);
         set(INVOKE_POLYMORPHIC);
         set(INVOKE_POLYMORPHIC_RANGE);
+        set(INVOKE_CUSTOM);
+        set(INVOKE_CUSTOM_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 6f135de..9afee41 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -261,6 +261,8 @@
     public static final int USHR_INT_LIT8 = 0xe2;
     public static final int INVOKE_POLYMORPHIC = 0xfa;
     public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb;
+    public static final int INVOKE_CUSTOM = 0xfc;
+    public static final int INVOKE_CUSTOM_RANGE = 0xfd;
     // END(opcodes)
 
     // TODO: Generate these payload opcodes with opcode-gen.
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index 6c4d0d8..74fce3c 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -92,6 +92,11 @@
  */
 #define DEX_MAGIC_VERS_37  "037\0"
 
+/* The version for android O, encoded in 4 bytes of ASCII. This differentiates dex files that may
+ * contain invoke-custom, invoke-polymorphic, call-sites, and method handles.
+ */
+#define DEX_MAGIC_VERS_38  "038\0"
+
 /* current version, encoded in 4 bytes of ASCII */
 #define DEX_MAGIC_VERS  "036\0"
 
@@ -191,6 +196,8 @@
     kDexAnnotationLong          = 0x06,
     kDexAnnotationFloat         = 0x10,
     kDexAnnotationDouble        = 0x11,
+    kDexAnnotationMethodType    = 0x15,
+    kDexAnnotationMethodHandle  = 0x16,
     kDexAnnotationString        = 0x17,
     kDexAnnotationType          = 0x18,
     kDexAnnotationField         = 0x19,
@@ -214,6 +221,8 @@
     kDexTypeFieldIdItem              = 0x0004,
     kDexTypeMethodIdItem             = 0x0005,
     kDexTypeClassDefItem             = 0x0006,
+    kDexTypeCallSiteIdItem           = 0x0007,
+    kDexTypeMethodHandleItem         = 0x0008,
     kDexTypeMapList                  = 0x1000,
     kDexTypeTypeList                 = 0x1001,
     kDexTypeAnnotationSetRefList     = 0x1002,
@@ -355,6 +364,23 @@
 };
 
 /*
+ * Direct-mapped "call_site_id_item"
+ */
+struct DexCallSiteId {
+    u4  callSiteOff;        /* file offset to DexEncodedArray */
+};
+
+/*
+ * Direct-mapped "method_handle_item"
+ */
+struct DexMethodHandleItem {
+    u2 methodHandleType;    /* type of method handle */
+    u2 reserved1;           /* reserved for future use */
+    u2 fieldOrMethodIdx;    /* index of associated field or method */
+    u2 reserved2;           /* reserved for future use */
+};
+
+/*
  * Direct-mapped "type_item".
  */
 struct DexTypeItem {
diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp
index d8f850e..8a98772 100644
--- a/libdex/DexOpcodes.cpp
+++ b/libdex/DexOpcodes.cpp
@@ -282,8 +282,8 @@
     "+invoke-virtual-quick/range",
     "invoke-polymorphic",
     "invoke-polymorphic/range",
-    "+iput-object-volatile",
-    "+sget-object-volatile",
+    "invoke-custom",
+    "invoke-custom/range",
     "+sput-object-volatile",
     "unused-ff",
     // END(libdex-opcode-names)
diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h
index 09fdcdb..625a2e8 100644
--- a/libdex/DexOpcodes.h
+++ b/libdex/DexOpcodes.h
@@ -320,8 +320,8 @@
     OP_INVOKE_VIRTUAL_QUICK_RANGE   = 0xf9,
     OP_INVOKE_POLYMORPHIC           = 0xfa,
     OP_INVOKE_POLYMORPHIC_RANGE     = 0xfb,
-    OP_IPUT_OBJECT_VOLATILE         = 0xfc,
-    OP_SGET_OBJECT_VOLATILE         = 0xfd,
+    OP_INVOKE_CUSTOM                = 0xfc,
+    OP_INVOKE_CUSTOM_RANGE          = 0xfd,
     OP_SPUT_OBJECT_VOLATILE         = 0xfe,
     OP_UNUSED_FF                    = 0xff,
     // END(libdex-opcode-enum)
@@ -586,8 +586,8 @@
         H(OP_INVOKE_VIRTUAL_QUICK_RANGE),                                     \
         H(OP_INVOKE_POLYMORPHIC),                                             \
         H(OP_INVOKE_POLYMORPHIC_RANGE),                                       \
-        H(OP_IPUT_OBJECT_VOLATILE),                                           \
-        H(OP_SGET_OBJECT_VOLATILE),                                           \
+        H(OP_INVOKE_CUSTOM),                                                  \
+        H(OP_INVOKE_CUSTOM_RANGE),                                            \
         H(OP_SPUT_OBJECT_VOLATILE),                                           \
         H(OP_UNUSED_FF),                                                      \
         /* END(libdex-goto-table) */                                          \
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
index 54d0c33..bd9140c 100644
--- a/libdex/DexSwapVerify.cpp
+++ b/libdex/DexSwapVerify.cpp
@@ -45,10 +45,12 @@
 struct CheckState {
     const DexHeader*  pHeader;
     const u1*         fileStart;
-    const u1*         fileEnd;      // points to fileStart + fileLen
+    const u1*         fileEnd;             // points to fileStart + fileLen
     u4                fileLen;
-    DexDataMap*       pDataMap;     // set after map verification
-    const DexFile*    pDexFile;     // set after intraitem verification
+    DexDataMap*       pDataMap;            // set after map verification
+    const DexFile*    pDexFile;            // set after intraitem verification
+    const DexMapItem* pCallSiteIds;        // set after intraitem verification
+    const DexMapItem* pMethodHandleItems;  // set after intraitem verification
 
     /*
      * bitmap of type_id indices that have been used to define classes;
@@ -335,6 +337,8 @@
         case kDexTypeAnnotationItem:           return 1 << 15;
         case kDexTypeEncodedArrayItem:         return 1 << 16;
         case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
+        case kDexTypeCallSiteIdItem:           return 1 << 18;
+        case kDexTypeMethodHandleItem:         return 1 << 19;
         default: {
             ALOGE("Unknown map item type %04x", mapType);
             return 0;
@@ -430,6 +434,12 @@
             return false;
         }
 
+        if (item->type == kDexTypeCallSiteIdItem) {
+            state->pCallSiteIds = item;
+        } else if (item->type == kDexTypeMethodHandleItem) {
+            state->pMethodHandleItems = item;
+        }
+
         usedBits |= bit;
         lastOffset = item->offset;
         item++;
@@ -1036,6 +1046,48 @@
     return (void*) (item + 1);
 }
 
+/* Perform cross-item verification of call_site_id. */
+static void* crossVerifyCallSiteId(const CheckState* state, void* ptr) {
+    const DexCallSiteId* item = (const DexCallSiteId*) ptr;
+    if (state->pCallSiteIds == nullptr) {
+        ALOGE("Verifying call site but expecting none");
+        return NULL;
+    }
+    if (item->callSiteOff < state->pHeader->dataOff ||
+        item->callSiteOff >= state->pHeader->dataOff + state->pHeader->dataSize) {
+        ALOGE("Bad call site offset: %u", item->callSiteOff);
+        return NULL;
+    }
+    return (void*) (item + 1);
+}
+
+/* Perform cross-item verification of method_handle_item. */
+static void* crossVerifyMethodHandleItem(const CheckState* state, void* ptr) {
+    const DexMethodHandleItem* item = (const DexMethodHandleItem*) ptr;
+    if (state->pMethodHandleItems == nullptr) {
+        ALOGE("Verifying method handle but expecting none");
+        return NULL;
+    }
+    if (item->methodHandleType <= 3 &&
+        item->fieldOrMethodIdx >= state->pHeader->fieldIdsSize) {
+        // 0-3 are field accessors.
+        ALOGE("Method handle has invalid field id: %u\n", item->fieldOrMethodIdx);
+        return NULL;
+    }
+    if (item->methodHandleType >= 4 &&
+        item->methodHandleType <= 6 &&
+        item->fieldOrMethodIdx >= state->pHeader->methodIdsSize) {
+        // 4-6 are method invocations.
+        ALOGE("Method handle has invalid method id: %u\n", item->fieldOrMethodIdx);
+        return NULL;
+    }
+    if (item->methodHandleType >= 7) {
+        ALOGE("Unknown method handle type: %u", item->methodHandleType);
+        return NULL;
+    }
+    return (void*) (item + 1);
+}
+
 /* Helper for swapAnnotationsDirectoryItem(), which performs
  * byte-swapping and intra-item verification on an
  * annotation_directory_item's field elements. */
@@ -1164,6 +1216,26 @@
     return addr;
 }
 
+static void* swapCallSiteId(const CheckState* state, void* ptr) {
+    DexCallSiteId* item = (DexCallSiteId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_OFFSET4(item->callSiteOff);
+
+    return (item + 1);
+}
+
+static void* swapMethodHandleItem(const CheckState* state, void* ptr) {
+    DexMethodHandleItem* item = (DexMethodHandleItem*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_FIELD2(item->methodHandleType);
+    SWAP_FIELD2(item->fieldOrMethodIdx);
+
+    return (item + 1);
+}
+
+
 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
  * field elements. */
 static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
@@ -2144,6 +2216,13 @@
     return data;
 }
 
+static u4 numberOfMethodHandles(const CheckState* state) {
+    if (state->pMethodHandleItems != nullptr) {
+        return state->pMethodHandleItems->size;
+    }
+    return 0;
+}
+
 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
  * verifies an encoded_value. */
 static const u1* verifyEncodedValue(const CheckState* state,
@@ -2186,6 +2265,24 @@
             data += valueArg + 1;
             break;
         }
+        case kDexAnnotationMethodType: {
+            if (valueArg > 3) {
+                ALOGE("Bogus method type size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->protoIdsSize);
+            break;
+        }
+        case kDexAnnotationMethodHandle: {
+            if (valueArg > 3) {
+                ALOGE("Bogus method type size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, numberOfMethodHandles(state));
+            break;
+        }
         case kDexAnnotationString: {
             if (valueArg > 3) {
                 ALOGE("Bogus string size %#x", valueArg);
@@ -2595,6 +2692,18 @@
                         sizeof(u4), &lastOffset);
                 break;
             }
+            case kDexTypeCallSiteIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, sectionOffset, sectionCount,
+                        swapCallSiteId, sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeMethodHandleItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, sectionOffset, sectionCount,
+                        swapMethodHandleItem, sizeof(u4), &lastOffset);
+                break;
+            }
             case kDexTypeMapList: {
                 /*
                  * The map section was swapped early on, but do some
@@ -2742,6 +2851,16 @@
                 state->pDefinedClassBits = NULL;
                 break;
             }
+            case kDexTypeCallSiteIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyCallSiteId, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeMethodHandleItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyMethodHandleItem, sizeof(u4), NULL);
+                break;
+            }
             case kDexTypeAnnotationSetRefList: {
                 okay = iterateSection(state, sectionOffset, sectionCount,
                         crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
@@ -2792,8 +2911,9 @@
     }
 
     if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
-            (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0) &&
-            (memcmp(version, DEX_MAGIC_VERS_37, 4) != 0)) {
+        (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0) &&
+        (memcmp(version, DEX_MAGIC_VERS_37, 4) != 0) &&
+        (memcmp(version, DEX_MAGIC_VERS_38, 4) != 0)) {
         /*
          * Magic was correct, but this is an unsupported older or
          * newer format variant.
diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp
index 3b7d552..3e81398 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, 4, 4, 2, 2, 2, 0,
+    3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 3, 3, 2, 0,
     // END(libdex-widths)
 };
 
@@ -309,8 +309,8 @@
     kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
     kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
     kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
-    kInstrCanContinue|kInstrCanThrow,
-    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
     kInstrCanContinue|kInstrCanThrow,
     0,
     // END(libdex-flags)
@@ -358,7 +358,7 @@
     kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,  kFmt20bc,
     kFmt35mi, kFmt3rmi, kFmt35c,  kFmt10x,  kFmt22cs, kFmt22cs, kFmt22cs,
     kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt45cc, kFmt4rcc,
-    kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,
+    kFmt35c,  kFmt3rc,  kFmt21c,  kFmt00x,
     // END(libdex-formats)
 };
 
@@ -452,7 +452,7 @@
     kIndexFieldOffset,  kIndexFieldOffset,  kIndexFieldOffset,
     kIndexFieldOffset,  kIndexFieldOffset,  kIndexVtableOffset,
     kIndexVtableOffset, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef,
-    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kCallSiteRef,       kCallSiteRef,       kIndexFieldRef,
     kIndexUnknown,
     // END(libdex-index-types)
 };
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
index 2f34bd9..e8ae4c8 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -80,7 +80,8 @@
     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
+    kIndexMethodAndProtoRef, // method index and proto index
+    kCallSiteRef             // call site index
 };
 
 /*
diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt
index dc0778d..840d433 100644
--- a/opcode-gen/bytecode.txt
+++ b/opcode-gen/bytecode.txt
@@ -69,6 +69,7 @@
 #     vtable-offset
 #     field-offset
 #     method-and-proto-ref
+#     call-site-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
@@ -343,11 +344,11 @@
 # 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
+op   fc invoke-custom               35c  y call-site-ref continue|throw|invoke
+op   fd invoke-custom/range         3rc  y call-site-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
 
 # unused: op ff
diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk
index d1e9a08..baf774b 100644
--- a/opcode-gen/opcode-gen.awk
+++ b/opcode-gen/opcode-gen.awk
@@ -485,6 +485,7 @@
     indexTypeValues["vtable-offset"]        = "kIndexVtableOffset";
     indexTypeValues["field-offset"]         = "kIndexFieldOffset";
     indexTypeValues["method-and-proto-ref"] = "kIndexMethodAndProtoRef";
+    indexTypeValues["call-site-ref"]        = "kCallSiteRef";
 }
 
 # Initialize the flags data.