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