1 /* 2 * Copyright (c) 2018, 2024, 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 package runtime.valhalla.inlinetypes; 24 25 import java.lang.invoke.*; 26 27 import test.java.lang.invoke.lib.InstructionHelper; 28 29 /* 30 * @test ObjectMethods 31 * @summary Check object methods implemented by the VM behave with value types 32 * @library /test/lib /test/jdk/java/lang/invoke/common 33 * @enablePreview 34 * @compile ObjectMethods.java 35 * @run main/othervm -XX:+UseCompressedClassPointers runtime.valhalla.inlinetypes.ObjectMethods 36 * @run main/othervm -XX:-UseCompressedClassPointers runtime.valhalla.inlinetypes.ObjectMethods 37 * @run main/othervm -noverify runtime.valhalla.inlinetypes.ObjectMethods noverify 38 */ 39 40 public class ObjectMethods { 41 42 public static void main(String[] args) { 43 testObjectMethods((args.length > 0 && args[0].equals("noverify"))); 44 } 45 46 public static void testObjectMethods(boolean verifierDisabled) { 47 MyInt val = new MyInt(7); 48 MyInt sameVal = new MyInt(7); 49 50 // Exercise all the Object native/VM methods... 51 52 if (verifierDisabled) { // Just noverifier... 53 checkMonitorExit(val); 54 return; 55 } 56 57 // getClass() 58 checkGetClass(val, MyInt.class); 59 60 //hashCode()/identityHashCode() 61 checkHashCodes(val, sameVal.hashCode()); 62 63 // clone() - test the default implementation from j.l.Object 64 checkNotCloneable(val); 65 checkCloneable(new MyCloneableInt(78)); 66 67 // synchronized 68 checkSynchronized(val); 69 70 // wait/notify() 71 checkWait(val); 72 checkNotify(val); 73 74 System.gc(); 75 } 76 77 78 static void checkGetClass(Object val, Class<?> expectedClass) { 79 Class<?> clazz = val.getClass(); 80 if (clazz == null) { 81 throw new RuntimeException("getClass return null"); 82 } else if (clazz != expectedClass) { 83 throw new RuntimeException("getClass (" + clazz + ") doesn't match " + expectedClass); 84 } 85 } 86 87 // Just check we don't crash the VM 88 static void checkHashCodes(Object val, int expectedHashCode) { 89 int hash = val.hashCode(); 90 if (hash != expectedHashCode) { 91 throw new RuntimeException("Hash code mismatch value: " + hash + 92 " expected: " + expectedHashCode); 93 } 94 hash = System.identityHashCode(val); 95 if (hash != expectedHashCode) { 96 throw new RuntimeException("Identity hash code mismatch value: " + hash + 97 " expected: " + expectedHashCode); 98 } 99 } 100 101 static void checkNotCloneable(MyInt val) { 102 boolean sawCnse = false; 103 try { 104 val.attemptClone(); 105 } catch (CloneNotSupportedException cnse) { 106 sawCnse = true; 107 } 108 if (!sawCnse) { 109 throw new RuntimeException("clone() did not fail"); 110 } 111 } 112 113 static void checkCloneable(MyCloneableInt val) { 114 boolean sawCnse = false; 115 MyCloneableInt val2 = null; 116 try { 117 val2 = (MyCloneableInt)val.attemptClone(); 118 } catch (CloneNotSupportedException cnse) { 119 sawCnse = true; 120 } 121 if (sawCnse) { 122 throw new RuntimeException("clone() did fail"); 123 } 124 if (val != val2) { 125 throw new RuntimeException("Cloned value is not identical to the original"); 126 } 127 } 128 129 static void checkSynchronized(Object val) { 130 boolean sawIe = false; 131 try { 132 synchronized (val) { 133 throw new IdentityException("Unreachable code, reached"); 134 } 135 } catch (IdentityException ie) { 136 sawIe = true; 137 } 138 if (!sawIe) { 139 throw new RuntimeException("monitorenter did not fail"); 140 } 141 // synchronized method modifiers tested by "BadInlineTypes" CFP tests 142 // jni monitor ops tested by "InlineWithJni" 143 } 144 145 // Check we haven't broken the mismatched monitor block check... 146 static void checkMonitorExit(Object val) { 147 boolean sawIe = false; 148 try { 149 InstructionHelper.buildMethodHandle(MethodHandles.lookup(), 150 "mismatchedMonitorExit", 151 MethodType.methodType(Void.TYPE, Object.class), 152 CODE-> { 153 CODE 154 .aload(0) 155 .monitorexit(); 156 CODE.return_(); 157 }).invokeExact(val); 158 throw new IllegalStateException("Unreachable code, reached"); 159 } catch (Throwable t) { 160 if (t instanceof IllegalMonitorStateException) { 161 sawIe = true; 162 } else { 163 throw new RuntimeException(t); 164 } 165 } 166 if (!sawIe) { 167 throw new RuntimeException("monitorexit did not fail"); 168 } 169 } 170 171 static void checkWait(Object val) { 172 boolean sawImse = false; 173 try { 174 val.wait(); 175 } catch (IllegalMonitorStateException imse) { 176 sawImse = true; 177 } catch (InterruptedException intExc) { 178 throw new RuntimeException(intExc); 179 } 180 if (!sawImse) { 181 throw new RuntimeException("wait() did not fail"); 182 } 183 184 sawImse = false; 185 try { 186 val.wait(1l); 187 } catch (IllegalMonitorStateException imse) { 188 sawImse = true; 189 } catch (InterruptedException intExc) { 190 throw new RuntimeException(intExc); 191 } 192 if (!sawImse) { 193 throw new RuntimeException("wait() did not fail"); 194 } 195 196 sawImse = false; 197 try { 198 val.wait(0l, 100); 199 } catch (IllegalMonitorStateException imse) { 200 sawImse = true; 201 } catch (InterruptedException intExc) { 202 throw new RuntimeException(intExc); 203 } 204 if (!sawImse) { 205 throw new RuntimeException("wait() did not fail"); 206 } 207 } 208 209 static void checkNotify(Object val) { 210 boolean sawImse = false; 211 try { 212 val.notify(); 213 } catch (IllegalMonitorStateException imse) { 214 sawImse = true; 215 } 216 if (!sawImse) { 217 throw new RuntimeException("notify() did not fail"); 218 } 219 220 sawImse = false; 221 try { 222 val.notifyAll(); 223 } catch (IllegalMonitorStateException imse) { 224 sawImse = true; 225 } 226 if (!sawImse) { 227 throw new RuntimeException("notifyAll() did not fail"); 228 } 229 } 230 231 static value class MyInt { 232 int value; 233 public MyInt(int v) { value = v; } 234 public Object attemptClone() throws CloneNotSupportedException { 235 try { // Check it is not possible to clone... 236 MethodHandles.Lookup lookup = MethodHandles.lookup(); 237 MethodHandle mh = lookup.findVirtual(getClass(), 238 "clone", 239 MethodType.methodType(Object.class)); 240 return mh.invokeExact(this); 241 } catch (Throwable t) { 242 if (t instanceof CloneNotSupportedException) { 243 throw (CloneNotSupportedException) t; 244 } 245 throw new RuntimeException(t); 246 } 247 } 248 } 249 250 static value class MyCloneableInt implements Cloneable { 251 int value; 252 public MyCloneableInt(int v) { value = v; } 253 public Object attemptClone() throws CloneNotSupportedException { 254 try { // Check it is not possible to clone... 255 MethodHandles.Lookup lookup = MethodHandles.lookup(); 256 MethodHandle mh = lookup.findVirtual(getClass(), 257 "clone", 258 MethodType.methodType(Object.class)); 259 return mh.invokeExact(this); 260 } catch (Throwable t) { 261 if (t instanceof CloneNotSupportedException) { 262 throw (CloneNotSupportedException) t; 263 } 264 throw new RuntimeException(t); 265 } 266 } 267 } 268 269 }