1 /*
   2  * Copyright (c) 2012, 2019, 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 
  24 
  25 package org.graalvm.compiler.hotspot.test;
  26 
  27 import java.lang.invoke.ConstantCallSite;
  28 import java.lang.invoke.MethodHandles;
  29 import java.lang.invoke.MethodType;
  30 
  31 import org.graalvm.compiler.api.directives.GraalDirectives;
  32 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  33 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  34 import org.graalvm.compiler.hotspot.HotSpotBackend;
  35 import org.graalvm.compiler.nodes.IfNode;
  36 import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
  37 import org.junit.Test;
  38 
  39 /**
  40  * Tests HotSpot specific {@link MethodSubstitution}s.
  41  */
  42 public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest {
  43 
  44     @Test
  45     public void testObjectSubstitutions() {
  46         TestClassA obj = new TestClassA();
  47 
  48         testGraph("getClass0");
  49         testGraph("objectHashCode");
  50 
  51         test("getClass0", "a string");
  52         test("objectHashCode", obj);
  53 
  54         testGraph("objectNotify", "Object.notify");
  55         testGraph("objectNotifyAll", "Object.notifyAll");
  56 
  57         synchronized (obj) {
  58             test("objectNotify", obj);
  59             test("objectNotifyAll", obj);
  60         }
  61         // Test with IllegalMonitorStateException (no synchronized block)
  62         test("objectNotify", obj);
  63         test("objectNotifyAll", obj);
  64     }
  65 
  66     @SuppressWarnings("all")
  67     public static Class<?> getClass0(Object obj) {
  68         return obj.getClass();
  69     }
  70 
  71     @SuppressWarnings("all")
  72     public static int objectHashCode(TestClassA obj) {
  73         return obj.hashCode();
  74     }
  75 
  76     @SuppressWarnings("all")
  77     public static void objectNotify(Object obj) {
  78         obj.notify();
  79     }
  80 
  81     @SuppressWarnings("all")
  82     public static void objectNotifyAll(Object obj) {
  83         obj.notifyAll();
  84     }
  85 
  86     @Test
  87     public void testClassSubstitutions() {
  88         testGraph("getModifiers");
  89         testGraph("isInterface");
  90         testGraph("isArray");
  91         testGraph("isPrimitive");
  92         testGraph("getSuperClass");
  93         testGraph("getComponentType");
  94 
  95         for (Class<?> c : new Class<?>[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
  96             test("getModifiers", c);
  97             test("isInterface", c);
  98             test("isArray", c);
  99             test("isPrimitive", c);
 100             test("getSuperClass", c);
 101             test("getComponentType", c);
 102         }
 103     }
 104 
 105     @SuppressWarnings("all")
 106     public static int getModifiers(Class<?> clazz) {
 107         return clazz.getModifiers();
 108     }
 109 
 110     @SuppressWarnings("all")
 111     public static boolean isInterface(Class<?> clazz) {
 112         return clazz.isInterface();
 113     }
 114 
 115     @SuppressWarnings("all")
 116     public static boolean isArray(Class<?> clazz) {
 117         return clazz.isArray();
 118     }
 119 
 120     @SuppressWarnings("all")
 121     public static boolean isPrimitive(Class<?> clazz) {
 122         return clazz.isPrimitive();
 123     }
 124 
 125     @SuppressWarnings("all")
 126     public static Class<?> getSuperClass(Class<?> clazz) {
 127         return clazz.getSuperclass();
 128     }
 129 
 130     @SuppressWarnings("all")
 131     public static Class<?> getComponentType(Class<?> clazz) {
 132         return clazz.getComponentType();
 133     }
 134 
 135     @Test
 136     public void testThreadSubstitutions() {
 137         GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig();
 138         testGraph("currentThread");
 139         if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) {
 140             assertInGraph(testGraph("threadIsInterrupted", "isInterrupted", true), IfNode.class);
 141             assertInGraph(testGraph("threadInterrupted", "isInterrupted", true), IfNode.class);
 142         }
 143 
 144         Thread currentThread = Thread.currentThread();
 145         test("currentThread", currentThread);
 146         if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) {
 147             test("threadIsInterrupted", currentThread);
 148         }
 149     }
 150 
 151     @SuppressWarnings("all")
 152     public static boolean currentThread(Thread other) {
 153         return Thread.currentThread() == other;
 154     }
 155 
 156     @SuppressWarnings("all")
 157     public static boolean threadIsInterrupted(Thread thread) {
 158         return thread.isInterrupted();
 159     }
 160 
 161     @SuppressWarnings("all")
 162     public static boolean threadInterrupted() {
 163         return Thread.interrupted();
 164     }
 165 
 166     @Test
 167     public void testSystemSubstitutions() {
 168         testGraph("systemTime");
 169         testGraph("systemIdentityHashCode");
 170 
 171         for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
 172             test("systemIdentityHashCode", o);
 173         }
 174     }
 175 
 176     @SuppressWarnings("all")
 177     public static long systemTime() {
 178         return System.currentTimeMillis() + System.nanoTime();
 179     }
 180 
 181     @SuppressWarnings("all")
 182     public static int systemIdentityHashCode(Object obj) {
 183         return System.identityHashCode(obj);
 184     }
 185 
 186     private static class TestClassA {
 187     }
 188 
 189     public static String testCallSiteGetTargetSnippet(int i) throws Exception {
 190         ConstantCallSite site;
 191         MethodHandles.Lookup lookup = MethodHandles.lookup();
 192         switch (i) {
 193             case 1:
 194                 site = GraalDirectives.opaque(new ConstantCallSite(lookup.findVirtual(String.class, "replace", MethodType.methodType(String.class, char.class, char.class))));
 195                 break;
 196             default:
 197                 site = GraalDirectives.opaque(new ConstantCallSite(lookup.findStatic(java.util.Arrays.class, "asList", MethodType.methodType(java.util.List.class, Object[].class))));
 198         }
 199         return site.getTarget().toString();
 200     }
 201 
 202     public static String testCastSnippet(int i, Object obj) throws Exception {
 203         Class<?> c;
 204         switch (i) {
 205             case 1:
 206                 c = GraalDirectives.opaque(Number.class);
 207                 break;
 208             default:
 209                 c = GraalDirectives.opaque(Integer.class);
 210                 break;
 211         }
 212         return c.cast(obj).toString();
 213     }
 214 
 215     public static String testGetClassSnippet(int i) {
 216         Object c;
 217         switch (i) {
 218             case 1:
 219                 c = GraalDirectives.opaque(new Object());
 220                 break;
 221             default:
 222                 c = GraalDirectives.opaque("TEST");
 223                 break;
 224         }
 225         return c.getClass().toString();
 226     }
 227 
 228     /**
 229      * Tests ambiguous receiver of CallSite.getTarget.
 230      */
 231     @Test
 232     public void testCallSiteGetTarget() {
 233         test("testCallSiteGetTargetSnippet", 1);
 234     }
 235 
 236     /**
 237      * Tests ambiguous receiver of Class.cast.
 238      */
 239     @Test
 240     public void testCast() {
 241         test("testCastSnippet", 1, Integer.valueOf(1));
 242     }
 243 
 244     /**
 245      * Tests ambiguous receiver of Object.getClass.
 246      */
 247     @Test
 248     public void testGetClass() {
 249         test("testGetClassSnippet", 1);
 250     }
 251 }