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.compilercontrol.share.scenario;
25 
26 import jdk.test.lib.Asserts;
27 
28 import java.util.Arrays;
29 import java.util.Optional;
30 
31 /**
32  * Represents method compilation state
33  */
34 public class State {
35     // Each of the two-elements array contains a state for each compiler
36     private Optional<Boolean>[] compile =
37             (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
38     private Optional<Boolean>[] forceInline =
39             (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
40     private Optional<Boolean>[] dontInline =
41             (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
42     private Optional<Boolean> printAssembly = Optional.empty();
43     private Optional<Boolean> printInline = Optional.empty();
44     private Optional<Boolean> log = Optional.empty();
45 
State()46     public State() {
47         Arrays.fill(compile, Optional.empty());
48         Arrays.fill(forceInline, Optional.empty());
49         Arrays.fill(dontInline, Optional.empty());
50     }
51 
52     /**
53      * Creates state from the string
54      *
55      * @param strings array of strings that represent the state
56      * @return State instance
57      * @see #toString()
58      */
fromString(String[] strings)59     public static State fromString(String[] strings) {
60         Asserts.assertNotNull(strings, "Non null array is required");
61         Asserts.assertNE(strings.length, 0, "Non empty array is required");
62         State st = new State();
63         for (String string : strings) {
64             int i = string.indexOf(' ');
65             String command = string.substring(0, i);
66             String values = string.substring(i + 1); // skip space symbol
67             switch (command) {
68                 case "compile" :
69                     parseArray(st.compile, values);
70                     break;
71                 case "force_inline" :
72                     parseArray(st.forceInline, values);
73                     break;
74                 case "dont_inline" :
75                     parseArray(st.dontInline, values);
76                     break;
77                 case "log" :
78                     st.log = parseElement(values);
79                     break;
80                 case "print_assembly" :
81                     st.printAssembly = parseElement(values);
82                     break;
83                 case "print_inline" :
84                     st.printInline = parseElement(values);
85                     break;
86                 default:
87                     throw new Error("TESTBUG: ");
88             }
89         }
90         return  st;
91     }
92 
parseArray(Optional<Boolean>[] array, String str)93     private static void parseArray(Optional<Boolean>[] array, String str) {
94         Asserts.assertNotNull(str);
95         int beginBrace = 0;
96         int endBrace = str.length() - 1;
97         if (str.charAt(beginBrace) != '[' || str.charAt(endBrace) != ']') {
98             throw new Error("TESTBUG: not an array type: " + str);
99         }
100         // Get all elements divided with comma as an array
101         String[] strValues = str.substring(beginBrace + 1, endBrace)
102                 .split(", ");
103         Asserts.assertEQ(strValues.length, array.length, "Different amount of "
104                 + "elements in the string");
105         for (int i = 0; i < strValues.length; i++) {
106             array[i] = parseElement(strValues[i]);
107         }
108     }
109 
parseElement(String str)110     private static Optional<Boolean> parseElement(String str) {
111         Asserts.assertNotNull(str);
112         Asserts.assertTrue(str.startsWith(Optional.class.getSimpleName()),
113                 "String is not of type Optional: " + str);
114         if ("Optional.empty".equals(str)) {
115             return Optional.empty();
116         }
117         int begin = str.indexOf('[');
118         Asserts.assertNE(begin, -1, "TEST BUG: Wrong Optional string");
119         int end = str.indexOf(']');
120         Asserts.assertEQ(end, str.length() - 1);
121         boolean b = Boolean.parseBoolean(str.substring(begin + 1, end));
122         return Optional.of(b);
123     }
124 
125     /**
126      * Gets string representation of this state
127      */
128     @Override
toString()129     public String toString() {
130         return "compile " + Arrays.toString(compile)
131                 + "\nforce_inline " + Arrays.toString(forceInline)
132                 + "\ndont_inline " + Arrays.toString(dontInline)
133                 + "\nlog " + log
134                 + "\nprint_assembly " + printAssembly
135                 + "\nprint_inline " + printInline;
136     }
137 
getCompilableOptional(Scenario.Compiler compiler)138     public Optional<Boolean> getCompilableOptional(Scenario.Compiler compiler) {
139         return compile[compiler.ordinal()];
140     }
141 
isC1Compilable()142     public boolean isC1Compilable() {
143         return compile[Scenario.Compiler.C1.ordinal()].orElse(true);
144     }
145 
isC2Compilable()146     public boolean isC2Compilable() {
147         return compile[Scenario.Compiler.C2.ordinal()].orElse(true);
148     }
149 
isCompilable()150     public boolean isCompilable() {
151         return isC1Compilable() && isC2Compilable();
152     }
153 
setC1Compilable(boolean value)154     public void setC1Compilable(boolean value) {
155         setCompilable(Scenario.Compiler.C1.ordinal(), value);
156     }
157 
setC2Compilable(boolean value)158     public void setC2Compilable(boolean value) {
159         setCompilable(Scenario.Compiler.C2.ordinal(), value);
160     }
161 
setCompilable(Scenario.Compiler compiler, boolean value)162     public void setCompilable(Scenario.Compiler compiler, boolean value) {
163         if (compiler == null) {
164             setC1Compilable(value);
165             setC2Compilable(value);
166             return;
167         }
168         switch (compiler) {
169             case C1:
170                 setC1Compilable(value);
171                 break;
172             case C2:
173                 setC2Compilable(value);
174                 break;
175             default:
176                 throw new Error("Unknown compiler");
177         }
178     }
179 
setCompilable(int level, boolean value)180     private void setCompilable(int level, boolean value) {
181         check(level);
182         compile[level] = Optional.of(value);
183         if (!value) {
184             setDontInline(level);
185         }
186     }
187 
isC1Inlinable()188     public boolean isC1Inlinable() {
189         return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false)
190                 && isC1Compilable();
191     }
192 
isC2Inlinable()193     public boolean isC2Inlinable() {
194         return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false)
195                 && isC2Compilable();
196     }
197 
isInlinable()198     public boolean isInlinable() {
199         return isC1Inlinable() && isC2Inlinable();
200     }
201 
setDontInline(int level)202     private void setDontInline(int level) {
203         check(level);
204         dontInline[level] = Optional.of(true);
205         forceInline[level] = Optional.of(false);
206     }
207 
setForceInline(int level)208     private void setForceInline(int level) {
209         check(level);
210         dontInline[level] = Optional.of(false);
211         forceInline[level] = Optional.of(true);
212     }
213 
isC1ForceInline()214     public boolean isC1ForceInline() {
215         return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false)
216                 && isC1Compilable();
217     }
218 
isC2ForceInline()219     public boolean isC2ForceInline() {
220         return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false)
221                 && isC2Compilable();
222     }
223 
isForceInline()224     public boolean isForceInline() {
225         return isC1ForceInline() && isC2ForceInline();
226     }
227 
setC1Inline(boolean value)228     public void setC1Inline(boolean value) {
229         if (value && isC1Compilable()) {
230             setForceInline(Scenario.Compiler.C1.ordinal());
231         } else {
232             setDontInline(Scenario.Compiler.C1.ordinal());
233         }
234     }
235 
setC2Inline(boolean value)236     public void setC2Inline(boolean value) {
237         if (value && isC2Compilable()) {
238             setForceInline(Scenario.Compiler.C2.ordinal());
239         } else {
240             setDontInline(Scenario.Compiler.C2.ordinal());
241         }
242     }
243 
setInline(Scenario.Compiler compiler, boolean value)244     public void setInline(Scenario.Compiler compiler, boolean value) {
245         if (compiler == null) {
246             setC1Inline(value);
247             setC2Inline(value);
248             return;
249         }
250         switch (compiler) {
251             case C1:
252                 setC1Inline(value);
253                 break;
254             case C2:
255                 setC2Inline(value);
256                 break;
257             default:
258                 throw new Error("Unknown compiler");
259         }
260     }
261 
isPrintAssembly()262     public boolean isPrintAssembly() {
263         return printAssembly.orElse(false);
264     }
265 
setPrintAssembly(boolean value)266     public void setPrintAssembly(boolean value) {
267         printAssembly = Optional.of(value);
268     }
269 
isPrintInline()270     public boolean isPrintInline() {
271         return printInline.orElse(false);
272     }
273 
setPrintInline(boolean value)274     public void setPrintInline(boolean value) {
275         printInline = Optional.of(value);
276     }
277 
isLog()278     public boolean isLog() {
279         return log.orElse(false);
280     }
281 
setLog(boolean log)282     public void setLog(boolean log) {
283         this.log = Optional.of(log);
284     }
285 
check(int level)286     private void check(int level) {
287         if (level < 0 || level > compile.length) {
288             throw new IllegalArgumentException("TESTBUG: Wrong level " + level);
289         }
290     }
291 
292     /**
293      * Applies given command to the state.
294      *
295      * @param compileCommand command to be applied
296      */
apply(CompileCommand compileCommand)297     public void apply(CompileCommand compileCommand) {
298         switch (compileCommand.command) {
299             case COMPILEONLY:
300                 setCompilable(compileCommand.compiler, true);
301                 break;
302             case EXCLUDE:
303                 setCompilable(compileCommand.compiler, false);
304                 break;
305             case INLINE:
306                 setInline(compileCommand.compiler, true);
307                 break;
308             case DONTINLINE:
309                 setInline(compileCommand.compiler, false);
310                 break;
311             case LOG:
312                 setLog(true);
313                 break;
314             case PRINT:
315                 setPrintAssembly(true);
316                 break;
317             case QUIET:
318             case NONEXISTENT:
319                 // doesn't apply the state
320                 break;
321             default:
322                 throw new Error("Wrong command: " + compileCommand.command);
323         }
324     }
325 
326     /**
327      * Merges two given states with different priority
328      *
329      * @param low  state with lower merge priority
330      * @param high state with higher merge priority
331      */
merge(State low, State high)332     public static State merge(State low, State high) {
333         if (high == null) {
334             if (low == null) {
335                 return new State();
336             }
337             return low;
338         }
339         if (low == null) {
340             return high;
341         }
342         State result = new State();
343         // Compilable
344         result.compile[Scenario.Compiler.C1.ordinal()] = mergeOptional(
345                 high.compile[Scenario.Compiler.C1.ordinal()],
346                 low.compile[Scenario.Compiler.C1.ordinal()]);
347         result.compile[Scenario.Compiler.C2.ordinal()] = mergeOptional(
348                 high.compile[Scenario.Compiler.C2.ordinal()],
349                 low.compile[Scenario.Compiler.C2.ordinal()]);
350         // Force inline
351         result.forceInline[Scenario.Compiler.C1.ordinal()] = mergeOptional(
352                 high.forceInline[Scenario.Compiler.C1.ordinal()],
353                 low.forceInline[Scenario.Compiler.C1.ordinal()]);
354         result.forceInline[Scenario.Compiler.C2.ordinal()] = mergeOptional(
355                 high.forceInline[Scenario.Compiler.C2.ordinal()],
356                 low.forceInline[Scenario.Compiler.C2.ordinal()]);
357         // Don't inline
358         result.dontInline[Scenario.Compiler.C1.ordinal()] = mergeOptional(
359                 high.dontInline[Scenario.Compiler.C1.ordinal()],
360                 low.dontInline[Scenario.Compiler.C1.ordinal()]);
361         result.dontInline[Scenario.Compiler.C2.ordinal()] = mergeOptional(
362                 high.dontInline[Scenario.Compiler.C2.ordinal()],
363                 low.dontInline[Scenario.Compiler.C2.ordinal()]);
364         // set PrintAssembly
365         result.printAssembly = mergeOptional(high.printAssembly,
366                 low.printAssembly);
367         // set PrintInline
368         result.printInline = mergeOptional(high.printInline, low.printInline);
369         // set LogCompilation
370         result.log = mergeOptional(high.log, low.log);
371         return result;
372     }
373 
mergeOptional(Optional<T> high, Optional<T> low)374     private static <T> Optional<T> mergeOptional(Optional<T> high,
375                                                  Optional<T> low) {
376         T val = high.orElse(low.orElse(null));
377         return Optional.ofNullable(val);
378     }
379 }
380