summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrion Hodson <oth@google.com>2017-09-21 15:27:51 +0100
committerOrion Hodson <oth@google.com>2017-09-27 13:34:02 +0100
commit766a678339e615d7e0b3935111392b7eef50df24 (patch)
tree1a1354274682c320f1230e6e23c790846ccce32a
parent395c9e9c1b6f367c80c6203ed6f22a65c6586a7e (diff)
downloaddalvik-766a678339e615d7e0b3935111392b7eef50df24.tar.gz
New bytecodes for constant-method-{handle,type}
Adds new bytecodes with const-method-handle and const-method-type for loading constant method handles and method types. Both bytecodes use format 21c. Updates dexdump and libdex to include new bytecodes. Increases the DEX file version to 039 and API level to 27 for DEX files using these new bytecodes. Bug: 66562179 Test: dx/tests/run-test 142 Test: dx/tests/run-all-tests Change-Id: If349a1e026b2ab604560d200e3c6424378958491
-rw-r--r--dexdump/DexDump.cpp20
-rw-r--r--dx/src/com/android/dex/DexFormat.java33
-rw-r--r--dx/src/com/android/dx/cf/code/BasicBlocker.java7
-rw-r--r--dx/src/com/android/dx/cf/code/Simulator.java25
-rw-r--r--dx/src/com/android/dx/dex/DexOptions.java42
-rw-r--r--dx/src/com/android/dx/dex/code/Dops.java10
-rw-r--r--dx/src/com/android/dx/dex/code/RopToDop.java11
-rw-r--r--dx/src/com/android/dx/dex/code/form/Form21c.java10
-rw-r--r--dx/src/com/android/dx/dex/file/DexFile.java7
-rw-r--r--dx/src/com/android/dx/dex/file/MethodHandleItem.java4
-rw-r--r--dx/src/com/android/dx/io/IndexType.java8
-rw-r--r--dx/src/com/android/dx/io/OpcodeInfo.java10
-rw-r--r--dx/src/com/android/dx/io/Opcodes.java2
-rw-r--r--dx/src/com/android/dx/rop/cst/CstMethodHandle.java15
-rw-r--r--dx/src/com/android/dx/rop/cst/CstProtoRef.java8
-rw-r--r--dx/src/com/android/dx/rop/type/Type.java3
-rw-r--r--dx/tests/142-const-method-handle/constmethodhandle.jarbin0 -> 1819 bytes
-rw-r--r--dx/tests/142-const-method-handle/expected.txt5
-rwxr-xr-xdx/tests/142-const-method-handle/generate-test38
-rw-r--r--dx/tests/142-const-method-handle/info.txt2
-rwxr-xr-xdx/tests/142-const-method-handle/run40
-rw-r--r--dx/tests/142-const-method-handle/src/Main.java30
-rw-r--r--dx/tests/142-const-method-handle/src/constmethodhandle/ConstTest.java31
-rw-r--r--dx/tests/142-const-method-handle/src/constmethodhandle/TestGenerator.java113
-rw-r--r--libdex/DexFile.h5
-rw-r--r--libdex/DexOpcodes.cpp18
-rw-r--r--libdex/DexOpcodes.h36
-rw-r--r--libdex/InstrUtils.cpp34
-rw-r--r--libdex/InstrUtils.h4
-rw-r--r--opcode-gen/bytecode.txt30
-rw-r--r--opcode-gen/opcode-gen.awk4
31 files changed, 482 insertions, 123 deletions
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index 8dbdd22d0..f76cae316 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -916,9 +916,27 @@ static char* indexString(DexFile* pDexFile, const DecodedInstruction* pDecInsn,
free(protoInfo.parameterTypes);
}
break;
- case kCallSiteRef:
+ case kIndexCallSiteRef:
outSize = snprintf(buf, bufSize, "call_site@%0*x", width, index);
break;
+ case kIndexMethodHandleRef:
+ outSize = snprintf(buf, bufSize, "methodhandle@%0*x", width, index);
+ break;
+ case kIndexProtoRef:
+ {
+ ProtoInfo protoInfo;
+ if (getProtoInfo(pDexFile, index, &protoInfo)) {
+ outSize = snprintf(buf, bufSize, "(%s)%s // proto@%0*x",
+ protoInfo.parameterTypes, protoInfo.returnType,
+ width, index);
+
+ } else {
+ outSize = snprintf(buf, bufSize, "<proto?> // proto@%0*x",
+ width, secondaryIndex);
+ }
+ free(protoInfo.parameterTypes);
+ }
+ break;
default:
outSize = snprintf(buf, bufSize, "<?>");
break;
diff --git a/dx/src/com/android/dex/DexFormat.java b/dx/src/com/android/dex/DexFormat.java
index 97771d813..f86917a8b 100644
--- a/dx/src/com/android/dex/DexFormat.java
+++ b/dx/src/com/android/dex/DexFormat.java
@@ -23,8 +23,11 @@ package com.android.dex;
public final class DexFormat {
private DexFormat() {}
- /** API level to target in order to generate invoke-polymorphic */
- public static final int API_INVOKE_POLYMORPHIC = 26;
+ /** API level to target in order to generate const-method-handle and const-method-type */
+ public static final int API_CONST_METHOD_HANDLE = 27;
+
+ /** API level to target in order to generate invoke-polymorphic and invoke-custom */
+ public static final int API_METHOD_HANDLES = 26;
/** API level to target in order to pass through default and static interface methods */
public static final int API_DEFAULT_INTERFACE_METHODS = 24;
@@ -36,7 +39,10 @@ public final class DexFormat {
* API level to target in order to produce the most modern file
* format
*/
- public static final int API_CURRENT = API_INVOKE_POLYMORPHIC;
+ public static final int API_CURRENT = API_CONST_METHOD_HANDLE;
+
+ /** dex file version number for API level 27 and earlier */
+ public static final String VERSION_FOR_API_27 = "039";
/** dex file version number for API level 26 and earlier */
public static final String VERSION_FOR_API_26 = "038";
@@ -54,7 +60,7 @@ public final class DexFormat {
* completed and is not considered a valid dex file format.
* </p>
*/
- public static final String VERSION_CURRENT = VERSION_FOR_API_26;
+ public static final String VERSION_CURRENT = VERSION_FOR_API_27;
/**
* file name of the primary {@code .dex} file inside an
@@ -90,6 +96,9 @@ public final class DexFormat {
* Returns the API level corresponding to the given magic number,
* or {@code -1} if the given array is not a well-formed dex file
* magic number.
+ *
+ * @param magic array of bytes containing DEX file magic string
+ * @return API level corresponding to magic string if valid, -1 otherwise.
*/
public static int magicToApi(byte[] magic) {
if (magic.length != 8) {
@@ -108,7 +117,9 @@ public final class DexFormat {
} else if (version.equals(VERSION_FOR_API_24)) {
return API_DEFAULT_INTERFACE_METHODS;
} else if (version.equals(VERSION_FOR_API_26)) {
- return API_INVOKE_POLYMORPHIC;
+ return API_METHOD_HANDLES;
+ } else if (version.equals(VERSION_FOR_API_27)) {
+ return API_CONST_METHOD_HANDLE;
} else if (version.equals(VERSION_CURRENT)) {
return API_CURRENT;
}
@@ -118,13 +129,18 @@ public final class DexFormat {
/**
* Returns the magic number corresponding to the given target API level.
+ *
+ * @param targetApiLevel level of API (minimum supported value 13).
+ * @return Magic string corresponding to API level supplied.
*/
public static String apiToMagic(int targetApiLevel) {
String version;
if (targetApiLevel >= API_CURRENT) {
version = VERSION_CURRENT;
- } else if (targetApiLevel >= API_INVOKE_POLYMORPHIC) {
+ } else if (targetApiLevel >= API_CONST_METHOD_HANDLE) {
+ version = VERSION_FOR_API_27;
+ } else if (targetApiLevel >= API_METHOD_HANDLES) {
version = VERSION_FOR_API_26;
} else if (targetApiLevel >= API_DEFAULT_INTERFACE_METHODS) {
version = VERSION_FOR_API_24;
@@ -135,6 +151,11 @@ public final class DexFormat {
return MAGIC_PREFIX + version + MAGIC_SUFFIX;
}
+ /**
+ * Checks whether a DEX file magic string is supported.
+ * @param magic string from DEX file
+ * @return
+ */
public static boolean isSupportedDexMagic(byte[] magic) {
int api = magicToApi(magic);
return api > 0;
diff --git a/dx/src/com/android/dx/cf/code/BasicBlocker.java b/dx/src/com/android/dx/cf/code/BasicBlocker.java
index 31f9627eb..0c5d5a409 100644
--- a/dx/src/com/android/dx/cf/code/BasicBlocker.java
+++ b/dx/src/com/android/dx/cf/code/BasicBlocker.java
@@ -19,6 +19,8 @@ package com.android.dx.cf.code;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstInvokeDynamic;
import com.android.dx.rop.cst.CstMemberRef;
+import com.android.dx.rop.cst.CstMethodHandle;
+import com.android.dx.rop.cst.CstProtoRef;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.Type;
@@ -204,8 +206,9 @@ public final class BasicBlocker implements BytecodeArray.Visitor {
Constant cst, int value) {
visitCommon(offset, length, true);
- if ((cst instanceof CstMemberRef) || (cst instanceof CstType) ||
- (cst instanceof CstString) || (cst instanceof CstInvokeDynamic)) {
+ if (cst instanceof CstMemberRef || cst instanceof CstType ||
+ cst instanceof CstString || cst instanceof CstInvokeDynamic ||
+ cst instanceof CstMethodHandle || cst instanceof CstProtoRef) {
/*
* Instructions with these sorts of constants have the
* possibility of throwing, so this instruction needs to
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 2fa625c4c..05d0d4f5e 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -24,7 +24,9 @@ import com.android.dx.rop.cst.CstFieldRef;
import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.cst.CstInterfaceMethodRef;
import com.android.dx.rop.cst.CstInvokeDynamic;
+import com.android.dx.rop.cst.CstMethodHandle;
import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstProtoRef;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.Prototype;
import com.android.dx.rop.type.Type;
@@ -670,7 +672,7 @@ public class Simulator {
*/
if (cst instanceof CstInterfaceMethodRef) {
if (opcode != ByteOps.INVOKEINTERFACE) {
- if (!dexOptions.canUseDefaultInterfaceMethods()) {
+ if (!dexOptions.apiIsSupported(DexFormat.API_DEFAULT_INTERFACE_METHODS)) {
throw new SimException(
"default or static interface method used without " +
"--min-sdk-version >= " + DexFormat.API_DEFAULT_INTERFACE_METHODS);
@@ -685,10 +687,10 @@ public class Simulator {
if (cst instanceof CstMethodRef) {
CstMethodRef methodRef = (CstMethodRef) cst;
if (methodRef.isSignaturePolymorphic()) {
- if (!dexOptions.canUseInvokePolymorphic()) {
+ if (!dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) {
throw new SimException(
"signature-polymorphic method called without " +
- "--min-sdk-version >= " + DexFormat.API_INVOKE_POLYMORPHIC);
+ "--min-sdk-version >= " + DexFormat.API_METHOD_HANDLES);
}
if (opcode != ByteOps.INVOKEVIRTUAL) {
throw new SimException(
@@ -709,11 +711,11 @@ public class Simulator {
break;
}
case ByteOps.INVOKEDYNAMIC: {
- if (!dexOptions.canUseInvokeCustom()) {
+ if (!dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) {
throw new SimException(
"invalid opcode " + Hex.u1(opcode) +
" (invokedynamic requires --min-sdk-version >= " +
- DexFormat.API_INVOKE_POLYMORPHIC + ")");
+ DexFormat.API_METHOD_HANDLES + ")");
}
CstInvokeDynamic invokeDynamicRef = (CstInvokeDynamic) cst;
Prototype prototype = invokeDynamicRef.getPrototype();
@@ -738,6 +740,19 @@ public class Simulator {
machine.popArgs(frame, prototype);
break;
}
+ case ByteOps.LDC:
+ case ByteOps.LDC_W: {
+ if ((cst instanceof CstMethodHandle || cst instanceof CstProtoRef)) {
+ if (!dexOptions.apiIsSupported(DexFormat.API_CONST_METHOD_HANDLE)) {
+ throw new SimException(
+ "invalid constant type " + cst.typeName() +
+ " requires --min-sdk-version >= " +
+ DexFormat.API_CONST_METHOD_HANDLE + ")");
+ }
+ }
+ machine.clearArgs();
+ break;
+ }
default: {
machine.clearArgs();
break;
diff --git a/dx/src/com/android/dx/dex/DexOptions.java b/dx/src/com/android/dx/dex/DexOptions.java
index 34f4b6f83..087599471 100644
--- a/dx/src/com/android/dx/dex/DexOptions.java
+++ b/dx/src/com/android/dx/dex/DexOptions.java
@@ -45,44 +45,20 @@ public class DexOptions {
/**
* Gets the dex file magic number corresponding to this instance.
+ * @return string representing the dex file magic number
*/
public String getMagic() {
return DexFormat.apiToMagic(minSdkVersion);
}
/**
- * Returns whether default and static interface methods are allowed.
- *
- * This became allowed as of Nougat (SDK version 24).
- *
- * @return true if supported on the currently selected SDK.
+ * Checks whether an API feature is supported.
+ * @param apiLevel the API level to test
+ * @return returns true if the current API level is at least sdkVersion
*/
- public boolean canUseDefaultInterfaceMethods() {
- return minSdkVersion >= DexFormat.API_DEFAULT_INTERFACE_METHODS;
+ public boolean apiIsSupported(int apiLevel) {
+ // TODO: the naming here is awkward. Tooling may rely on the minSdkVersion,
+ // but it is referred to as API in DexFormat. Currently indistinguishable.
+ return minSdkVersion >= apiLevel;
}
-
- /**
- * Returns whether invoke-polymorphic can be used. This is emitted for calls
- * to {@code java.lang.invoke.MethodHandle.invoke()} and
- * {@code java.lang.invoke.MethodHandle.invokeExact()}.
- *
- * This became allowed as of the Android O release (SDK version 26).
- *
- * @return true if supported on the currently selected SDK.
- */
- public boolean canUseInvokePolymorphic() {
- return minSdkVersion >= DexFormat.API_INVOKE_POLYMORPHIC;
- }
-
- /**
- * Returns whether invoke-custom can be used.
- *
- * This became allowed as of the Android O release (SDK version 26).
- *
- * @return true if supported on the currently selected SDK.
- */
- public boolean canUseInvokeCustom() {
- // invoke-custom and invoke-polymorphic are both covered by the same API level.
- return minSdkVersion >= DexFormat.API_INVOKE_POLYMORPHIC;
- }
-}
+} \ No newline at end of file
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index b70911e2c..743e544c6 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -953,6 +953,14 @@ public final class Dops {
new Dop(Opcodes.INVOKE_CUSTOM_RANGE, Opcodes.INVOKE_CUSTOM,
Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop CONST_METHOD_HANDLE =
+ new Dop(Opcodes.CONST_METHOD_HANDLE, Opcodes.CONST_METHOD_HANDLE,
+ Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+
+ public static final Dop CONST_METHOD_TYPE =
+ new Dop(Opcodes.CONST_METHOD_TYPE, Opcodes.CONST_METHOD_TYPE,
+ Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+
// END(dops)
// Static initialization.
@@ -1184,6 +1192,8 @@ public final class Dops {
set(INVOKE_POLYMORPHIC_RANGE);
set(INVOKE_CUSTOM);
set(INVOKE_CUSTOM_RANGE);
+ set(CONST_METHOD_HANDLE);
+ set(CONST_METHOD_TYPE);
// 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 1f1d131e8..082d05100 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -24,6 +24,8 @@ import com.android.dx.rop.code.Rops;
import com.android.dx.rop.code.ThrowingCstInsn;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstMethodHandle;
+import com.android.dx.rop.cst.CstProtoRef;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.Type;
@@ -215,6 +217,8 @@ public final class RopToDop {
// Opcodes.USHR_INT_LIT8
// Opcodes.INVOKE_POLYMORPHIC
// Opcodes.INVOKE_CUSTOM
+ // Opcodes.CONST_METHOD_HANDLE
+ // Opcodes.CONST_METHOD_TYPE
// END(first-opcodes)
static {
@@ -580,8 +584,13 @@ public final class RopToDop {
return Dops.CONST_CLASS;
} else if (cst instanceof CstString) {
return Dops.CONST_STRING;
+ } else if (cst instanceof CstMethodHandle) {
+ return Dops.CONST_METHOD_HANDLE;
+ } else if (cst instanceof CstProtoRef) {
+ return Dops.CONST_METHOD_TYPE;
+ } else {
+ throw new RuntimeException("Unexpected constant type");
}
- break;
}
}
diff --git a/dx/src/com/android/dx/dex/code/form/Form21c.java b/dx/src/com/android/dx/dex/code/form/Form21c.java
index 9d074aa1d..40a03dace 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21c.java
@@ -23,6 +23,8 @@ import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstMethodHandle;
+import com.android.dx.rop.cst.CstProtoRef;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.util.AnnotatedOutput;
@@ -110,9 +112,11 @@ public final class Form21c extends InsnFormat {
return false;
}
- return (cst instanceof CstType) ||
- (cst instanceof CstFieldRef) ||
- (cst instanceof CstString);
+ return cst instanceof CstType ||
+ cst instanceof CstFieldRef ||
+ cst instanceof CstString ||
+ cst instanceof CstMethodHandle ||
+ cst instanceof CstProtoRef;
}
/** {@inheritDoc} */
diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java
index 04babb37f..7df046c31 100644
--- a/dx/src/com/android/dx/dex/file/DexFile.java
+++ b/dx/src/com/android/dx/dex/file/DexFile.java
@@ -16,6 +16,7 @@
package com.android.dx.dex.file;
+import com.android.dex.DexFormat;
import com.android.dex.util.ExceptionWithContext;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.file.MixedItemSection.SortType;
@@ -140,7 +141,7 @@ public final class DexFile {
* Prepare the list of sections in the order they appear in
* the final output.
*/
- if (dexOptions.canUseInvokeCustom()) {
+ if (dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) {
/*
* Method handles and call sites only visible in DEX files
* from SDK version 26 onwards. Do not create or add sections unless
@@ -618,12 +619,12 @@ public final class DexFile {
classDefs.prepare();
classData.prepare();
wordData.prepare();
- if (dexOptions.canUseInvokePolymorphic()) {
+ if (dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) {
// Prepare call site ids before byteData where the call site items are placed.
callSiteIds.prepare();
}
byteData.prepare();
- if (dexOptions.canUseInvokePolymorphic()) {
+ if (dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) {
// Prepare method handles after call site items placed in byteData.
methodHandles.prepare();
}
diff --git a/dx/src/com/android/dx/dex/file/MethodHandleItem.java b/dx/src/com/android/dx/dex/file/MethodHandleItem.java
index 8e5f01e89..faa64c265 100644
--- a/dx/src/com/android/dx/dex/file/MethodHandleItem.java
+++ b/dx/src/com/android/dx/dex/file/MethodHandleItem.java
@@ -67,7 +67,7 @@ public final class MethodHandleItem extends IndexedItem {
public void writeTo(DexFile file, AnnotatedOutput out) {
int targetIndex = getTargetIndex(file);
if (out.annotates()) {
- out.annotate(2, "kind: " + Hex.u2(methodHandle.getType()));
+ out.annotate(2, "kind: " + Hex.u2(methodHandle.getMethodHandleType()));
out.annotate(2, "reserved:" + Hex.u2(0));
if (methodHandle.isAccessor()) {
out.annotate(2, "fieldId: " + targetIndex);
@@ -76,7 +76,7 @@ public final class MethodHandleItem extends IndexedItem {
}
out.annotate(2, "reserved:" + Hex.u2(0));
}
- out.writeShort(methodHandle.getType());
+ out.writeShort(methodHandle.getMethodHandleType());
out.writeShort(0);
out.writeShort(getTargetIndex(file));
out.writeShort(0);
diff --git a/dx/src/com/android/dx/io/IndexType.java b/dx/src/com/android/dx/io/IndexType.java
index 0bd142a89..fb8763ed1 100644
--- a/dx/src/com/android/dx/io/IndexType.java
+++ b/dx/src/com/android/dx/io/IndexType.java
@@ -54,5 +54,11 @@ public enum IndexType {
VTABLE_OFFSET,
/** direct field offset (for static linked field accesses) */
- FIELD_OFFSET;
+ FIELD_OFFSET,
+
+ /** method handle reference index (for loading constant method handles) */
+ METHOD_HANDLE_REF,
+
+ /** proto reference index (for loading constant proto ref) */
+ PROTO_REF;
}
diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java
index 500abf7a2..40def04e0 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -947,6 +947,14 @@ public final class OpcodeInfo {
new Info(Opcodes.INVOKE_CUSTOM_RANGE, "invoke-custom/range",
InstructionCodec.FORMAT_3RC, IndexType.CALL_SITE_REF);
+ public static final Info CONST_METHOD_HANDLE =
+ new Info(Opcodes.CONST_METHOD_HANDLE, "const-method-handle",
+ InstructionCodec.FORMAT_21C, IndexType.METHOD_HANDLE_REF);
+
+ public static final Info CONST_METHOD_TYPE =
+ new Info(Opcodes.CONST_METHOD_TYPE, "const-method-type",
+ InstructionCodec.FORMAT_21C, IndexType.PROTO_REF);
+
// END(opcode-info-defs)
// Static initialization.
@@ -1184,6 +1192,8 @@ public final class OpcodeInfo {
set(INVOKE_POLYMORPHIC_RANGE);
set(INVOKE_CUSTOM);
set(INVOKE_CUSTOM_RANGE);
+ set(CONST_METHOD_HANDLE);
+ set(CONST_METHOD_TYPE);
// 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 9afee410b..ee2c2793f 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -263,6 +263,8 @@ public final class Opcodes {
public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb;
public static final int INVOKE_CUSTOM = 0xfc;
public static final int INVOKE_CUSTOM_RANGE = 0xfd;
+ public static final int CONST_METHOD_HANDLE = 0xfe;
+ public static final int CONST_METHOD_TYPE = 0xff;
// END(opcodes)
// TODO: Generate these payload opcodes with opcode-gen.
diff --git a/dx/src/com/android/dx/rop/cst/CstMethodHandle.java b/dx/src/com/android/dx/rop/cst/CstMethodHandle.java
index d571b5efa..6c39dae9f 100644
--- a/dx/src/com/android/dx/rop/cst/CstMethodHandle.java
+++ b/dx/src/com/android/dx/rop/cst/CstMethodHandle.java
@@ -16,10 +16,12 @@
package com.android.dx.rop.cst;
+import com.android.dx.rop.type.Type;
+
/**
* Constants of type {@code MethodHandle}.
*/
-public final class CstMethodHandle extends Constant {
+public final class CstMethodHandle extends TypedConstant {
public static final int METHOD_HANDLE_TYPE_STATIC_PUT = 0;
public static final int METHOD_HANDLE_TYPE_STATIC_GET = 1;
@@ -92,7 +94,7 @@ public final class CstMethodHandle extends Constant {
*
* @return the type
*/
- public int getType() {
+ public int getMethodHandleType() {
return type;
}
@@ -171,10 +173,10 @@ public final class CstMethodHandle extends Constant {
@Override
protected int compareTo0(Constant other) {
CstMethodHandle otherHandle = (CstMethodHandle) other;
- if (getType() == otherHandle.getType()) {
+ if (getMethodHandleType() == otherHandle.getMethodHandleType()) {
return getRef().compareTo(otherHandle.getRef());
} else {
- return Integer.compare(getType(), otherHandle.getType());
+ return Integer.compare(getMethodHandleType(), otherHandle.getMethodHandleType());
}
}
@@ -195,4 +197,9 @@ public final class CstMethodHandle extends Constant {
public String toHuman() {
return getTypeName(type)+ "," + ref.toString();
}
+
+ @Override
+ public Type getType() {
+ return Type.METHOD_HANDLE;
+ }
}
diff --git a/dx/src/com/android/dx/rop/cst/CstProtoRef.java b/dx/src/com/android/dx/rop/cst/CstProtoRef.java
index a91ec87c0..9d0a78382 100644
--- a/dx/src/com/android/dx/rop/cst/CstProtoRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstProtoRef.java
@@ -16,11 +16,12 @@
package com.android.dx.rop.cst;
import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.Type;
/**
* Prototype reference.
*/
-public final class CstProtoRef extends Constant {
+public final class CstProtoRef extends TypedConstant {
/** {@code non-null;} the prototype */
private final Prototype prototype;
@@ -90,4 +91,9 @@ public final class CstProtoRef extends Constant {
public Prototype getPrototype() {
return prototype;
}
+
+ @Override
+ public Type getType() {
+ return Type.METHOD_TYPE;
+ }
}
diff --git a/dx/src/com/android/dx/rop/type/Type.java b/dx/src/com/android/dx/rop/type/Type.java
index a8c0b3b16..783ef45fb 100644
--- a/dx/src/com/android/dx/rop/type/Type.java
+++ b/dx/src/com/android/dx/rop/type/Type.java
@@ -122,6 +122,9 @@ public final class Type implements TypeBearer, Comparable<Type> {
/** {@code non-null;} instance representing {@code java.lang.invoke.MethodHandle} */
public static final Type METHOD_HANDLE = new Type("Ljava/lang/invoke/MethodHandle;", BT_OBJECT);
+ /** {@code non-null;} instance representing {@code java.lang.invoke.MethodType} */
+ public static final Type METHOD_TYPE = new Type("Ljava/lang/invoke/MethodType;", BT_OBJECT);
+
/** {@code non-null;} instance representing {@code java.lang.invoke.VarHandle} */
public static final Type VAR_HANDLE = new Type("Ljava/lang/invoke/VarHandle;", BT_OBJECT);
diff --git a/dx/tests/142-const-method-handle/constmethodhandle.jar b/dx/tests/142-const-method-handle/constmethodhandle.jar
new file mode 100644
index 000000000..692303ee4
--- /dev/null
+++ b/dx/tests/142-const-method-handle/constmethodhandle.jar
Binary files differ
diff --git a/dx/tests/142-const-method-handle/expected.txt b/dx/tests/142-const-method-handle/expected.txt
new file mode 100644
index 000000000..56b8ed67b
--- /dev/null
+++ b/dx/tests/142-const-method-handle/expected.txt
@@ -0,0 +1,5 @@
+Trying SDK version 26 with const-method-handle.
+Trying SDK version 27 with const-method-handle.
+"dex\n039\0"
+const-method-handle v0, invoke-instance,method{java.lang.Object.getClass:()Ljava/lang/Class;}
+const-method-type v0, (CSIJFDLjava/lang/Object;)Z
diff --git a/dx/tests/142-const-method-handle/generate-test b/dx/tests/142-const-method-handle/generate-test
new file mode 100755
index 000000000..1658bca3d
--- /dev/null
+++ b/dx/tests/142-const-method-handle/generate-test
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# 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.
+
+function fail() {
+ echo Build failed: $1 1>&2
+ exit 1
+}
+
+if [[ -z "${ANDROID_BUILD_TOP}" ]]; then
+ fail "ANDROID_BUILD_TOP is not defined. Try running 'lunch' first."
+fi
+
+SCRIPT_PATH=$( cd $(dirname $0) ; pwd -P )
+ASM_CLASSPATH="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-5.2.jar"
+SRC_PATH="${SCRIPT_PATH}/src"
+BUILD_PATH="${SCRIPT_PATH}/classes"
+JAR_FILE="${SCRIPT_PATH}/constmethodhandle.jar"
+
+if [[ ! -d "${BUILD_PATH}" ]]; then
+ mkdir "$BUILD_PATH" || exit 1
+fi
+
+(cd "${SRC_PATH}" && javac -cp "${ASM_CLASSPATH}" -d "${BUILD_PATH}" Main.java constmethodhandle/*.java) || fail "javac error"
+(cd "${SCRIPT_PATH}" && java -cp "${ASM_CLASSPATH}:${BUILD_PATH}" constmethodhandle.TestGenerator "${BUILD_PATH}") || fail "generator failure"
+(cd "${BUILD_PATH}" && jar cf "${JAR_FILE}" Main.class constmethodhandle/ConstTest.class) || fail "jar creation error"
diff --git a/dx/tests/142-const-method-handle/info.txt b/dx/tests/142-const-method-handle/info.txt
new file mode 100644
index 000000000..4942773e9
--- /dev/null
+++ b/dx/tests/142-const-method-handle/info.txt
@@ -0,0 +1,2 @@
+This test checks the conversion of ldc with a MethodHandle operand
+and a MethodType operand.
diff --git a/dx/tests/142-const-method-handle/run b/dx/tests/142-const-method-handle/run
new file mode 100755
index 000000000..2d61db746
--- /dev/null
+++ b/dx/tests/142-const-method-handle/run
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# 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.
+
+UNSUPPORTED_SDK_VERSION=26
+SUPPORTED_SDK_VERSION=27
+
+# Expect failure with unsupported SDK version
+EXPECTED_STATUS[${UNSUPPORTED_SDK_VERSION}]=1
+
+# Expect success with supported SDK version
+EXPECTED_STATUS[${SUPPORTED_SDK_VERSION}]=0
+
+DX_OUTPUT=dx.log
+rm -f ${DX_OUTPUT} 2>/dev/null
+
+for SDK_VERSION in ${UNSUPPORTED_SDK_VERSION} ${SUPPORTED_SDK_VERSION}; do
+ echo Trying SDK version ${SDK_VERSION} with const-method-handle.
+ dx --min-sdk-version=${SDK_VERSION} --dex --output=constmethodhandle.dex \
+ --verbose-dump --dump-to=- --dump-width=1000 constmethodhandle.jar 2>&1
+ STATUS=$?
+ if [[ ${STATUS} != ${EXPECTED_STATUS[$SDK_VERSION]} ]]; then
+ echo Unexpected status ${STATUS} for SDK version ${SDK_VERSION}.
+ exit 1
+ fi
+done > ${DX_OUTPUT}
+
+sed -n -e 's/.*: //g' -e 's_ *//.*__' -e '/const-method/p' -e '/dex[\\]/p' ${DX_OUTPUT}
diff --git a/dx/tests/142-const-method-handle/src/Main.java b/dx/tests/142-const-method-handle/src/Main.java
new file mode 100644
index 000000000..6ab922d94
--- /dev/null
+++ b/dx/tests/142-const-method-handle/src/Main.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+import constmethodhandle.ConstTest;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class Main{
+ public static void main(String[] args) throws Throwable {
+ // At compilation time, ConstTest.main has not yet been
+ // generated. It is generated before execution / linking.
+ MethodHandle generatedMain = MethodHandles.lookup()
+ .findStatic(ConstTest.class, "main", MethodType.methodType(void.class, String[].class));
+ generatedMain.invokeExact(args);
+ }
+}
diff --git a/dx/tests/142-const-method-handle/src/constmethodhandle/ConstTest.java b/dx/tests/142-const-method-handle/src/constmethodhandle/ConstTest.java
new file mode 100644
index 000000000..31abb97f4
--- /dev/null
+++ b/dx/tests/142-const-method-handle/src/constmethodhandle/ConstTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 constmethodhandle;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+
+public class ConstTest {
+ private static void displayMethodHandle(MethodHandle mh) throws Throwable {
+ System.out.println("MethodHandle " + mh + " => " +
+ (Class) mh.invoke((Object) Float.valueOf(1.23e4f)));
+ }
+
+ private static void displayMethodType(MethodType mt) {
+ System.out.println("MethodType " + mt);
+ }
+}
diff --git a/dx/tests/142-const-method-handle/src/constmethodhandle/TestGenerator.java b/dx/tests/142-const-method-handle/src/constmethodhandle/TestGenerator.java
new file mode 100644
index 000000000..f769da92b
--- /dev/null
+++ b/dx/tests/142-const-method-handle/src/constmethodhandle/TestGenerator.java
@@ -0,0 +1,113 @@
+/*
+ * 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 constmethodhandle;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class TestGenerator {
+
+ private final Path classNamePath;
+
+ public static void main(String[] args) throws IOException {
+ assert args.length == 1;
+ TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
+ TestGenerator.class.getPackage().getName(), ConstTest.class.getSimpleName() + ".class"));
+ testGenerator.generateTests();
+ }
+
+ public TestGenerator(Path classNamePath) {
+ this.classNamePath = classNamePath;
+ }
+
+ private void generateTests() throws IOException {
+ ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile()));
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+ cr.accept(
+ new ClassVisitor(Opcodes.ASM5, cw) {
+ @Override
+ public void visitEnd() {
+ generateMethodTest1(cw);
+ generateMethodTest2(cw);
+ generateMethodMain(cw);
+ super.visitEnd();
+ }
+ }, 0);
+ new FileOutputStream(classNamePath.toFile()).write(cw.toByteArray());
+ }
+
+ /* generate main method that only call all test methods. */
+ private void generateMethodMain(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
+ "main", "([Ljava/lang/String;)V", null, null);
+ String internalName = Type.getInternalName(ConstTest.class);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test1",
+ "()Ljava/lang/invoke/MethodHandle;", false);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName,
+ "displayMethodHandle", "(Ljava/lang/invoke/MethodHandle;)V", false);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test2",
+ "()Ljava/lang/invoke/MethodType;", false);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "displayMethodType",
+ "(Ljava/lang/invoke/MethodType;)V", false);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(-1, -1);
+ }
+
+ /**
+ * Generate a test that returns a constant method handle.
+ */
+ private void generateMethodTest1(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test1",
+ "()Ljava/lang/invoke/MethodHandle;", null, null);
+ MethodType mt = MethodType.methodType(Class.class);
+ Handle mh = new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(Object.class),
+ "getClass", mt.toMethodDescriptorString(), false);
+ mv.visitLdcInsn(mh);
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(-1, -1);
+ }
+
+ /**
+ * Generate a test that returns a constant method type.
+ */
+ private void generateMethodTest2(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test2",
+ "()Ljava/lang/invoke/MethodType;", null, null);
+ Type mt = Type.getMethodType(Type.getType(boolean.class), Type.getType(char.class),
+ Type.getType(short.class), Type.getType(int.class),
+ Type.getType(long.class), Type.getType(float.class),
+ Type.getType(double.class), Type.getType(Object.class));
+ mv.visitLdcInsn(mt);
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(-1, -1);
+ }
+}
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index c274e64c9..a12f0256e 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -97,6 +97,11 @@ typedef int64_t s8;
*/
#define DEX_MAGIC_VERS_38 "038\0"
+/* The version for android P, encoded in 4 bytes of ASCII. This differentiates dex files that may
+ * contain const-method-handle and const-proto.
+ */
+#define DEX_MAGIC_VERS_39 "039\0"
+
/* current version, encoded in 4 bytes of ASCII */
#define DEX_MAGIC_VERS "036\0"
diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp
index 8a9877239..d3db79b67 100644
--- a/libdex/DexOpcodes.cpp
+++ b/libdex/DexOpcodes.cpp
@@ -273,19 +273,19 @@ static const char* gOpNames[kNumPackedOpcodes] = {
"+invoke-object-init/range",
"+return-void-barrier",
"+iget-quick",
- "+iget-wide-quick",
- "+iget-object-quick",
- "+iput-quick",
- "+iput-wide-quick",
- "+iput-object-quick",
- "+invoke-virtual-quick",
- "+invoke-virtual-quick/range",
+ "unused-f3",
+ "unused-f4",
+ "unused-f5",
+ "unused-f6",
+ "unused-f7",
+ "unused-f8",
+ "unused-f9",
"invoke-polymorphic",
"invoke-polymorphic/range",
"invoke-custom",
"invoke-custom/range",
- "+sput-object-volatile",
- "unused-ff",
+ "const-method-handle",
+ "const-method-type",
// END(libdex-opcode-names)
};
diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h
index 625a2e875..1c684ab63 100644
--- a/libdex/DexOpcodes.h
+++ b/libdex/DexOpcodes.h
@@ -311,19 +311,19 @@ enum Opcode {
OP_INVOKE_OBJECT_INIT_RANGE = 0xf0,
OP_RETURN_VOID_BARRIER = 0xf1,
OP_IGET_QUICK = 0xf2,
- OP_IGET_WIDE_QUICK = 0xf3,
- OP_IGET_OBJECT_QUICK = 0xf4,
- OP_IPUT_QUICK = 0xf5,
- OP_IPUT_WIDE_QUICK = 0xf6,
- OP_IPUT_OBJECT_QUICK = 0xf7,
- OP_INVOKE_VIRTUAL_QUICK = 0xf8,
- OP_INVOKE_VIRTUAL_QUICK_RANGE = 0xf9,
+ OP_UNUSED_F3 = 0xf3,
+ OP_UNUSED_F4 = 0xf4,
+ OP_UNUSED_F5 = 0xf5,
+ OP_UNUSED_F6 = 0xf6,
+ OP_UNUSED_F7 = 0xf7,
+ OP_UNUSED_F8 = 0xf8,
+ OP_UNUSED_F9 = 0xf9,
OP_INVOKE_POLYMORPHIC = 0xfa,
OP_INVOKE_POLYMORPHIC_RANGE = 0xfb,
OP_INVOKE_CUSTOM = 0xfc,
OP_INVOKE_CUSTOM_RANGE = 0xfd,
- OP_SPUT_OBJECT_VOLATILE = 0xfe,
- OP_UNUSED_FF = 0xff,
+ OP_CONST_METHOD_HANDLE = 0xfe,
+ OP_CONST_METHOD_TYPE = 0xff,
// END(libdex-opcode-enum)
};
@@ -577,19 +577,19 @@ enum Opcode {
H(OP_INVOKE_OBJECT_INIT_RANGE), \
H(OP_RETURN_VOID_BARRIER), \
H(OP_IGET_QUICK), \
- H(OP_IGET_WIDE_QUICK), \
- H(OP_IGET_OBJECT_QUICK), \
- H(OP_IPUT_QUICK), \
- H(OP_IPUT_WIDE_QUICK), \
- H(OP_IPUT_OBJECT_QUICK), \
- H(OP_INVOKE_VIRTUAL_QUICK), \
- H(OP_INVOKE_VIRTUAL_QUICK_RANGE), \
+ H(OP_UNUSED_F3), \
+ H(OP_UNUSED_F4), \
+ H(OP_UNUSED_F5), \
+ H(OP_UNUSED_F6), \
+ H(OP_UNUSED_F7), \
+ H(OP_UNUSED_F8), \
+ H(OP_UNUSED_F9), \
H(OP_INVOKE_POLYMORPHIC), \
H(OP_INVOKE_POLYMORPHIC_RANGE), \
H(OP_INVOKE_CUSTOM), \
H(OP_INVOKE_CUSTOM_RANGE), \
- H(OP_SPUT_OBJECT_VOLATILE), \
- H(OP_UNUSED_FF), \
+ H(OP_CONST_METHOD_HANDLE), \
+ H(OP_CONST_METHOD_TYPE), \
/* END(libdex-goto-table) */ \
};
diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp
index 3e813984a..168f3e17f 100644
--- a/libdex/InstrUtils.cpp
+++ b/libdex/InstrUtils.cpp
@@ -47,7 +47,7 @@ static InstructionWidth gInstructionWidthTable[kNumPackedOpcodes] = {
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, 3, 3, 2, 0,
+ 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 4, 4, 3, 3, 2, 2,
// END(libdex-widths)
};
@@ -300,19 +300,19 @@ static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = {
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanReturn,
kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow,
- 0,
+ kInstrCanContinue|kInstrCanThrow,
// END(libdex-flags)
};
@@ -356,9 +356,9 @@ static u1 gInstructionFormatTable[kNumPackedOpcodes] = {
kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b,
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, kFmt45cc, kFmt4rcc,
- kFmt35c, kFmt3rc, kFmt21c, kFmt00x,
+ kFmt35mi, kFmt3rmi, kFmt35c, kFmt10x, kFmt22cs, kFmt00x, kFmt00x,
+ kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt45cc, kFmt4rcc,
+ kFmt35c, kFmt3rc, kFmt21c, kFmt21c,
// END(libdex-formats)
};
@@ -449,11 +449,11 @@ static u1 gInstructionIndexTypeTable[kNumPackedOpcodes] = {
kIndexFieldRef, kIndexFieldRef, kIndexUnknown,
kIndexVaries, kIndexInlineMethod, kIndexInlineMethod,
kIndexMethodRef, kIndexNone, kIndexFieldOffset,
- kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset,
- kIndexFieldOffset, kIndexFieldOffset, kIndexVtableOffset,
- kIndexVtableOffset, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef,
- kCallSiteRef, kCallSiteRef, kIndexFieldRef,
- kIndexUnknown,
+ kIndexUnknown, kIndexUnknown, kIndexUnknown,
+ kIndexUnknown, kIndexUnknown, kIndexUnknown,
+ kIndexUnknown, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef,
+ kIndexCallSiteRef, kIndexCallSiteRef, kIndexMethodHandleRef,
+ kIndexProtoRef,
// END(libdex-index-types)
};
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
index e8ae4c8dc..c5bf77cb0 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -81,7 +81,9 @@ enum InstructionIndexType {
kIndexVtableOffset, // vtable offset (for static linked methods)
kIndexFieldOffset, // field offset (for static linked fields)
kIndexMethodAndProtoRef, // method index and proto index
- kCallSiteRef // call site index
+ kIndexCallSiteRef, // call site index
+ kIndexMethodHandleRef, // constant method handle reference index
+ kIndexProtoRef, // constant prototype reference index
};
/*
diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt
index 840d433b1..0129ad980 100644
--- a/opcode-gen/bytecode.txt
+++ b/opcode-gen/bytecode.txt
@@ -70,6 +70,8 @@ format 3rms
# field-offset
# method-and-proto-ref
# call-site-ref
+# method-handle-ref
+# 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
@@ -333,22 +335,20 @@ op ef +execute-inline/range 3rmi n inline-method optimized|continue|thro
op f0 +invoke-object-init/range 35c n method-ref optimized|continue|throw|invoke
op f1 +return-void-barrier 10x n none optimized|return
op f2 +iget-quick 22cs y field-offset optimized|continue|throw
-op f3 +iget-wide-quick 22cs y field-offset optimized|continue|throw
-op f4 +iget-object-quick 22cs y field-offset optimized|continue|throw
-op f5 +iput-quick 22cs n field-offset optimized|continue|throw
-op f6 +iput-wide-quick 22cs n field-offset optimized|continue|throw
-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
-# 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
+# unused: op f3..f9
-# More optimized opcodes (not valid in an unoptimized dex file)
+#
+# Bytecodes relating to method handles API.
+#
+
+# Invoke-polymorphic
+op fa invoke-polymorphic 45cc n method-and-proto-ref continue|throw|invoke
+op fb invoke-polymorphic/range 4rcc n method-and-proto-ref continue|throw|invoke
+op fc invoke-custom 35c n call-site-ref continue|throw|invoke
+op fd invoke-custom/range 3rc n call-site-ref continue|throw|invoke
-op fe +sput-object-volatile 21c n field-ref optimized|continue|throw
+# Constant loading for method handles and method types. NB these may throw OOME
+op fe const-method-handle 21c y method-handle-ref continue|throw
+op ff const-method-type 21c y proto-ref continue|throw
-# unused: op ff
diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk
index baf774b6b..16823bbf5 100644
--- a/opcode-gen/opcode-gen.awk
+++ b/opcode-gen/opcode-gen.awk
@@ -485,7 +485,9 @@ function initIndexTypes() {
indexTypeValues["vtable-offset"] = "kIndexVtableOffset";
indexTypeValues["field-offset"] = "kIndexFieldOffset";
indexTypeValues["method-and-proto-ref"] = "kIndexMethodAndProtoRef";
- indexTypeValues["call-site-ref"] = "kCallSiteRef";
+ indexTypeValues["call-site-ref"] = "kIndexCallSiteRef";
+ indexTypeValues["method-handle-ref"] = "kIndexMethodHandleRef";
+ indexTypeValues["proto-ref"] = "kIndexProtoRef";
}
# Initialize the flags data.