< prev index next >

test/jdk/valhalla/valuetypes/MethodHandleTest.java

Print this page

        

*** 22,39 **** */ /* * @test ! * @summary test MethodHandles on value types * @build Point Line MutablePath * @run testng/othervm -XX:+EnableValhalla MethodHandleTest */ import java.lang.invoke.*; import java.lang.reflect.Field; import java.util.*; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; --- 22,42 ---- */ /* * @test ! * @summary test MethodHandle/VarHandle on value types * @build Point Line MutablePath + * @compile -XDallowFlattenabilityModifiers MethodHandleTest.java * @run testng/othervm -XX:+EnableValhalla MethodHandleTest */ import java.lang.invoke.*; import java.lang.reflect.Field; + import java.lang.reflect.Modifier; import java.util.*; + import java.util.stream.Stream; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*;
*** 59,77 **** public static void testMutablePath() throws Throwable { MethodHandleTest test = new MethodHandleTest("MutablePath", PATH, "p1", "p2"); test.run(); // set the mutable fields Point p = Point.makePoint(100, 200); ! test.setFlattenedField(p); } @Test public static void testMixedValues() throws Throwable { MixedValues mv = new MixedValues(P, L, PATH, "mixed", "types"); ! MethodHandleTest test = new MethodHandleTest("MethodHandleTest$MixedValues", mv, "p", "l", "mutablePath", "list"); test.run(); } @Test public static void testArrayElementSetterAndGetter() throws Throwable { testArray(Point[].class, P); --- 62,107 ---- public static void testMutablePath() throws Throwable { MethodHandleTest test = new MethodHandleTest("MutablePath", PATH, "p1", "p2"); test.run(); // set the mutable fields + MutablePath path = MutablePath.makePath(1, 2, 3, 44); Point p = Point.makePoint(100, 200); ! test.setValueField("p1", path, p); ! test.setValueField("p2", path, p); ! } ! ! @Test ! public static void testValueFields() throws Throwable { ! MutablePath path = MutablePath.makePath(1, 2, 3, 4); ! // p1 and p2 are a non-final field of value type in a reference ! MethodHandleTest test1 = new MethodHandleTest("Point", path.p1, "x", "y"); ! test1.run(); ! ! MethodHandleTest test2 = new MethodHandleTest("Point", path.p2, "x", "y"); ! test2.run(); } @Test public static void testMixedValues() throws Throwable { MixedValues mv = new MixedValues(P, L, PATH, "mixed", "types"); ! MethodHandleTest test = ! new MethodHandleTest("MethodHandleTest$MixedValues", mv, "p", "l", "mutablePath", "list", "nfp"); test.run(); + + Point p = Point.makePoint(100, 200); + Line l = Line.makeLine(100, 200, 300, 400); + test.setValueField("p", mv, p); + test.setValueField("nfp", mv, p); + test.setValueField("l", mv, l); + test.setValueField("l", mv, l); + test.setValueField("staticPoint", null, p); + test.setValueField("staticLine", null, l); + // remove the following cases when javac and jvm make + // static value fields be flattenable + test.setValueField("staticPoint", null, null); + test.setValueField("staticLine", null, null); } @Test public static void testArrayElementSetterAndGetter() throws Throwable { testArray(Point[].class, P);
*** 92,110 **** Object v = (Object)getter.invoke(array, i); assertEquals(v, o); } // set an array element to null - /* Class<?> elementType = c.getComponentType(); try { Object v = (Object)setter.invoke(array, 0, null); assertFalse(elementType.isValue(), "should fail to set a value array element to null"); } catch (NullPointerException e) { assertTrue(elementType.isValue(), "should only fail to set a value array element to null"); } - */ } private final Class<?> c; private final Object o; private final List<String> names; --- 122,139 ---- Object v = (Object)getter.invoke(array, i); assertEquals(v, o); } // set an array element to null Class<?> elementType = c.getComponentType(); try { + // value array element is flattenable Object v = (Object)setter.invoke(array, 0, null); assertFalse(elementType.isValue(), "should fail to set a value array element to null"); } catch (NullPointerException e) { assertTrue(elementType.isValue(), "should only fail to set a value array element to null"); } } private final Class<?> c; private final Object o; private final List<String> names;
*** 118,128 **** for (String name : names) { Field f = c.getDeclaredField(name); unreflectField(f); findGetter(f); varHandle(f); ! // ensureNonNullable(f); } } public List<String> names() { return names; --- 147,160 ---- for (String name : names) { Field f = c.getDeclaredField(name); unreflectField(f); findGetter(f); varHandle(f); ! if (c.isValue()) ! ensureImmutable(f); ! else ! ensureNullable(f); } } public List<String> names() { return names;
*** 141,205 **** void unreflectField(Field f) throws Throwable { MethodHandle mh = MethodHandles.lookup().unreflectGetter(f); Object value = mh.invoke(o); } ! void setFlattenedField(Object value) throws Exception { ! for (String name : names) { Field f = c.getDeclaredField(name); ! assertTrue(isFlattened(f)); ! f.set(o, value); ! Object nv = f.get(o); ! assertEquals(nv, value); } } ! void ensureNonNullable(Field f) throws Throwable { ! boolean nullable = !f.getType().isValue(); try { f.set(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); - } catch (IllegalAccessException e) { - assertTrue(c.isValue()); } try { MethodHandle mh = MethodHandles.lookup().findSetter(c, f.getName(), f.getType()); mh.invoke(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); - } catch (IllegalAccessException e) { - assertTrue(c.isValue()); } try { VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType()); vh.set(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); - } catch (UnsupportedOperationException e) { // TODO: this should be IAE - assertTrue(c.isValue()); } } boolean isFlattened(Field f) { return (f.getModifiers() & 0x00008000) == 0x00008000; } static class MixedValues { Point p; Line l; MutablePath mutablePath; List<String> list; public MixedValues(Point p, Line l, MutablePath path, String... names) { this.p = p; this.l = l; this.mutablePath = path; this.list = List.of(names); } } } --- 173,317 ---- void unreflectField(Field f) throws Throwable { MethodHandle mh = MethodHandles.lookup().unreflectGetter(f); Object value = mh.invoke(o); } ! /* ! * Test setting value field to a new value. ! * The field must be flattenable but may or may not be flattened. ! */ ! void setValueField(String name, Object obj, Object value) throws Throwable { Field f = c.getDeclaredField(name); ! boolean isStatic = Modifier.isStatic(f.getModifiers()); ! assertTrue(f.getType().isValue()); ! assertTrue((isStatic && obj == null) || (!isStatic && obj != null)); ! Object v = f.get(obj); ! ! // Field::set ! try { ! f.set(obj, value); ! assertEquals(f.get(obj), value); ! } finally { ! f.set(obj, v); ! } ! ! ! if (isStatic) { ! // MethodHandle::invoke ! try { ! MethodHandle mh = MethodHandles.lookup().findStaticSetter(c, f.getName(), f.getType()); ! mh.invoke(f.getType().cast(value)); ! assertEquals(f.get(obj), value); ! } finally { ! f.set(obj, v); ! } ! // VarHandle::set ! try { ! VarHandle vh = MethodHandles.lookup().findStaticVarHandle(c, f.getName(), f.getType()); ! vh.set(f.getType().cast(value)); ! assertEquals(f.get(obj), value); ! } finally { ! f.set(obj, v); ! } ! } else { ! // MethodHandle::invoke ! try { ! MethodHandle mh = MethodHandles.lookup().findSetter(c, f.getName(), f.getType()); ! mh.invoke(obj, value); ! assertEquals(f.get(obj), value); ! } finally { ! f.set(obj, v); ! } ! // VarHandle::set ! try { ! VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType()); ! vh.set(obj, value); ! assertEquals(f.get(obj), value); ! } finally { ! f.set(obj, v); ! } } } ! /* ! * Test setting the given field to null via reflection, method handle ! * and var handle. ! */ ! void ensureNullable(Field f) throws Throwable { ! assertFalse(Modifier.isStatic(f.getModifiers())); ! // flattenable implies non-nullable ! boolean nullable = !isFlattenable(f); ! // test reflection try { f.set(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); } + // test method handle, i.e. putfield bytecode behavior try { MethodHandle mh = MethodHandles.lookup().findSetter(c, f.getName(), f.getType()); mh.invoke(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); } + // test var handle try { VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType()); vh.set(o, null); assertTrue(nullable, f + " cannot be set to null"); } catch (NullPointerException e) { assertFalse(nullable, f + " should allow be set to null"); } } + void ensureImmutable(Field f) throws Throwable { + assertFalse(Modifier.isStatic(f.getModifiers())); + Object v = f.get(o); + // test reflection + try { + f.set(o, v); + throw new RuntimeException(f + " should be immutable"); + } catch (IllegalAccessException e) {} + + // test method handle, i.e. putfield bytecode behavior + try { + MethodHandle mh = MethodHandles.lookup().findSetter(c, f.getName(), f.getType()); + mh.invoke(o, v); + throw new RuntimeException(f + " should be immutable"); + } catch (IllegalAccessException e) { } + // test var handle + try { + VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType()); + vh.set(o, v); + throw new RuntimeException(f + " should be immutable"); + } catch (UnsupportedOperationException e) {} + } boolean isFlattened(Field f) { return (f.getModifiers() & 0x00008000) == 0x00008000; } + boolean isFlattenable(Field f) { + return (f.getModifiers() & 0x00000100) == 0x00000100; + } + static class MixedValues { + static Point staticPoint = Point.makePoint(10, 10); + static Line staticLine; // LW1 allows null static value field Point p; Line l; MutablePath mutablePath; List<String> list; + __NotFlattened Point nfp; public MixedValues(Point p, Line l, MutablePath path, String... names) { this.p = p; this.l = l; this.mutablePath = path; this.list = List.of(names); + this.nfp = p; } } }
< prev index next >