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  */
  40 
  41 public class ObjectMethods {
  42 
  43     public static void main(String[] args) {
  44         testObjectMethods((args.length > 0 && args[0].equals("noverify")));
  45     }
  46 
  47     public static void testObjectMethods(boolean verifierDisabled) {
  48         MyInt val = MyInt.create(7);
  49         MyInt sameVal = MyInt.create(7);
  50 
  51         // Exercise all the Object native/VM methods...
  52 
  53         if (verifierDisabled) { // Just noverifier...
  54             checkMonitorExit(val);
  55             return;
  56         }
  57 
  58         // getClass()
  59         checkGetClass(val, MyInt.class);
  60 
  61         //hashCode()/identityHashCode()
  62         checkHashCodes(val, sameVal.hashCode());
  63 
  64         // clone()
  65         checkNotCloneable(val);
  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         if (val.hashCode() != expectedHashCode) {
  90             throw new RuntimeException("Hash code mismatch value: " + val.hashCode() +
  91                                        " expected: " + expectedHashCode);
  92         }
  93     }
  94 
  95     static void checkNotCloneable(MyInt val) {
  96         boolean sawCnse = false;
  97         try {
  98             val.attemptClone();
  99         } catch (CloneNotSupportedException cnse) {
 100             sawCnse = true;
 101         }
 102         if (!sawCnse) {
 103             throw new RuntimeException("clone() did not fail");
 104         }
 105         // Cloneable value type checked by "BadValueTypes" CFP tests
 106     }
 107 
 108     static void checkSynchronized(Object val) {
 109         boolean sawImse = false;
 110         try {
 111             synchronized (val) {
 112                 throw new IllegalStateException("Unreachable code, reached");
 113             }
 114         } catch (IllegalMonitorStateException imse) {
 115             sawImse = true;
 116         }
 117         if (!sawImse) {
 118             throw new RuntimeException("monitorenter did not fail");
 119         }
 120         // synchronized method modifiers tested by "BadValueTypes" CFP tests
 121         // jni monitor ops tested by "ValueWithJni"
 122     }
 123 
 124     // Check we haven't broken the mismatched monitor block check...
 125     static void checkMonitorExit(Object val) {
 126         boolean sawImse = false;
 127         try {
 128             MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 129                                          "mismatchedMonitorExit",
 130                                          MethodType.methodType(Void.TYPE, Object.class),
 131                                          CODE->{
 132                                              CODE
 133                                                  .aload(0)
 134                                                  .monitorexit()
 135                                                  .return_();
 136                                          }).invokeExact(val);
 137             throw new IllegalStateException("Unreachable code, reached");
 138         } catch (Throwable t) {
 139             if (t instanceof IllegalMonitorStateException) {
 140                 sawImse = true;
 141             }
 142             else {
 143                 throw new RuntimeException(t);
 144             }
 145         }
 146         if (!sawImse) {
 147             throw new RuntimeException("monitorexit did not fail");
 148         }
 149     }
 150 
 151     static void checkWait(Object val) {
 152         boolean sawImse = false;
 153         try {
 154             val.wait();
 155         } catch (IllegalMonitorStateException imse) {
 156             sawImse = true;
 157         } catch (InterruptedException intExc) {
 158             throw new RuntimeException(intExc);
 159         }
 160         if (!sawImse) {
 161             throw new RuntimeException("wait() did not fail");
 162         }
 163 
 164         sawImse = false;
 165         try {
 166             val.wait(1l);
 167         } catch (IllegalMonitorStateException imse) {
 168             sawImse = true;
 169         } catch (InterruptedException intExc) {
 170             throw new RuntimeException(intExc);
 171         }
 172         if (!sawImse) {
 173             throw new RuntimeException("wait() did not fail");
 174         }
 175 
 176         sawImse = false;
 177         try {
 178             val.wait(0l, 100);
 179         } catch (IllegalMonitorStateException imse) {
 180             sawImse = true;
 181         } catch (InterruptedException intExc) {
 182             throw new RuntimeException(intExc);
 183         }
 184         if (!sawImse) {
 185             throw new RuntimeException("wait() did not fail");
 186         }
 187     }
 188 
 189     static void checkNotify(Object val) {
 190         boolean sawImse = false;
 191         try {
 192             val.notify();
 193         } catch (IllegalMonitorStateException imse) {
 194             sawImse = true;
 195         }
 196         if (!sawImse) {
 197             throw new RuntimeException("notify() did not fail");
 198         }
 199 
 200         sawImse = false;
 201         try {
 202             val.notifyAll();
 203         } catch (IllegalMonitorStateException imse) {
 204             sawImse = true;
 205         }
 206         if (!sawImse) {
 207             throw new RuntimeException("notifyAll() did not fail");
 208         }
 209     }
 210 
 211     static final __ByValue class MyInt {
 212         final int value;
 213         private MyInt() { value = 0; }
 214         public static MyInt create(int v) {
 215             MyInt mi = __MakeDefault MyInt();
 216             mi = __WithField(mi.value, v);
 217             return mi;
 218         }
 219         public Object attemptClone() throws CloneNotSupportedException {
 220             try { // Check it is not possible to clone...
 221                 MethodHandles.Lookup lookup = MethodHandles.lookup();
 222                 MethodHandle mh = lookup.findVirtual(getClass(),
 223                                                      "clone",
 224                                                      MethodType.methodType(Object.class));
 225                 return mh.invokeExact(this);
 226             } catch (Throwable t) {
 227                 if (t instanceof CloneNotSupportedException) {
 228                     throw (CloneNotSupportedException) t;
 229                 }
 230                 throw new RuntimeException(t);
 231             }
 232         }
 233     }
 234 
 235 }