From cbcb488d7724ab694a7fe9c779afd65e96b1acda Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Thu, 19 Dec 2019 03:46:03 +0100 Subject: [PATCH 1/5] Added tag jdk-14+28 for changeset 2069b4bfd23b --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 87f4de23368..e10b7583427 100644 --- a/.hgtags +++ b/.hgtags @@ -600,3 +600,4 @@ c16ac7a2eba4e73cb4f7ee9294dd647860eebff0 jdk-14+21 17d242844fc9e7d18b3eac97426490a9c246119e jdk-14+25 288777cf0702914e5266bc1e5d380eed9032ca41 jdk-14+26 91a3f092682fc715d991a87eb6ec6f28886d2035 jdk-14+27 +2069b4bfd23b56b6fc659fba8b75aaaa23debbe0 jdk-14+28 From 9847d8161b82017914b6061c25538c3735f404d3 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 19 Dec 2019 14:19:34 +0100 Subject: [PATCH 2/5] 8236110: Windows (MSVC 2013) build failures after JDK-8233299 Reviewed-by: erikj --- make/autoconf/hotspot.m4 | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4 index 649e48cb675..d0cdedd1c23 100644 --- a/make/autoconf/hotspot.m4 +++ b/make/autoconf/hotspot.m4 @@ -345,10 +345,27 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], fi # Only enable ZGC on supported platforms + if (test "x$OPENJDK_TARGET_OS" = "xwindows" && test "x$OPENJDK_TARGET_CPU" = "xx86_64"); then + AC_MSG_CHECKING([if zgc can be built on windows]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include ]], + [[struct MEM_EXTENDED_PARAMETER x;]]) + ], + [ + AC_MSG_RESULT([yes]) + CAN_BUILD_ZGC_ON_WINDOWS="yes" + ], + [ + AC_MSG_RESULT([no, missing required APIs]) + CAN_BUILD_ZGC_ON_WINDOWS="no" + ] + ) + fi + AC_MSG_CHECKING([if zgc can be built]) if (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \ (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64") || \ - (test "x$OPENJDK_TARGET_OS" = "xwindows" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \ + (test "x$CAN_BUILD_ZGC_ON_WINDOWS" = "xyes") || \ (test "x$OPENJDK_TARGET_OS" = "xmacosx" && test "x$OPENJDK_TARGET_CPU" = "xx86_64"); then AC_MSG_RESULT([yes]) else From c751493f0c69ce7eeeb8b7770ef2b226af66c2d7 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 19 Dec 2019 15:20:53 -0500 Subject: [PATCH 3/5] 8235738: [macos] tools/jpackage tests timeout on macOS Reviewed-by: herrick, asemenyuk --- .../jpackage/internal/MacDmgBundler.java | 2 +- .../incubator/jpackage/internal/Executor.java | 21 ++++++++++++++++++- .../incubator/jpackage/internal/IOUtils.java | 21 +++++++++++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java index 243bcd0cc99..3b0527df9f1 100644 --- a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java @@ -289,7 +289,7 @@ private File buildDMG( protoDMG.getAbsolutePath(), hdiUtilVerbosityFlag, "-mountroot", imagesRoot.getAbsolutePath()); - IOUtils.exec(pb); + IOUtils.exec(pb, false, null, true); File mountedRoot = new File(imagesRoot.getAbsolutePath(), APP_NAME.fetchFrom(params)); diff --git a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/Executor.java b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/Executor.java index 742b30e6192..4340d2b4a4f 100644 --- a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/Executor.java +++ b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/Executor.java @@ -48,6 +48,11 @@ Executor saveOutput(boolean v) { return this; } + Executor setWaitBeforeOutput(boolean v) { + waitBeforeOutput = v; + return this; + } + Executor setProcessBuilder(ProcessBuilder v) { pb = v; return this; @@ -88,6 +93,16 @@ int execute() throws IOException { Log.verbose(String.format("Running %s", createLogMessage(pb))); Process p = pb.start(); + int code = 0; + if (waitBeforeOutput) { + try { + code = p.waitFor(); + } catch (InterruptedException ex) { + Log.verbose(ex); + throw new RuntimeException(ex); + } + } + if (needProcessOutput) { try (var br = new BufferedReader(new InputStreamReader( p.getInputStream()))) { @@ -131,7 +146,10 @@ int execute() throws IOException { } try { - return p.waitFor(); + if (!waitBeforeOutput) { + code = p.waitFor(); + } + return code; } catch (InterruptedException ex) { Log.verbose(ex); throw new RuntimeException(ex); @@ -157,6 +175,7 @@ private static String createLogMessage(ProcessBuilder pb) { private ProcessBuilder pb; private boolean saveOutput; + private boolean waitBeforeOutput; private List output; private Consumer> outputConsumer; } diff --git a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/IOUtils.java b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/IOUtils.java index 34e7bb2f1e0..5264abe4699 100644 --- a/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/IOUtils.java +++ b/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/IOUtils.java @@ -147,20 +147,33 @@ public static void run(String launcher, File paramFile) public static void exec(ProcessBuilder pb) throws IOException { - exec(pb, false, null); + exec(pb, false, null, false); } - static void exec(ProcessBuilder pb, boolean testForPresenseOnly, + // Reading output from some processes (currently known "hdiutil attach" might hang even if process already + // exited. Only possible workaround found in "hdiutil attach" case is to wait for process to exit before + // reading output. + public static void exec(ProcessBuilder pb, boolean waitBeforeOutput) + throws IOException { + exec(pb, false, null, waitBeforeOutput); + } + + static void exec(ProcessBuilder pb, boolean testForPresenceOnly, PrintStream consumer) throws IOException { + exec(pb, testForPresenceOnly, consumer, false); + } + + static void exec(ProcessBuilder pb, boolean testForPresenceOnly, + PrintStream consumer, boolean waitBeforeOutput) throws IOException { List output = new ArrayList<>(); - Executor exec = Executor.of(pb).setOutputConsumer(lines -> { + Executor exec = Executor.of(pb).setWaitBeforeOutput(waitBeforeOutput).setOutputConsumer(lines -> { lines.forEach(output::add); if (consumer != null) { output.forEach(consumer::println); } }); - if (testForPresenseOnly) { + if (testForPresenceOnly) { exec.execute(); } else { exec.executeExpectSuccess(); From cfddf53c01cb2bac3d7146afc0ce319b75184b2f Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Thu, 19 Dec 2019 13:20:58 -0800 Subject: [PATCH 4/5] 8236139: [Graal] java/lang/RuntimeTests/exec/LotsOfOutput.java fails with JVMCI enabled Reviewed-by: kvn --- test/jdk/ProblemList-graal.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList-graal.txt b/test/jdk/ProblemList-graal.txt index dbba25dd710..63d35923bb9 100644 --- a/test/jdk/ProblemList-graal.txt +++ b/test/jdk/ProblemList-graal.txt @@ -34,7 +34,7 @@ java/util/concurrent/tck/JSR166TestCase.java 8187486 java/lang/ref/OOMEInReferenceHandler.java 8196611 generic-all java/lang/ref/SoftReference/Pin.java 8196611 generic-all -java/lang/Runtime/exec/LotsOfOutput.java 8196611 generic-all +java/lang/RuntimeTests/exec/LotsOfOutput.java 8196611 generic-all java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java 8196611 generic-all com/sun/crypto/provider/KeyFactory/TestProviderLeak.java 8196611 generic-all From 261f4bffae802c19cec6332f00d1a70b78e5400f Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 19 Dec 2019 15:13:24 -0800 Subject: [PATCH 5/5] 8235927: Update Graal Reviewed-by: kvn --- .../jaotc/binformat/BinaryContainer.java | 16 + .../src/jdk/tools/jaotc/MarkProcessor.java | 9 +- .../test/BlackholeDirectiveTest.java | 11 +- .../test/ControlFlowAnchorDirectiveTest.java | 13 +- .../directives/test/OpaqueDirectiveTest.java | 11 +- .../AArch64LoadStoreMergingAssemblerTest.java | 311 ++++++++++++++++++ .../asm/aarch64/AArch64Assembler.java | 29 +- .../asm/aarch64/AArch64MacroAssembler.java | 191 ++++++++++- .../test/AArch64PairLoadStoreTest.java | 87 +++++ .../common/util/UnsafeArrayTypeWriter.java | 5 + .../core/test/CheckGraalInvariants.java | 9 + .../test/ConditionalEliminationTestBase.java | 6 +- .../compiler/core/test/CountedLoopTest.java | 5 +- .../compiler/core/test/GraalCompilerTest.java | 20 +- .../core/test/MergeCanonicalizerTest.java | 6 +- .../core/test/OptionsVerifierTest.java | 10 +- .../compiler/core/test/SubprocessTest.java | 2 +- .../compiler/core/test/VerifyDebugUsage.java | 2 +- .../core/test/ea/PEAAssertionsTest.java | 11 +- .../graalvm/compiler/debug/DebugContext.java | 13 + .../aarch64/AArch64HotSpotSafepointOp.java | 8 +- .../amd64/AMD64HotSpotSafepointOp.java | 15 +- .../test/BenchmarkCounterOverflowTest.java | 2 +- .../sparc/test/SPARCAllocatorTest.java | 8 +- .../sparc/SPARCHotSpotSafepointOp.java | 19 +- .../hotspot/test/CompilationWrapperTest.java | 38 +-- .../hotspot/test/ReservedStackAccessTest.java | 3 +- .../hotspot/GraalHotSpotVMConfig.java | 1 + .../GraalHotSpotVMConfigVersioned.java | 3 + .../optimize/ConditionalElimination02.java | 15 +- .../compiler/lir/aarch64/AArch64Move.java | 24 +- .../compiler/lir/aarch64/AArch64Unary.java | 18 +- .../lir/asm/CompilationResultBuilder.java | 11 + .../graalvm/compiler/nodes/GraphDecoder.java | 290 +++++++++++++--- .../test/classfile/RedefineIntrinsicTest.java | 2 +- .../replacements/classfile/Classfile.java | 2 +- .../graalvm/compiler/test/SubprocessUtil.java | 72 +++- 37 files changed, 1131 insertions(+), 167 deletions(-) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64LoadStoreMergingAssemblerTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64PairLoadStoreTest.java diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index a4b067f37e6..0c35a871245 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -31,6 +31,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,6 +44,7 @@ import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; /** * A format-agnostic container class that holds various components of a binary. @@ -67,6 +69,8 @@ public final class BinaryContainer implements SymbolTable { private final int codeEntryAlignment; + private final boolean threadLocalHandshakes; + /** * Container holding code bits and any other related information. */ @@ -292,6 +296,8 @@ public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotS this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; + this.threadLocalHandshakes = graalHotSpotVMConfig.threadLocalHandshakes; + // Section unique name is limited to 8 characters due to limitation on Windows. // Name could be longer but only first 8 characters are stored on Windows. @@ -350,6 +356,12 @@ private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, Grap // @formatter:on // @Checkstyle: resume + if (JavaVersionUtil.JAVA_SPEC < 14) { + // See JDK-8220049. Thread local handshakes are on by default since JDK14, the command line option has been removed. + booleanFlags = Arrays.copyOf(booleanFlags, booleanFlags.length + 1); + booleanFlags[booleanFlags.length - 1] = graalHotSpotVMConfig.threadLocalHandshakes; + } + byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags); int size0 = configContainer.getByteStreamSize(); @@ -449,6 +461,10 @@ public int getCodeEntryAlignment() { return codeEntryAlignment; } + public boolean getThreadLocalHandshakes() { + return threadLocalHandshakes; + } + /** * Gets the global AOT symbol associated with the function name. * diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java index a68d0808164..eef99a15e46 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -56,8 +56,11 @@ void process(CompiledMethodInfo methodInfo, Mark mark) { break; case POLL_FAR: case POLL_RETURN_FAR: - // skip relocation - break; + if (binaryContainer.getThreadLocalHandshakes()) { + // skip relocation + break; + } + // fallthrough case CARD_TABLE_ADDRESS: case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java index c4c146cd69f..e47d7cdc66f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java @@ -29,16 +29,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Assert; +import org.junit.Test; /** * Tests for {@link GraalDirectives#blackhole}. @@ -134,8 +131,8 @@ public void testObject() { } @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java index 127ce5cdf2c..013328c1241 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java @@ -33,9 +33,6 @@ import java.util.Collections; import java.util.List; -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.graph.Node; @@ -46,11 +43,11 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.junit.Assert; +import org.junit.Test; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest { @@ -244,8 +241,8 @@ private static List getNodeCountAnnotations(StructuredGraph graph) { } @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java index 30de577e397..7c717c33528 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java @@ -29,9 +29,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.nodes.ConstantNode; @@ -40,8 +37,8 @@ import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Assert; +import org.junit.Test; /** * Tests for {@link GraalDirectives#opaque}. @@ -133,8 +130,8 @@ public void testObject() { } @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64LoadStoreMergingAssemblerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64LoadStoreMergingAssemblerTest.java new file mode 100644 index 00000000000..d81ea970658 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64LoadStoreMergingAssemblerTest.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Arm Limited. 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. + * + * 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 org.graalvm.compiler.asm.aarch64.test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.runtime.JVMCI; +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.test.GraalTest; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assume.assumeTrue; + +public class AArch64LoadStoreMergingAssemblerTest extends GraalTest { + private Register base; + private Register rt1; + private Register rt2; + + @Before + public void checkAArch64() { + TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget(); + assumeTrue("skipping non AArch64 specific test", target.arch instanceof AArch64); + } + + @Before + public void setupEnvironment() { + base = AArch64.sp; + rt1 = AArch64.r1; + rt2 = AArch64.r2; + } + + private abstract static class AArch64LoadStoreCodeGen { + protected AArch64MacroAssembler masm1; + protected AArch64MacroAssembler masm2; + + AArch64LoadStoreCodeGen() { + TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget(); + masm1 = new AArch64MacroAssembler(target); + masm2 = new AArch64MacroAssembler(target); + } + + void emitScaledImmLdr(int size, Register rt, Register base, int imm12) { + AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12); + masm2.ldr(size, rt, address); + } + + void emitUnscaledImmLdr(int size, Register rt, Register base, int imm9) { + AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9); + masm2.ldr(size, rt, address1); + } + + void emitScaledImmStr(int size, Register rt, Register base, int imm12) { + AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12); + masm2.str(size, rt, address); + } + + void emitUnscaledImmStr(int size, Register rt, Register base, int imm9) { + AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9); + masm2.str(size, rt, address1); + } + + void emitScaledLdp(int size, Register rt1, Register rt2, Register base, int imm7) { + AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7); + masm1.ldp(size, rt1, rt2, mergeAddress); + } + + void emitScaledStp(int size, Register rt1, Register rt2, Register base, int imm7) { + AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7); + masm1.stp(size, rt1, rt2, mergeAddress); + } + + void emitUnscaledLdp(int size, Register rt1, Register rt2, Register base, int imm) { + AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm); + masm1.ldp(size, rt1, rt2, mergeAddress); + } + + void emitUnscaledStp(int size, Register rt1, Register rt2, Register base, int imm) { + AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm); + masm1.stp(size, rt1, rt2, mergeAddress); + } + + abstract void checkAssembly(); + } + + private static class AArch64LoadStoreMergingCodeGen extends AArch64LoadStoreCodeGen { + AArch64LoadStoreMergingCodeGen() { + super(); + } + + @Override + void checkAssembly() { + byte[] expected = masm1.close(false); + byte[] actual = masm2.close(false); + assertArrayEquals(expected, actual); + } + } + + @Test + public void testLoad64BitsScaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmLdr(64, rt1, base, 4); + codeGen.emitScaledImmLdr(64, rt2, base, 5); + codeGen.emitScaledLdp(64, rt1, rt2, base, 4); + codeGen.checkAssembly(); + } + + @Test + public void testLoad32BitsScaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 5); + codeGen.emitScaledImmLdr(32, rt2, base, 4); + codeGen.emitScaledLdp(32, rt2, rt1, base, 4); + codeGen.checkAssembly(); + } + + @Test + public void testStore64BitsScaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmStr(64, rt1, base, 4); + codeGen.emitScaledImmStr(64, rt2, base, 5); + codeGen.emitScaledStp(64, rt1, rt2, base, 4); + codeGen.checkAssembly(); + } + + @Test + public void testStore32BitsScaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmStr(32, rt1, base, 4); + codeGen.emitScaledImmStr(32, rt2, base, 5); + codeGen.emitScaledStp(32, rt1, rt2, base, 4); + codeGen.checkAssembly(); + } + + @Test + public void testLoad64BitsUnscaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmLdr(64, rt1, base, -32); + codeGen.emitUnscaledImmLdr(64, rt2, base, -24); + codeGen.emitUnscaledLdp(64, rt1, rt2, base, -32); + codeGen.checkAssembly(); + } + + @Test + public void testLoad32BitsUnscaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmLdr(32, rt1, base, 248); + codeGen.emitUnscaledImmLdr(32, rt2, base, 252); + codeGen.emitUnscaledLdp(32, rt1, rt2, base, 248); + codeGen.checkAssembly(); + } + + @Test + public void testStore64BitsUnscaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmStr(64, rt1, base, 32); + codeGen.emitUnscaledImmStr(64, rt2, base, 40); + codeGen.emitUnscaledStp(64, rt1, rt2, base, 32); + codeGen.checkAssembly(); + } + + @Test + public void testStore32BitsUnscaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmStr(32, rt1, base, 32); + codeGen.emitUnscaledImmStr(32, rt2, base, 36); + codeGen.emitUnscaledStp(32, rt1, rt2, base, 32); + codeGen.checkAssembly(); + } + + @Test + public void testLoadUnscaledScaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmLdr(32, rt1, base, 48); + codeGen.emitScaledImmLdr(32, rt2, base, 13); + codeGen.emitScaledLdp(32, rt1, rt2, base, 12); + codeGen.checkAssembly(); + } + + @Test + public void testLoadScaledUnscaledImmAddress() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 13); + codeGen.emitUnscaledImmLdr(32, rt2, base, 48); + codeGen.emitUnscaledLdp(32, rt2, rt1, base, 48); + codeGen.checkAssembly(); + } + + @Test + public void testLoadMaxAlignedOffset() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitScaledImmLdr(64, rt1, base, 62); + codeGen.emitScaledImmLdr(64, rt2, base, 63); + codeGen.emitScaledLdp(64, rt1, rt2, base, 62); + codeGen.checkAssembly(); + } + + @Test + public void testStoreMinAlignedOffest() { + AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen(); + codeGen.emitUnscaledImmStr(32, rt1, base, -256); + codeGen.emitUnscaledImmStr(32, rt2, base, -252); + codeGen.emitUnscaledStp(32, rt1, rt2, base, -256); + codeGen.checkAssembly(); + } + + // All the following tests are the negative ones that ldr/str will not be merged to ldp/stp. + private static class AArch64LoadStoreNotMergingCodeGen extends AArch64LoadStoreCodeGen { + AArch64LoadStoreNotMergingCodeGen() { + super(); + } + + @Override + void checkAssembly() { + boolean isMerged = masm2.isImmLoadStoreMerged(); + masm2.close(false); + Assert.assertFalse(isMerged); + } + } + + @Test + public void testDifferentBase() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 4); + codeGen.emitScaledImmLdr(32, rt2, AArch64.r3, 5); + codeGen.checkAssembly(); + } + + @Test + public void testDifferentSize() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 4); + codeGen.emitScaledImmLdr(64, rt2, base, 5); + codeGen.checkAssembly(); + } + + @Test + public void testSameRt() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 4); + codeGen.emitScaledImmLdr(32, rt1, base, 5); + codeGen.checkAssembly(); + } + + @Test + public void testDependencyLdrs() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, rt1, 4); + codeGen.emitScaledImmLdr(32, rt2, rt1, 5); + codeGen.checkAssembly(); + } + + @Test + public void testUnalignedOffset() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitUnscaledImmLdr(32, rt1, base, 34); + codeGen.emitUnscaledImmLdr(32, rt2, base, 38); + codeGen.checkAssembly(); + } + + @Test + public void testUncontinuousOffset() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 4); + codeGen.emitScaledImmLdr(32, rt2, base, 6); + codeGen.checkAssembly(); + } + + @Test + public void testGreaterThanMaxOffset() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 66); + codeGen.emitScaledImmLdr(32, rt2, base, 67); + codeGen.checkAssembly(); + } + + @Test + public void testLdrStr() { + AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen(); + codeGen.emitScaledImmLdr(32, rt1, base, 4); + codeGen.emitScaledImmStr(32, rt2, base, 5); + codeGen.checkAssembly(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index f1fd4367511..f876cbd74e9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -1301,6 +1301,16 @@ private void loadStoreInstruction(Instruction instr, Register reg, AArch64Addres } } + /** + * Insert ldp/stp at the specified position. + */ + protected void insertLdpStp(int size, Instruction instr, Register rt, Register rt2, Register base, int offset, int position) { + InstructionType type = generalFromSize(size); + int scaledOffset = maskField(7, offset); + int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(base) | rt(rt); + emitInt(memop | LoadStorePairOp | (0b010 << 23), position); + } + /** * Load Pair of Registers calculates an address from a base register value and an immediate * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from @@ -1308,7 +1318,7 @@ private void loadStoreInstruction(Instruction instr, Register reg, AArch64Addres */ public void ldp(int size, Register rt, Register rt2, AArch64Address address) { assert size == 32 || size == 64; - loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size)); + loadStorePairInstruction(size, LDP, rt, rt2, address); } /** @@ -1318,15 +1328,24 @@ public void ldp(int size, Register rt, Register rt2, AArch64Address address) { */ public void stp(int size, Register rt, Register rt2, AArch64Address address) { assert size == 32 || size == 64; - loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size)); + loadStorePairInstruction(size, STP, rt, rt2, address); } - private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) { - int scaledOffset = maskField(7, address.getImmediateRaw()); // LDP/STP use a 7-bit scaled - // offset + private void loadStorePairInstruction(int size, Instruction instr, Register rt, Register rt2, AArch64Address address) { + InstructionType type = generalFromSize(size); + // LDP/STP uses a 7-bit scaled offset + int offset = address.getImmediateRaw(); + if (address.getAddressingMode() == AddressingMode.IMMEDIATE_UNSCALED) { + int sizeInBytes = size / Byte.SIZE; + long mask = sizeInBytes - 1; + assert (offset & mask) == 0 : "LDP/STP only supports aligned offset."; + offset = offset / sizeInBytes; + } + int scaledOffset = maskField(7, offset); int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt); switch (address.getAddressingMode()) { case IMMEDIATE_SCALED: + case IMMEDIATE_UNSCALED: emitInt(memop | LoadStorePairOp | (0b010 << 23)); break; case IMMEDIATE_POST_INDEXED: diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java index e38d5750618..a166067c004 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java @@ -35,6 +35,8 @@ import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED; import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED; import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP; import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE; import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX; import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK; @@ -55,6 +57,10 @@ public class AArch64MacroAssembler extends AArch64Assembler { // Points to the next free scratch register private int nextFreeScratchRegister = 0; + // Last immediate ldr/str instruction, which is a candidate to be merged. + private AArch64MemoryEncoding lastImmLoadStoreEncoding; + private boolean isImmLoadStoreMerged = false; + public AArch64MacroAssembler(TargetDescription target) { super(target); } @@ -81,6 +87,43 @@ public ScratchRegister getScratchRegister() { return scratchRegister[nextFreeScratchRegister++]; } + @Override + public void bind(Label l) { + super.bind(l); + // Clear last ldr/str instruction to prevent the labeled ldr/str being merged. + lastImmLoadStoreEncoding = null; + } + + private static class AArch64MemoryEncoding { + private AArch64Address address; + private Register result; + private int sizeInBytes; + private int position; + private boolean isStore; + + AArch64MemoryEncoding(int sizeInBytes, Register result, AArch64Address address, boolean isStore, int position) { + this.sizeInBytes = sizeInBytes; + this.result = result; + this.address = address; + this.isStore = isStore; + this.position = position; + AArch64Address.AddressingMode addressingMode = address.getAddressingMode(); + assert addressingMode == IMMEDIATE_SCALED || addressingMode == IMMEDIATE_UNSCALED : "Invalid address mode" + + "to merge: " + addressingMode; + } + + Register getBase() { + return address.getBase(); + } + + int getOffset() { + if (address.getAddressingMode() == IMMEDIATE_UNSCALED) { + return address.getImmediateRaw(); + } + return address.getImmediate() * sizeInBytes; + } + } + /** * Specifies what actions have to be taken to turn an arbitrary address of the form * {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address. @@ -321,6 +364,132 @@ public void loadAddress(Register dst, AArch64Address address, int transferSize) } } + private boolean tryMerge(int sizeInBytes, Register rt, AArch64Address address, boolean isStore) { + isImmLoadStoreMerged = false; + if (lastImmLoadStoreEncoding == null) { + return false; + } + + // Only immediate scaled/unscaled address can be merged. + // Pre-index and post-index mode can't be merged. + AArch64Address.AddressingMode addressMode = address.getAddressingMode(); + if (addressMode != IMMEDIATE_SCALED && addressMode != IMMEDIATE_UNSCALED) { + return false; + } + + // Only the two adjacent ldrs/strs can be merged. + int lastPosition = position() - 4; + if (lastPosition < 0 || lastPosition != lastImmLoadStoreEncoding.position) { + return false; + } + + if (isStore != lastImmLoadStoreEncoding.isStore) { + return false; + } + + // Only merge ldr/str with the same size of 32bits or 64bits. + if (sizeInBytes != lastImmLoadStoreEncoding.sizeInBytes || (sizeInBytes != 4 && sizeInBytes != 8)) { + return false; + } + + // Base register must be the same one. + Register curBase = address.getBase(); + Register preBase = lastImmLoadStoreEncoding.getBase(); + if (!curBase.equals(preBase)) { + return false; + } + + // If the two ldrs have the same rt register, they can't be merged. + // If the two ldrs have dependence, they can't be merged. + Register curRt = rt; + Register preRt = lastImmLoadStoreEncoding.result; + if (!isStore && (curRt.equals(preRt) || preRt.equals(curBase))) { + return false; + } + + // Offset checking. Offsets of the two ldrs/strs must be continuous. + int curOffset = address.getImmediateRaw(); + if (addressMode == IMMEDIATE_SCALED) { + curOffset = curOffset * sizeInBytes; + } + int preOffset = lastImmLoadStoreEncoding.getOffset(); + if (Math.abs(curOffset - preOffset) != sizeInBytes) { + return false; + } + + // Offset must be in ldp/stp instruction's range. + int offset = curOffset > preOffset ? preOffset : curOffset; + int minOffset = -64 * sizeInBytes; + int maxOffset = 63 * sizeInBytes; + if (offset < minOffset || offset > maxOffset) { + return false; + } + + // Alignment checking. + if (isFlagSet(AArch64.Flag.AvoidUnalignedAccesses)) { + // AArch64 sp is 16-bytes aligned. + if (curBase.equals(sp)) { + long pairMask = sizeInBytes * 2 - 1; + if ((offset & pairMask) != 0) { + return false; + } + } else { + // If base is not sp, we can't guarantee the access is aligned. + return false; + } + } else { + // ldp/stp only supports sizeInBytes aligned offset. + long mask = sizeInBytes - 1; + if ((curOffset & mask) != 0 || (preOffset & mask) != 0) { + return false; + } + } + + // Merge two ldrs/strs to ldp/stp. + Register rt1 = preRt; + Register rt2 = curRt; + if (curOffset < preOffset) { + rt1 = curRt; + rt2 = preRt; + } + int immediate = offset / sizeInBytes; + Instruction instruction = isStore ? STP : LDP; + int size = sizeInBytes * Byte.SIZE; + insertLdpStp(size, instruction, rt1, rt2, curBase, immediate, lastPosition); + lastImmLoadStoreEncoding = null; + isImmLoadStoreMerged = true; + return true; + } + + /** + * Try to merge two continuous ldr/str to one ldp/stp. If this current ldr/str is not merged, + * save it as the last ldr/str. + */ + private boolean tryMergeLoadStore(int srcSize, Register rt, AArch64Address address, boolean isStore) { + int sizeInBytes = srcSize / Byte.SIZE; + if (tryMerge(sizeInBytes, rt, address, isStore)) { + return true; + } + + // Save last ldr/str if it is not merged. + AArch64Address.AddressingMode addressMode = address.getAddressingMode(); + if (addressMode == IMMEDIATE_SCALED || addressMode == IMMEDIATE_UNSCALED) { + if (addressMode == IMMEDIATE_UNSCALED) { + long mask = sizeInBytes - 1; + int offset = address.getImmediateRaw(); + if ((offset & mask) != 0) { + return false; + } + } + lastImmLoadStoreEncoding = new AArch64MemoryEncoding(sizeInBytes, rt, address, isStore, position()); + } + return false; + } + + public boolean isImmLoadStoreMerged() { + return isImmLoadStoreMerged; + } + public void movx(Register dst, Register src) { mov(64, dst, src); } @@ -505,7 +674,7 @@ public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address addres assert targetSize == 32 || targetSize == 64; assert srcSize <= targetSize; if (targetSize == srcSize) { - super.ldr(srcSize, rt, address); + ldr(srcSize, rt, address); } else { super.ldrs(targetSize, srcSize, rt, address); } @@ -521,7 +690,25 @@ public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address addres */ @Override public void ldr(int srcSize, Register rt, AArch64Address address) { - super.ldr(srcSize, rt, address); + // Try to merge two adjacent loads into one ldp. + if (!tryMergeLoadStore(srcSize, rt, address, false)) { + super.ldr(srcSize, rt, address); + } + } + + /** + * Stores register rt into memory pointed by address. + * + * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64. + * @param rt general purpose register. May not be null or stackpointer. + * @param address all addressing modes allowed. May not be null. + */ + @Override + public void str(int destSize, Register rt, AArch64Address address) { + // Try to merge two adjacent stores into one stp. + if (!tryMergeLoadStore(destSize, rt, address, true)) { + super.str(destSize, rt, address); + } } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64PairLoadStoreTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64PairLoadStoreTest.java new file mode 100644 index 00000000000..4063265ae4d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64PairLoadStoreTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Arm Limited and 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. + * + * 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 org.graalvm.compiler.core.aarch64.test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.runtime.JVMCI; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assume.assumeTrue; + +public class AArch64PairLoadStoreTest extends GraalCompilerTest { + + @Before + public void checkAArch64() { + assumeTrue("skipping AArch64 specific test", JVMCI.getRuntime().getHostJVMCIBackend().getTarget().arch instanceof AArch64); + } + + public static long parameterSpill(long v1, long v2, long v3, long v4, long v5, long v6, long v7, long v8, long v9, long v10) { + long value0 = v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8; + long value1 = v9 + v10; + return value0 + value1; + } + + @Test + public void testParameterSpill() { + test("parameterSpill", 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L); + } + + static class A { + static String a = "adsaf"; + + static String b = "asfgsfd"; + + static int c; + + static int d; + } + + public static int pairLoadStaticFields() { + if (A.a == null || A.a != A.b) { + return A.b.length(); + } + return A.a.length(); + } + + @Test + public void testPairLoadStaticFields() { + test("pairLoadStaticFields"); + } + + public static int pairStoreStaticFields(int m, int n) { + A.c = m; + A.d = n; + return A.c + A.d; + } + + @Test + public void testPairStoreStaticFields() { + test("pairStoreStaticFields", 1, 2); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java index a327803c5c4..ad1196c19bf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java @@ -116,6 +116,11 @@ public final ByteBuffer toByteBuffer(ByteBuffer buffer) { return buffer; } + public final byte[] toArray() { + byte[] result = new byte[TypeConversion.asS4(getBytesWritten())]; + return toArray(result); + } + @Override public final void putS1(long value) { long offset = writeOffset(Byte.BYTES); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java index 7146b306d39..3723b748954 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java @@ -190,6 +190,13 @@ protected void handleParsingException(Throwable t) { public boolean shouldVerifyFoldableMethods() { return true; } + + /** + * Makes edits to the list of verifiers to be run. + */ + @SuppressWarnings("unused") + protected void updateVerifiers(List> verifiers) { + } } @Test @@ -304,6 +311,8 @@ public static void runTest(InvariantsTool tool) { verifiers.add(foldableMethodsVerifier); } + tool.updateVerifiers(verifiers); + for (Method m : BadUsageWithEquals.class.getDeclaredMethods()) { ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); try (DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER)) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java index ad66e42514e..21ff4346f1c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java @@ -32,13 +32,11 @@ import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.ConditionalEliminationPhase; import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; import org.graalvm.compiler.phases.common.LoweringPhase; import org.graalvm.compiler.phases.schedule.SchedulePhase; -import org.graalvm.compiler.phases.tiers.HighTierContext; import org.junit.Assert; /** @@ -55,8 +53,8 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest { * code based on method profiles. */ @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } protected void testConditionalElimination(String snippet, String referenceSnippet) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java index fb57c1e1565..b11580a6514 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java @@ -45,7 +45,6 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.tiers.HighTierContext; import org.junit.Test; import jdk.vm.ci.meta.JavaKind; @@ -647,9 +646,9 @@ protected void checkHighTierGraph(StructuredGraph graph) { } @Override - protected HighTierContext getDefaultHighTierContext() { + protected OptimisticOptimizations getOptimisticOptimizations() { // Don't convert unreached paths into Guard - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE); + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } private Object[] argsToBind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java index 94f6c33ead8..d233ca45b1f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java @@ -54,6 +54,7 @@ import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.api.test.ModuleSupport; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.CompilationPrinter; import org.graalvm.compiler.core.GraalCompiler; @@ -126,7 +127,6 @@ import org.graalvm.compiler.runtime.RuntimeProvider; import org.graalvm.compiler.test.AddExports; import org.graalvm.compiler.test.GraalTest; -import org.graalvm.compiler.api.test.ModuleSupport; import org.junit.After; import org.junit.Assert; import org.junit.BeforeClass; @@ -606,11 +606,21 @@ protected final Providers getProviders() { return providers; } - protected HighTierContext getDefaultHighTierContext() { + /** + * Override the {@link OptimisticOptimizations} settings used for the test. This is called for + * all the paths where the value is set so it is the proper place for a test override. Setting + * it in other places can result in inconsistent values being used in other parts of the + * compiler. + */ + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL; + } + + protected final HighTierContext getDefaultHighTierContext() { return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), getOptimisticOptimizations()); } - protected MidTierContext getDefaultMidTierContext() { + protected final MidTierContext getDefaultMidTierContext() { return new MidTierContext(getProviders(), getTargetProvider(), getOptimisticOptimizations(), null); } @@ -1081,10 +1091,6 @@ protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options); } - protected OptimisticOptimizations getOptimisticOptimizations() { - return OptimisticOptimizations.ALL; - } - /** * Compiles a given method. * diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java index adb040adac8..1a89843c329 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java @@ -29,8 +29,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; import org.junit.Test; public class MergeCanonicalizerTest extends GraalCompilerTest { @@ -39,8 +37,8 @@ public class MergeCanonicalizerTest extends GraalCompilerTest { * These tests assume all code paths are reachable so disable profile based dead code removal. */ @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } public static int staticField; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java index 6fe07cceb4d..52c6531d169 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java @@ -33,6 +33,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.TreeSet; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionDescriptors; @@ -54,12 +55,19 @@ */ public class OptionsVerifierTest { + private static Set WHITELIST = new TreeSet<>(Arrays.asList(// + // Generated options delegating default values to PolyglotCompilerOptions + "org.graalvm.compiler.truffle.compiler.SharedTruffleCompilerOptions")); + @Test public void verifyOptions() throws IOException { HashSet> checked = new HashSet<>(); for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) { for (OptionDescriptor desc : opts) { - OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked); + Class descDeclaringClass = desc.getDeclaringClass(); + if (!WHITELIST.contains(descDeclaringClass.getName())) { + OptionsVerifier.checkClass(descDeclaringClass, desc, checked); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java index 064de926a26..82e51665147 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubprocessTest.java @@ -48,7 +48,7 @@ public void launchSubprocess(Runnable runnable) throws InterruptedException, IOE runnable.run(); } else { List vmArgs = withoutDebuggerArguments(getVMCommandLine()); - vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions()); + vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS); vmArgs.add("-D" + recursionPropName + "=true"); configSubprocess(vmArgs); SubprocessUtil.Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java index ca44df79b6d..e840d107068 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java @@ -110,7 +110,7 @@ protected void verify(StructuredGraph graph, CoreProviders context) { } } - private void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList args, ResolvedJavaType stringType, int startArgIdx) { + protected void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList args, ResolvedJavaType stringType, int startArgIdx) { if (callTarget.targetMethod().isVarArgs() && args.get(args.count() - 1) instanceof NewArrayNode) { // unpack the arguments to the var args List unpacked = new ArrayList<>(args.snapshot()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java index 2bdbfc78ecb..2a7f484ace8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -24,14 +24,11 @@ package org.graalvm.compiler.core.test.ea; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.code.SourceStackTraceBailoutException; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Test; public class PEAAssertionsTest extends GraalCompilerTest { @@ -39,8 +36,8 @@ public class PEAAssertionsTest extends GraalCompilerTest { * These tests assume all code paths are reachable so disable profile based dead code removal. */ @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } public static Object field; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java index f4df912b43c..def11c7690c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java @@ -53,6 +53,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Formatter; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedMap; @@ -2161,6 +2162,18 @@ private void printMetrics(PrintStream out, Object compilable, Integer identity, out.println(); } + public Map getMetricsSnapshot() { + Map res = new HashMap<>(); + for (MetricKey key : KeyRegistry.getKeys()) { + int index = ((AbstractKey) key).getIndex(); + if (index < metricValues.length && metricValues[index] != 0) { + long value = metricValues[index]; + res.put(key, value); + } + } + return res; + } + @SuppressWarnings({"unused", "unchecked"}) private static E rethrowSilently(Class type, Throwable ex) throws E { throw (E) ex; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java index 18052d44449..fadf20eead8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -81,7 +81,11 @@ private static boolean isPollingPageFar(GraalHotSpotVMConfig config) { } public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch, LIRFrameState state) { - emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state); + if (config.threadLocalHandshakes) { + emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state); + } else { + emitGlobalPoll(crb, masm, config, onReturn, scratch, state); + } } private static void emitGlobalPoll(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java index 8c158488228..84ec50d6235 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -67,7 +67,12 @@ public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, this.state = state; this.config = config; this.thread = thread; - temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind())); + if (config.threadLocalHandshakes || isPollingPageFar(config) || ImmutableCode.getValue(tool.getOptions())) { + temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind())); + } else { + // Don't waste a register if it's unneeded + temp = Value.ILLEGAL; + } } @Override @@ -76,7 +81,11 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { } public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread, Register scratch) { - emitThreadLocalPoll(crb, asm, config, atReturn, state, thread, scratch); + if (config.threadLocalHandshakes) { + emitThreadLocalPoll(crb, asm, config, atReturn, state, thread, scratch); + } else { + emitGlobalPoll(crb, asm, config, atReturn, state, scratch); + } } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java index 873916e21de..16fe6e0425f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java @@ -106,7 +106,7 @@ public void spawnSubprocess() throws IOException, InterruptedException { List vmArgs = withoutDebuggerArguments(getVMCommandLine()); vmArgs.add("-XX:JVMCICounterSize=1"); vmArgs.add("-Dgraal." + BenchmarkCounters.Options.AbortOnBenchmarkCounterOverflow.getName() + "=true"); - vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions()); + vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS); vmArgs.add("-D" + SUBPROCESS_PROPERTY + "=true"); // Disable increment range checks (e.g. HotSpotCounterOp.checkIncrements()) diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java index 5a7f44ed51a..501b257deb8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -47,7 +47,7 @@ public void checkSPARC() { @Test public void test1() { - testAllocation("test1snippet", 1 , 0, 0); + testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); } public static long test1snippet(long x) { @@ -56,7 +56,7 @@ public static long test1snippet(long x) { @Test public void test2() { - testAllocation("test2snippet", 1, 0, 0); + testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); } public static long test2snippet(long x) { @@ -65,7 +65,7 @@ public static long test2snippet(long x) { @Test public void test3() { - testAllocation("test3snippet", 3, 0, 0); + testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0); } public static long test3snippet(long x) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java index 53b2e318e6c..bb91bbfde69 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -75,7 +75,11 @@ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread, Value safepointPollAddress) { - emitThreadLocalPoll(crb, masm, config, atReturn, state, thread); + if (config.threadLocalHandshakes) { + emitThreadLocalPoll(crb, masm, config, atReturn, state, thread); + } else { + emitGlobalPoll(crb, masm, config, atReturn, state, asRegister(safepointPollAddress)); + } } /** @@ -113,10 +117,19 @@ private static void emitThreadLocalPoll(CompilationResultBuilder crb, SPARCMacro } static AllocatableValue getSafepointAddressValue(SPARCHotSpotLIRGenerator gen) { - return Value.ILLEGAL; + if (gen.config.threadLocalHandshakes) { + return Value.ILLEGAL; + } else { + return gen.newVariable(LIRKind.value(gen.target().arch.getWordKind())); + } } static void emitPrologue(SPARCHotSpotNodeLIRBuilder lir, SPARCHotSpotLIRGenerator gen) { + if (!gen.config.threadLocalHandshakes) { + AllocatableValue var = gen.getSafepointAddressValue(); + lir.append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, gen.config)); + gen.append(((HotSpotDebugInfoBuilder) lir.getDebugInfoBuilder()).lockStack()); + } } public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java index 717c4bc1be8..d80b6813dba 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot.test; -import static org.graalvm.compiler.test.SubprocessUtil.getPackageOpeningOptions; import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; @@ -51,13 +50,6 @@ */ public class CompilationWrapperTest extends GraalCompilerTest { - private static List join(List l1, List l2) { - ArrayList result = new ArrayList<>(l1.size() + l2.size()); - result.addAll(l1); - result.addAll(l2); - return result; - } - /** * Tests compilation requested by the VM. */ @@ -167,11 +159,11 @@ String test() { public void testTruffleCompilation1() throws IOException, InterruptedException { assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), - join(getPackageOpeningOptions(), - Arrays.asList( - "-Dgraal.CompilationFailureAction=ExitVM", - "-Dgraal.TrufflePerformanceWarningsAreFatal=true", - "-Dgraal.CrashAt=root test1")), + Arrays.asList( + SubprocessUtil.PACKAGE_OPENING_OPTIONS, + "-Dgraal.CompilationFailureAction=ExitVM", + "-Dgraal.TrufflePerformanceWarningsAreFatal=true", + "-Dgraal.CrashAt=root test1"), "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); } @@ -184,11 +176,11 @@ public void testTruffleCompilation2() throws IOException, InterruptedException { new Probe("Exiting VM due to TruffleCompilationExceptionsAreFatal=true", 1), }; testHelper(Arrays.asList(probes), - join(getPackageOpeningOptions(), - Arrays.asList( - "-Dgraal.CompilationFailureAction=Silent", - "-Dgraal.TruffleCompilationExceptionsAreFatal=true", - "-Dgraal.CrashAt=root test1")), + Arrays.asList( + SubprocessUtil.PACKAGE_OPENING_OPTIONS, + "-Dgraal.CompilationFailureAction=Silent", + "-Dgraal.TruffleCompilationExceptionsAreFatal=true", + "-Dgraal.CrashAt=root test1"), "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); } @@ -202,11 +194,11 @@ public void testTruffleCompilation3() throws IOException, InterruptedException { new Probe("Exiting VM due to TrufflePerformanceWarningsAreFatal=true", 1), }; testHelper(Arrays.asList(probes), - join(getPackageOpeningOptions(), - Arrays.asList( - "-Dgraal.CompilationFailureAction=Silent", - "-Dgraal.TrufflePerformanceWarningsAreFatal=true", - "-Dgraal.CrashAt=root test1:PermanentBailout")), + Arrays.asList( + SubprocessUtil.PACKAGE_OPENING_OPTIONS, + "-Dgraal.CompilationFailureAction=Silent", + "-Dgraal.TrufflePerformanceWarningsAreFatal=true", + "-Dgraal.CrashAt=root test1:PermanentBailout"), "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java index f1a2e24b5ec..797f7f6cb77 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java @@ -67,12 +67,13 @@ public static void main(String[] args) { @Test public void run() throws IOException, InterruptedException { + Assume.assumeFalse("GR-19833", runtime().getVMConfig().osName.equals("windows")); Assume.assumeTrue(runtime().getVMConfig().enableStackReservedZoneAddress != 0); List vmArgs = SubprocessUtil.withoutDebuggerArguments(SubprocessUtil.getVMCommandLine()); vmArgs.add("-XX:+UseJVMCICompiler"); vmArgs.add("-Dgraal.Inline=false"); vmArgs.add("-XX:CompileCommand=exclude,java/util/concurrent/locks/AbstractOwnableSynchronizer.setExclusiveOwnerThread"); - vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions()); + vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS); // Avoid SOE in HotSpotJVMCIRuntime.adjustCompilationLevel vmArgs.add("-Dgraal.CompileGraalWithC1Only=false"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index 3b0ce94c045..ec8ceb3c2f5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -96,6 +96,7 @@ public CompressEncoding getKlassEncoding() { public final boolean useAESCTRIntrinsics = getFlag("UseAESCTRIntrinsics", Boolean.class, false); public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class); public final boolean useCRC32CIntrinsics = versioned.useCRC32CIntrinsics; + public final boolean threadLocalHandshakes = versioned.threadLocalHandshakes; private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class); private final boolean useSHA1Intrinsics = getFlag("UseSHA1Intrinsics", Boolean.class); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java index 060113501eb..f9203adc8a9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java @@ -89,4 +89,7 @@ final class GraalHotSpotVMConfigVersioned extends HotSpotVMConfigAccess { // JDK-8186777 int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); boolean classMirrorIsHandle = true; + + // JDK-8220049 + boolean threadLocalHandshakes = true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java index 060f5c5e029..2e28edf0ea5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -26,14 +26,11 @@ import java.util.EnumSet; -import jdk.vm.ci.meta.DeoptimizationReason; - -import org.junit.Test; - import org.graalvm.compiler.jtt.JTTTest; import org.graalvm.compiler.phases.OptimisticOptimizations; -import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; -import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Test; + +import jdk.vm.ci.meta.DeoptimizationReason; public class ConditionalElimination02 extends JTTTest { @@ -68,8 +65,8 @@ public int test(A a, boolean isNull, boolean isVeryNull) { * These tests assume all code paths are reachable so disable profile based dead code removal. */ @Override - protected HighTierContext getDefaultHighTierContext() { - return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode); } @Test diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java index f05f65ca1aa..e6fcfc0cc1e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java @@ -255,10 +255,19 @@ abstract static class MemOp extends AArch64LIRInstruction implements StandardOp. @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + int prePosition = masm.position(); + emitMemAccess(crb, masm); if (state != null) { - crb.recordImplicitException(masm.position(), state); + int implicitExceptionPosition = prePosition; + // Adjust implicit exception position if this ldr/str has been merged to ldp/stp. + if (kind.isInteger() && prePosition == masm.position() && masm.isImmLoadStoreMerged()) { + implicitExceptionPosition = prePosition - 4; + if (crb.isImplicitExceptionExist(implicitExceptionPosition)) { + return; + } + } + crb.recordImplicitException(implicitExceptionPosition, state); } - emitMemAccess(crb, masm); } @Override @@ -346,8 +355,17 @@ public NullCheckOp(AArch64AddressValue address, LIRFrameState state) { @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - crb.recordImplicitException(masm.position(), state); + int prePosition = masm.position(); masm.ldr(64, zr, address.toAddress()); + int implicitExceptionPosition = prePosition; + // Adjust implicit exception position if this ldr has been merged to ldp. + if (prePosition == masm.position() && masm.isImmLoadStoreMerged()) { + implicitExceptionPosition = prePosition - 4; + if (crb.isImplicitExceptionExist(implicitExceptionPosition)) { + return; + } + } + crb.recordImplicitException(implicitExceptionPosition, state); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java index 36ed637e369..07816fefc46 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -72,9 +72,7 @@ public MemoryOp(boolean isSigned, int targetSize, int srcSize, AllocatableValue @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } + int prePosition = masm.position(); AArch64Address address = input.toAddress(); Register dst = asRegister(result); if (isSigned) { @@ -82,6 +80,18 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } else { masm.ldr(srcSize, dst, address); } + + if (state != null) { + int implicitExceptionPosition = prePosition; + // Adjust implicit exception position if this ldr/str has been merged to ldp/stp. + if (prePosition == masm.position() && masm.isImmLoadStoreMerged()) { + implicitExceptionPosition = prePosition - 4; + if (crb.isImplicitExceptionExist(implicitExceptionPosition)) { + return; + } + } + crb.recordImplicitException(implicitExceptionPosition, state); + } } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java index eaaa5367ca8..f93942aa700 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java @@ -72,6 +72,7 @@ import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.code.site.ConstantReference; import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.code.site.Infopoint; import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.meta.Constant; @@ -295,6 +296,16 @@ public void recordImplicitException(int pcOffset, LIRFrameState info) { assert info.exceptionEdge == null; } + public boolean isImplicitExceptionExist(int pcOffset) { + List infopoints = compilationResult.getInfopoints(); + for (Infopoint infopoint : infopoints) { + if (infopoint.pcOffset == pcOffset && infopoint.reason == InfopointReason.IMPLICIT_EXCEPTION) { + return true; + } + } + return false; + } + public void recordDirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) { DebugInfo debugInfo = info != null ? info.debugInfo() : null; compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java index 88f1a48e7bb..2a4029593f4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java @@ -160,17 +160,70 @@ public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) } + /** + * Marker to distinguish the reasons for the creation of a loop scope during partial evaluation. + */ + public enum LoopScopeTrigger { + /** + * Start loop scope: creation triggered manually at the beginning of partial evaluation. + */ + START, + + /** + * Loop scope created for the next iteration of a loop if unrolling is enabled in the loop + * explosion mode. See {@link LoopExplosionKind#unrollLoops()} for details. Loop unrolling + * will merge loop end nodes for each iteration of the original loop. + */ + LOOP_BEGIN_UNROLLING, + + /** + * Loop scope created for the next iteration of a loop along a particular loop end node if + * {@link LoopExplosionKind#duplicateLoopEnds()} is enabled and loops are exploded. This + * means for every loop end we duplicate the next loop iteration of the original loop. + */ + LOOP_END_DUPLICATION, + + /** + * Loop scope created for a loop exit node if {@link LoopExplosionKind#duplicateLoopExits()} + * is enabled, i.e., code after a loop exit is duplicated per loop exit node. + * + * Special case nested loops: For compilation units with nested loops where inner loops + * continue loops at a level n -1 the partial evaluation algorithm will merge outer loops to + * avoid loop explosion along loop end nodes (which would be the same as + * {@link #LOOP_END_DUPLICATION}. + */ + LOOP_EXIT_DUPLICATION + } + /** Decoding state maintained for each loop in the encoded graph. */ protected static class LoopScope { public final MethodScope methodScope; public final LoopScope outer; public final int loopDepth; public final int loopIteration; + + /** + * Creation trigger of this particular loop scope, i.e., the reason it was created. + */ + final LoopScopeTrigger trigger; /** - * Upcoming loop iterations during loop explosions that have not been processed yet. Only - * used when {@link MethodScope#loopExplosion} is not {@link LoopExplosionKind#NONE}. + * Upcoming, not yet processed, loop iterations created in the context of code duplication + * along loop exits. Only used when {@link MethodScope#loopExplosion} has + * {@link LoopExplosionKind#duplicateLoopExits()} enabled. */ - public Deque nextIterations; + public Deque nextIterationFromLoopExitDuplication; + /** + * Same as {@link #nextIterationFromLoopExitDuplication} except that upcoming iterations + * have been created because the duplication of loop ends + * {@link LoopExplosionKind#duplicateLoopEnds()} is enabled. + */ + public Deque nextIterationFromLoopEndDuplication; + /** + * Same as {@link #nextIterationFromLoopExitDuplication} except that upcoming iterations + * have been created because the unrolling of a loop with constant iteration count + * {@link LoopExplosionKind#unrollLoops()} is enabled. + */ + public Deque nextIterationsFromUnrolling; /** * Information about already processed loop iterations for state merging during loop * explosion. Only used when {@link MethodScope#loopExplosion} is @@ -196,7 +249,9 @@ protected static class LoopScope { protected LoopScope(MethodScope methodScope) { this.methodScope = methodScope; this.outer = null; - this.nextIterations = methodScope.loopExplosion.duplicateLoopExits() ? new ArrayDeque<>(2) : null; + this.nextIterationFromLoopExitDuplication = methodScope.loopExplosion.duplicateLoopExits() || methodScope.loopExplosion.mergeLoops() ? new ArrayDeque<>(2) : null; + this.nextIterationFromLoopEndDuplication = methodScope.loopExplosion.duplicateLoopEnds() ? new ArrayDeque<>(2) : null; + this.nextIterationsFromUnrolling = methodScope.loopExplosion.unrollLoops() ? new ArrayDeque<>(2) : null; this.loopDepth = 0; this.loopIteration = 0; this.iterationStates = null; @@ -205,15 +260,21 @@ protected LoopScope(MethodScope methodScope) { this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); this.createdNodes = new Node[nodeCount]; this.initialCreatedNodes = null; + this.trigger = LoopScopeTrigger.START; } - protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes, - Deque nextIterations, EconomicMap iterationStates) { + protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, LoopScopeTrigger trigger, Node[] initialCreatedNodes, Node[] createdNodes, + Deque nextIterationFromLoopExitDuplication, + Deque nextIterationFromLoopEndDuplication, + Deque nextIterationsFromUnrolling, EconomicMap iterationStates) { this.methodScope = methodScope; this.outer = outer; this.loopDepth = loopDepth; this.loopIteration = loopIteration; - this.nextIterations = nextIterations; + this.trigger = trigger; + this.nextIterationFromLoopExitDuplication = nextIterationFromLoopExitDuplication; + this.nextIterationFromLoopEndDuplication = nextIterationFromLoopEndDuplication; + this.nextIterationsFromUnrolling = nextIterationsFromUnrolling; this.iterationStates = iterationStates; this.loopBeginOrderId = loopBeginOrderId; this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); @@ -223,7 +284,41 @@ protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int @Override public String toString() { - return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId); + return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId) + " triggered by " + trigger; + } + + /** + * Determines if iterations generated when decoding this loop have yet to be processed. + * + * @return {@code true} if there are iterations to be decoded, {@code false} else + */ + public boolean hasIterationsToProcess() { + return nextIterationFromLoopEndDuplication != null && !nextIterationFromLoopEndDuplication.isEmpty() || + nextIterationFromLoopExitDuplication != null && !nextIterationFromLoopExitDuplication.isEmpty() || + nextIterationsFromUnrolling != null && !nextIterationsFromUnrolling.isEmpty(); + } + + /** + * Return the next iteration yet to be processed that has been created in the context of + * decoding this loop scope. + * + * @param remove determines if the query of the next iteration should remove it from the + * list of iterations to be processed + * @return the next {@link LoopScope} to be processed that has been created in the context + * of decoding this loop scope. Note that the order is not necessarily reflecting + * the number of loop iterations. + */ + public LoopScope getNextIterationToProcess(boolean remove) { + if (nextIterationFromLoopEndDuplication != null && !nextIterationFromLoopEndDuplication.isEmpty()) { + return remove ? nextIterationFromLoopEndDuplication.removeFirst() : nextIterationFromLoopEndDuplication.peekFirst(); + } + if (nextIterationFromLoopExitDuplication != null && !nextIterationFromLoopExitDuplication.isEmpty()) { + return remove ? nextIterationFromLoopExitDuplication.removeFirst() : nextIterationFromLoopExitDuplication.peekFirst(); + } + if (nextIterationsFromUnrolling != null && !nextIterationsFromUnrolling.isEmpty()) { + return remove ? nextIterationsFromUnrolling.removeFirst() : nextIterationsFromUnrolling.peekFirst(); + } + return null; } } @@ -408,7 +503,6 @@ protected final void decode(LoopScope initialLoopScope) { /* Process loops of method. */ while (loopScope != null) { - /* Process nodes of loop. */ while (!loopScope.nodesToProcess.isEmpty()) { loopScope = processNextNode(methodScope, loopScope); @@ -419,10 +513,8 @@ protected final void decode(LoopScope initialLoopScope) { } /* Finished with a loop. */ - if (loopScope.nextIterations != null && !loopScope.nextIterations.isEmpty()) { - /* Loop explosion: process the loop iteration. */ - assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1; - loopScope = loopScope.nextIterations.removeFirst(); + if (loopScope.hasIterationsToProcess()) { + loopScope = loopScope.getNextIterationToProcess(true); } else { propagateCreatedNodes(loopScope); loopScope = loopScope.outer; @@ -461,18 +553,34 @@ private static void propagateCreatedNodes(LoopScope loopScope) { } } + public static final boolean DUMP_DURING_FIXED_NODE_PROCESSING = false; + protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) { int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0); loopScope.nodesToProcess.clear(nodeOrderId); FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId); + if (node.isDeleted()) { return loopScope; } - + if (DUMP_DURING_FIXED_NODE_PROCESSING) { + if (node != null) { + try { + debug.dump(DebugContext.DETAILED_LEVEL, graph, "Before processing node %s", node); + } catch (Throwable t) { + // swallow here, dumping uninitialized nodes can cause problems + } + } + } if ((node instanceof MergeNode || - (node instanceof LoopBeginNode && (methodScope.loopExplosion.unrollLoops() && !methodScope.loopExplosion.mergeLoops()))) && + (node instanceof LoopBeginNode && (methodScope.loopExplosion.unrollLoops() && + !methodScope.loopExplosion.mergeLoops()))) && ((AbstractMergeNode) node).forwardEndCount() == 1) { + /* + * In case node is a loop begin and we are unrolling loops we remove the loop begin + * since the loop will be gone after PE. + */ AbstractMergeNode merge = (AbstractMergeNode) node; EndNode singleEnd = merge.forwardEndAt(0); @@ -498,10 +606,15 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope * of the inner loop. */ LoopScope outerScope = loopScope.outer; - int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1; - successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, + int nextIterationNumber = outerScope.nextIterationFromLoopExitDuplication.isEmpty() ? outerScope.loopIteration + 1 + : outerScope.nextIterationFromLoopExitDuplication.getLast().loopIteration + 1; + successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, LoopScopeTrigger.LOOP_EXIT_DUPLICATION, outerScope.initialCreatedNodes == null ? null : Arrays.copyOf(outerScope.initialCreatedNodes, outerScope.initialCreatedNodes.length), - Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates); + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), + outerScope.nextIterationFromLoopExitDuplication, + outerScope.nextIterationFromLoopEndDuplication, + outerScope.nextIterationsFromUnrolling, + outerScope.iterationStates); checkLoopExplosionIteration(methodScope, successorAddScope); /* @@ -513,7 +626,7 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope successorAddScope.createdNodes[id] = null; } - outerScope.nextIterations.addLast(successorAddScope); + outerScope.nextIterationFromLoopExitDuplication.addLast(successorAddScope); } else { successorAddScope = loopScope.outer; } @@ -542,27 +655,91 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope } else if (node instanceof MergeNode) { handleMergeNode(((MergeNode) node)); - } else if (node instanceof AbstractEndNode) { LoopScope phiInputScope = loopScope; LoopScope phiNodeScope = loopScope; + int mergeOrderId = readOrderId(methodScope); - if (methodScope.loopExplosion.useExplosion() && node instanceof LoopEndNode) { - node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node); - phiNodeScope = loopScope.nextIterations.getLast(); - } + boolean requiresMergeOfOuterLoop = methodScope.loopExplosion.unrollLoops() && + methodScope.loopExplosion.duplicateLoopExits() && + (!methodScope.loopExplosion.duplicateLoopEnds()) && + (!methodScope.loopExplosion.mergeLoops()) && + node instanceof LoopEndNode && + loopScope.trigger == LoopScopeTrigger.LOOP_EXIT_DUPLICATION; + + if (requiresMergeOfOuterLoop) { + EndNode replacementNode = graph.add(new EndNode()); + node.replaceAtPredecessor(replacementNode); + node.safeDelete(); + node = replacementNode; + /* + * We are in a loop exit duplicated loop scope and see a loop end node, this can + * only happen if we have a loop end to an outer loop. When duplicating over loop + * exits we have to merge outer loops for nested inner loops. + * + * Therefore, we create a correct outer loop iteration and check if there is already + * one, if not we create it else we re-use it. + */ + if (loopScope.nextIterationsFromUnrolling.isEmpty()) { + // create it + int nextIterationNumber = loopScope.nextIterationsFromUnrolling.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterationsFromUnrolling.getLast().loopIteration + 1; + LoopScope outerLoopMergeScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, + LoopScopeTrigger.LOOP_BEGIN_UNROLLING, + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), + loopScope.nextIterationFromLoopExitDuplication, + loopScope.nextIterationFromLoopEndDuplication, + loopScope.nextIterationsFromUnrolling, + loopScope.iterationStates); + checkLoopExplosionIteration(methodScope, outerLoopMergeScope); + loopScope.nextIterationsFromUnrolling.addLast(outerLoopMergeScope); + registerNode(outerLoopMergeScope, loopScope.loopBeginOrderId, null, true, true); + makeStubNode(methodScope, outerLoopMergeScope, loopScope.loopBeginOrderId); + phiNodeScope = outerLoopMergeScope; + } else { + // re-use it + phiNodeScope = loopScope.nextIterationsFromUnrolling.getLast(); + } - int mergeOrderId = readOrderId(methodScope); + } else if (methodScope.loopExplosion.useExplosion() && node instanceof LoopEndNode) { + EndNode replacementNode = graph.add(new EndNode()); + node.replaceAtPredecessor(replacementNode); + node.safeDelete(); + node = replacementNode; + LoopScopeTrigger trigger = handleLoopExplosionEnd(methodScope, loopScope); + Deque phiScope = loopScope.nextIterationsFromUnrolling; + if (trigger == LoopScopeTrigger.LOOP_END_DUPLICATION) { + phiScope = loopScope.nextIterationFromLoopEndDuplication; + } + phiNodeScope = phiScope.getLast(); + } AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId); if (merge == null) { merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId); - if (merge instanceof LoopBeginNode) { + /* + * In contrast to the LoopScopeTrigger.START created at the beginning of every + * PE, we see a real loop here and create the first real loop scope associated + * with a loop. + * + * Creation of a loop scope if we reach a loop begin node. We process a loop + * begin node (always before encountering a loop end associated with the loop + * begin) and simply create a normal loop scope. This does not imply an advanced + * unrolling strategy (however it can later if we see duplicate over loop end or + * exits). Therefore, we still use the start marker here, we could also use the + * unrolling marker. + * + * If we unroll loops we will later remove the loop begin node and replace it + * with its forward end (since we do not need to create a loop begin node if we + * unroll the entire loop and it has a constant trip count). + */ assert phiNodeScope == phiInputScope && phiNodeScope == loopScope; - resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId, + resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId, LoopScopeTrigger.START, methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null, methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, // - methodScope.loopExplosion.useExplosion() ? new ArrayDeque<>(2) : null, // + methodScope.loopExplosion.duplicateLoopExits() || methodScope.loopExplosion.mergeLoops() ? new ArrayDeque<>(2) : null, + methodScope.loopExplosion.duplicateLoopEnds() ? new ArrayDeque<>(2) : null, + methodScope.loopExplosion.unrollLoops() ? new ArrayDeque<>(2) : null, // methodScope.loopExplosion.mergeLoops() ? EconomicMap.create(Equivalence.DEFAULT) : null); phiInputScope = resultScope; phiNodeScope = resultScope; @@ -574,9 +751,7 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope resultScope.nodesToProcess.set(mergeOrderId); } } - handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge); - } else if (node instanceof Invoke) { InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node); resultScope = handleInvoke(methodScope, loopScope, invokeData); @@ -585,7 +760,15 @@ protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope } else { handleFixedNode(methodScope, loopScope, nodeOrderId, node); } - + if (DUMP_DURING_FIXED_NODE_PROCESSING) { + if (node != null) { + try { + debug.dump(DebugContext.DETAILED_LEVEL, graph, "After processing node %s", node); + } catch (Throwable t) { + // swallow here, dumping uninitialized nodes can cause problems + } + } + } return resultScope; } @@ -738,23 +921,44 @@ protected void checkLoopExplosionIteration(MethodScope methodScope, LoopScope lo throw shouldNotReachHere("when subclass uses loop explosion, it needs to implement this method"); } - protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) { - EndNode replacementNode = graph.add(new EndNode()); - loopEnd.replaceAtPredecessor(replacementNode); - loopEnd.safeDelete(); - - assert methodScope.loopExplosion.useExplosion(); - if (methodScope.loopExplosion.duplicateLoopEnds() || loopScope.nextIterations.isEmpty()) { - int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1; - LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, + protected LoopScopeTrigger handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope) { + /* + * This method is only called if we reach a loop end and we use some kind of loop explosion, + * i.e., we unroll loops or explode along loop ends. + */ + LoopScopeTrigger trigger = null; + Deque nextIterations = null; + if (methodScope.loopExplosion.duplicateLoopEnds()) { + /* + * Loop explosion along loop ends: We see a loop end, however we do not merge all loop + * ends at a common merge node but rather duplicate the rest of the loop for every loop + * end. + */ + trigger = LoopScopeTrigger.LOOP_END_DUPLICATION; + nextIterations = loopScope.nextIterationFromLoopEndDuplication; + } else if (loopScope.nextIterationsFromUnrolling.isEmpty()) { + /* + * Regular loop unrolling, i.e., we reach a loop end node of a loop that should be + * unrolled: We create a new successor scope. + */ + trigger = LoopScopeTrigger.LOOP_BEGIN_UNROLLING; + nextIterations = loopScope.nextIterationsFromUnrolling; + } + if (trigger != null) { + int nextIterationNumber = nextIterations.isEmpty() ? loopScope.loopIteration + 1 : nextIterations.getLast().loopIteration + 1; + LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, trigger, + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), - Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates); + loopScope.nextIterationFromLoopExitDuplication, + loopScope.nextIterationFromLoopEndDuplication, + loopScope.nextIterationsFromUnrolling, + loopScope.iterationStates); checkLoopExplosionIteration(methodScope, nextIterationScope); - loopScope.nextIterations.addLast(nextIterationScope); + nextIterations.addLast(nextIterationScope); registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true); makeStubNode(methodScope, nextIterationScope, loopScope.loopBeginOrderId); } - return replacementNode; + return trigger; } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java index 94bd3274ad0..0adff5458dd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java @@ -117,7 +117,7 @@ public void test() throws Throwable { } else { List vmArgs = withoutDebuggerArguments(getVMCommandLine()); vmArgs.add("-D" + recursionPropName + "=true"); - vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions()); + vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS); vmArgs.add("-Djdk.attach.allowAttachSelf=true"); Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName()); if (proc.exitCode != 0) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java index 931a1031433..a43cf81e46b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java @@ -49,7 +49,7 @@ public class Classfile { private final List codeAttributes; private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7 - private static final int MAJOR_VERSION_JAVA_MAX = 58; // JDK14 + private static final int MAJOR_VERSION_JAVA_MAX = 59; // JDK15 private static final int MAGIC = 0xCAFEBABE; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java index ad3533942c5..cec3b407eac 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Formatter; @@ -47,6 +49,14 @@ */ public final class SubprocessUtil { + /** + * The name of the boolean system property that can be set to preserve temporary files created + * as arguments files passed to the java launcher. + * + * @see "https://docs.oracle.com/javase/9/tools/java.htm#JSWOR-GUID-4856361B-8BFD-4964-AE84-121F5F6CF111" + */ + public static final String KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME = "test." + SubprocessUtil.class.getSimpleName() + ".keepTempArgumentFiles"; + private SubprocessUtil() { } @@ -184,8 +194,14 @@ public static class Subprocess { */ public final List output; - public Subprocess(List command, int exitCode, List output) { + /** + * Explicit environment variables. + */ + private Map env; + + public Subprocess(List command, Map env, int exitCode, List output) { this.command = command; + this.env = env; this.exitCode = exitCode; this.output = output; } @@ -202,6 +218,13 @@ public String toString(String delimiter) { if (delimiter != null) { msg.format("%s%n", delimiter); } + if (env != null && !env.isEmpty()) { + msg.format("env"); + for (Map.Entry e : env.entrySet()) { + msg.format(" %s=%s", e.getKey(), quoteShellArg(e.getValue())); + } + msg.format("\\%n"); + } msg.format("%s%n", CollectionsUtil.mapAndJoin(command, e -> quoteShellArg(String.valueOf(e)), " ")); for (String line : output) { msg.format("%s%n", line); @@ -222,6 +245,14 @@ public String toString() { } } + /** + * A sentinel value which when present in the {@code vmArgs} parameter for any of the + * {@code java(...)} methods in this class is replaced with a temporary argument file containing + * the contents of {@link #getPackageOpeningOptions}. The argument file is preserved if the + * {@link #KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME} system property is true. + */ + public static final String PACKAGE_OPENING_OPTIONS = ";:PACKAGE_OPENING_OPTIONS_IN_TEMPORARY_ARGUMENTS_FILE:;"; + /** * Executes a Java subprocess. * @@ -272,7 +303,22 @@ public static Subprocess java(List vmArgs, Map env, List * @param mainClassAndArgs the main class and its arguments */ private static Subprocess javaHelper(List vmArgs, Map env, List mainClassAndArgs) throws IOException, InterruptedException { - List command = new ArrayList<>(vmArgs); + List command = new ArrayList<>(vmArgs.size()); + Path packageOpeningOptionsArgumentsFile = null; + for (String vmArg : vmArgs) { + if (vmArg == PACKAGE_OPENING_OPTIONS) { + if (packageOpeningOptionsArgumentsFile == null) { + List packageOpeningOptions = getPackageOpeningOptions(); + if (!packageOpeningOptions.isEmpty()) { + packageOpeningOptionsArgumentsFile = Files.createTempFile(Paths.get("."), "package-opening-options-arguments-file", ".txt").toAbsolutePath(); + Files.write(packageOpeningOptionsArgumentsFile, packageOpeningOptions); + command.add("@" + packageOpeningOptionsArgumentsFile); + } + } + } else { + command.add(vmArg); + } + } command.addAll(mainClassAndArgs); ProcessBuilder processBuilder = new ProcessBuilder(command); if (env != null) { @@ -280,14 +326,22 @@ private static Subprocess javaHelper(List vmArgs, Map en processBuilderEnv.putAll(env); } processBuilder.redirectErrorStream(true); - Process process = processBuilder.start(); - BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line; - List output = new ArrayList<>(); - while ((line = stdout.readLine()) != null) { - output.add(line); + try { + Process process = processBuilder.start(); + BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + List output = new ArrayList<>(); + while ((line = stdout.readLine()) != null) { + output.add(line); + } + return new Subprocess(command, env, process.waitFor(), output); + } finally { + if (packageOpeningOptionsArgumentsFile != null) { + if (!Boolean.getBoolean(KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME)) { + Files.delete(packageOpeningOptionsArgumentsFile); + } + } } - return new Subprocess(command, process.waitFor(), output); } private static final boolean isJava8OrEarlier = JavaVersionUtil.JAVA_SPEC <= 8;