1 /*
   2  * Copyright (c) 2013, 2014, 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 jdk.internal.jvmci.runtime.test;
  24 
  25 import static java.lang.reflect.Modifier.*;
  26 
  27 import java.io.*;
  28 import java.lang.reflect.*;
  29 import java.util.*;
  30 import java.util.Queue;
  31 import java.util.stream.*;
  32 
  33 import jdk.internal.jvmci.meta.*;
  34 import jdk.internal.jvmci.runtime.*;
  35 
  36 import org.junit.*;
  37 
  38 import sun.misc.*;
  39 
  40 //JaCoCo Exclude
  41 
  42 /**
  43  * Context for type related tests.
  44  */
  45 public class TypeUniverse {
  46 
  47     public static final Unsafe unsafe;
  48     public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version"));
  49 
  50     public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
  51     public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection();
  52     public static final Collection<Class<?>> classes = new HashSet<>();
  53     public static final Set<ResolvedJavaType> javaTypes;
  54     public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
  55 
  56     private static List<ConstantValue> constants;
  57 
  58     public class InnerClass {
  59 
  60     }
  61 
  62     public static class InnerStaticClass {
  63 
  64     }
  65 
  66     public static final class InnerStaticFinalClass {
  67 
  68     }
  69 
  70     private class PrivateInnerClass {
  71 
  72     }
  73 
  74     protected class ProtectedInnerClass {
  75 
  76     }
  77 
  78     static {
  79         Unsafe theUnsafe = null;
  80         try {
  81             theUnsafe = Unsafe.getUnsafe();
  82         } catch (Exception e) {
  83             try {
  84                 Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
  85                 theUnsafeField.setAccessible(true);
  86                 theUnsafe = (Unsafe) theUnsafeField.get(null);
  87             } catch (Exception e1) {
  88                 throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1);
  89             }
  90         }
  91         unsafe = theUnsafe;
  92 
  93         Class<?>[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, boolean[].class,
  94                         byte[].class, short[].class, char[].class, int[].class, float[].class, long[].class, double[].class, Object[].class, Class[].class, List[].class, boolean[][].class,
  95                         byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class,
  96                         ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class,
  97                         HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, TrustedInterface.class, InnerClass.class,
  98                         InnerStaticClass.class, InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class};
  99         for (Class<?> c : initialClasses) {
 100             addClass(c);
 101         }
 102 
 103         javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet()));
 104     }
 105 
 106     static class ConstantsUniverse {
 107         static final Object[] ARRAYS = classes.stream().map(c -> c != void.class && !c.isArray() ? Array.newInstance(c, 42) : null).filter(o -> o != null).collect(Collectors.toList()).toArray();
 108         static final Object CONST1 = new ArrayList<>();
 109         static final Object CONST2 = new ArrayList<>();
 110         static final Object CONST3 = new IdentityHashMap<>();
 111         static final Object CONST4 = new LinkedHashMap<>();
 112         static final Object CONST5 = new TreeMap<>();
 113         static final Object CONST6 = new ArrayDeque<>();
 114         static final Object CONST7 = new LinkedList<>();
 115         static final Object CONST8 = "a string";
 116         static final Object CONST9 = 42;
 117         static final Object CONST10 = String.class;
 118         static final Object CONST11 = String[].class;
 119     }
 120 
 121     public static List<ConstantValue> constants() {
 122         if (constants == null) {
 123             List<ConstantValue> res = readConstants(JavaConstant.class);
 124             res.addAll(readConstants(ConstantsUniverse.class));
 125             constants = res;
 126         }
 127         return constants;
 128     }
 129 
 130     public static class ConstantValue {
 131         public final String name;
 132         public final JavaConstant value;
 133         public final Object boxed;
 134 
 135         public ConstantValue(String name, JavaConstant value, Object boxed) {
 136             this.name = name;
 137             this.value = value;
 138             this.boxed = boxed;
 139         }
 140 
 141         @Override
 142         public String toString() {
 143             return name + "=" + value;
 144         }
 145 
 146         public String getSimpleName() {
 147             return name.substring(name.lastIndexOf('.') + 1);
 148         }
 149     }
 150 
 151     /**
 152      * Reads the value of all {@code static final} fields from a given class into an array of
 153      * {@link ConstantValue}s.
 154      */
 155     public static List<ConstantValue> readConstants(Class<?> fromClass) {
 156         try {
 157             List<ConstantValue> res = new ArrayList<>();
 158             for (Field field : fromClass.getDeclaredFields()) {
 159                 if (isStatic(field.getModifiers()) && isFinal(field.getModifiers())) {
 160                     JavaField javaField = metaAccess.lookupJavaField(field);
 161                     Object boxed = field.get(null);
 162                     if (boxed instanceof JavaConstant) {
 163                         res.add(new ConstantValue(javaField.format("%H.%n"), (JavaConstant) boxed, boxed));
 164                     } else {
 165                         JavaConstant value = constantReflection.readConstantFieldValue(javaField, null);
 166                         if (value != null) {
 167                             res.add(new ConstantValue(javaField.format("%H.%n"), value, boxed));
 168                             if (boxed instanceof Object[]) {
 169                                 Object[] arr = (Object[]) boxed;
 170                                 for (int i = 0; i < arr.length; i++) {
 171                                     JavaConstant element = constantReflection.readArrayElement(value, i);
 172                                     if (element != null) {
 173                                         res.add(new ConstantValue(javaField.format("%H.%n[" + i + "]"), element, arr[i]));
 174                                     }
 175                                 }
 176                             }
 177                         }
 178                     }
 179                 }
 180             }
 181             return res;
 182         } catch (Exception e) {
 183             throw new AssertionError(e);
 184         }
 185     }
 186 
 187     public synchronized Class<?> getArrayClass(Class<?> componentType) {
 188         Class<?> arrayClass = arrayClasses.get(componentType);
 189         if (arrayClass == null) {
 190             arrayClass = Array.newInstance(componentType, 0).getClass();
 191             arrayClasses.put(componentType, arrayClass);
 192         }
 193         return arrayClass;
 194     }
 195 
 196     public static int dimensions(Class<?> c) {
 197         if (c.getComponentType() != null) {
 198             return 1 + dimensions(c.getComponentType());
 199         }
 200         return 0;
 201     }
 202 
 203     private static void addClass(Class<?> c) {
 204         if (classes.add(c)) {
 205             if (c.getSuperclass() != null) {
 206                 addClass(c.getSuperclass());
 207             }
 208             for (Class<?> sc : c.getInterfaces()) {
 209                 addClass(sc);
 210             }
 211             for (Class<?> dc : c.getDeclaredClasses()) {
 212                 addClass(dc);
 213             }
 214             for (Method m : c.getDeclaredMethods()) {
 215                 addClass(m.getReturnType());
 216                 for (Class<?> p : m.getParameterTypes()) {
 217                     addClass(p);
 218                 }
 219             }
 220 
 221             if (c != void.class && dimensions(c) < 2) {
 222                 Class<?> arrayClass = Array.newInstance(c, 0).getClass();
 223                 arrayClasses.put(c, arrayClass);
 224                 addClass(arrayClass);
 225             }
 226         }
 227     }
 228 }