--- /dev/null 2018-04-25 09:38:36.139592716 +0200 +++ new/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java 2018-05-07 15:52:13.116534101 +0200 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package runtime.valhalla.valuetypes; + +import java.lang.invoke.*; + +import jdk.experimental.value.MethodHandleBuilder; + +/* + * @test ObjectMethods + * @summary Check object method implemented by the VM behave with value types + * @modules java.base/jdk.experimental.bytecode + * java.base/jdk.experimental.value + * @library /test/lib + * @compile -XDenableValueTypes ObjectMethods.java + * @run main/othervm -Xint -XX:+EnableValhalla -XX:+UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods + * @run main/othervm -Xint -XX:+EnableValhalla -XX:-UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods + * @run main/othervm -Xint -XX:+EnableValhalla -noverify runtime.valhalla.valuetypes.ObjectMethods noverify + */ + +public class ObjectMethods { + + public static void main(String[] args) { + testObjectMethods((args.length > 0 && args[0].equals("noverify"))); + } + + public static void testObjectMethods(boolean verifierDisabled) { + MyInt val = MyInt.create(7); + MyInt sameVal = MyInt.create(7); + + // Exercise all the Object native/VM methods... + + if (verifierDisabled) { // Just noverifier... + checkMonitorExit(val); + return; + } + + // getClass() + checkGetClass(val, MyInt.class); + + //hashCode()/identityHashCode() + checkHashCodes(val, sameVal.hashCode()); + + // clone() + checkNotCloneable(val); + + // synchronized + checkSynchronized(val); + + // wait/notify() + checkWait(val); + checkNotify(val); + } + + + static void checkGetClass(Object val, Class expectedClass) { + Class clazz = val.getClass(); + if (clazz == null) { + throw new RuntimeException("getClass return null"); + } else if (clazz != expectedClass) { + throw new RuntimeException("getClass (" + clazz + ") doesn't match " + expectedClass); + } + } + + // Just check we don't crash the VM + static void checkHashCodes(Object val, int expectedHashCode) { + if (val.hashCode() != expectedHashCode) { + throw new RuntimeException("Hash code mismatch value: " + val.hashCode() + + " expected: " + expectedHashCode); + } + } + + static void checkNotCloneable(MyInt val) { + boolean sawCnse = false; + try { + val.attemptClone(); + } catch (CloneNotSupportedException cnse) { + sawCnse = true; + } + if (!sawCnse) { + throw new RuntimeException("clone() did not fail"); + } + // Cloneable value type checked by "BadValueTypes" CFP tests + } + + static void checkSynchronized(Object val) { + boolean sawImse = false; + try { + synchronized (val) { + throw new IllegalStateException("Unreachable code, reached"); + } + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } + if (!sawImse) { + throw new RuntimeException("monitorenter did not fail"); + } + // synchronized method modifiers tested by "BadValueTypes" CFP tests + // jni monitor ops tested by "ValueWithJni" + } + + // Check we haven't broken the mismatched monitor block check... + static void checkMonitorExit(Object val) { + boolean sawImse = false; + try { + MethodHandleBuilder.loadCode(MethodHandles.lookup(), + "mismatchedMonitorExit", + MethodType.methodType(Void.TYPE, Object.class), + CODE->{ + CODE + .aload(0) + .monitorexit() + .return_(); + }).invokeExact(val); + throw new IllegalStateException("Unreachable code, reached"); + } catch (Throwable t) { + if (t instanceof IllegalMonitorStateException) { + sawImse = true; + } + else { + throw new RuntimeException(t); + } + } + if (!sawImse) { + throw new RuntimeException("monitorexit did not fail"); + } + } + + static void checkWait(Object val) { + boolean sawImse = false; + try { + val.wait(); + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } catch (InterruptedException intExc) { + throw new RuntimeException(intExc); + } + if (!sawImse) { + throw new RuntimeException("wait() did not fail"); + } + + sawImse = false; + try { + val.wait(1l); + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } catch (InterruptedException intExc) { + throw new RuntimeException(intExc); + } + if (!sawImse) { + throw new RuntimeException("wait() did not fail"); + } + + sawImse = false; + try { + val.wait(0l, 100); + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } catch (InterruptedException intExc) { + throw new RuntimeException(intExc); + } + if (!sawImse) { + throw new RuntimeException("wait() did not fail"); + } + } + + static void checkNotify(Object val) { + boolean sawImse = false; + try { + val.notify(); + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } + if (!sawImse) { + throw new RuntimeException("notify() did not fail"); + } + + sawImse = false; + try { + val.notifyAll(); + } catch (IllegalMonitorStateException imse) { + sawImse = true; + } + if (!sawImse) { + throw new RuntimeException("notifyAll() did not fail"); + } + } + + static final __ByValue class MyInt { + final int value; + private MyInt() { value = 0; } + public static MyInt create(int v) { + MyInt mi = __MakeDefault MyInt(); + mi = __WithField(mi.value, v); + return mi; + } + public Object attemptClone() throws CloneNotSupportedException { + try { // Check it is not possible to clone... + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle mh = lookup.findVirtual(getClass(), + "clone", + MethodType.methodType(Object.class)); + return mh.invokeExact(this); + } catch (Throwable t) { + if (t instanceof CloneNotSupportedException) { + throw (CloneNotSupportedException) t; + } + throw new RuntimeException(t); + } + } + } + +}