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