1.1 --- a/src/share/classes/java/dyn/MethodHandles.java Fri Jun 18 15:23:57 2010 -0700
1.2 +++ b/src/share/classes/java/dyn/MethodHandles.java Sat Jun 19 01:14:40 2010 -0700
1.3 @@ -411,41 +411,68 @@
1.4
1.5 /**
1.6 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
1.7 - * Produce a method handle giving read access to a field.
1.8 + * Produce a method handle giving read access to a non-static field.
1.9 * The type of the method handle will have a return type of the field's
1.10 * value type.
1.11 - * If the field is static, the method handle will take no arguments.
1.12 - * Otherwise, its single argument will be the instance containing
1.13 + * The method handle's single argument will be the instance containing
1.14 * the field.
1.15 * Access checking is performed immediately on behalf of the lookup class.
1.16 * @param name the field's name
1.17 * @param type the field's type
1.18 - * @param isStatic true if and only if the field is static
1.19 * @return a method handle which can load values from the field
1.20 * @exception NoAccessException if access checking fails
1.21 */
1.22 - public MethodHandle findGetter(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoAccessException {
1.23 - return makeAccessor(refc, name, type, isStatic, false);
1.24 + public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoAccessException {
1.25 + return makeAccessor(refc, name, type, false, false);
1.26 }
1.27
1.28 /**
1.29 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
1.30 - * Produce a method handle giving write access to a reflected field.
1.31 + * Produce a method handle giving write access to a non-static field.
1.32 * The type of the method handle will have a void return type.
1.33 - * If the field is static, the method handle will take a single
1.34 - * argument, of the field's value type, the value to be stored.
1.35 - * Otherwise, the two arguments will be the instance containing
1.36 + * The method handle will take two arguments, the instance containing
1.37 * the field, and the value to be stored.
1.38 + * The second argument will be of the field's value type.
1.39 * Access checking is performed immediately on behalf of the lookup class.
1.40 * @param name the field's name
1.41 * @param type the field's type
1.42 - * @param isStatic true if and only if the field is static
1.43 - * @return a method handle which can store values into the reflected field
1.44 + * @return a method handle which can store values into the field
1.45 * @exception NoAccessException if access checking fails
1.46 */
1.47 - public MethodHandle findSetter(Class<?> refc, String name, Class<?> type,
1.48 - boolean isStatic) throws NoAccessException {
1.49 - return makeAccessor(refc, name, type, isStatic, true);
1.50 + public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoAccessException {
1.51 + return makeAccessor(refc, name, type, false, true);
1.52 + }
1.53 +
1.54 + /**
1.55 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
1.56 + * Produce a method handle giving read access to a static field.
1.57 + * The type of the method handle will have a return type of the field's
1.58 + * value type.
1.59 + * The method handle will take no arguments.
1.60 + * Access checking is performed immediately on behalf of the lookup class.
1.61 + * @param name the field's name
1.62 + * @param type the field's type
1.63 + * @return a method handle which can load values from the field
1.64 + * @exception NoAccessException if access checking fails
1.65 + */
1.66 + public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoAccessException {
1.67 + return makeAccessor(refc, name, type, true, false);
1.68 + }
1.69 +
1.70 + /**
1.71 + * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
1.72 + * Produce a method handle giving write access to a static field.
1.73 + * The type of the method handle will have a void return type.
1.74 + * The method handle will take a single
1.75 + * argument, of the field's value type, the value to be stored.
1.76 + * Access checking is performed immediately on behalf of the lookup class.
1.77 + * @param name the field's name
1.78 + * @param type the field's type
1.79 + * @return a method handle which can store values into the field
1.80 + * @exception NoAccessException if access checking fails
1.81 + */
1.82 + public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoAccessException {
1.83 + return makeAccessor(refc, name, type, true, true);
1.84 }
1.85
1.86 /**
2.1 --- a/src/share/classes/sun/dyn/MethodHandleNatives.java Fri Jun 18 15:23:57 2010 -0700
2.2 +++ b/src/share/classes/sun/dyn/MethodHandleNatives.java Sat Jun 19 01:14:40 2010 -0700
2.3 @@ -258,6 +258,20 @@
2.4 //T_ARRAY = 13
2.5 T_VOID = 14;
2.6 //T_ADDRESS = 15
2.7 +
2.8 + /**
2.9 + * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
2.10 + */
2.11 + static final int
2.12 + REF_getField = 1,
2.13 + REF_getStatic = 2,
2.14 + REF_putField = 3,
2.15 + REF_putStatic = 4,
2.16 + REF_invokeVirtual = 5,
2.17 + REF_invokeStatic = 6,
2.18 + REF_invokeSpecial = 7,
2.19 + REF_newInvokeSpecial = 8,
2.20 + REF_invokeInterface = 9;
2.21 }
2.22
2.23 private static native int getNamedCon(int which, Object[] name);
2.24 @@ -304,4 +318,24 @@
2.25 return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
2.26 }
2.27
2.28 + /**
2.29 + * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
2.30 + * It will make an up-call to this method. (Do not change the name or signature.)
2.31 + */
2.32 + static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
2.33 + Class<?> defc, String name, Object type) {
2.34 + Lookup lookup = IMPL_LOOKUP.in(callerClass);
2.35 + switch (refKind) {
2.36 + case REF_getField: return lookup.findGetter( defc, name, (Class<?>) type );
2.37 + case REF_getStatic: return lookup.findStaticGetter( defc, name, (Class<?>) type );
2.38 + case REF_putField: return lookup.findSetter( defc, name, (Class<?>) type );
2.39 + case REF_putStatic: return lookup.findStaticSetter( defc, name, (Class<?>) type );
2.40 + case REF_invokeVirtual: return lookup.findVirtual( defc, name, (MethodType) type );
2.41 + case REF_invokeStatic: return lookup.findStatic( defc, name, (MethodType) type );
2.42 + case REF_invokeSpecial: return lookup.findSpecial( defc, name, (MethodType) type, callerClass );
2.43 + case REF_newInvokeSpecial: return lookup.findConstructor( defc, (MethodType) type );
2.44 + case REF_invokeInterface: return lookup.findVirtual( defc, name, (MethodType) type );
2.45 + }
2.46 + throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
2.47 + }
2.48 }
3.1 --- a/src/share/javavm/export/classfile_constants.h Fri Jun 18 15:23:57 2010 -0700
3.2 +++ b/src/share/javavm/export/classfile_constants.h Sat Jun 19 01:14:40 2010 -0700
3.3 @@ -84,7 +84,22 @@
3.4 JVM_CONSTANT_Fieldref = 9,
3.5 JVM_CONSTANT_Methodref = 10,
3.6 JVM_CONSTANT_InterfaceMethodref = 11,
3.7 - JVM_CONSTANT_NameAndType = 12
3.8 + JVM_CONSTANT_NameAndType = 12,
3.9 + JVM_CONSTANT_MethodHandle = 15, // JSR 292
3.10 + JVM_CONSTANT_MethodType = 16 // JSR 292
3.11 +};
3.12 +
3.13 +/* JVM_CONSTANT_MethodHandle subtypes */
3.14 +enum {
3.15 + JVM_REF_getField = 1,
3.16 + JVM_REF_getStatic = 2,
3.17 + JVM_REF_putField = 3,
3.18 + JVM_REF_putStatic = 4,
3.19 + JVM_REF_invokeVirtual = 5,
3.20 + JVM_REF_invokeStatic = 6,
3.21 + JVM_REF_invokeSpecial = 7,
3.22 + JVM_REF_newInvokeSpecial = 8,
3.23 + JVM_REF_invokeInterface = 9
3.24 };
3.25
3.26 /* StackMapTable type item numbers */
4.1 --- a/src/share/native/common/check_code.c Fri Jun 18 15:23:57 2010 -0700
4.2 +++ b/src/share/native/common/check_code.c Sat Jun 19 01:14:40 2010 -0700
4.3 @@ -204,6 +204,8 @@
4.4
4.5 #define LDC_CLASS_MAJOR_VERSION 49
4.6
4.7 +#define LDC_METHOD_HANDLE_MAJOR_VERSION 51
4.8 +
4.9 #define ALLOC_STACK_SIZE 16 /* big enough */
4.10
4.11 typedef struct alloc_stack_type {
4.12 @@ -1181,6 +1183,10 @@
4.13 if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {
4.14 types |= 1 << JVM_CONSTANT_Class;
4.15 }
4.16 + if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {
4.17 + types |= (1 << JVM_CONSTANT_MethodHandle) |
4.18 + (1 << JVM_CONSTANT_MethodType);
4.19 + }
4.20 this_idata->operand.i = key;
4.21 verify_constant_pool_type(context, key, types);
4.22 break;
4.23 @@ -1194,6 +1200,10 @@
4.24 if (context->major_version >= LDC_CLASS_MAJOR_VERSION) {
4.25 types |= 1 << JVM_CONSTANT_Class;
4.26 }
4.27 + if (context->major_version >= LDC_METHOD_HANDLE_MAJOR_VERSION) {
4.28 + types |= (1 << JVM_CONSTANT_MethodHandle) |
4.29 + (1 << JVM_CONSTANT_MethodType);
4.30 + }
4.31 this_idata->operand.i = key;
4.32 verify_constant_pool_type(context, key, types);
4.33 break;
4.34 @@ -2667,6 +2677,22 @@
4.35 full_info = make_class_info_from_name(context,
4.36 "java/lang/Class");
4.37 break;
4.38 + case JVM_CONSTANT_MethodHandle:
4.39 + case JVM_CONSTANT_MethodType:
4.40 + if (context->major_version < LDC_METHOD_HANDLE_MAJOR_VERSION)
4.41 + CCerror(context, "Internal error #3");
4.42 + stack_results = "A";
4.43 + switch (type_table[operand]) {
4.44 + case JVM_CONSTANT_MethodType:
4.45 + full_info = make_class_info_from_name(context,
4.46 + "java/dyn/MethodType");
4.47 + break;
4.48 + default: //JVM_CONSTANT_MethodHandle
4.49 + full_info = make_class_info_from_name(context,
4.50 + "java/dyn/MethodHandle");
4.51 + break;
4.52 + }
4.53 + break;
4.54 default:
4.55 CCerror(context, "Internal error #3");
4.56 stack_results = ""; /* Never reached: keep lint happy */
5.1 --- a/test/java/dyn/MethodHandlesTest.java Fri Jun 18 15:23:57 2010 -0700
5.2 +++ b/test/java/dyn/MethodHandlesTest.java Sat Jun 19 01:14:40 2010 -0700
5.3 @@ -47,6 +47,10 @@
5.4 public class MethodHandlesTest {
5.5 // How much output?
5.6 static int verbosity = 0;
5.7 + static {
5.8 + String vstr = System.getProperty("test.java.dyn.MethodHandlesTest.verbosity");
5.9 + if (vstr != null) verbosity = Integer.parseInt(vstr);
5.10 + }
5.11
5.12 // Set this true during development if you want to fast-forward to
5.13 // a particular new, non-working test. Tests which are known to
5.14 @@ -109,7 +113,7 @@
5.15 String vers = properties.getProperty("java.vm.version");
5.16 String name = properties.getProperty("java.vm.name");
5.17 String arch = properties.getProperty("os.arch");
5.18 - if ((arch.equals("i386") || arch.equals("amd64") ||
5.19 + if ((arch.equals("amd64") || arch.equals("i386") || arch.equals("x86") ||
5.20 arch.equals("sparc") || arch.equals("sparcv9")) &&
5.21 (name.contains("Client") || name.contains("Server"))
5.22 ) {
5.23 @@ -121,6 +125,7 @@
5.24 }
5.25
5.26 String testName;
5.27 + static int allPosTests, allNegTests;
5.28 int posTests, negTests;
5.29 @After
5.30 public void printCounts() {
5.31 @@ -128,6 +133,8 @@
5.32 System.out.println();
5.33 if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
5.34 if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
5.35 + allPosTests += posTests;
5.36 + allNegTests += negTests;
5.37 posTests = negTests = 0;
5.38 }
5.39 }
5.40 @@ -153,6 +160,12 @@
5.41
5.42 @AfterClass
5.43 public static void tearDownClass() throws Exception {
5.44 + int posTests = allPosTests, negTests = allNegTests;
5.45 + if (verbosity >= 2 && (posTests | negTests) != 0) {
5.46 + System.out.println();
5.47 + if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
5.48 + if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
5.49 + }
5.50 }
5.51
5.52 static List<Object> calledLog = new ArrayList<Object>();
5.53 @@ -811,28 +824,52 @@
5.54 }
5.55 }
5.56
5.57 + static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC_FIELD = 3;
5.58 + static boolean testModeMatches(int testMode, boolean isStatic) {
5.59 + switch (testMode) {
5.60 + case TEST_FIND_STATIC_FIELD: return isStatic;
5.61 + case TEST_FIND_FIELD: return !isStatic;
5.62 + default: return true; // unreflect matches both
5.63 + }
5.64 + }
5.65 +
5.66 @Test
5.67 public void testUnreflectGetter() throws Throwable {
5.68 + startTest("unreflectGetter");
5.69 + testGetter(TEST_UNREFLECT);
5.70 + }
5.71 + @Test
5.72 + public void testFindGetter() throws Throwable {
5.73 + startTest("findGetter");
5.74 + testGetter(TEST_FIND_FIELD);
5.75 + }
5.76 + @Test
5.77 + public void testFindStaticGetter() throws Throwable {
5.78 + startTest("findStaticGetter");
5.79 + testGetter(TEST_FIND_STATIC_FIELD);
5.80 + }
5.81 + public void testGetter(int testMode) throws Throwable {
5.82 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
5.83 - startTest("unreflectGetter");
5.84 for (Object[] c : HasFields.CASES) {
5.85 Field f = (Field)c[0];
5.86 Object value = c[1];
5.87 Class<?> type = f.getType();
5.88 - if (type.isPrimitive() && type != int.class)
5.89 - continue; //FIXME
5.90 - testUnreflectGetter(lookup, f, type, value);
5.91 + testGetter(lookup, f, type, value, testMode);
5.92 }
5.93 }
5.94 - public void testUnreflectGetter(MethodHandles.Lookup lookup,
5.95 - Field f, Class<?> type, Object value) throws Throwable {
5.96 + public void testGetter(MethodHandles.Lookup lookup,
5.97 + Field f, Class<?> type, Object value, int testMode) throws Throwable {
5.98 + boolean isStatic = Modifier.isStatic(f.getModifiers());
5.99 + Class<?> fclass = f.getDeclaringClass();
5.100 + String fname = f.getName();
5.101 + Class<?> ftype = f.getType();
5.102 + if (!testModeMatches(testMode, isStatic)) return;
5.103 countTest(true);
5.104 - boolean isStatic = Modifier.isStatic(f.getModifiers());
5.105 MethodType expType = MethodType.methodType(type, HasFields.class);
5.106 if (isStatic) expType = expType.dropParameterTypes(0, 1);
5.107 MethodHandle mh = lookup.unreflectGetter(f);
5.108 assertSame(mh.type(), expType);
5.109 - assertEquals(mh.toString(), f.getName());
5.110 + assertEquals(mh.toString(), fname);
5.111 HasFields fields = new HasFields();
5.112 Object sawValue;
5.113 Class<?> rtype = type;
5.114 @@ -862,26 +899,49 @@
5.115
5.116 @Test
5.117 public void testUnreflectSetter() throws Throwable {
5.118 + startTest("unreflectSetter");
5.119 + testSetter(TEST_UNREFLECT);
5.120 + }
5.121 + @Test
5.122 + public void testFindSetter() throws Throwable {
5.123 + startTest("findSetter");
5.124 + testSetter(TEST_FIND_FIELD);
5.125 + }
5.126 + @Test
5.127 + public void testFindStaticSetter() throws Throwable {
5.128 + startTest("findStaticSetter");
5.129 + testSetter(TEST_FIND_STATIC_FIELD);
5.130 + }
5.131 + public void testSetter(int testMode) throws Throwable {
5.132 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
5.133 startTest("unreflectSetter");
5.134 for (Object[] c : HasFields.CASES) {
5.135 Field f = (Field)c[0];
5.136 Object value = c[1];
5.137 Class<?> type = f.getType();
5.138 - if (type.isPrimitive() && type != int.class)
5.139 - continue; //FIXME
5.140 - testUnreflectSetter(lookup, f, type, value);
5.141 + testSetter(lookup, f, type, value, testMode);
5.142 }
5.143 }
5.144 - public void testUnreflectSetter(MethodHandles.Lookup lookup,
5.145 - Field f, Class<?> type, Object value) throws Throwable {
5.146 + public void testSetter(MethodHandles.Lookup lookup,
5.147 + Field f, Class<?> type, Object value, int testMode) throws Throwable {
5.148 + boolean isStatic = Modifier.isStatic(f.getModifiers());
5.149 + Class<?> fclass = f.getDeclaringClass();
5.150 + String fname = f.getName();
5.151 + Class<?> ftype = f.getType();
5.152 + if (!testModeMatches(testMode, isStatic)) return;
5.153 countTest(true);
5.154 - boolean isStatic = Modifier.isStatic(f.getModifiers());
5.155 MethodType expType = MethodType.methodType(void.class, HasFields.class, type);
5.156 if (isStatic) expType = expType.dropParameterTypes(0, 1);
5.157 - MethodHandle mh = lookup.unreflectSetter(f);
5.158 + MethodHandle mh;
5.159 + if (testMode == TEST_UNREFLECT)
5.160 + mh = lookup.unreflectSetter(f);
5.161 + else if (testMode == TEST_FIND_FIELD)
5.162 + mh = lookup.findSetter(fclass, fname, ftype);
5.163 + else if (testMode == TEST_FIND_STATIC_FIELD)
5.164 + mh = lookup.findStaticSetter(fclass, fname, ftype);
5.165 + else throw new InternalError();
5.166 assertSame(mh.type(), expType);
5.167 - assertEquals(mh.toString(), f.getName());
5.168 + assertEquals(mh.toString(), fname);
5.169 HasFields fields = new HasFields();
5.170 Object sawValue;
5.171 Class<?> vtype = type;