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