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