1 /*
2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
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  * @test
26  * @summary Basic tests for ObjectMethods
27  * @compile --enable-preview -source ${jdk.version} ObjectMethodsTest.java
28  * @run testng/othervm --enable-preview ObjectMethodsTest
29  * @run testng/othervm/java.security.policy=empty.policy --enable-preview ObjectMethodsTest
30  */
31 
32 import java.lang.invoke.CallSite;
33 import java.lang.invoke.MethodHandle;
34 import java.lang.invoke.MethodHandles;
35 import java.lang.invoke.MethodType;
36 import java.lang.runtime.ObjectMethods;
37 import org.testng.annotations.Test;
38 import static java.lang.invoke.MethodType.methodType;
39 import static org.testng.Assert.assertEquals;
40 import static org.testng.Assert.assertThrows;
41 import static org.testng.Assert.assertFalse;
42 import static org.testng.Assert.assertTrue;
43 
44 @Test
45 public class ObjectMethodsTest {
46 
47     public static class C {
48         static final MethodType EQUALS_DESC = methodType(boolean.class, C.class, Object.class);
49         static final MethodType HASHCODE_DESC = methodType(int.class, C.class);
50         static final MethodType TO_STRING_DESC = methodType(String.class, C.class);
51 
52         static final MethodHandle[] ACCESSORS = accessors();
53         static final String NAME_LIST = "x;y";
accessors()54         private static MethodHandle[] accessors() {
55             try {
56                 return  new MethodHandle[]{
57                         MethodHandles.lookup().findGetter(C.class, "x", int.class),
58                         MethodHandles.lookup().findGetter(C.class, "y", int.class),
59                 };
60             } catch (Exception e) {
61                 throw new AssertionError(e);
62             }
63         }
64 
65         private final int x;
66         private final int y;
C(int x, int y)67         C (int x, int y) { this.x = x; this.y = y; }
x()68         public int x() { return x; }
y()69         public int y() { return y; }
70     }
71 
72     static class Empty {
73         static final MethodType EQUALS_DESC = methodType(boolean.class, Empty.class, Object.class);
74         static final MethodType HASHCODE_DESC = methodType(int.class, Empty.class);
75         static final MethodType TO_STRING_DESC = methodType(String.class, Empty.class);
76         static final MethodHandle[] ACCESSORS = new MethodHandle[] { };
77         static final String NAME_LIST = "";
Empty()78         Empty () {  }
79     }
80 
81     static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
82 
testEqualsC()83     public void testEqualsC() throws Throwable {
84         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
85         MethodHandle handle = cs.dynamicInvoker();
86         C c = new C(5, 5);
87         assertTrue((boolean)handle.invokeExact(c, (Object)c));
88         assertTrue((boolean)handle.invokeExact(c, (Object)new C(5, 5)));
89         assertFalse((boolean)handle.invokeExact(c, (Object)new C(5, 4)));
90         assertFalse((boolean)handle.invokeExact(c, (Object)new C(4, 5)));
91         assertFalse((boolean)handle.invokeExact(c, (Object)null));
92         assertFalse((boolean)handle.invokeExact(c, new Object()));
93     }
94 
testEqualsEmpty()95     public void testEqualsEmpty() throws Throwable {
96         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", Empty.EQUALS_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
97         MethodHandle handle = cs.dynamicInvoker();
98         Empty e = new Empty();
99         assertTrue((boolean)handle.invokeExact(e, (Object)e));
100         assertTrue((boolean)handle.invokeExact(e, (Object)new Empty()));
101         assertFalse((boolean)handle.invokeExact(e, (Object)null));
102         assertFalse((boolean)handle.invokeExact(e, new Object()));
103     }
104 
testHashCodeC()105     public void testHashCodeC() throws Throwable {
106         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", C.HASHCODE_DESC, C.class, null, C.ACCESSORS);
107         MethodHandle handle = cs.dynamicInvoker();
108         C c = new C(6, 7);
109         int hc = (int)handle.invokeExact(c);
110         assertEquals(hc, hashCombiner(c.x(), c.y()));
111 
112         assertEquals((int)handle.invokeExact(new C(100, 1)),  hashCombiner(100, 1));
113         assertEquals((int)handle.invokeExact(new C(0, 0)),    hashCombiner(0, 0));
114         assertEquals((int)handle.invokeExact(new C(-1, 100)), hashCombiner(-1, 100));
115         assertEquals((int)handle.invokeExact(new C(100, 1)),  hashCombiner(100, 1));
116         assertEquals((int)handle.invokeExact(new C(100, -1)), hashCombiner(100, -1));
117     }
118 
testHashCodeEmpty()119     public void testHashCodeEmpty() throws Throwable {
120         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", Empty.HASHCODE_DESC, Empty.class, "", Empty.ACCESSORS);
121         MethodHandle handle = cs.dynamicInvoker();
122         Empty e = new Empty();
123         assertEquals((int)handle.invokeExact(e), 0);
124     }
125 
testToStringC()126     public void testToStringC() throws Throwable {
127         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
128         MethodHandle handle = cs.dynamicInvoker();
129         assertEquals((String)handle.invokeExact(new C(8, 9)),    "C[x=8, y=9]"   );
130         assertEquals((String)handle.invokeExact(new C(10, 11)),  "C[x=10, y=11]" );
131         assertEquals((String)handle.invokeExact(new C(100, -9)), "C[x=100, y=-9]");
132         assertEquals((String)handle.invokeExact(new C(0, 0)),    "C[x=0, y=0]"   );
133     }
134 
testToStringEmpty()135     public void testToStringEmpty() throws Throwable {
136         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", Empty.TO_STRING_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
137         MethodHandle handle = cs.dynamicInvoker();
138         assertEquals((String)handle.invokeExact(new Empty()),    "Empty[]");
139     }
140 
141     Class<NullPointerException> NPE = NullPointerException.class;
142     Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
143 
exceptions()144     public void exceptions()  {
145         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "badName",  C.EQUALS_DESC,    C.class,         C.NAME_LIST, C.ACCESSORS));
146         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class,         "x;y;z",     C.ACCESSORS));
147         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class,         "x;y",       new MethodHandle[]{}));
148         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, this.getClass(), "x;y",       C.ACCESSORS));
149 
150         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.EQUALS_DESC,    C.class, "x;y", C.ACCESSORS));
151         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "hashCode", C.TO_STRING_DESC, C.class, "x;y", C.ACCESSORS));
152         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "equals",   C.HASHCODE_DESC,  C.class, "x;y", C.ACCESSORS));
153 
154         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, "x;y", null)       );
155         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, null,  C.ACCESSORS));
156         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, null,    "x;y", C.ACCESSORS));
157         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "equals",   C.EQUALS_DESC,    null,    "x;y", C.ACCESSORS));
158         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "hashCode", C.HASHCODE_DESC,  null,    "x;y", C.ACCESSORS));
159 
160         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", null,             C.class, "x;y", C.ACCESSORS));
161         assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, null,       C.TO_STRING_DESC, C.class, "x;y", C.ACCESSORS));
162       //assertThrows(NPE, () -> ObjectMethods.bootstrap(null,   "toString", C.TO_STRING_DESC, C.class, "x;y", C.ACCESSORS));
163     }
164 
165     // Based on the ObjectMethods internal implementation
hashCombiner(int x, int y)166     private static int hashCombiner(int x, int y) {
167         return x*31 + y;
168     }
169 }
170