From e459aebf91bf8ebd4ffaa0b90d87fd4a30553869 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 29 Feb 2024 19:17:10 +0100 Subject: [PATCH] add labels to the output of PrintIntrinsics for intrinsics that are disabled or cannot be disabled --- .../hotspot/test/PrintIntrinsicsTest.java | 113 ++++++++++++++++++ .../graal/compiler/debug/MethodFilter.java | 38 ++++++ .../meta/HotSpotInvocationPlugins.java | 18 +++ .../graphbuilderconf/InvocationPlugins.java | 31 ++++- 4 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/PrintIntrinsicsTest.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/PrintIntrinsicsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/PrintIntrinsicsTest.java new file mode 100644 index 0000000000000..7447f16cf79a5 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/PrintIntrinsicsTest.java @@ -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, ""); + assertLineInOutput(subprocess, ""); + + // 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 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 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))); + } + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/MethodFilter.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/MethodFilter.java index 48592138f99d5..f3a63f7a64fe8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/MethodFilter.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/MethodFilter.java @@ -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; @@ -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 argTypes) { + return matches(baseFilter -> baseFilter.matchesWithArgs(declaringClassName, name, argTypes)); + } + /** * Determines if a given class name is matched by this filter. */ @@ -255,6 +265,22 @@ private boolean matchesSignature(Signature sig) { return true; } + private boolean matchesArgTypes(List 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 @@ -267,6 +293,18 @@ private boolean matches(String javaClassName, String name, Signature sig) { return matchesSignature(sig); } + private boolean matchesWithArgs(String javaClassName, String name, List 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); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java index 0755027632e21..697fb94644612 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java @@ -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 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); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugins.java index cd64cd5c7a11e..b4e3a84a6a790 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugins.java @@ -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; @@ -984,6 +985,24 @@ public String toString() { */ @NativeImageReinitialize private static Set 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 @@ -1006,9 +1025,15 @@ public boolean maybePrintIntrinsics(OptionValues options) { UnmodifiableMapCursor> entries = getInvocationPlugins(false, true).getEntries(); Set 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); }