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.