1 /*
  2  * Copyright (c) 2021, 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.lib.ir_framework;
 25 
 26 import compiler.lib.ir_framework.driver.IRMatcher;
 27 import compiler.lib.ir_framework.shared.*;
 28 import jdk.test.lib.Platform;
 29 import sun.hotspot.WhiteBox;
 30 
 31 import java.util.ArrayList;
 32 import java.util.List;
 33 
 34 /**
 35  * This class provides default regex strings that can be used in {@link IR @IR} annotations to specify IR constraints.
 36  * <p>
 37  * There are two types of default regexes:
 38  * <ul>
 39  *     <li><p>Standalone regexes: Use them directly.</li>
 40  *     <li><p>Composite regexes: Their names contain "{@code _OF}" and expect another string in a list in
 41  *            {@link IR#failOn()} and {@link IR#counts()}. They cannot be use as standalone regex and will result in a
 42  *            {@link TestFormatException} when doing so.</li>
 43  * </ul>
 44  *
 45  * @see IR
 46  */
 47 public class IRNode {
 48     private static final String START = "(\\d+(\\s){2}(";
 49     private static final String MID = ".*)+(\\s){2}===.*";
 50     private static final String END = ")";
 51     private static final String COMPOSITE_PREFIX = "#PRE#"; // Prefix for regexes that require an additional user-defined string.
 52     private static final String IS_REPLACED = "#IS_REPLACED#"; // Is replaced by an additional user-defined string.
 53     private static final String STORE_OF_CLASS_POSTFIX = "(:|\\+)\\S* \\*" + END;
 54     private static final String LOAD_OF_CLASS_POSTFIX = "(:|\\+)\\S* \\*" + END;
 55 
 56     public static final String ALLOC = "(.*precise .*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
 57     public static final String ALLOC_OF = COMPOSITE_PREFIX + "(.*precise .*" + IS_REPLACED + ":.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_instance_Java" + END;
 58     public static final String ALLOC_ARRAY = "(.*precise \\[.*\\R((.*(?i:mov|xor|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
 59     public static final String ALLOC_ARRAY_OF = COMPOSITE_PREFIX + "(.*precise \\[.*" + IS_REPLACED + ":.*\\R((.*(?i:mov|xorl|nop|spill).*|\\s*|.*LGHI.*)\\R)*.*(?i:call,static).*wrapper for: _new_array_Java" + END;
 60 
 61     public static final String CHECKCAST_ARRAY = "(((?i:cmp|CLFI|CLR).*precise \\[.*:|.*(?i:mov|or).*precise \\[.*:.*\\R.*(cmp|CMP|CLR))" + END;
 62     public static final String CHECKCAST_ARRAY_OF = COMPOSITE_PREFIX + "(((?i:cmp|CLFI|CLR).*precise \\[.*" + IS_REPLACED + ":|.*(?i:mov|or).*precise \\[.*" + IS_REPLACED + ":.*\\R.*(cmp|CMP|CLR))" + END;
 63     // Does not work on s390 (a rule containing this regex will be skipped on s390).
 64     public static final String CHECKCAST_ARRAYCOPY = "(.*((?i:call_leaf_nofp,runtime)|CALL,\\s?runtime leaf nofp|BCTRL.*.leaf call).*checkcast_arraycopy.*" + END;
 65 
 66     public static final String FIELD_ACCESS = "(.*Field: *" + END;
 67 
 68     public static final String STORE = START + "Store(B|C|S|I|L|F|D|P|N)" + MID + END;
 69     public static final String STORE_B = START + "StoreB" + MID + END; // Store to boolean is also mapped to byte
 70     public static final String STORE_C = START + "StoreC" + MID + END;
 71     public static final String STORE_I = START + "StoreI" + MID + END; // Store to short is also mapped to int
 72     public static final String STORE_L = START + "StoreL" + MID + END;
 73     public static final String STORE_F = START + "StoreF" + MID + END;
 74     public static final String STORE_D = START + "StoreD" + MID + END;
 75     public static final String STORE_P = START + "StoreP" + MID + END;
 76     public static final String STORE_N = START + "StoreN" + MID + END;
 77     public static final String STORE_OF_CLASS = COMPOSITE_PREFIX + START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 78     public static final String STORE_B_OF_CLASS = COMPOSITE_PREFIX + START + "StoreB" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 79     public static final String STORE_C_OF_CLASS = COMPOSITE_PREFIX + START + "StoreC" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 80     public static final String STORE_I_OF_CLASS = COMPOSITE_PREFIX + START + "StoreI" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 81     public static final String STORE_L_OF_CLASS = COMPOSITE_PREFIX + START + "StoreL" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 82     public static final String STORE_F_OF_CLASS = COMPOSITE_PREFIX + START + "StoreF" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 83     public static final String STORE_D_OF_CLASS = COMPOSITE_PREFIX + START + "StoreD" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 84     public static final String STORE_P_OF_CLASS = COMPOSITE_PREFIX + START + "StoreP" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 85     public static final String STORE_N_OF_CLASS = COMPOSITE_PREFIX + START + "StoreN" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX;
 86     public static final String STORE_OF_FIELD = COMPOSITE_PREFIX + START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@.*name=" + IS_REPLACED + ",.*" + END;
 87 
 88     public static final String LOAD = START + "Load(B|UB|S|US|I|L|F|D|P|N)" + MID + END;
 89     public static final String LOAD_B = START + "LoadB" + MID + END;
 90     public static final String LOAD_UB = START + "LoadUB" + MID + END; // Load from boolean
 91     public static final String LOAD_S = START + "LoadS" + MID + END;
 92     public static final String LOAD_US = START + "LoadUS" + MID + END; // Load from char
 93     public static final String LOAD_I = START + "LoadI" + MID + END;
 94     public static final String LOAD_L = START + "LoadL" + MID + END;
 95     public static final String LOAD_F = START + "LoadF" + MID + END;
 96     public static final String LOAD_D = START + "LoadD" + MID + END;
 97     public static final String LOAD_P = START + "LoadP" + MID + END;
 98     public static final String LOAD_N = START + "LoadN" + MID + END;
 99     public static final String LOAD_OF_CLASS = COMPOSITE_PREFIX + START + "Load(B|UB|S|US|I|L|F|D|P|N)" + MID + "@\\S*"+  IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
100     public static final String LOAD_B_OF_CLASS = COMPOSITE_PREFIX + START + "LoadB" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
101     public static final String LOAD_UB_OF_CLASS = COMPOSITE_PREFIX + START + "LoadUB" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
102     public static final String LOAD_S_OF_CLASS = COMPOSITE_PREFIX + START + "LoadS" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
103     public static final String LOAD_US_OF_CLASS = COMPOSITE_PREFIX + START + "LoadUS" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
104     public static final String LOAD_I_OF_CLASS = COMPOSITE_PREFIX + START + "LoadI" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
105     public static final String LOAD_L_OF_CLASS = COMPOSITE_PREFIX + START + "LoadL" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
106     public static final String LOAD_F_OF_CLASS = COMPOSITE_PREFIX + START + "LoadF" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
107     public static final String LOAD_D_OF_CLASS = COMPOSITE_PREFIX + START + "LoadD" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
108     public static final String LOAD_P_OF_CLASS = COMPOSITE_PREFIX + START + "LoadP" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
109     public static final String LOAD_N_OF_CLASS = COMPOSITE_PREFIX + START + "LoadN" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX;
110     public static final String LOAD_OF_FIELD = COMPOSITE_PREFIX + START + "Load(B|C|S|I|L|F|D|P|N)" + MID + "@.*name=" + IS_REPLACED + ",.*" + END;
111     public static final String LOAD_KLASS  = START + "LoadN?K" + MID + END;
112 
113     public static final String LOOP   = START + "Loop" + MID + END;
114     public static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + END;
115     public static final String COUNTEDLOOP_MAIN = START + "CountedLoop\\b" + MID + "main" + END;
116 
117     public static final String CALL = START + "Call.*Java" + MID + END;
118     public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + START + "Call.*Java" + MID + IS_REPLACED + " " +  END;
119     public static final String DYNAMIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallDynamicJava" + MID + IS_REPLACED + " " + END;
120     public static final String STATIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallStaticJava" + MID + IS_REPLACED + " " +  END;
121     public static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*reason" + END;
122     public static final String PREDICATE_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*predicate" + END;
123     public static final String UNSTABLE_IF_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unstable_if" + END;
124     public static final String CLASS_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*class_check" + END;
125     public static final String NULL_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*null_check" + END;
126     public static final String NULL_ASSERT_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*null_assert" + END;
127     public static final String RANGE_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*range_check" + END;
128     public static final String UNHANDLED_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unhandled" + END;
129     public static final String INTRINSIC_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic" + END;
130     // Does not work for VM builds without JVMCI like x86_32 (a rule containing this regex will be skipped without having JVMCI built).
131     public static final String INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic_or_type_checked_inlining" + END;
132 
133     public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END;
134     public static final String MEMBAR = START + "MemBar" + MID + END;
135 
136     /**
137      * Called by {@link IRMatcher} to merge special composite nodes together with additional user-defined input.
138      */
139     public static List<String> mergeNodes(String[] nodes) {
140         List<String> mergedNodes = new ArrayList<>();
141         for (int i = 0; i < nodes.length; i += 2) {
142             String node = nodes[i];
143             if (node.startsWith(COMPOSITE_PREFIX)) {
144                 if (i + 1 == nodes.length) {
145                     reportMissingCompositeValue(node, i);
146                 }
147                 // Replace placeholder with user defined string.
148                 node = node.substring(COMPOSITE_PREFIX.length()).replaceAll(IS_REPLACED, nodes[i + 1]);
149             } else {
150                 i--; // No composite node, do not increment by 2.
151             }
152             mergedNodes.add(node);
153         }
154         return mergedNodes;
155     }
156 
157     /**
158      * Is default regex supported on current platform, used VM build, etc.?
159      * Throws a {@link CheckedTestFrameworkException} if the default regex is unsupported.
160      */
161     public static void checkDefaultRegexSupported(String node) throws CheckedTestFrameworkException {
162         switch (node) {
163             case INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP -> {
164                 if (!WhiteBox.getWhiteBox().isJVMCISupportedByGC()) {
165                     throw new CheckedTestFrameworkException("INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP is unsupported in builds without JVMCI.");
166                 }
167             }
168             case CHECKCAST_ARRAYCOPY -> {
169                 if (Platform.isS390x()) {
170                     throw new CheckedTestFrameworkException("CHECKCAST_ARRAYCOPY is unsupported on s390.");
171                 }
172             }
173             // default: do nothing -> default regex is supported
174         }
175     }
176 
177     /**
178      * Mapping from string variable value to string variable name for better error reporting.
179      */
180     private static void reportMissingCompositeValue(String node, int i) {
181         String varName = switch (node) {
182             case ALLOC_OF -> "ALLOC_OF";
183             case ALLOC_ARRAY_OF -> "ALLOC_ARRAY_OF";
184             case CHECKCAST_ARRAY_OF -> "CHECKCAST_ARRAY_OF";
185             case STORE_OF_CLASS -> "STORE_OF_CLASS";
186             case STORE_B_OF_CLASS -> "STORE_B_OF_CLASS";
187             case STORE_C_OF_CLASS -> "STORE_C_OF_CLASS";
188             case STORE_D_OF_CLASS -> "STORE_D_OF_CLASS";
189             case STORE_F_OF_CLASS -> "STORE_F_OF_CLASS";
190             case STORE_I_OF_CLASS -> "STORE_I_OF_CLASS";
191             case STORE_L_OF_CLASS -> "STORE_L_OF_CLASS";
192             case STORE_N_OF_CLASS -> "STORE_N_OF_CLASS";
193             case STORE_P_OF_CLASS -> "STORE_P_OF_CLASS";
194             case STORE_OF_FIELD -> "STORE_OF_FIELD";
195             case LOAD_OF_CLASS -> "LOAD_OF_CLASS";
196             case LOAD_B_OF_CLASS -> "LOAD_B_OF_CLASS";
197             case LOAD_UB_OF_CLASS -> "LOAD_UB_OF_CLASS";
198             case LOAD_D_OF_CLASS -> "LOAD_D_OF_CLASS";
199             case LOAD_F_OF_CLASS -> "LOAD_F_OF_CLASS";
200             case LOAD_I_OF_CLASS -> "LOAD_I_OF_CLASS";
201             case LOAD_L_OF_CLASS -> "LOAD_L_OF_CLASS";
202             case LOAD_N_OF_CLASS -> "LOAD_N_OF_CLASS";
203             case LOAD_P_OF_CLASS -> "LOAD_P_OF_CLASS";
204             case LOAD_S_OF_CLASS -> "LOAD_S_OF_CLASS";
205             case LOAD_US_OF_CLASS -> "LOAD_US_OF_CLASS";
206             case LOAD_OF_FIELD -> "LOAD_OF_FIELD";
207             default -> throw new TestFrameworkException("Missing variable mapping for " + node);
208         };
209         TestFormat.fail("Must provide additional value at index " + (i + 1) + " right after " + varName);
210     }
211 }