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