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
24package compiler.whitebox;
25
26import sun.hotspot.WhiteBox;
27
28import java.lang.reflect.Constructor;
29import java.lang.reflect.Executable;
30import java.lang.reflect.Method;
31import java.util.concurrent.Callable;
32
33public enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase {
34    /** constructor test case */
35    CONSTRUCTOR_TEST(SimpleTestCaseHelper.CONSTRUCTOR, SimpleTestCaseHelper.CONSTRUCTOR_CALLABLE, false),
36    /** method test case */
37    METHOD_TEST(SimpleTestCaseHelper.METHOD, SimpleTestCaseHelper.METHOD_CALLABLE, false),
38    /** static method test case */
39    STATIC_TEST(SimpleTestCaseHelper.STATIC, SimpleTestCaseHelper.STATIC_CALLABLE, false),
40    /** OSR constructor test case */
41    OSR_CONSTRUCTOR_TEST(SimpleTestCaseHelper.OSR_CONSTRUCTOR, SimpleTestCaseHelper.OSR_CONSTRUCTOR_CALLABLE, true),
42    /** OSR method test case */
43    OSR_METHOD_TEST(SimpleTestCaseHelper.OSR_METHOD, SimpleTestCaseHelper.OSR_METHOD_CALLABLE, true),
44    /** OSR static method test case */
45    OSR_STATIC_TEST(SimpleTestCaseHelper.OSR_STATIC, SimpleTestCaseHelper.OSR_STATIC_CALLABLE, true);
46
47    private final Executable executable;
48    private final Callable<Integer> callable;
49    private final boolean isOsr;
50
51    private SimpleTestCase(Executable executable, Callable<Integer> callable,
52            boolean isOsr) {
53        this.executable = executable;
54        this.callable = callable;
55        this.isOsr = isOsr;
56    }
57
58    @Override
59    public Executable getExecutable() {
60        return executable;
61    }
62
63    @Override
64    public Callable<Integer> getCallable() {
65        return callable;
66    }
67
68    @Override
69    public boolean isOsr() {
70        return isOsr;
71    }
72}
73
74    class SimpleTestCaseHelper {
75
76        public static final Callable<Integer> CONSTRUCTOR_CALLABLE
77                = new Callable<Integer>() {
78            @Override
79            public Integer call() throws Exception {
80                return new SimpleTestCaseHelper(1337).hashCode();
81            }
82        };
83
84        public static final Callable<Integer> METHOD_CALLABLE
85                = new Callable<Integer>() {
86            private final SimpleTestCaseHelper helper = new SimpleTestCaseHelper();
87
88            @Override
89            public Integer call() throws Exception {
90                return helper.method();
91            }
92        };
93
94        public static final Callable<Integer> STATIC_CALLABLE
95                = new Callable<Integer>() {
96            @Override
97            public Integer call() throws Exception {
98                return staticMethod();
99            }
100        };
101
102        public static final Callable<Integer> OSR_CONSTRUCTOR_CALLABLE
103                = new Callable<Integer>() {
104            @Override
105            public Integer call() throws Exception {
106                return new SimpleTestCaseHelper(null, CompilerWhiteBoxTest.BACKEDGE_THRESHOLD).hashCode();
107            }
108        };
109
110        public static final Callable<Integer> OSR_METHOD_CALLABLE
111                = new Callable<Integer>() {
112            private final SimpleTestCaseHelper helper = new SimpleTestCaseHelper();
113
114            @Override
115            public Integer call() throws Exception {
116                return helper.osrMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD);
117            }
118        };
119
120        public static final Callable<Integer> OSR_STATIC_CALLABLE
121                = new Callable<Integer>() {
122            @Override
123            public Integer call() throws Exception {
124                return osrStaticMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD);
125            }
126        };
127
128        public static final Constructor CONSTRUCTOR;
129        public static final Constructor OSR_CONSTRUCTOR;
130        public static final Method METHOD;
131        public static final Method STATIC;
132        public static final Method OSR_METHOD;
133        public static final Method OSR_STATIC;
134
135        static {
136            try {
137                CONSTRUCTOR = SimpleTestCaseHelper.class.getDeclaredConstructor(int.class);
138            } catch (NoSuchMethodException | SecurityException e) {
139                throw new RuntimeException(
140                        "exception on getting method Helper.<init>(int)", e);
141            }
142            try {
143                OSR_CONSTRUCTOR = SimpleTestCaseHelper.class.getDeclaredConstructor(
144                        Object.class, long.class);
145            } catch (NoSuchMethodException | SecurityException e) {
146                throw new RuntimeException(
147                        "exception on getting method Helper.<init>(Object, long)", e);
148            }
149            METHOD = getMethod("method");
150            STATIC = getMethod("staticMethod");
151            OSR_METHOD = getMethod("osrMethod", long.class);
152            OSR_STATIC = getMethod("osrStaticMethod", long.class);
153        }
154
155        private static Method getMethod(String name, Class<?>... parameterTypes) {
156            try {
157                return SimpleTestCaseHelper.class.getDeclaredMethod(name, parameterTypes);
158            } catch (NoSuchMethodException | SecurityException e) {
159                throw new RuntimeException(
160                        "exception on getting method Helper." + name, e);
161            }
162        }
163
164        private static int staticMethod() {
165            return 1138;
166        }
167
168        private int method() {
169            return 42;
170        }
171
172        /**
173         * Deoptimizes all non-osr versions of the given executable after
174         * compilation finished.
175         *
176         * @param e Executable
177         * @throws Exception
178         */
179        private static void waitAndDeoptimize(Executable e) {
180            CompilerWhiteBoxTest.waitBackgroundCompilation(e);
181            if (WhiteBox.getWhiteBox().isMethodQueuedForCompilation(e)) {
182                throw new RuntimeException(e + " must not be in queue");
183            }
184            // Deoptimize non-osr versions of executable
185            WhiteBox.getWhiteBox().deoptimizeMethod(e, false);
186        }
187
188        /**
189         * Executes the method multiple times to make sure we have
190         * enough profiling information before triggering an OSR
191         * compilation. Otherwise the C2 compiler may add uncommon traps.
192         *
193         * @param m Method to be executed
194         * @return Number of times the method was executed
195         * @throws Exception
196         */
197        private static int warmup(Method m) throws Exception {
198            waitAndDeoptimize(m);
199            SimpleTestCaseHelper helper = new SimpleTestCaseHelper();
200            int result = 0;
201            for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) {
202                result += (int)m.invoke(helper, 1);
203            }
204            // Wait to make sure OSR compilation is not blocked by
205            // non-OSR compilation in the compile queue
206            CompilerWhiteBoxTest.waitBackgroundCompilation(m);
207            return result;
208        }
209
210        /**
211         * Executes the constructor multiple times to make sure we
212         * have enough profiling information before triggering an OSR
213         * compilation. Otherwise the C2 compiler may add uncommon traps.
214         *
215         * @param c Constructor to be executed
216         * @return Number of times the constructor was executed
217         * @throws Exception
218         */
219        private static int warmup(Constructor c) throws Exception {
220            waitAndDeoptimize(c);
221            int result = 0;
222            for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) {
223                result += c.newInstance(null, 1).hashCode();
224            }
225            // Wait to make sure OSR compilation is not blocked by
226            // non-OSR compilation in the compile queue
227            CompilerWhiteBoxTest.waitBackgroundCompilation(c);
228            return result;
229        }
230
231        private static int osrStaticMethod(long limit) throws Exception {
232            int result = 0;
233            if (limit != 1) {
234                result = warmup(OSR_STATIC);
235            }
236            // Trigger osr compilation
237            for (long i = 0; i < limit; ++i) {
238                result += staticMethod();
239            }
240            return result;
241        }
242
243        private int osrMethod(long limit) throws Exception {
244            int result = 0;
245            if (limit != 1) {
246                result = warmup(OSR_METHOD);
247            }
248            // Trigger osr compilation
249            for (long i = 0; i < limit; ++i) {
250                result += method();
251            }
252            return result;
253        }
254
255        private final int x;
256
257        // for method and OSR method test case
258        public SimpleTestCaseHelper() {
259            x = 0;
260        }
261
262        // for OSR constructor test case
263        private SimpleTestCaseHelper(Object o, long limit) throws Exception {
264            int result = 0;
265            if (limit != 1) {
266                result = warmup(OSR_CONSTRUCTOR);
267            }
268            // Trigger osr compilation
269            for (long i = 0; i < limit; ++i) {
270                result += method();
271            }
272            x = result;
273        }
274
275        // for constructor test case
276        private SimpleTestCaseHelper(int x) {
277            this.x = x;
278        }
279
280        @Override
281        public int hashCode() {
282            return x;
283        }
284    }
285
286