1 package compiler.jvmci.compilerToVM;
   2 
   3 import jdk.vm.ci.code.InstalledCode;
   4 import jdk.vm.ci.code.InvalidInstalledCodeException;
   5 import jdk.vm.ci.hotspot.CompilerToVMHelper;
   6 import jdk.test.lib.Asserts;
   7 import jdk.test.lib.Pair;
   8 import sun.hotspot.code.NMethod;
   9 
  10 import java.lang.reflect.Constructor;
  11 import java.lang.reflect.Executable;
  12 import java.lang.reflect.InvocationTargetException;
  13 import java.lang.reflect.Method;
  14 import java.lang.reflect.Modifier;
  15 import java.util.ArrayList;
  16 import java.util.HashMap;
  17 import java.util.List;
  18 import java.util.Map;
  19 
  20 /*
  21  * @test
  22  * @bug 8136421
  23  * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
  24  * @library /testlibrary /../../test/lib /
  25  * @compile ../common/CompilerToVMHelper.java
  26  * @build sun.hotspot.WhiteBox
  27  *        compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest
  28  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  29  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  30  *                              jdk.vm.ci.hotspot.CompilerToVMHelper
  31  * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
  32  *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  33  *      compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest
  34  */
  35 
  36 public class ExecuteInstalledCodeTest {
  37 
  38 
  39     public static void main(String[] args) {
  40         ExecuteInstalledCodeTest test = new ExecuteInstalledCodeTest();
  41         List<CompileCodeTestCase> testCases = new ArrayList<>();
  42         testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1));
  43         testCases .stream()
  44                 // ignore <init> of abstract class -- 8138793
  45                 .filter(e -> !(e.executable instanceof Constructor
  46                         && Modifier.isAbstract(
  47                                 e.executable.getDeclaringClass()
  48                                         .getModifiers())))
  49                 .forEach(test::checkSanity);
  50     }
  51 
  52     private void checkSanity(CompileCodeTestCase testCase) {
  53         System.out.println(testCase);
  54         // to have a clean state
  55         testCase.deoptimize();
  56         Pair<Object, ? extends Throwable> reflectionResult;
  57         Object[] args = getArguments(testCase.executable);
  58         reflectionResult = invoke(testCase, args);
  59         NMethod nMethod = testCase.compile();
  60         if (nMethod == null) {
  61             throw new Error(testCase + " : nmethod is null");
  62         }
  63         InstalledCode installedCode = new InstalledCode(
  64                 testCase.executable.getName());
  65         installedCode.setAddress(nMethod.address);
  66         Object result = null;
  67         Throwable expectedException = reflectionResult.second;
  68         boolean gotException = true;
  69         try {
  70             args = addReceiver(testCase, args);
  71             result = CompilerToVMHelper.executeInstalledCode(
  72                     args, installedCode);
  73             if (testCase.executable instanceof Constructor) {
  74                 // <init> doesn't have return value, it changes receiver
  75                 result = args[0];
  76             }
  77             gotException = false;
  78         } catch (InvalidInstalledCodeException e) {
  79             throw new AssertionError(
  80                     testCase + " : unexpected InvalidInstalledCodeException", e);
  81         } catch (Throwable t) {
  82             if (expectedException == null) {
  83                 throw new AssertionError(testCase
  84                         + " : got unexpected execption : " + t.getMessage(), t);
  85             }
  86 
  87             if (expectedException.getClass() != t.getClass()) {
  88                 System.err.println("exception from CompilerToVM:");
  89                 t.printStackTrace();
  90                 System.err.println("exception from reflection:");
  91                 expectedException.printStackTrace();
  92                 throw new AssertionError(String.format(
  93                         "%s : got unexpected different exceptions : %s != %s",
  94                         testCase, expectedException.getClass(), t.getClass()));
  95             }
  96         }
  97 
  98         Asserts.assertEQ(reflectionResult.first, result, testCase
  99                 + " : different return value");
 100         if (!gotException) {
 101             Asserts.assertNull(expectedException, testCase
 102                     + " : expected exception hasn't been thrown");
 103         }
 104     }
 105 
 106     private Object[] addReceiver(CompileCodeTestCase testCase, Object[] args) {
 107         if (!Modifier.isStatic(testCase.executable.getModifiers())) {
 108             // add instance as 0th arg
 109             Object[] newArgs = new Object[args.length + 1];
 110             newArgs[0] = getReciever(testCase);
 111             System.arraycopy(args, 0, newArgs, 1, args.length);
 112             args = newArgs;
 113         }
 114         return args;
 115     }
 116 
 117     private Object getReciever(CompileCodeTestCase testCase) {
 118         return CompileCodeTestCase.RECEIVERS.get(
 119                 testCase.executable.getDeclaringClass());
 120     }
 121 
 122     public Pair<Object, ? extends Throwable> invoke(
 123             CompileCodeTestCase testCase, Object[] args) {
 124         Executable executable = testCase.executable;
 125         boolean old = executable.isAccessible();
 126         executable.setAccessible(true);
 127         try {
 128             try {
 129                 if (executable instanceof Method) {
 130                     Method m = (Method) executable;
 131                     return new Pair<>(m.invoke(getReciever(testCase), args), null);
 132                 }
 133 
 134                 if (executable instanceof Constructor) {
 135                     Constructor c = (Constructor) executable;
 136                     return new Pair<>(c.newInstance(args), null);
 137                 }
 138             } catch (InvocationTargetException e) {
 139                 return new Pair<>(null, e.getCause());
 140             } catch (Throwable e) {
 141                 return new Pair<>(null, e);
 142             }
 143         } finally {
 144             executable.setAccessible(old);
 145         }
 146         throw new Error(executable + " has unsupported type "
 147                 + executable.getClass());
 148     }
 149 
 150     private Object[] getArguments(Executable method) {
 151         Class<?>[] params = method.getParameterTypes();
 152         Object[] result = new Object[params.length];
 153         int i = 0;
 154         for (Class<?> aClass : params) {
 155             result[i++] = getArgument(aClass);
 156         }
 157         return result;
 158     }
 159     private static Map<Class<?>, Object> DEFAULT_VALUES = new HashMap<>();
 160     static {
 161         DEFAULT_VALUES.put(boolean.class, false);
 162         DEFAULT_VALUES.put(byte.class, (byte) 0);
 163         DEFAULT_VALUES.put(short.class, (short) 0);
 164         DEFAULT_VALUES.put(char.class, '\0');
 165         DEFAULT_VALUES.put(int.class, 0);
 166         DEFAULT_VALUES.put(long.class, 0L);
 167         DEFAULT_VALUES.put(float.class, 0.0f);
 168         DEFAULT_VALUES.put(double.class, 0.0d);
 169     }
 170     private Object getArgument(Class<?> aClass) {
 171         if (aClass.isPrimitive()) {
 172             return DEFAULT_VALUES.get(aClass);
 173         }
 174         return null;
 175     }
 176 }