CompileCodeTestCase.java revision 11707:ad7af1afda7a
1/*
2 * Copyright (c) 2015, 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 */
24
25package compiler.jvmci.compilerToVM;
26
27import compiler.jvmci.common.CTVMUtilities;
28import compiler.testlibrary.CompilerUtils;
29import jdk.test.lib.Pair;
30import jdk.test.lib.Utils;
31import jdk.vm.ci.code.InstalledCode;
32import sun.hotspot.WhiteBox;
33import sun.hotspot.code.NMethod;
34
35import java.lang.reflect.Constructor;
36import java.lang.reflect.Executable;
37import java.lang.reflect.InvocationTargetException;
38import java.lang.reflect.Method;
39import java.lang.reflect.Modifier;
40import java.util.ArrayList;
41import java.util.Arrays;
42import java.util.Collections;
43import java.util.HashMap;
44import java.util.List;
45import java.util.Map;
46
47/**
48 * A test case for tests which require compiled code.
49 */
50public class CompileCodeTestCase {
51    private static final WhiteBox WB = WhiteBox.getWhiteBox();
52    private static final int COMP_LEVEL;
53    static {
54        int[] levels = CompilerUtils.getAvailableCompilationLevels();
55        if (levels.length == 0) {
56            throw new Error("TESTBUG: no compilers available");
57        }
58        COMP_LEVEL = levels[levels.length - 1];
59    }
60    private static final Class<?>[] CLASSES = {
61            Interface.class,
62            Dummy.class,
63            DummyEx.class};
64    private static final Map<Class<?>, Object> RECEIVERS;
65
66    public final Object receiver;
67    public final Executable executable;
68    public final int bci;
69    private final boolean isOsr;
70
71    public CompileCodeTestCase(Object receiver, Executable executable,
72            int bci) {
73        this.receiver = receiver;
74        this.executable = executable;
75        this.bci = bci;
76        isOsr = (bci >= 0);
77    }
78
79    public NMethod compile() {
80        return compile(COMP_LEVEL);
81    }
82
83    public Pair<Object, ? extends Throwable> invoke(Object[] args) {
84        boolean old = executable.isAccessible();
85        executable.setAccessible(true);
86        try {
87            try {
88                if (executable instanceof Method) {
89                    Method m = (Method) executable;
90                    return new Pair<>(m.invoke(receiver, args), null);
91                }
92
93                if (executable instanceof Constructor) {
94                    Constructor c = (Constructor) executable;
95                    return new Pair<>(c.newInstance(args), null);
96                }
97            } catch (InvocationTargetException e) {
98                return new Pair<>(null, e.getCause());
99            } catch (Throwable e) {
100                return new Pair<>(null, e);
101            }
102        } finally {
103            executable.setAccessible(old);
104        }
105        throw new Error(executable + " has unsupported type "
106                + executable.getClass());
107    }
108
109    public NMethod compile(int level) {
110        boolean enqueued = WB.enqueueMethodForCompilation(executable,
111                level, bci);
112        if (!enqueued) {
113            throw new Error(String.format(
114                    "%s can't be enqueued for %scompilation on level %d",
115                    executable, bci >= 0 ? "osr-" : "", level));
116        }
117        Utils.waitForCondition(() -> WB.isMethodCompiled(executable, isOsr));
118        return NMethod.get(executable, isOsr);
119    }
120
121    public static List<CompileCodeTestCase> generate(int bci) {
122        ArrayList<CompileCodeTestCase> result = new ArrayList<>();
123        for (Class<?> aClass : CLASSES) {
124            Object receiver = RECEIVERS.get(aClass);
125            if (receiver == null) {
126                throw new Error("TESTBUG : no receiver for class " + aClass);
127            }
128            for (Executable m : aClass.getDeclaredConstructors()) {
129                result.add(new CompileCodeTestCase(receiver, m, bci));
130            }
131            Arrays.stream(aClass.getDeclaredMethods())
132                    .filter(m -> !Modifier.isAbstract(m.getModifiers()))
133                    .filter(m -> !Modifier.isNative(m.getModifiers()))
134                    .map(m -> new CompileCodeTestCase(receiver, m, bci))
135                    .forEach(result::add);
136        }
137        return result;
138    }
139
140    public NMethod toNMethod() {
141        return NMethod.get(executable, isOsr);
142    }
143
144    public InstalledCode toInstalledCode() {
145        NMethod nmethod = toNMethod();
146        long address = nmethod == null ? 0L : nmethod.address;
147        long entryPoint = nmethod == null ? 0L : nmethod.entry_point;
148        return CTVMUtilities.getInstalledCode(
149                executable.getName(), address, entryPoint);
150    }
151
152    @Override
153    public String toString() {
154        return "CompileCodeTestCase{" +
155                "executable=" + executable +
156                ", bci=" + bci +
157                '}';
158    }
159
160    public void deoptimize() {
161        WB.deoptimizeMethod(executable, isOsr);
162    }
163
164    public NMethod deoptimizeAndCompile() {
165        deoptimize();
166        return compile();
167    }
168
169    // classes which are used as "input" data in test cases
170    private static interface Interface {
171        Interface interfaceMethod();
172        default Long defaultOverriddenMethod(Interface[] array) {
173            return array == null ? 0L : array.length;
174        }
175        default int defaultMethod(Object o) {
176            return o != null ? o.hashCode() : 0;
177        }
178    }
179
180    private static abstract class Dummy implements Interface {
181        protected Dummy() {
182        }
183
184        private static void staticMethod() {
185        }
186
187        Dummy instanceMethod(int i) {
188            return null;
189        }
190
191        abstract Object abstractMethod(double d);
192
193        @Override
194        public Long defaultOverriddenMethod(Interface[] array) {
195            return 0L;
196        }
197    }
198
199    public static class DummyEx extends Dummy {
200        @Override
201        public boolean equals(Object o) {
202            if (this == o) {
203                return true;
204            }
205            if (o == null || getClass() != o.getClass()) {
206                return false;
207            }
208            return true;
209        }
210
211        @Override
212        public int hashCode() {
213            return 0;
214        }
215
216        public DummyEx() {
217        }
218
219        protected Dummy instanceMethod(int i) {
220            if (i == 0) {
221                return this;
222            }
223            return null;
224        }
225
226        @Override
227        Object abstractMethod(double d) {
228            return this;
229        }
230
231        @Override
232        public Interface interfaceMethod() {
233            return null;
234        }
235    }
236
237    static {
238        Map<Class<?>, Object> map = new HashMap<>();;
239        map.put(CompileCodeTestCase.DummyEx.class,
240                new CompileCodeTestCase.DummyEx());
241        map.put(CompileCodeTestCase.Dummy.class,
242                new CompileCodeTestCase.Dummy() {
243                    @Override
244                    public CompileCodeTestCase.Interface interfaceMethod() {
245                        throw new AbstractMethodError();
246                    }
247
248                    @Override
249                    Object abstractMethod(double d) {
250                        throw new AbstractMethodError();
251                    }
252                });
253        map.put(CompileCodeTestCase.Interface.class,
254                new CompileCodeTestCase.Interface() {
255                    @Override
256                    public CompileCodeTestCase.Interface interfaceMethod() {
257                        throw new AbstractMethodError();
258                    }
259                });
260        RECEIVERS = Collections.unmodifiableMap(map);
261    }
262
263}
264