7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 /*
26 * @test
27 * @summary test MethodHandle/VarHandle on value types
28 * @compile -XDallowWithFieldOperator Point.java Line.java MutablePath.java MixedValues.java
29 * @run testng/othervm -XX:+EnableValhalla MethodHandleTest
30 */
31
32 import java.lang.invoke.*;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Modifier;
35 import java.util.*;
36
37 import org.testng.annotations.BeforeTest;
38 import org.testng.annotations.DataProvider;
39 import org.testng.annotations.Test;
40 import static org.testng.Assert.*;
41
42 public class MethodHandleTest {
43 private static final Point P = Point.makePoint(10, 20);
44 private static final Line L = Line.makeLine(10, 20, 30, 40);
45 private static final MutablePath PATH = MutablePath.makePath(10, 20, 30, 40);
46
47 @Test
54 public static void testLineClass() throws Throwable {
55 MethodHandleTest test = new MethodHandleTest("Line", L, "p1", "p2");
56 test.run();
57 }
58
59 @Test
60 public static void testMutablePath() throws Throwable {
61 MethodHandleTest test = new MethodHandleTest("MutablePath", PATH, "p1", "p2");
62 test.run();
63
64 // set the mutable fields
65 MutablePath path = MutablePath.makePath(1, 2, 3, 44);
66 Point p = Point.makePoint(100, 200);
67 test.setValueField("p1", path, p);
68 test.setValueField("p2", path, p);
69 }
70
71 @Test
72 public static void testValueFields() throws Throwable {
73 MutablePath path = MutablePath.makePath(1, 2, 3, 4);
74 // p1 and p2 are a non-final field of value type in a reference
75 MethodHandleTest test1 = new MethodHandleTest("Point", path.p1, "x", "y");
76 test1.run();
77
78 MethodHandleTest test2 = new MethodHandleTest("Point", path.p2, "x", "y");
79 test2.run();
80 }
81
82 @Test
83 public static void testMixedValues() throws Throwable {
84 MixedValues mv = new MixedValues(P, L, PATH, "mixed", "types");
85 MethodHandleTest test =
86 new MethodHandleTest("MixedValues", mv, "p", "l", "mutablePath", "list", "nfp");
87 test.run();
88
89 Point p = Point.makePoint(100, 200);
90 Line l = Line.makeLine(100, 200, 300, 400);
91 test.setValueField("p", mv, p);
92 test.setValueField("nfp", mv, p);
93 test.setValueField("l", mv, l);
94 test.setValueField("l", mv, l);
105 testArray(MutablePath[].class, PATH);
106 }
107
108 static void testArray(Class<?> c, Object o) throws Throwable {
109 MethodHandle setter = MethodHandles.arrayElementSetter(c);
110 MethodHandle getter = MethodHandles.arrayElementGetter(c);
111 MethodHandle ctor = MethodHandles.arrayConstructor(c);
112 int size = 5;
113 Object[] array = (Object[])ctor.invoke(size);
114 for (int i=0; i < size; i++) {
115 setter.invoke(array, i, o);
116 }
117 for (int i=0; i < size; i++) {
118 Object v = (Object)getter.invoke(array, i);
119 assertEquals(v, o);
120 }
121
122 // set an array element to null
123 Class<?> elementType = c.getComponentType();
124 try {
125 // value array element is flattenable
126 Object v = (Object)setter.invoke(array, 0, null);
127 assertFalse(elementType.isValue(), "should fail to set a value array element to null");
128 } catch (NullPointerException e) {
129 assertTrue(elementType.isValue(), "should only fail to set a value array element to null");
130 }
131 }
132
133 private final Class<?> c;
134 private final Object o;
135 private final List<String> names;
136 public MethodHandleTest(String cn, Object o, String... fields) throws Exception {
137 this.c = Class.forName(cn);
138 this.o = o;
139 this.names = List.of(fields);
140 }
141
142 public void run() throws Throwable {
143 for (String name : names) {
144 Field f = c.getDeclaredField(name);
145 unreflectField(f);
146 findGetter(f);
147 varHandle(f);
148 if (c.isValue())
149 ensureImmutable(f);
155 public List<String> names() {
156 return names;
157 }
158
159 void findGetter(Field f) throws Throwable {
160 MethodHandle mh = MethodHandles.lookup().findGetter(c, f.getName(), f.getType());
161 Object value = mh.invoke(o);
162 }
163
164 void varHandle(Field f) throws Throwable {
165 VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType());
166 Object value = vh.get(o);
167 }
168
169 void unreflectField(Field f) throws Throwable {
170 MethodHandle mh = MethodHandles.lookup().unreflectGetter(f);
171 Object value = mh.invoke(o);
172 }
173
174 /*
175 * Test setting value field to a new value.
176 * The field must be flattenable but may or may not be flattened.
177 */
178 void setValueField(String name, Object obj, Object value) throws Throwable {
179 Field f = c.getDeclaredField(name);
180 boolean isStatic = Modifier.isStatic(f.getModifiers());
181 assertTrue(f.getType().isValue());
182 assertTrue((isStatic && obj == null) || (!isStatic && obj != null));
183 Object v = f.get(obj);
184
185 // Field::set
186 try {
187 f.set(obj, value);
188 assertEquals(f.get(obj), value);
189 } finally {
190 f.set(obj, v);
191 }
192
193
194 if (isStatic) {
195 setStaticField(f, value);
|
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 /*
26 * @test
27 * @summary test MethodHandle/VarHandle on inline types
28 * @compile -XDallowWithFieldOperator Point.java Line.java MutablePath.java MixedValues.java
29 * @run testng/othervm -XX:+EnableValhalla MethodHandleTest
30 */
31
32 import java.lang.invoke.*;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Modifier;
35 import java.util.*;
36
37 import org.testng.annotations.BeforeTest;
38 import org.testng.annotations.DataProvider;
39 import org.testng.annotations.Test;
40 import static org.testng.Assert.*;
41
42 public class MethodHandleTest {
43 private static final Point P = Point.makePoint(10, 20);
44 private static final Line L = Line.makeLine(10, 20, 30, 40);
45 private static final MutablePath PATH = MutablePath.makePath(10, 20, 30, 40);
46
47 @Test
54 public static void testLineClass() throws Throwable {
55 MethodHandleTest test = new MethodHandleTest("Line", L, "p1", "p2");
56 test.run();
57 }
58
59 @Test
60 public static void testMutablePath() throws Throwable {
61 MethodHandleTest test = new MethodHandleTest("MutablePath", PATH, "p1", "p2");
62 test.run();
63
64 // set the mutable fields
65 MutablePath path = MutablePath.makePath(1, 2, 3, 44);
66 Point p = Point.makePoint(100, 200);
67 test.setValueField("p1", path, p);
68 test.setValueField("p2", path, p);
69 }
70
71 @Test
72 public static void testValueFields() throws Throwable {
73 MutablePath path = MutablePath.makePath(1, 2, 3, 4);
74 // p1 and p2 are a non-final field of inline type in a reference
75 MethodHandleTest test1 = new MethodHandleTest("Point", path.p1, "x", "y");
76 test1.run();
77
78 MethodHandleTest test2 = new MethodHandleTest("Point", path.p2, "x", "y");
79 test2.run();
80 }
81
82 @Test
83 public static void testMixedValues() throws Throwable {
84 MixedValues mv = new MixedValues(P, L, PATH, "mixed", "types");
85 MethodHandleTest test =
86 new MethodHandleTest("MixedValues", mv, "p", "l", "mutablePath", "list", "nfp");
87 test.run();
88
89 Point p = Point.makePoint(100, 200);
90 Line l = Line.makeLine(100, 200, 300, 400);
91 test.setValueField("p", mv, p);
92 test.setValueField("nfp", mv, p);
93 test.setValueField("l", mv, l);
94 test.setValueField("l", mv, l);
105 testArray(MutablePath[].class, PATH);
106 }
107
108 static void testArray(Class<?> c, Object o) throws Throwable {
109 MethodHandle setter = MethodHandles.arrayElementSetter(c);
110 MethodHandle getter = MethodHandles.arrayElementGetter(c);
111 MethodHandle ctor = MethodHandles.arrayConstructor(c);
112 int size = 5;
113 Object[] array = (Object[])ctor.invoke(size);
114 for (int i=0; i < size; i++) {
115 setter.invoke(array, i, o);
116 }
117 for (int i=0; i < size; i++) {
118 Object v = (Object)getter.invoke(array, i);
119 assertEquals(v, o);
120 }
121
122 // set an array element to null
123 Class<?> elementType = c.getComponentType();
124 try {
125 // inline array element is flattenable
126 Object v = (Object)setter.invoke(array, 0, null);
127 assertFalse(elementType.isValue(), "should fail to set an inline class array element to null");
128 } catch (NullPointerException e) {
129 assertTrue(elementType.isValue(), "should only fail to set an inline class array element to null");
130 }
131 }
132
133 private final Class<?> c;
134 private final Object o;
135 private final List<String> names;
136 public MethodHandleTest(String cn, Object o, String... fields) throws Exception {
137 this.c = Class.forName(cn);
138 this.o = o;
139 this.names = List.of(fields);
140 }
141
142 public void run() throws Throwable {
143 for (String name : names) {
144 Field f = c.getDeclaredField(name);
145 unreflectField(f);
146 findGetter(f);
147 varHandle(f);
148 if (c.isValue())
149 ensureImmutable(f);
155 public List<String> names() {
156 return names;
157 }
158
159 void findGetter(Field f) throws Throwable {
160 MethodHandle mh = MethodHandles.lookup().findGetter(c, f.getName(), f.getType());
161 Object value = mh.invoke(o);
162 }
163
164 void varHandle(Field f) throws Throwable {
165 VarHandle vh = MethodHandles.lookup().findVarHandle(c, f.getName(), f.getType());
166 Object value = vh.get(o);
167 }
168
169 void unreflectField(Field f) throws Throwable {
170 MethodHandle mh = MethodHandles.lookup().unreflectGetter(f);
171 Object value = mh.invoke(o);
172 }
173
174 /*
175 * Test setting a field of an inline type to a new value.
176 * The field must be flattenable but may or may not be flattened.
177 */
178 void setValueField(String name, Object obj, Object value) throws Throwable {
179 Field f = c.getDeclaredField(name);
180 boolean isStatic = Modifier.isStatic(f.getModifiers());
181 assertTrue(f.getType().isValue());
182 assertTrue((isStatic && obj == null) || (!isStatic && obj != null));
183 Object v = f.get(obj);
184
185 // Field::set
186 try {
187 f.set(obj, value);
188 assertEquals(f.get(obj), value);
189 } finally {
190 f.set(obj, v);
191 }
192
193
194 if (isStatic) {
195 setStaticField(f, value);
|