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 package compiler.calls.common;
25 
26 import compiler.testlibrary.CompilerUtils;
27 import jdk.test.lib.Asserts;
28 import sun.hotspot.WhiteBox;
29 
30 import java.lang.reflect.Method;
31 import java.util.Arrays;
32 
33 /**
34  * A common class for Invoke* classes
35  */
36 public abstract class CallsBase {
37     public static final String CALL_ERR_MSG = "Call insuccessfull";
38     protected final Method calleeMethod;
39     protected final Method callerMethod;
40     protected final WhiteBox wb = WhiteBox.getWhiteBox();
41     protected int compileCallee = -1;
42     protected int compileCaller = -1;
43     protected boolean nativeCallee = false;
44     protected boolean nativeCaller = false;
45     protected boolean calleeVisited = false;
46     protected boolean checkCallerCompilationLevel;
47     protected boolean checkCalleeCompilationLevel;
48     protected int expectedCallerCompilationLevel;
49     protected int expectedCalleeCompilationLevel;
50 
CallsBase()51     protected CallsBase() {
52         try {
53             callerMethod = getClass().getDeclaredMethod("caller");
54             calleeMethod = getClass().getDeclaredMethod("callee",
55                     getCalleeParametersTypes());
56             wb.testSetDontInlineMethod(callerMethod, /* dontinline= */ true);
57             wb.testSetDontInlineMethod(calleeMethod, /* dontinline= */ true);
58         } catch (NoSuchMethodException e) {
59             throw new Error("TEST BUG: can't find test method", e);
60         }
61     }
62 
63     /**
64      * Provides callee parameters types to search method
65      * @return array of types
66      */
getCalleeParametersTypes()67     protected Class[] getCalleeParametersTypes() {
68         return new Class[] {int.class, long.class, float.class,
69             double.class, String.class};
70     }
71 
72     /**
73      * Loads native library(libCallsNative.so)
74      */
loadNativeLibrary()75     protected static void loadNativeLibrary() {
76         System.loadLibrary("CallsNative");
77     }
78 
79     /**
80      * Checks if requested compilation levels are inside of current vm capabilities
81      * @return true if vm is capable of requested compilation levels
82      */
compilationLevelsSupported()83     protected final boolean compilationLevelsSupported() {
84         int[] compLevels = CompilerUtils.getAvailableCompilationLevels();
85         boolean callerCompLevelSupported = compileCaller <= 0 || (compileCaller > 0
86                 && Arrays.stream(compLevels)
87                         .filter(elem -> elem == compileCaller)
88                         .findAny()
89                         .isPresent());
90         boolean calleeCompLevelSupported = compileCallee <= 0 || (compileCallee > 0
91                 && Arrays.stream(compLevels)
92                         .filter(elem -> elem == compileCallee)
93                         .findAny()
94                         .isPresent());
95         return callerCompLevelSupported && calleeCompLevelSupported;
96     }
97 
98     /**
99      * Parse test arguments
100      * @param args test arguments
101      */
parseArgs(String args[])102     protected final void parseArgs(String args[]) {
103         for (int i = 0; i < args.length; i++) {
104             switch (args[i]) {
105                 case "-nativeCallee":
106                     nativeCallee = true;
107                     break;
108                 case "-nativeCaller":
109                     nativeCaller = true;
110                     break;
111                 case "-compileCallee":
112                     compileCallee = Integer.parseInt(args[++i]);
113                     break;
114                 case "-compileCaller":
115                     compileCaller = Integer.parseInt(args[++i]);
116                     break;
117                 case "-checkCallerCompileLevel":
118                     checkCallerCompilationLevel = true;
119                     expectedCallerCompilationLevel = Integer.parseInt(args[++i]);
120                     break;
121                 case "-checkCalleeCompileLevel":
122                     checkCalleeCompilationLevel = true;
123                     expectedCalleeCompilationLevel = Integer.parseInt(args[++i]);
124                     break;
125                 default:
126                     throw new Error("Can't parse test parameter:" + args[i]);
127             }
128         }
129     }
130 
131     /**
132      * Run basic logic of a test by doing compile
133      * action(if needed). An arguments can be -compileCallee
134      * $calleeCompilationLevel and/or -compileCaller $callerCompilationLevel
135      * and/or -nativeCaller and/or -nativeCallee to indicate that native methods
136      * for caller/callee should be used
137      * @param args test args
138      */
runTest(String args[])139     protected final void runTest(String args[]) {
140         parseArgs(args);
141         if (compilationLevelsSupported()) {
142             if (nativeCaller || nativeCallee) {
143                 CallsBase.loadNativeLibrary();
144             }
145             Object lock = getLockObject();
146             Asserts.assertNotNull(lock, "Lock object is null");
147             /* a following lock is needed in case several instances of this
148                test are launched in same vm */
149             synchronized (lock) {
150                 if (compileCaller > 0 || compileCallee > 0) {
151                     caller(); // call once to have everything loaded
152                     calleeVisited = false; // reset state
153                 }
154                 // compile with requested level if needed
155                 if (compileCallee > 0 && !compileMethod(calleeMethod, compileCallee)) {
156                     System.out.println("WARNING: Blocking compilation failed for calleeMethod (timeout?). Skipping.");
157                     return;
158                 }
159                 if (checkCalleeCompilationLevel) {
160                     Asserts.assertEQ(expectedCalleeCompilationLevel,
161                             wb.getMethodCompilationLevel(calleeMethod),
162                             "Unexpected callee compilation level");
163                 }
164                 if (compileCaller > 0 && !compileMethod(callerMethod, compileCaller)) {
165                     System.out.println("WARNING: Blocking compilation failed for callerMethod (timeout?). Skipping.");
166                     return;
167                 }
168                 if (checkCallerCompilationLevel) {
169                     Asserts.assertEQ(expectedCallerCompilationLevel,
170                             wb.getMethodCompilationLevel(callerMethod),
171                             "Unexpected caller compilation level");
172                 }
173                 // do calling work
174                 if (nativeCaller) {
175                     callerNative();
176                 } else {
177                     caller();
178                 }
179             }
180         } else {
181             System.out.println("WARNING: Requested compilation levels are "
182                     + "out of current vm capabilities. Skipping.");
183         }
184     }
185 
186     /**
187      * A method to compile another method, searching it by name in current class
188      * @param method a method to compile
189      * @param compLevel a compilation level
190      * @return true if method was enqueued for compilation
191      */
compileMethod(Method method, int compLevel)192     protected final boolean compileMethod(Method method, int compLevel) {
193         wb.deoptimizeMethod(method);
194         Asserts.assertTrue(wb.isMethodCompilable(method, compLevel));
195         return wb.enqueueMethodForCompilation(method, compLevel);
196     }
197 
198     /*
199      * @return Object to lock on during execution
200      */
201 
getLockObject()202     protected abstract Object getLockObject();
203 
caller()204     protected abstract void caller();
205 
callerNative()206     protected abstract void callerNative();
207 
208     /**
209      * A method checking values. Should be used to verify if all parameters are
210      * passed as expected. Parameter N should have a value indicating number "N"
211      * in respective type representation.
212      */
checkValues(int param1, long param2, float param3, double param4, String param5)213     public static void checkValues(int param1, long param2, float param3,
214             double param4, String param5) {
215         Asserts.assertEQ(param1, 1);
216         Asserts.assertEQ(param2, 2L);
217         Asserts.assertEQ(param3, 3.0f);
218         Asserts.assertEQ(param4, 4.0d);
219         Asserts.assertEQ(param5, "5");
220     }
221 }
222