001/*
002 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package jdk.internal.jvmci.runtime.test;
024
025import static java.lang.reflect.Modifier.*;
026
027import java.io.*;
028import java.lang.reflect.*;
029import java.util.*;
030import java.util.Queue;
031import java.util.stream.*;
032
033import jdk.internal.jvmci.meta.*;
034import jdk.internal.jvmci.runtime.*;
035
036import org.junit.*;
037
038import sun.misc.*;
039
040//JaCoCo Exclude
041
042/**
043 * Context for type related tests.
044 */
045public class TypeUniverse {
046
047    public static final Unsafe unsafe;
048    public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version"));
049
050    public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
051    public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection();
052    public static final Collection<Class<?>> classes = new HashSet<>();
053    public static final Set<ResolvedJavaType> javaTypes;
054    public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
055
056    private static List<ConstantValue> constants;
057
058    public class InnerClass {
059
060    }
061
062    public static class InnerStaticClass {
063
064    }
065
066    public static final class InnerStaticFinalClass {
067
068    }
069
070    private class PrivateInnerClass {
071
072    }
073
074    protected class ProtectedInnerClass {
075
076    }
077
078    static {
079        Unsafe theUnsafe = null;
080        try {
081            theUnsafe = Unsafe.getUnsafe();
082        } catch (Exception e) {
083            try {
084                Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
085                theUnsafeField.setAccessible(true);
086                theUnsafe = (Unsafe) theUnsafeField.get(null);
087            } catch (Exception e1) {
088                throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1);
089            }
090        }
091        unsafe = theUnsafe;
092
093        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,
094                        byte[].class, short[].class, char[].class, int[].class, float[].class, long[].class, double[].class, Object[].class, Class[].class, List[].class, boolean[][].class,
095                        byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class,
096                        ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class,
097                        HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, TrustedInterface.class, InnerClass.class,
098                        InnerStaticClass.class, InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class};
099        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}