Merge "New bytecodes for constant-method-{handle,type}"
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index 8dbdd22..f76cae3 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -916,9 +916,27 @@
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 97771d8..f86917a 100644
--- a/dx/src/com/android/dex/DexFormat.java
+++ b/dx/src/com/android/dex/DexFormat.java
@@ -23,8 +23,11 @@
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 @@
* 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 @@
* 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 @@
* 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 @@
} 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 @@
/**
* 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 @@
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 31f9627..0c5d5a4 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 @@
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 @@
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 2fa625c..05d0d4f 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.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 @@
*/
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 @@
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 @@
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 @@
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 34f4b6f..0875994 100644
--- a/dx/src/com/android/dx/dex/DexOptions.java
+++ b/dx/src/com/android/dx/dex/DexOptions.java
@@ -45,44 +45,20 @@
/**
* 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 b70911e..743e544 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 @@
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 @@
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 1f1d131..082d051 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.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 @@
// 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 @@
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 9d074aa..40a03da 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.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 @@
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 04babb3..7df046c 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 @@
* 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 @@
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 8e5f01e..faa64c2 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 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 @@
}
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 0bd142a..fb8763e 100644
--- a/dx/src/com/android/dx/io/IndexType.java
+++ b/dx/src/com/android/dx/io/IndexType.java
@@ -54,5 +54,11 @@
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 500abf7..40def04 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -947,6 +947,14 @@
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 @@
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 9afee41..ee2c279 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -263,6 +263,8 @@
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 d571b5e..6c39dae 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 @@
*
* @return the type
*/
- public int getType() {
+ public int getMethodHandleType() {
return type;
}
@@ -171,10 +173,10 @@
@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 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 a91ec87..9d0a783 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 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 a8c0b3b..783ef45 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 @@
/** {@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 0000000..692303e
--- /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 0000000..56b8ed6
--- /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 0000000..1658bca
--- /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 0000000..4942773
--- /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 0000000..2d61db7
--- /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 0000000..6ab922d
--- /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 0000000..31abb97
--- /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 0000000..f769da9
--- /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 c274e64..a12f025 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -97,6 +97,11 @@
*/
#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 8a98772..d3db79b 100644
--- a/libdex/DexOpcodes.cpp
+++ b/libdex/DexOpcodes.cpp
@@ -273,19 +273,19 @@
"+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 625a2e8..1c684ab 100644
--- a/libdex/DexOpcodes.h
+++ b/libdex/DexOpcodes.h
@@ -311,19 +311,19 @@
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 @@
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 3e81398..168f3e1 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, 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 @@
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanReturn,
kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
- kInstrCanContinue|kInstrCanThrow,
0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+ kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+ kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+ kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+ kInstrCanContinue|kInstrCanThrow,
+ kInstrCanContinue|kInstrCanThrow,
// END(libdex-flags)
};
@@ -356,9 +356,9 @@
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 @@
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 e8ae4c8..c5bf77c 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -81,7 +81,9 @@
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 840d433..0129ad9 100644
--- a/opcode-gen/bytecode.txt
+++ b/opcode-gen/bytecode.txt
@@ -70,6 +70,8 @@
# 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 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
+
+# unused: op f3..f9
+
+#
+# Bytecodes relating to method handles API.
+#
# 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
+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
-# More optimized opcodes (not valid in an unoptimized dex file)
+# 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
-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 baf774b..16823bb 100644
--- a/opcode-gen/opcode-gen.awk
+++ b/opcode-gen/opcode-gen.awk
@@ -485,7 +485,9 @@
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.