• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2019, 2020, 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  * @bug 8246774
27  * @summary Basic tests for ObjectMethods
28  * @run testng ObjectMethodsTest
29  * @run testng/othervm/java.security.policy=empty.policy ObjectMethodsTest
30  */
31 
32 package test.java.lang.runtime;
33 
34 import java.util.List;
35 import java.lang.invoke.CallSite;
36 import java.lang.invoke.MethodHandle;
37 import java.lang.invoke.MethodHandles;
38 import java.lang.invoke.MethodType;
39 import java.lang.runtime.ObjectMethods;
40 import org.testng.annotations.Test;
41 import static java.lang.invoke.MethodType.methodType;
42 import static org.testng.Assert.assertEquals;
43 import static org.testng.Assert.assertThrows;
44 import static org.testng.Assert.assertFalse;
45 import static org.testng.Assert.assertTrue;
46 
47 @Test
48 public class ObjectMethodsTest {
49 
50     public static class C {
51         static final MethodType EQUALS_DESC = methodType(boolean.class, C.class, Object.class);
52         static final MethodType HASHCODE_DESC = methodType(int.class, C.class);
53         static final MethodType TO_STRING_DESC = methodType(String.class, C.class);
54 
55         static final MethodHandle[] ACCESSORS = accessors();
56         static final String NAME_LIST = "x;y";
accessors()57         private static MethodHandle[] accessors() {
58             try {
59                 return  new MethodHandle[]{
60                         MethodHandles.lookup().findGetter(C.class, "x", int.class),
61                         MethodHandles.lookup().findGetter(C.class, "y", int.class),
62                 };
63             } catch (Exception e) {
64                 throw new AssertionError(e);
65             }
66         }
67 
68         private final int x;
69         private final int y;
C(int x, int y)70         C (int x, int y) { this.x = x; this.y = y; }
x()71         public int x() { return x; }
y()72         public int y() { return y; }
73     }
74 
75     static class Empty {
76         static final MethodType EQUALS_DESC = methodType(boolean.class, Empty.class, Object.class);
77         static final MethodType HASHCODE_DESC = methodType(int.class, Empty.class);
78         static final MethodType TO_STRING_DESC = methodType(String.class, Empty.class);
79         static final MethodHandle[] ACCESSORS = new MethodHandle[] { };
80         static final String NAME_LIST = "";
Empty()81         Empty () {  }
82     }
83 
84     static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
85 
testEqualsC()86     public void testEqualsC() throws Throwable {
87         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
88         MethodHandle handle = cs.dynamicInvoker();
89         C c = new C(5, 5);
90         assertTrue((boolean)handle.invokeExact(c, (Object)c));
91         assertTrue((boolean)handle.invokeExact(c, (Object)new C(5, 5)));
92         assertFalse((boolean)handle.invokeExact(c, (Object)new C(5, 4)));
93         assertFalse((boolean)handle.invokeExact(c, (Object)new C(4, 5)));
94         assertFalse((boolean)handle.invokeExact(c, (Object)null));
95         assertFalse((boolean)handle.invokeExact(c, new Object()));
96     }
97 
testEqualsEmpty()98     public void testEqualsEmpty() throws Throwable {
99         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", Empty.EQUALS_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
100         MethodHandle handle = cs.dynamicInvoker();
101         Empty e = new Empty();
102         assertTrue((boolean)handle.invokeExact(e, (Object)e));
103         assertTrue((boolean)handle.invokeExact(e, (Object)new Empty()));
104         assertFalse((boolean)handle.invokeExact(e, (Object)null));
105         assertFalse((boolean)handle.invokeExact(e, new Object()));
106     }
107 
testHashCodeC()108     public void testHashCodeC() throws Throwable {
109         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", C.HASHCODE_DESC, C.class, "x;y", C.ACCESSORS);
110         MethodHandle handle = cs.dynamicInvoker();
111         C c = new C(6, 7);
112         int hc = (int)handle.invokeExact(c);
113         assertEquals(hc, hashCombiner(c.x(), c.y()));
114 
115         assertEquals((int)handle.invokeExact(new C(100, 1)),  hashCombiner(100, 1));
116         assertEquals((int)handle.invokeExact(new C(0, 0)),    hashCombiner(0, 0));
117         assertEquals((int)handle.invokeExact(new C(-1, 100)), hashCombiner(-1, 100));
118         assertEquals((int)handle.invokeExact(new C(100, 1)),  hashCombiner(100, 1));
119         assertEquals((int)handle.invokeExact(new C(100, -1)), hashCombiner(100, -1));
120     }
121 
testHashCodeEmpty()122     public void testHashCodeEmpty() throws Throwable {
123         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", Empty.HASHCODE_DESC, Empty.class, "", Empty.ACCESSORS);
124         MethodHandle handle = cs.dynamicInvoker();
125         Empty e = new Empty();
126         assertEquals((int)handle.invokeExact(e), 0);
127     }
128 
testToStringC()129     public void testToStringC() throws Throwable {
130         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
131         MethodHandle handle = cs.dynamicInvoker();
132         assertEquals((String)handle.invokeExact(new C(8, 9)),    "C[x=8, y=9]"   );
133         assertEquals((String)handle.invokeExact(new C(10, 11)),  "C[x=10, y=11]" );
134         assertEquals((String)handle.invokeExact(new C(100, -9)), "C[x=100, y=-9]");
135         assertEquals((String)handle.invokeExact(new C(0, 0)),    "C[x=0, y=0]"   );
136     }
137 
testToStringEmpty()138     public void testToStringEmpty() throws Throwable {
139         CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", Empty.TO_STRING_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
140         MethodHandle handle = cs.dynamicInvoker();
141         assertEquals((String)handle.invokeExact(new Empty()),    "Empty[]");
142     }
143 
144     Class<NullPointerException> NPE = NullPointerException.class;
145     Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
146 
exceptions()147     public void exceptions()  {
148         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "badName",  C.EQUALS_DESC,    C.class,         C.NAME_LIST, C.ACCESSORS));
149         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class,         "x;y;z",     C.ACCESSORS));
150         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class,         "x;y",       new MethodHandle[]{}));
151         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, this.getClass(), "x;y",       C.ACCESSORS));
152 
153         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.EQUALS_DESC,    C.class, "x;y", C.ACCESSORS));
154         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "hashCode", C.TO_STRING_DESC, C.class, "x;y", C.ACCESSORS));
155         assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "equals",   C.HASHCODE_DESC,  C.class, "x;y", C.ACCESSORS));
156 
157         record NamePlusType(String mn, MethodType mt) {}
158         List<NamePlusType> namePlusTypeList = List.of(
159                 new NamePlusType("toString", C.TO_STRING_DESC),
160                 new NamePlusType("equals", C.EQUALS_DESC),
161                 new NamePlusType("hashCode", C.HASHCODE_DESC)
162         );
163 
164         for (NamePlusType npt : namePlusTypeList) {
165             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), npt.mt(), C.class, "x;y", null));
166             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), npt.mt(), C.class, "x;y", new MethodHandle[]{null}));
167             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), npt.mt(), C.class, null,  C.ACCESSORS));
168             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), npt.mt(), null,    "x;y", C.ACCESSORS));
169             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), null,     C.class, "x;y", C.ACCESSORS));
170             assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, null,     npt.mt(), C.class, "x;y", C.ACCESSORS));
171             assertThrows(NPE, () -> ObjectMethods.bootstrap(null, npt.mn(),     npt.mt(), C.class, "x;y", C.ACCESSORS));
172         }
173     }
174 
175     // Based on the ObjectMethods internal implementation
hashCombiner(int x, int y)176     private static int hashCombiner(int x, int y) {
177         return x*31 + y;
178     }
179 }
180