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