diff --git a/jdk/src/share/classes/java/dyn/MethodHandles.java b/jdk/src/share/classes/java/dyn/MethodHandles.java
index 879f3c73d70..ac35f88e143 100644
--- a/jdk/src/share/classes/java/dyn/MethodHandles.java
+++ b/jdk/src/share/classes/java/dyn/MethodHandles.java
@@ -411,41 +411,68 @@ public class MethodHandles {
/**
* PROVISIONAL API, WORK IN PROGRESS:
- * Produce a method handle giving read access to a field.
+ * Produce a method handle giving read access to a non-static field.
* The type of the method handle will have a return type of the field's
* value type.
- * If the field is static, the method handle will take no arguments.
- * Otherwise, its single argument will be the instance containing
+ * The method handle's single argument will be the instance containing
* the field.
* Access checking is performed immediately on behalf of the lookup class.
* @param name the field's name
* @param type the field's type
- * @param isStatic true if and only if the field is static
* @return a method handle which can load values from the field
* @exception NoAccessException if access checking fails
*/
- public MethodHandle findGetter(Class> refc, String name, Class> type, boolean isStatic) throws NoAccessException {
- return makeAccessor(refc, name, type, isStatic, false);
+ public MethodHandle findGetter(Class> refc, String name, Class> type) throws NoAccessException {
+ return makeAccessor(refc, name, type, false, false);
}
/**
* PROVISIONAL API, WORK IN PROGRESS:
- * Produce a method handle giving write access to a reflected field.
+ * Produce a method handle giving write access to a non-static field.
* The type of the method handle will have a void return type.
- * If the field is static, the method handle will take a single
- * argument, of the field's value type, the value to be stored.
- * Otherwise, the two arguments will be the instance containing
+ * The method handle will take two arguments, the instance containing
* the field, and the value to be stored.
+ * The second argument will be of the field's value type.
* Access checking is performed immediately on behalf of the lookup class.
* @param name the field's name
* @param type the field's type
- * @param isStatic true if and only if the field is static
- * @return a method handle which can store values into the reflected field
+ * @return a method handle which can store values into the field
* @exception NoAccessException if access checking fails
*/
- public MethodHandle findSetter(Class> refc, String name, Class> type,
- boolean isStatic) throws NoAccessException {
- return makeAccessor(refc, name, type, isStatic, true);
+ public MethodHandle findSetter(Class> refc, String name, Class> type) throws NoAccessException {
+ return makeAccessor(refc, name, type, false, true);
+ }
+
+ /**
+ * PROVISIONAL API, WORK IN PROGRESS:
+ * Produce a method handle giving read access to a static field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * The method handle will take no arguments.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can load values from the field
+ * @exception NoAccessException if access checking fails
+ */
+ public MethodHandle findStaticGetter(Class> refc, String name, Class> type) throws NoAccessException {
+ return makeAccessor(refc, name, type, true, false);
+ }
+
+ /**
+ * PROVISIONAL API, WORK IN PROGRESS:
+ * Produce a method handle giving write access to a static field.
+ * The type of the method handle will have a void return type.
+ * The method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can store values into the field
+ * @exception NoAccessException if access checking fails
+ */
+ public MethodHandle findStaticSetter(Class> refc, String name, Class> type) throws NoAccessException {
+ return makeAccessor(refc, name, type, true, true);
}
/**
diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java
index 0dd9e9f5216..84470c8a870 100644
--- a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java
+++ b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java
@@ -258,6 +258,20 @@ class MethodHandleNatives {
//T_ARRAY = 13
T_VOID = 14;
//T_ADDRESS = 15
+
+ /**
+ * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
+ */
+ static final int
+ REF_getField = 1,
+ REF_getStatic = 2,
+ REF_putField = 3,
+ REF_putStatic = 4,
+ REF_invokeVirtual = 5,
+ REF_invokeStatic = 6,
+ REF_invokeSpecial = 7,
+ REF_newInvokeSpecial = 8,
+ REF_invokeInterface = 9;
}
private static native int getNamedCon(int which, Object[] name);
@@ -304,4 +318,24 @@ class MethodHandleNatives {
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
}
+ /**
+ * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
+ * It will make an up-call to this method. (Do not change the name or signature.)
+ */
+ static MethodHandle linkMethodHandleConstant(Class> callerClass, int refKind,
+ Class> defc, String name, Object type) {
+ Lookup lookup = IMPL_LOOKUP.in(callerClass);
+ switch (refKind) {
+ case REF_getField: return lookup.findGetter( defc, name, (Class>) type );
+ case REF_getStatic: return lookup.findStaticGetter( defc, name, (Class>) type );
+ case REF_putField: return lookup.findSetter( defc, name, (Class>) type );
+ case REF_putStatic: return lookup.findStaticSetter( defc, name, (Class>) type );
+ case REF_invokeVirtual: return lookup.findVirtual( defc, name, (MethodType) type );
+ case REF_invokeStatic: return lookup.findStatic( defc, name, (MethodType) type );
+ case REF_invokeSpecial: return lookup.findSpecial( defc, name, (MethodType) type, callerClass );
+ case REF_newInvokeSpecial: return lookup.findConstructor( defc, (MethodType) type );
+ case REF_invokeInterface: return lookup.findVirtual( defc, name, (MethodType) type );
+ }
+ throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
+ }
}
diff --git a/jdk/src/share/javavm/export/classfile_constants.h b/jdk/src/share/javavm/export/classfile_constants.h
index 86da17ccbd4..9030935c5c6 100644
--- a/jdk/src/share/javavm/export/classfile_constants.h
+++ b/jdk/src/share/javavm/export/classfile_constants.h
@@ -84,7 +84,22 @@ enum {
JVM_CONSTANT_Fieldref = 9,
JVM_CONSTANT_Methodref = 10,
JVM_CONSTANT_InterfaceMethodref = 11,
- JVM_CONSTANT_NameAndType = 12
+ JVM_CONSTANT_NameAndType = 12,
+ JVM_CONSTANT_MethodHandle = 15, // JSR 292
+ JVM_CONSTANT_MethodType = 16 // JSR 292
+};
+
+/* JVM_CONSTANT_MethodHandle subtypes */
+enum {
+ JVM_REF_getField = 1,
+ JVM_REF_getStatic = 2,
+ JVM_REF_putField = 3,
+ JVM_REF_putStatic = 4,
+ JVM_REF_invokeVirtual = 5,
+ JVM_REF_invokeStatic = 6,
+ JVM_REF_invokeSpecial = 7,
+ JVM_REF_newInvokeSpecial = 8,
+ JVM_REF_invokeInterface = 9
};
/* StackMapTable type item numbers */
diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c
index 6dd422d4e45..337a11f4ca4 100644
--- a/jdk/src/share/native/common/check_code.c
+++ b/jdk/src/share/native/common/check_code.c
@@ -204,6 +204,8 @@ enum {
#define LDC_CLASS_MAJOR_VERSION 49
+#define LDC_METHOD_HANDLE_MAJOR_VERSION 51
+
#define ALLOC_STACK_SIZE 16 /* big enough */
typedef struct alloc_stack_type {
@@ -1181,6 +1183,10 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {
types |= 1 << JVM_CONSTANT_Class;
}
+ if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {
+ types |= (1 << JVM_CONSTANT_MethodHandle) |
+ (1 << JVM_CONSTANT_MethodType);
+ }
this_idata->operand.i = key;
verify_constant_pool_type(context, key, types);
break;
@@ -1194,6 +1200,10 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {
types |= 1 << JVM_CONSTANT_Class;
}
+ if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {
+ types |= (1 << JVM_CONSTANT_MethodHandle) |
+ (1 << JVM_CONSTANT_MethodType);
+ }
this_idata->operand.i = key;
verify_constant_pool_type(context, key, types);
break;
@@ -2667,6 +2677,22 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta
full_info = make_class_info_from_name(context,
"java/lang/Class");
break;
+ case JVM_CONSTANT_MethodHandle:
+ case JVM_CONSTANT_MethodType:
+ if (context->major_version < LDC_METHOD_HANDLE_MAJOR_VERSION)
+ CCerror(context, "Internal error #3");
+ stack_results = "A";
+ switch (type_table[operand]) {
+ case JVM_CONSTANT_MethodType:
+ full_info = make_class_info_from_name(context,
+ "java/dyn/MethodType");
+ break;
+ default: //JVM_CONSTANT_MethodHandle
+ full_info = make_class_info_from_name(context,
+ "java/dyn/MethodHandle");
+ break;
+ }
+ break;
default:
CCerror(context, "Internal error #3");
stack_results = ""; /* Never reached: keep lint happy */
diff --git a/jdk/test/java/dyn/MethodHandlesTest.java b/jdk/test/java/dyn/MethodHandlesTest.java
index 10a513cbe63..3b33cef0e01 100644
--- a/jdk/test/java/dyn/MethodHandlesTest.java
+++ b/jdk/test/java/dyn/MethodHandlesTest.java
@@ -47,6 +47,10 @@ import static org.junit.Assume.*;
public class MethodHandlesTest {
// How much output?
static int verbosity = 0;
+ static {
+ String vstr = System.getProperty("test.java.dyn.MethodHandlesTest.verbosity");
+ if (vstr != null) verbosity = Integer.parseInt(vstr);
+ }
// Set this true during development if you want to fast-forward to
// a particular new, non-working test. Tests which are known to
@@ -109,7 +113,7 @@ public class MethodHandlesTest {
String vers = properties.getProperty("java.vm.version");
String name = properties.getProperty("java.vm.name");
String arch = properties.getProperty("os.arch");
- if ((arch.equals("i386") || arch.equals("amd64") ||
+ if ((arch.equals("amd64") || arch.equals("i386") || arch.equals("x86") ||
arch.equals("sparc") || arch.equals("sparcv9")) &&
(name.contains("Client") || name.contains("Server"))
) {
@@ -121,6 +125,7 @@ public class MethodHandlesTest {
}
String testName;
+ static int allPosTests, allNegTests;
int posTests, negTests;
@After
public void printCounts() {
@@ -128,6 +133,8 @@ public class MethodHandlesTest {
System.out.println();
if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
+ allPosTests += posTests;
+ allNegTests += negTests;
posTests = negTests = 0;
}
}
@@ -153,6 +160,12 @@ public class MethodHandlesTest {
@AfterClass
public static void tearDownClass() throws Exception {
+ int posTests = allPosTests, negTests = allNegTests;
+ if (verbosity >= 2 && (posTests | negTests) != 0) {
+ System.out.println();
+ if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
+ if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
+ }
}
static List