1/*
2 * Copyright (c) 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
24/**
25 * @test
26 * @library /test/lib /
27 *
28 * @run driver compiler.jsr292.ContinuousCallSiteTargetChange
29 */
30
31package compiler.jsr292;
32
33import jdk.test.lib.Asserts;
34import jdk.test.lib.process.OutputAnalyzer;
35import jdk.test.lib.process.ProcessTools;
36
37import java.lang.invoke.CallSite;
38import java.lang.invoke.MethodHandle;
39import java.lang.invoke.MethodHandles;
40import java.lang.invoke.MethodType;
41import java.lang.invoke.MutableCallSite;
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.List;
45
46public class ContinuousCallSiteTargetChange {
47    static final int ITERATIONS = Integer.parseInt(System.getProperty("iterations", "50"));
48
49    static void runTest(Class<?> test, String... extraArgs) throws Exception {
50        List<String> argsList = new ArrayList<>(
51                List.of("-XX:+IgnoreUnrecognizedVMOptions",
52                    "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10",
53                    "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining"));
54
55        argsList.addAll(Arrays.asList(extraArgs));
56
57        argsList.add(test.getName());
58        argsList.add(Integer.toString(ITERATIONS));
59
60        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
61                argsList.toArray(new String[argsList.size()]));
62
63        OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
64
65        analyzer.shouldHaveExitValue(0);
66
67        analyzer.shouldNotContain("made not compilable");
68        analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff");
69
70    }
71
72    static void testServer(Class<?> test, String... args) throws Exception {
73        List<String> extraArgsList = new ArrayList<>(
74                List.of("-server", "-XX:-TieredCompilation"));
75        extraArgsList.addAll(Arrays.asList(args));
76
77        runTest(test, extraArgsList.toArray(new String[extraArgsList.size()]));
78    }
79
80    static void testClient(Class<?> test, String... args) throws Exception {
81        List<String> extraArgsList = new ArrayList<>(
82                List.of("-client", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"));
83        extraArgsList.addAll(Arrays.asList(args));
84
85        runTest(test, extraArgsList.toArray(new String[extraArgsList.size()]));
86    }
87
88    public static void main(String[] args) throws Exception {
89        testServer(RecompilationTest.class, "-Xbatch");
90        testClient(RecompilationTest.class, "-Xbatch");
91
92        testServer(PingPongTest.class);
93        testClient(PingPongTest.class);
94    }
95
96    static MethodHandle findStatic(Class<?> cls, String name, MethodType mt) {
97        try {
98            return MethodHandles.lookup().findStatic(cls, name, mt);
99        } catch (Exception e) {
100            throw new Error(e);
101        }
102    }
103
104    static class RecompilationTest {
105        static final MethodType mt = MethodType.methodType(void.class);
106        static final CallSite cs = new MutableCallSite(mt);
107
108        static final MethodHandle mh = cs.dynamicInvoker();
109
110        static void f() {
111        }
112
113        static void test1() throws Throwable {
114            mh.invokeExact();
115        }
116
117        static void test2() throws Throwable {
118            cs.getTarget().invokeExact();
119        }
120
121        static void iteration() throws Throwable {
122            MethodHandle mh1 = findStatic(RecompilationTest.class, "f", mt);
123            cs.setTarget(mh1);
124            for (int i = 0; i < 20_000; i++) {
125                test1();
126                test2();
127            }
128        }
129
130        public static void main(String[] args) throws Throwable {
131            int iterations = Integer.parseInt(args[0]);
132            for (int i = 0; i < iterations; i++) {
133                iteration();
134            }
135        }
136    }
137
138    static class PingPongTest {
139        static final MethodType mt = MethodType.methodType(void.class);
140        static final CallSite cs = new MutableCallSite(mt);
141
142        static final MethodHandle mh = cs.dynamicInvoker();
143
144        static final MethodHandle ping = findStatic(PingPongTest.class, "ping", mt);
145        static final MethodHandle pong = findStatic(PingPongTest.class, "pong", mt);
146
147        static void ping() {
148            Asserts.assertEQ(cs.getTarget(), ping, "wrong call site target");
149            cs.setTarget(pong);
150        }
151
152        static void pong() {
153            Asserts.assertEQ(cs.getTarget(), pong, "wrong call site target");
154            cs.setTarget(ping);
155        }
156
157        static void iteration() throws Throwable {
158            cs.setTarget(ping);
159            for (int i = 0; i < 20_000; i++) {
160                mh.invokeExact();
161            }
162        }
163
164        public static void main(String[] args) throws Throwable {
165            int iterations = Integer.parseInt(args[0]);
166            for (int i = 0; i < iterations; i++) {
167                iteration();
168            }
169        }
170    }
171}
172