Skip to content

Commit a2315dd

Browse files
Evgeny Nikitinlmesnik
authored andcommitted
8357739: [jittester] disable the hashCode method
Reviewed-by: lmesnik
1 parent 66836d4 commit a2315dd

File tree

4 files changed

+435
-154
lines changed

4 files changed

+435
-154
lines changed

test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ java/lang/System::nanoTime()
3131
java/lang/annotation/IncompleteAnnotationException::IncompleteAnnotationException(Ljava/lang/Class;Ljava/lang/String;)
3232
java/util/AbstractSet::toString()
3333
java/util/HashSet::toString()
34+
35+
#Unstable methods
36+
*::hashCode
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*
2+
* Copyright (c) 2025, 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 jdk.test.lib.jittester;
25+
26+
import java.io.IOException;
27+
import java.io.StringReader;
28+
import java.lang.reflect.Constructor;
29+
import java.lang.reflect.Executable;
30+
import java.util.ArrayList;
31+
import java.util.Arrays;
32+
import java.util.Collection;
33+
import java.util.List;
34+
import java.util.Optional;
35+
import java.util.regex.Matcher;
36+
import java.util.regex.Pattern;
37+
38+
import jdk.test.lib.Asserts;
39+
40+
import static java.util.function.Predicate.not;
41+
42+
43+
/**
44+
* A wrapper for string method templates, similar to the CompileCommand patterns.
45+
*/
46+
public final class MethodTemplate {
47+
48+
/**
49+
* String that can have wildcard symbols on its ends, allowing it to match a family of strings.
50+
* For example, "abc*" matches "abc123", and so on.
51+
*/
52+
public static class WildcardString {
53+
private final String pattern;
54+
private final boolean frontWildcarded;
55+
private final boolean tailWildcarded;
56+
57+
/**
58+
* Creates a WildcardString from given string.
59+
* @param pattern string pattern, like "some*"
60+
*/
61+
public WildcardString(String pattern) {
62+
// check for the leading '*'
63+
frontWildcarded = pattern.charAt(0) == '*';
64+
pattern = frontWildcarded ? pattern.substring(1) : pattern;
65+
66+
// check for the trailing '*'
67+
tailWildcarded = pattern.length() > 0 && pattern.charAt(pattern.length() - 1) == '*';
68+
pattern = tailWildcarded ? pattern.substring(0, pattern.length() - 1) : pattern;
69+
70+
this.pattern = pattern;
71+
}
72+
73+
/**
74+
* Returns true it this WildcardString matches given other string.
75+
* @param other the string that this WildcardString should be matched against
76+
* @return true in case of a match.
77+
*/
78+
public boolean matches(String other) {
79+
boolean result = pattern.equals(other);
80+
result |= frontWildcarded ? other.endsWith(pattern) : result;
81+
result |= tailWildcarded ? other.startsWith(pattern) : result;
82+
result |= tailWildcarded && frontWildcarded ? other.contains(pattern) : result;
83+
return result;
84+
}
85+
}
86+
87+
private static final Pattern METHOD_PATTERN = Pattern.compile(generateMethodPattern());
88+
89+
private final WildcardString klassName;
90+
private final WildcardString methodName;
91+
private final Optional<List<Class<?>>> signature;
92+
93+
private MethodTemplate(String klassName, String methodName, Optional<List<Class<?>>> signature) {
94+
this.klassName = new WildcardString(klassName);
95+
this.methodName = new WildcardString(methodName);
96+
this.signature = signature;
97+
}
98+
99+
private static String generateMethodPattern() {
100+
// Sample valid template(s): java/lang/String::indexOf(Ljava/lang/String;I)
101+
// java/lang/::*(Ljava/lang/String;I)
102+
// *String::indexOf(*)
103+
// java/lang/*::indexOf
104+
105+
String primitiveType = "[ZBSCIJFD]"; // Simply a letter, like 'I'
106+
String referenceType = "L[\\w/$]+;"; // Like 'Ljava/lang/String;'
107+
String primOrRefType =
108+
"\\[?" + primitiveType + // Bracket is optional: '[Z', or 'Z'
109+
"|" +
110+
"\\[?" + referenceType; // Bracket is optional: '[LSomeObject;' or 'LSomeObject;'
111+
String argTypesOrWildcard = "(" + // Method argument(s) Ljava/lang/String;Z...
112+
"(" + primOrRefType + ")*" +
113+
")|\\*"; // .. or a wildcard:
114+
115+
return
116+
"(?<klassName>[\\w/$]*\\*?)" + // Class name, like 'java/lang/String'
117+
"::" + // Simply '::'
118+
"(?<methodName>\\*?[\\w$]+\\*?)" + // method name, 'indexOf''
119+
"(\\((?<argTypes>" + // Method argument(s) in brackets:
120+
argTypesOrWildcard + // (Ljava/lang/String;Z) or '*' or nothing
121+
")\\))?";
122+
}
123+
124+
/**
125+
* Returns true iff none of the given MethodTemplates matches the given Executable.
126+
*
127+
* @param templates the collection of templates to check
128+
* @param method the executable to match the colletions templates
129+
* @return true if none of the given templates matches the method, false otherwise
130+
*/
131+
public static boolean noneMatches(Collection<MethodTemplate> templates, Executable method) {
132+
for (MethodTemplate template : templates) {
133+
if (template.matches(method)) {
134+
return false;
135+
}
136+
}
137+
return true;
138+
}
139+
140+
/**
141+
* Returns true if this MethodTemplate matches the given Executable.
142+
*
143+
* @param other the Executable to try to match to
144+
* @return whether the other matches this MethodTemplate
145+
*/
146+
public boolean matches(Executable other) {
147+
boolean result = klassName.matches(other.getDeclaringClass().getName());
148+
149+
result &= (other instanceof Constructor)
150+
? result
151+
: methodName.matches(other.getName());
152+
153+
return result &&
154+
signature.map(Arrays.asList(other.getParameterTypes())::equals)
155+
.orElse(true);
156+
}
157+
158+
/**
159+
* Parses the given string and returs a MethodTemplate.
160+
*
161+
* @param methodStr the string to parse
162+
* @return created MethodTemplate
163+
*/
164+
public static MethodTemplate parse(String methodStr) {
165+
Matcher matcher = METHOD_PATTERN.matcher(methodStr);
166+
String msg = String.format("Format of the methods exclude input file is incorrect,"
167+
+ " methodStr \"%s\" has wrong format", methodStr);
168+
Asserts.assertTrue(matcher.matches(), msg);
169+
170+
String klassName = matcher.group("klassName").replaceAll("/", "\\.");
171+
String methodName = matcher.group("methodName");
172+
Optional<List<Class<?>>> signature = Optional.ofNullable(matcher.group("argTypes"))
173+
.filter(not("*"::equals))
174+
.map(MethodTemplate::parseSignature);
175+
return new MethodTemplate(klassName, methodName, signature);
176+
}
177+
178+
private static List<Class<?>> parseSignature(String signature) {
179+
List<Class<?>> sigClasses = new ArrayList<>();
180+
char typeChar;
181+
boolean isArray;
182+
String klassName;
183+
StringBuilder sb;
184+
StringBuilder arrayDim;
185+
try (StringReader str = new StringReader(signature)) {
186+
int symbol = str.read();
187+
while (symbol != -1) {
188+
typeChar = (char) symbol;
189+
arrayDim = new StringBuilder();
190+
Class<?> primArrayClass = null;
191+
if (typeChar == '[') {
192+
isArray = true;
193+
arrayDim.append('[');
194+
symbol = str.read();
195+
while (symbol == '[') {
196+
arrayDim.append('[');
197+
symbol = str.read();
198+
}
199+
typeChar = (char) symbol;
200+
if (typeChar != 'L') {
201+
primArrayClass = Class.forName(arrayDim.toString() + typeChar);
202+
}
203+
} else {
204+
isArray = false;
205+
}
206+
switch (typeChar) {
207+
case 'Z':
208+
sigClasses.add(isArray ? primArrayClass : boolean.class);
209+
break;
210+
case 'I':
211+
sigClasses.add(isArray ? primArrayClass : int.class);
212+
break;
213+
case 'J':
214+
sigClasses.add(isArray ? primArrayClass : long.class);
215+
break;
216+
case 'F':
217+
sigClasses.add(isArray ? primArrayClass : float.class);
218+
break;
219+
case 'D':
220+
sigClasses.add(isArray ? primArrayClass : double.class);
221+
break;
222+
case 'B':
223+
sigClasses.add(isArray ? primArrayClass : byte.class);
224+
break;
225+
case 'S':
226+
sigClasses.add(isArray ? primArrayClass : short.class);
227+
break;
228+
case 'C':
229+
sigClasses.add(isArray ? primArrayClass : char.class);
230+
break;
231+
case 'L':
232+
sb = new StringBuilder();
233+
symbol = str.read();
234+
while (symbol != ';') {
235+
sb.append((char) symbol);
236+
symbol = str.read();
237+
}
238+
klassName = sb.toString().replaceAll("/", "\\.");
239+
if (isArray) {
240+
klassName = arrayDim.toString() + "L" + klassName + ";";
241+
}
242+
Class<?> klass = Class.forName(klassName);
243+
sigClasses.add(klass);
244+
break;
245+
default:
246+
throw new Error("Unknown type " + typeChar);
247+
}
248+
symbol = str.read();
249+
}
250+
} catch (IOException | ClassNotFoundException ex) {
251+
throw new Error("Unexpected exception while parsing exclude methods file", ex);
252+
}
253+
return sigClasses;
254+
}
255+
256+
}

0 commit comments

Comments
 (0)