Skip to content

Commit

Permalink
[GR-52415] Enhance PrintIntrinsics output.
Browse files Browse the repository at this point in the history
PullRequest: graal/17149
  • Loading branch information
dougxc committed Mar 2, 2024
2 parents 7d01e1a + 8173332 commit 63542e0
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public static SubprocessUtil.Subprocess launchSubprocess(Predicate<List<String>>
vmArgs = filter(vmArgs, vmArgsFilter);
}

String verboseProperty = testClass.getName() + ".verbose";
String verboseProperty = "debug." + testClass.getName() + ".verbose";
boolean verbose = Boolean.getBoolean(verboseProperty);
if (verbose) {
System.err.println(String.join(" ", vmArgs));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.hotspot.test;

import java.io.IOException;
import java.util.List;
import java.util.Set;

import jdk.graal.compiler.api.directives.GraalDirectives;
import jdk.graal.compiler.core.test.SubprocessTest;
import jdk.graal.compiler.hotspot.HotSpotBackend;
import jdk.graal.compiler.hotspot.nodes.VMErrorNode;
import jdk.graal.compiler.hotspot.replacements.AssertionSnippets;
import jdk.graal.compiler.hotspot.stubs.CreateExceptionStub;
import jdk.graal.compiler.nodes.PiNode;
import jdk.graal.compiler.replacements.ReplacementsUtil;
import jdk.graal.compiler.replacements.StringHelperIntrinsics;
import jdk.graal.compiler.replacements.StringUTF16Snippets;
import org.junit.Test;

import jdk.graal.compiler.test.SubprocessUtil.Subprocess;

/**
* Tests support for
* {@link jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Options#PrintIntrinsics}.
*/
public class PrintIntrinsicsTest extends SubprocessTest {

public void test() {

}

@Test
public void testInSubprocess() throws InterruptedException, IOException {
String[] args = {
"-XX:+EagerJVMCI",
"-Djdk.graal.PrintIntrinsics=true",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-UseAESIntrinsics",
"-Djdk.graal.DisableIntrinsics=java.lang.Integer.*",
"--version"
};
Subprocess subprocess = launchSubprocess(this::test, args);
assertLineInOutput(subprocess, "<Intrinsics>");
assertLineInOutput(subprocess, "</Intrinsics>");

// Random selection of intrinsics that should be stable.
assertLineInOutput(subprocess, "java.lang.Class.getModifiers()");
assertLineInOutput(subprocess, "java.lang.Byte.valueOf(byte)");
assertLineInOutput(subprocess, "java.lang.System.nanoTime()");
assertLineInOutput(subprocess, "java.lang.Thread.currentThread()");

// Test intrinsics disabled by -XX:-UseAESIntrinsics
assertLineInOutput(subprocess, "com.sun.crypto.provider.AESCrypt.implDecryptBlock(byte[];int;byte[];int) [disabled]");
assertLineInOutput(subprocess, "com.sun.crypto.provider.AESCrypt.implEncryptBlock(byte[];int;byte[];int) [disabled]");

// Test intrinsics disabled by -Djdk.graal.DisableIntrinsics
for (String line : subprocess.output) {
if (line.startsWith("java.lang.Integer.") && !line.endsWith(" [disabled]")) {
throw new AssertionError(String.format("Expected intrinsic to be labeled with [disabled]: %s", line));
}
}

String[] forcedIntrinsicPrefixes = {
GraalDirectives.class.getName(),
HotSpotBackend.class.getName(),
PiNode.class.getPackageName(),
ReplacementsUtil.class.getPackageName(),
VMErrorNode.class.getPackageName(),
AssertionSnippets.class.getPackageName(),
CreateExceptionStub.class.getPackageName()
};
Set<String> forcedIntrinsicPrefixExceptions = Set.of(
StringHelperIntrinsics.class.getName() + ".getByte(byte[];int)",
StringUTF16Snippets.class.getName() + ".getChar(byte[];int)");
for (String line : subprocess.output) {
for (var prefix : forcedIntrinsicPrefixes) {
if (line.startsWith(prefix) && !line.endsWith(" [cannot be disabled]") && !forcedIntrinsicPrefixExceptions.contains(line)) {
throw new AssertionError(String.format("Expected intrinsic to be labeled with [cannot be disabled]: %s", line));
}
}
}
}

private static void assertLineInOutput(Subprocess subprocess, String line) {
List<String> output = subprocess.output;
if (!output.contains(line)) {
throw new AssertionError(String.format("Missing line in subprocess: %s%nOutput:%n%s", line, String.join(System.lineSeparator(), output)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
*/
package jdk.graal.compiler.debug;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -139,6 +141,14 @@ public boolean matches(String javaClassName, String name, Signature sig) {
return matches(baseFilter -> baseFilter.matches(javaClassName, name, sig));
}

/**
* Determines if a given method with a given declaring class and argument types is matched by
* this filter.
*/
public boolean matchesWithArgs(String declaringClassName, String name, List<Type> argTypes) {
return matches(baseFilter -> baseFilter.matchesWithArgs(declaringClassName, name, argTypes));
}

/**
* Determines if a given class name is matched by this filter.
*/
Expand Down Expand Up @@ -255,6 +265,22 @@ private boolean matchesSignature(Signature sig) {
return true;
}

private boolean matchesArgTypes(List<Type> argTypes) {
if (signature == null) {
return true;
}
if (argTypes.size() != signature.length) {
return false;
}
for (int i = 0; i < signature.length; i++) {
String javaName = argTypes.get(i).getTypeName();
if (signature[i] != null && !signature[i].matcher(javaName).matches()) {
return false;
}
}
return true;
}

private boolean matches(String javaClassName, String name, Signature sig) {
assert sig != null || signature == null;
// check method name first, since MetaUtil.toJavaName is expensive
Expand All @@ -267,6 +293,18 @@ private boolean matches(String javaClassName, String name, Signature sig) {
return matchesSignature(sig);
}

private boolean matchesWithArgs(String javaClassName, String name, List<Type> argTypes) {
assert argTypes != null || signature == null;
// check method name first, since MetaUtil.toJavaName is expensive
if (methodName != null && !methodName.matcher(name).matches()) {
return false;
}
if (clazz != null && !clazz.matcher(javaClassName).matches()) {
return false;
}
return matchesArgTypes(argTypes);
}

@Override
public String toString() {
return toString(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.EnumMap;
import java.util.List;

import jdk.graal.compiler.util.SignatureUtil;
import jdk.vm.ci.common.NativeImageReinitialize;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
Expand Down Expand Up @@ -65,66 +66,8 @@ static synchronized void initPrimitiveKindCache(MetaAccessProvider metaAccess) {
}

public SnippetSignature(String signature) {
if (signature.length() == 0) {
throw new IllegalArgumentException("Signature cannot be empty");
}
this.originalString = signature;

if (signature.charAt(0) == '(') {
int cur = 1;
while (cur < signature.length() && signature.charAt(cur) != ')') {
int nextCur = parseSignature(signature, cur);
parameters.add(signature.substring(cur, nextCur));
cur = nextCur;
}

cur++;
int nextCur = parseSignature(signature, cur);
returnType = signature.substring(cur, nextCur);
if (nextCur != signature.length()) {
throw new IllegalArgumentException("Extra characters at end of signature: " + signature);
}
} else {
throw new IllegalArgumentException("Signature must start with a '(': " + signature);
}
}

private static int parseSignature(String signature, int start) {
try {
int cur = start;
char first;
do {
first = signature.charAt(cur);
cur++;
} while (first == '[');

switch (first) {
case 'L':
while (signature.charAt(cur) != ';') {
if (signature.charAt(cur) == '.') {
throw new IllegalArgumentException("Class name in signature contains '.' at index " + cur + ": " + signature);
}
cur++;
}
cur++;
break;
case 'V':
case 'I':
case 'B':
case 'C':
case 'D':
case 'F':
case 'J':
case 'S':
case 'Z':
break;
default:
throw new IllegalArgumentException("Invalid character '" + signature.charAt(cur - 1) + "' at index " + (cur - 1) + " in signature: " + signature);
}
return cur;
} catch (StringIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Truncated signature: " + signature);
}
returnType = SignatureUtil.parseSignature(signature, parameters);
originalString = signature;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
return true;
}

@Override
protected boolean isDisabled(InvocationPlugin plugin, String declaringClassInternalName, String declaringClassJavaName, OptionValues options) {
if (super.isDisabled(plugin, declaringClassInternalName, declaringClassJavaName, options)) {
return true;
}
EconomicSet<MethodKey> disabledIntrinsicsSet = disabledIntrinsics.get(declaringClassInternalName);
if (disabledIntrinsicsSet != null) {
for (MethodKey mk : disabledIntrinsicsSet) {
if (mk.name.equals(plugin.name)) {
if (mk.descriptor.startsWith(plugin.argumentsDescriptor)) {
return true;
}
}
}
}
return false;
}

@Override
public InvocationPlugin lookupInvocation(ResolvedJavaMethod method, boolean allowDecorators, boolean allowDisable, OptionValues options) {
InvocationPlugin invocationPlugin = super.lookupInvocation(method, allowDecorators, allowDisable, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.util.TreeSet;
import java.util.function.Predicate;

import jdk.vm.ci.meta.JavaType;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.Equivalence;
import org.graalvm.collections.MapCursor;
Expand Down Expand Up @@ -984,6 +985,24 @@ public String toString() {
*/
@NativeImageReinitialize private static Set<String> PrintedIntrinsics = new HashSet<>();

/**
* Determines if {@code plugin} is disabled by {@link Options#DisableIntrinsics}.
*
* @param declaringClassInternalName name of the declaring class for {@code plugin} as returned
* by {@link JavaType#getName()}
* @param declaringClassJavaName name of the declaring class for {@code plugin} as returned by
* by {@link JavaType#toJavaName()}
*/
protected boolean isDisabled(InvocationPlugin plugin, String declaringClassInternalName, String declaringClassJavaName, OptionValues options) {
initializeDisabledIntrinsicsFilter(options);
if (disabledIntrinsicsFilter != null) {
if (disabledIntrinsicsFilter.matchesWithArgs(declaringClassJavaName, plugin.name, List.of(plugin.argumentTypes))) {
return true;
}
}
return false;
}

/**
* Prints the methods for which there are intrinsics in this object if this is the first (or
* only) isolate in which this method is called and {@link Options#PrintIntrinsics} is true in
Expand All @@ -1006,9 +1025,15 @@ public boolean maybePrintIntrinsics(OptionValues options) {
UnmodifiableMapCursor<String, List<InvocationPlugin>> entries = getInvocationPlugins(false, true).getEntries();
Set<String> unique = new TreeSet<>();
while (entries.advance()) {
String c = MetaUtil.internalNameToJava(entries.getKey(), true, false);
for (InvocationPlugin invocationPlugin : entries.getValue()) {
String method = c + '.' + invocationPlugin.asMethodFilterString();
String declaringClassName = entries.getKey();
String c = MetaUtil.internalNameToJava(declaringClassName, true, false);
for (InvocationPlugin plugin : entries.getValue()) {
String method = c + '.' + plugin.asMethodFilterString();
if (!plugin.canBeDisabled()) {
method += " [cannot be disabled]";
} else if (isDisabled(plugin, declaringClassName, c, options)) {
method += " [disabled]";
}
if (PrintedIntrinsics.add(method)) {
unique.add(method);
}
Expand Down
Loading

0 comments on commit 63542e0

Please sign in to comment.