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:+UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods
  37  * @run main/othervm -Xint -XX:+EnableValhalla -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 
  75 
  76     static void checkGetClass(Object val, Class<?> expectedClass) {
  77         Class<?> clazz = val.getClass();
  78         if (clazz == null) {
  79             throw new RuntimeException("getClass return null");
  80         } else if (clazz != expectedClass) {
  81             throw new RuntimeException("getClass (" + clazz + ") doesn't match " + expectedClass);
  82         }
  83     }
  84 
  85     // Just check we don't crash the VM
  86     static void checkHashCodes(Object val, int expectedHashCode) {
  87         if (val.hashCode() != expectedHashCode) {
  88             throw new RuntimeException("Hash code mismatch value: " + val.hashCode() +
  89                                        " expected: " + expectedHashCode);
  90         }
  91     }
  92 
  93     static void checkNotCloneable(MyInt val) {
  94         boolean sawCnse = false;
  95         try {
  96             val.attemptClone();
  97         } catch (CloneNotSupportedException cnse) {
  98             sawCnse = true;
  99         }
 100         if (!sawCnse) {
 101             throw new RuntimeException("clone() did not fail");
 102         }
 103         // Cloneable value type checked by "BadValueTypes" CFP tests
 104     }
 105 
 106     static void checkSynchronized(Object val) {
 107         boolean sawImse = false;
 108         try {
 109             synchronized (val) {
 110                 throw new IllegalStateException("Unreachable code, reached");
 111             }
 112         } catch (IllegalMonitorStateException imse) {
 113             sawImse = true;
 114         }
 115         if (!sawImse) {
 116             throw new RuntimeException("monitorenter did not fail");
 117         }
 118         // synchronized method modifiers tested by "BadValueTypes" CFP tests
 119         // jni monitor ops tested by "ValueWithJni"
 120     }
 121 
 122     // Check we haven't broken the mismatched monitor block check...
 123     static void checkMonitorExit(Object val) {
 124         boolean sawImse = false;
 125         try {
 126             MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 127                                          "mismatchedMonitorExit",
 128                                          MethodType.methodType(Void.TYPE, Object.class),
 129                                          CODE->{
 130                                              CODE
 131                                                  .aload(0)
 132                                                  .monitorexit()
 133                                                  .return_();
 134                                          }).invokeExact(val);
 135             throw new IllegalStateException("Unreachable code, reached");
 136         } catch (Throwable t) {
 137             if (t instanceof IllegalMonitorStateException) {
 138                 sawImse = true;
 139             }
 140             else {
 141                 throw new RuntimeException(t);
 142             }
 143         }
 144         if (!sawImse) {
 145             throw new RuntimeException("monitorexit did not fail");
 146         }
 147     }
 148 
 149     static void checkWait(Object val) {
 150         boolean sawImse = false;
 151         try {
 152             val.wait();
 153         } catch (IllegalMonitorStateException imse) {
 154             sawImse = true;
 155         } catch (InterruptedException intExc) {
 156             throw new RuntimeException(intExc);
 157         }
 158         if (!sawImse) {
 159             throw new RuntimeException("wait() did not fail");
 160         }
 161 
 162         sawImse = false;
 163         try {
 164             val.wait(1l);
 165         } catch (IllegalMonitorStateException imse) {
 166             sawImse = true;
 167         } catch (InterruptedException intExc) {
 168             throw new RuntimeException(intExc);
 169         }
 170         if (!sawImse) {
 171             throw new RuntimeException("wait() did not fail");
 172         }
 173 
 174         sawImse = false;
 175         try {
 176             val.wait(0l, 100);
 177         } catch (IllegalMonitorStateException imse) {
 178             sawImse = true;
 179         } catch (InterruptedException intExc) {
 180             throw new RuntimeException(intExc);
 181         }
 182         if (!sawImse) {
 183             throw new RuntimeException("wait() did not fail");
 184         }
 185     }
 186 
 187     static void checkNotify(Object val) {
 188         boolean sawImse = false;
 189         try {
 190             val.notify();
 191         } catch (IllegalMonitorStateException imse) {
 192             sawImse = true;
 193         }
 194         if (!sawImse) {
 195             throw new RuntimeException("notify() did not fail");
 196         }
 197 
 198         sawImse = false;
 199         try {
 200             val.notifyAll();
 201         } catch (IllegalMonitorStateException imse) {
 202             sawImse = true;
 203         }
 204         if (!sawImse) {
 205             throw new RuntimeException("notifyAll() did not fail");
 206         }
 207     }
 208 
 209     static final __ByValue class MyInt {
 210         final int value;
 211         private MyInt() { value = 0; }
 212         public static MyInt create(int v) {
 213             MyInt mi = __MakeDefault MyInt();
 214             mi = __WithField(mi.value, v);
 215             return mi;
 216         }
 217         public Object attemptClone() throws CloneNotSupportedException {
 218             try { // Check it is not possible to clone...
 219                 MethodHandles.Lookup lookup = MethodHandles.lookup();
 220                 MethodHandle mh = lookup.findVirtual(getClass(),
 221                                                      "clone",
 222                                                      MethodType.methodType(Object.class));
 223                 return mh.invokeExact(this);
 224             } catch (Throwable t) {
 225                 if (t instanceof CloneNotSupportedException) {
 226                     throw (CloneNotSupportedException) t;
 227                 }
 228                 throw new RuntimeException(t);
 229             }
 230         }
 231     }
 232 
 233 }