diff --git a/ci/ci_common/ci-check.libsonnet b/ci/ci_common/ci-check.libsonnet index 4f945e78b482..0ae1ad090fb3 100644 --- a/ci/ci_common/ci-check.libsonnet +++ b/ci/ci_common/ci-check.libsonnet @@ -3,7 +3,7 @@ local std_get = (import 'common-utils.libsonnet').std_get; { # check that all non [gate, ondemand] entries have notify_emails or notify_groups defined local missing_notify(builds) = { - [x.name]: std_get(x, "defined_in") for x in builds if !std.objectHas(x, "notify_emails") && !std.objectHasAll(x, "notify_groups") && (std.member(x.targets, "daily") || std.member(x.targets, "weekly") || std.member(x.targets, "monthly")) + [x.name]: std_get(x, "defined_in") for x in builds if !std.objectHas(x, "notify_emails") && !std.objectHasAll(x, "notify_groups") && std.length(std.setInter(std.set(x.targets), std.set(["daily", "weekly", "monthly", "post-merge", "opt-post-merge"]))) != 0 }, verify_ci(builds):: diff --git a/ci/ci_common/common-utils.libsonnet b/ci/ci_common/common-utils.libsonnet index 19bc64d3d9bc..673bb3865830 100644 --- a/ci/ci_common/common-utils.libsonnet +++ b/ci/ci_common/common-utils.libsonnet @@ -26,6 +26,11 @@ else build, + # Adds a 'defined_in' key to all jobs in the list. + # Due to the nature of std.thisFile, the file name has to be explicitly passed. + # Usage: add_defined_in(builds, std.thisFile) + add_defined_in(builds, file):: [{ defined_in: file } + b for b in builds], + # Returns true if `str` contains `needle` as a substring. contains(str, needle):: std.findSubstr(needle, str) != [], diff --git a/ci_includes/publish-javadoc.jsonnet b/ci_includes/publish-javadoc.jsonnet index a64e0eef6eaa..65be4f0c8f89 100644 --- a/ci_includes/publish-javadoc.jsonnet +++ b/ci_includes/publish-javadoc.jsonnet @@ -62,5 +62,5 @@ common.post_merge + linux_amd64 + common.labsjdk21 + javadoc_publisher, ], // adds a "defined_in" field to all builds mentioning the location of this current file - builds:: [{ defined_in: std.thisFile } + b for b in all_builds] + builds:: utils.add_defined_in(all_builds, std.thisFile), } diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index b9e21d5a688c..71408f6e67e8 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -1,5 +1,6 @@ { local c = (import '../../../ci/ci_common/common.jsonnet'), + local utils = (import '../../../ci/ci_common/common-utils.libsonnet'), local bc = (import '../../../ci/ci_common/bench-common.libsonnet'), local cc = (import 'compiler-common.libsonnet'), local bench = (import 'benchmark-suites.libsonnet'), @@ -91,5 +92,5 @@ local all_builds = main_builds + weekly_amd64_forks_builds + weekly_aarch64_forks_builds + profiling_builds + avx_builds + zgc_builds + zgc_avx_builds + aarch64_builds + no_tiered_builds + no_profile_info_builds, local filtered_builds = [b for b in all_builds if b.is_jdk_supported(b.jdk_version) && b.is_arch_supported(b.arch)], // adds a "defined_in" field to all builds mentioning the location of this current file - builds:: [{ defined_in: std.thisFile } + b for b in filtered_builds] + builds:: utils.add_defined_in(filtered_builds, std.thisFile), } diff --git a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet index 16f6b468064a..57f4c503cfb3 100644 --- a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet +++ b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet @@ -1,5 +1,6 @@ { local c = (import '../../../ci/ci_common/common.jsonnet'), + local utils = (import '../../../ci/ci_common/common-utils.libsonnet'), local bc = (import '../../../ci/ci_common/bench-common.libsonnet'), local cc = (import '../ci_common/compiler-common.libsonnet'), local bench = (import '../ci_common/benchmark-suites.libsonnet'), @@ -79,5 +80,5 @@ local filtered_builds = [b for b in all_builds if b.is_jdk_supported(b.jdk_version) && b.is_arch_supported(b.arch)], // adds a "defined_in" field to all builds mentioning the location of this current file - builds:: [{ defined_in: std.thisFile } + b for b in filtered_builds] + builds:: utils.add_defined_in(filtered_builds, std.thisFile), } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest11.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest11.java index c081a0c660bb..a2d8b841a632 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest11.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest11.java @@ -126,7 +126,7 @@ public void test5() { public static int test6Snippet(int a) { if ((a & 8) != 0) { - GraalDirectives.deoptimize(); + GraalDirectives.deoptimizeAndInvalidate(); } if ((a & 15) != 15) { GraalDirectives.deoptimize(); @@ -135,8 +135,11 @@ public static int test6Snippet(int a) { } public static int reference6Snippet(int a) { + /* + * first guard needs higher priority than second guard, otherwise code folds to second guard + */ if ((a & 8) != 0) { - GraalDirectives.deoptimize(); + GraalDirectives.deoptimizeAndInvalidate(); } GraalDirectives.deoptimize(); return 0; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest9.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest9.java index 5e7c6f178b68..b3b208bdf426 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest9.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ConditionalEliminationTest9.java @@ -27,8 +27,6 @@ import jdk.graal.compiler.phases.common.ConditionalEliminationPhase; import org.junit.Test; -import jdk.graal.compiler.api.directives.GraalDirectives; - /** * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs * in this phase. @@ -40,7 +38,7 @@ public class ConditionalEliminationTest9 extends ConditionalEliminationTestBase @SuppressWarnings("all") public static int referenceSnippet(int a) { if (a == 0) { - GraalDirectives.deoptimize(); + return 1; } return 0; } @@ -54,10 +52,10 @@ public void test1() { public static int test1Snippet(int a) { if (a == 0) { if (a == 0) { - GraalDirectives.deoptimize(); + return 1; } if (a == 0) { - GraalDirectives.deoptimize(); + return 2; } } return 0; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java index b28fb68a3d20..446e2aa13d9e 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java @@ -136,6 +136,7 @@ import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.runtime.RuntimeProvider; import jdk.graal.compiler.test.GraalTest; +import jdk.graal.compiler.loop.phases.SpeculativeGuardMovementPhase; import org.junit.After; import org.junit.Assert; import org.junit.BeforeClass; @@ -283,6 +284,8 @@ protected Suites createSuites(OptionValues opts) { ret.getHighTier().removeSubTypePhases(Speculative.class); ret.getMidTier().removeSubTypePhases(Speculative.class); ret.getLowTier().removeSubTypePhases(Speculative.class); + // remove after GR-49600 is resolved: + ret.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); } ListIterator> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/HashCodeTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/HashCodeTest.java index cc823e482e95..fe55951e4176 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/HashCodeTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/HashCodeTest.java @@ -24,13 +24,13 @@ */ package jdk.graal.compiler.core.test; -import jdk.graal.compiler.core.phases.HighTier; -import jdk.graal.compiler.core.phases.MidTier; import jdk.graal.compiler.nodes.InvokeNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.tiers.MidTierContext; +import jdk.graal.compiler.phases.tiers.Suites; + import org.junit.Assert; import org.junit.Test; @@ -120,8 +120,9 @@ public void test06() { private StructuredGraph buildGraphAfterMidTier(String name) { StructuredGraph g = parseForCompile(getResolvedJavaMethod(name)); OptionValues options = getInitialOptions(); - new HighTier(options).apply(g, getDefaultHighTierContext()); - new MidTier(options).apply(g, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, g.getProfilingInfo())); + Suites suites = createSuites(options); + suites.getHighTier().apply(g, getDefaultHighTierContext()); + suites.getMidTier().apply(g, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, g.getProfilingInfo())); return g; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/Base64SubstitutionsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/Base64SubstitutionsTest.java index c11d10acdcdb..7a5662149e06 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/Base64SubstitutionsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/Base64SubstitutionsTest.java @@ -38,9 +38,6 @@ import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; - -import jdk.graal.compiler.core.common.GraalOptions; -import jdk.graal.compiler.options.OptionValues; import org.junit.Assert; import org.junit.Test; @@ -141,20 +138,6 @@ public void testEncodeByteArray1() { } } - /** - * The test at - * https://github.com/openjdk/jdk/blob/f2922682688a40529df269e1551246ac8da5d7ee/src/java.base/share/classes/java/util/Base64.java#L878 - * is converted to a guard and (too eagerly) floated outside the loop, leading to deopt even - * when the input byte array has a correct ending. - * - * GR-48430. - */ - private static OptionValues workaroundTooEagerDeopt() { - return new OptionValues(getInitialOptions(), - GraalOptions.OptConvertDeoptsToGuards, false, - GraalOptions.SpeculativeGuardMovement, false); - } - /** * Tests {@link Encoder#encode(byte[], byte[])}. */ @@ -297,7 +280,6 @@ public void testDecodeByteArray1() { */ @Test public void testDecodeByteArray2() { - OptionValues options = workaroundTooEagerDeopt(); ResolvedJavaMethod m = getResolvedJavaMethod(Decoder.class, "decode", byte[].class, byte[].class); for (DecoderTestCase tc : getDecoders()) { for (int i = 0; i < PLAIN_TEXT_BYTES.length; i++) { @@ -305,7 +287,7 @@ public void testDecodeByteArray2() { // JDK-8273108: Test for output buffer overrun byte[] suffix = {0, (byte) 167}; ByteArraySupplier bas = new ByteArraySupplier(srcBytes.length, suffix); - test(options, m, tc.decoder, srcBytes, bas); + test(m, tc.decoder, srcBytes, bas); Assert.assertEquals(bas.supplied.size(), 2); byte[] expect = Arrays.copyOfRange(bas.supplied.get(0), 0, srcBytes.length); byte[] actual = Arrays.copyOfRange(bas.supplied.get(1), 0, srcBytes.length); @@ -328,12 +310,11 @@ public static byte[] decodeByteBufferSnippet(Decoder decoder, ByteBuffer srcBuf) */ @Test public void testDecodeByteBuffer() { - OptionValues options = workaroundTooEagerDeopt(); for (DecoderTestCase tc : getDecoders()) { for (int i = 0; i < PLAIN_TEXT_BYTES.length; i++) { byte[] srcBytes = tc.encoded[i]; ByteBuffer srcBuf = ByteBuffer.wrap(srcBytes); - test(options, "decodeByteBufferSnippet", tc.decoder, srcBuf); + test("decodeByteBufferSnippet", tc.decoder, srcBuf); } } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/IfNodeCanonicalizationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/IfNodeCanonicalizationTest.java index 1a4061e2f6a9..57730d3959fc 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/IfNodeCanonicalizationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/IfNodeCanonicalizationTest.java @@ -24,7 +24,6 @@ */ package jdk.graal.compiler.nodes.test; -import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; @@ -123,10 +122,10 @@ public void test4() { public boolean testSnippet4(int a, int[] limit) { int l = limit.length; if (a < 0) { - GraalDirectives.deoptimize(); + return false; } if (a >= l) { - GraalDirectives.deoptimize(); + return false; } return true; } @@ -140,10 +139,10 @@ public void test5() { public boolean testSnippet5(int a, int[] limit) { int l = limit.length; if (a >= l) { - GraalDirectives.deoptimize(); + return false; } if (a < 0) { - GraalDirectives.deoptimize(); + return false; } return true; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TransferToInterpreterTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TransferToInterpreterTest.java index 6d33bfb5363f..f111e5fd5ce4 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TransferToInterpreterTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TransferToInterpreterTest.java @@ -90,7 +90,8 @@ public Object execute(VirtualFrame frame) { int x = (int) frame.getArguments()[0]; if (x == 0) { CompilerDirectives.transferToInterpreter(); - } else { + } + if (x == 1) { CompilerDirectives.transferToInterpreterAndInvalidate(); } return null; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/Stub.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/Stub.java index 698563930261..a8c93e302528 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/Stub.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/Stub.java @@ -61,6 +61,8 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.PhaseSuite; import jdk.graal.compiler.phases.Speculative; +import jdk.graal.compiler.loop.phases.SpeculativeGuardMovementPhase; +import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; @@ -321,6 +323,8 @@ protected Suites createSuites() { defaultSuites.getMidTier().removeSubTypePhases(Speculative.class); defaultSuites.getLowTier().removeSubTypePhases(Speculative.class); + // remove after GR-49600 is resolved: + defaultSuites.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); return new Suites(emptyHighTier, defaultSuites.getMidTier(), defaultSuites.getLowTier()); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java index 71d2709a4190..ac192632fdd6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java @@ -110,9 +110,6 @@ protected void run(final StructuredGraph graph, final CoreProviders context) { for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) { assert d.isAlive(); - if (!d.canFloat()) { - continue; - } try (DebugCloseable closable = d.withNodeSourcePosition()) { propagateFixed(d, d, context, lazyLoops); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/SpeculativeGuardMovementPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/SpeculativeGuardMovementPhase.java index 14a1e889fc68..6052577de895 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/SpeculativeGuardMovementPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/SpeculativeGuardMovementPhase.java @@ -122,8 +122,19 @@ */ public class SpeculativeGuardMovementPhase extends PostRunCanonicalizationPhase implements FloatingGuardPhase { + private final boolean ignoreFrequency; + private final boolean requireSpeculationLog; + public SpeculativeGuardMovementPhase(CanonicalizerPhase canonicalizer) { super(canonicalizer); + this.ignoreFrequency = false; + this.requireSpeculationLog = true; + } + + public SpeculativeGuardMovementPhase(CanonicalizerPhase canonicalizer, boolean ignoreFrequency, boolean requireSpeculationLog) { + super(canonicalizer); + this.ignoreFrequency = ignoreFrequency; + this.requireSpeculationLog = requireSpeculationLog; } @Override @@ -158,7 +169,7 @@ protected void run(StructuredGraph graph, MidTierContext context) { } LoopsData loops = context.getLoopsDataProvider().getLoopsData(graph); loops.detectCountedLoops(); - iterate = performSpeculativeGuardMovement(context, graph, loops); + iterate = performSpeculativeGuardMovement(context, graph, loops, ignoreFrequency, requireSpeculationLog); } if (change.getNodes().isEmpty() || !iterate) { break; @@ -174,20 +185,21 @@ public void updateGraphState(GraphState graphState) { } public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops) { - return performSpeculativeGuardMovement(context, graph, loops, null, false); + return performSpeculativeGuardMovement(context, graph, loops, null, false, true); } - public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops, boolean ignoreFrequency) { - return performSpeculativeGuardMovement(context, graph, loops, null, ignoreFrequency); + public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops, boolean ignoreFrequency, boolean requireSpeculationLog) { + return performSpeculativeGuardMovement(context, graph, loops, null, ignoreFrequency, requireSpeculationLog); } public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops, NodeBitMap toProcess) { - return performSpeculativeGuardMovement(context, graph, loops, toProcess, false); + return performSpeculativeGuardMovement(context, graph, loops, toProcess, false, true); } - public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops, NodeBitMap toProcess, boolean ignoreFrequency) { + public static boolean performSpeculativeGuardMovement(MidTierContext context, StructuredGraph graph, LoopsData loops, NodeBitMap toProcess, boolean ignoreFrequency, + boolean requireSpeculationLog) { SpeculativeGuardMovement spec = new SpeculativeGuardMovement(loops, graph.createNodeMap(), graph, context.getProfilingInfo(), graph.getSpeculationLog(), toProcess, - ignoreFrequency); + ignoreFrequency, requireSpeculationLog); spec.run(); return spec.iterate; } @@ -204,11 +216,12 @@ private static class SpeculativeGuardMovement implements Runnable { private final NodeBitMap toProcess; SpeculativeGuardMovement(LoopsData loops, NodeMap earliestCache, StructuredGraph graph, ProfilingInfo profilingInfo, SpeculationLog speculationLog, NodeBitMap toProcess, - boolean ignoreFrequency) { + boolean ignoreFrequency, boolean requireSpeculationLog) { this.loops = loops; this.earliestCache = earliestCache; this.graph = graph; this.profilingInfo = profilingInfo; + GraalError.guarantee(requireSpeculationLog ? speculationLog != null : true, "Graph has no speculation log attached: %s", graph); this.speculationLog = speculationLog; this.toProcess = toProcess; this.ignoreFrequency = ignoreFrequency; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/DeoptimizeNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/DeoptimizeNode.java index 61b72464b3c5..99c3a86dcdac 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/DeoptimizeNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/DeoptimizeNode.java @@ -138,7 +138,8 @@ public boolean canFloat() { * high and would be executed under the wrong conditions. */ public static boolean canFloat(DeoptimizationReason reason, DeoptimizationAction action) { - return action != DeoptimizationAction.None && reason != DeoptimizationReason.Unresolved; + return action != DeoptimizationAction.None && reason != DeoptimizationReason.Unresolved && reason != DeoptimizationReason.NotCompiledExceptionHandler && + reason != DeoptimizationReason.UnreachedCode; } @NodeIntrinsic diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/CountedLoopInfo.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/CountedLoopInfo.java index a93c026423d4..3954c647136a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/CountedLoopInfo.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/CountedLoopInfo.java @@ -35,6 +35,7 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.FixedGuardNode; import jdk.graal.compiler.nodes.GuardNode; import jdk.graal.compiler.nodes.IfNode; import jdk.graal.compiler.nodes.LogicConstantNode; @@ -310,14 +311,23 @@ private ValueNode findOrCreatePositivePi(LogicNode noEntryCheck, ValueNode div, } HIRBlock loopBlock = cfg.blockFor(loop.loopBegin()); for (Node checkUsage : noEntryCheck.usages()) { - if (checkUsage instanceof IfNode) { - IfNode ifCheck = (IfNode) checkUsage; - if (cfg.getNodeToBlock().isNew(ifCheck.falseSuccessor())) { + ValueNode candidateCheck = null; + if (checkUsage instanceof IfNode ifCheck) { + candidateCheck = ifCheck.falseSuccessor(); + } else if (checkUsage instanceof FixedGuardNode guard) { + if (!guard.isNegated()) { continue; } - if (cfg.blockFor(ifCheck.falseSuccessor()).dominates(loopBlock)) { - return graph.addOrUniqueWithInputs(PiNode.create(div, positiveIntStamp.improveWith(div.stamp(NodeView.DEFAULT)), ifCheck.falseSuccessor())); - } + candidateCheck = guard; + } else { + continue; + } + + if (cfg.getNodeToBlock().isNew(candidateCheck)) { + continue; + } + if (cfg.blockFor(candidateCheck).dominates(loopBlock)) { + return graph.addOrUniqueWithInputs(PiNode.create(div, positiveIntStamp.improveWith(div.stamp(NodeView.DEFAULT)), candidateCheck)); } } return null; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionKey.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionKey.java index 12471587bdef..8e485bb53ec1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionKey.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionKey.java @@ -50,12 +50,26 @@ public final void setDescriptor(OptionDescriptor descriptor) { /** * Returns the descriptor for this option, if it has been set by - * {@link #setDescriptor(OptionDescriptor)}. + * {@link #setDescriptor(OptionDescriptor)}. As descriptors are loaded lazily, this method will + * return {@code null} if the descriptors have not been loaded. Use {@link #loadDescriptor} + * instead to ensure a non-null descriptor is returned if available. */ public final OptionDescriptor getDescriptor() { return descriptor; } + /** + * Returns the descriptor for this option, triggering loading of descriptors if this descriptor + * is null. Note that it's still possible for this method to return null if this option does not + * have a descriptor created by a service loader. + */ + public final OptionDescriptor loadDescriptor() { + if (descriptor == null) { + Lazy.init(); + } + return descriptor; + } + /** * Checks that a descriptor exists for this key after triggering loading of descriptors. */ diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java index e74ae619b2c6..d4b0a6cdf27e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java @@ -61,6 +61,7 @@ import jdk.graal.compiler.lir.asm.CompilationResultBuilderFactory; import jdk.graal.compiler.lir.asm.EntryPointDecorator; import jdk.graal.compiler.lir.phases.LIRSuites; +import jdk.graal.compiler.loop.phases.SpeculativeGuardMovementPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -74,6 +75,7 @@ import jdk.graal.compiler.phases.PhaseSuite; import jdk.graal.compiler.phases.Speculative; import jdk.graal.compiler.phases.common.AbstractInliningPhase; +import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.tiers.Suites; @@ -414,6 +416,8 @@ private static void removeSpeculativePhases(Suites suites) { suites.getHighTier().removeSubTypePhases(Speculative.class); suites.getMidTier().removeSubTypePhases(Speculative.class); suites.getLowTier().removeSubTypePhases(Speculative.class); + // remove after GR-49600 is resolved: + suites.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); } @Override diff --git a/docs/reference-manual/java-on-truffle/README.md b/docs/reference-manual/java-on-truffle/README.md index 8419c55d1df8..892154fecbb8 100644 --- a/docs/reference-manual/java-on-truffle/README.md +++ b/docs/reference-manual/java-on-truffle/README.md @@ -31,12 +31,13 @@ Java on Truffle passes the Java Compatibility Kit (JCK or TCK for Java SE). As of GraalVM for JDK 21, Java on Truffle (known as Espresso) is available as a standalone distribution. You can download a standalone based on Oracle GraalVM or GraalVM Community Edition. -1. Download the Java on Truffle (Espresso) standalone for your operating system: - * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/04F488A062424081E0631818000A781E/content) - * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/04F556B0056D3A58E0631818000A322D/content) - * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/04F556B005743A58E0631818000A322D/content) - * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/04F556B0057A3A58E0631818000A322D/content) - * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/04F488A062484081E0631818000A781E/content) +1. Download the Java on Truffle (Espresso) 23.1 standalone for your operating system: + + * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/069B12298B3349EDE0631718000A11BC/content) + * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01B97519AE0631718000AA34D/content) + * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBBAF81ADE0631718000AA7AB/content) + * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/069B12298B4949EDE0631718000A11BC/content) + * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBBBD81ADE0631718000AA7AB/content) 2. Unzip the archive: diff --git a/docs/reference-manual/llvm/README.md b/docs/reference-manual/llvm/README.md index c02f5c6bde2f..b2efcae5ea70 100644 --- a/docs/reference-manual/llvm/README.md +++ b/docs/reference-manual/llvm/README.md @@ -17,19 +17,20 @@ This allows seamless interoperability with the dynamic languages supported by Gr As of GraalVM for JDK 21, the GraalVM LLVM runtime is available as a standalone distribution. You can download a standalone based on Oracle GraalVM or GraalVM Community Edition. -1. Download the LLVM standalone for your operating system: +1. Download the LLVM 23.1 standalone for your operating system: + - Native standalone - * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB6993C6E0631818000A2314/content) - * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/04F488A0621A4081E0631818000A781E/content) - * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/04F488A0621F4081E0631818000A781E/content) - * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/04F488A062244081E0631818000A781E/content) - * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/04F488A062294081E0631818000A781E/content) + * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC7C81ADE0631718000AA7AB/content) + * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC8181ADE0631718000AA7AB/content) + * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01CBE519AE0631718000AA34D/content) + * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/069B12298BE249EDE0631718000A11BC/content) + * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/069B12298BE749EDE0631718000A11BC/content) - JVM standalone - * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/04F488A0622E4081E0631818000A781E/content) - * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB5D93C6E0631818000A2314/content) - * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/04F488A062384081E0631818000A781E/content) - * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/04F488A0623D4081E0631818000A781E/content) - * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/04F556B005683A58E0631818000A322D/content) + * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/069B12298BEC49EDE0631718000A11BC/content) + * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01CC3519AE0631718000AA34D/content) + * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC8881ADE0631718000AA7AB/content) + * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01CC8519AE0631718000AA34D/content) + * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC8D81ADE0631718000AA7AB/content) 2. Unzip the archive: diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 39c8fc43a2c1..b26b3b5abd3c 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -137,7 +137,7 @@ By default, the build process tries to only use free memory (to avoid memory pre If less than 8GB of memory are free, the build process falls back to use 85% of total memory. Therefore, consider freeing up memory if your machine is slow during a build, for example, by closing applications that you do not need. -By default, the build process uses all available CPU cores to maximize speed. +By default, the build process uses all available processors to maximize speed, but not more than 32 threads. Use the `--parallelism` option to set the number of threads explicitly (for example, `--parallelism=4`). Use fewer threads to reduce load on your system as well as memory consumption (at the cost of a slower build process). diff --git a/docs/reference-manual/wasm/README.md b/docs/reference-manual/wasm/README.md index 16108df1b4b6..a5866d149534 100644 --- a/docs/reference-manual/wasm/README.md +++ b/docs/reference-manual/wasm/README.md @@ -16,19 +16,19 @@ The support for WebAssembly is in the early stages of its development. As of GraalVM for JDK 21, the GraalVM WebAssembly runtime (known as Wasm) is available as a standalone distribution. You can download a standalone based on Oracle GraalVM or GraalVM Community Edition. -1. Download the Wasm standalone for your operating system: +1. Download the Wasm 23.1 standalone for your operating system: - Native standalone - * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB3A93C6E0631818000A2314/content) - * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB3F93C6E0631818000A2314/content) - * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/04F488A062154081E0631818000A781E/content) - * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB4493C6E0631818000A2314/content) - * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB4993C6E0631818000A2314/content) + * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01C4D519AE0631718000AA34D/content) + * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01C5E519AE0631718000AA34D/content) + * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/069B12298B9149EDE0631718000A11BC/content) + * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01C7B519AE0631718000AA34D/content) + * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/069B12298BB049EDE0631718000A11BC/content) - JVM standalone - * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB4E93C6E0631818000A2314/content) - * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB5393C6E0631818000A2314/content) - * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB5893C6E0631818000A2314/content) - * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB5D93C6E0631818000A2314/content) - * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/05013E46CB6293C6E0631818000A2314/content) + * [Linux x64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01C98519AE0631718000AA34D/content) + * [Linux AArch64](https://gds.oracle.com/api/20220101/artifacts/069B12298BDD49EDE0631718000A11BC/content) + * [macOS x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC6481ADE0631718000AA7AB/content) + * [macOS AArch64](https://gds.oracle.com/api/20220101/artifacts/069B4EC01CB9519AE0631718000AA34D/content) + * [Windows x64](https://gds.oracle.com/api/20220101/artifacts/07867F4EBC7781ADE0631718000AA7AB/content) 2. Unzip the archive: diff --git a/graal-common.json b/graal-common.json index d97c3c5039d5..fb26b4262ed0 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "f197d31e391f68e62e7b7897e8e161b50e5e880d" + "overlay": "5b25b545821271da526df7d67d88876b89841102" } } diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeResourceAccess.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeResourceAccess.java index 355a4f06e4f7..1e26a651c290 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeResourceAccess.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeResourceAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,17 +40,16 @@ */ package org.graalvm.nativeimage.hosted; -import java.util.Arrays; -import java.util.Locale; -import java.util.Objects; -import java.util.regex.Pattern; - import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeResourceSupport; +import java.util.Arrays; +import java.util.Locale; +import java.util.Objects; + /** * This class can be used to register Java resources and ResourceBundles that should be accessible * at run time. @@ -69,8 +68,7 @@ public final class RuntimeResourceAccess { public static void addResource(Module module, String resourcePath) { Objects.requireNonNull(module); Objects.requireNonNull(resourcePath); - ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), - withModuleName(module, Pattern.quote(resourcePath))); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResource(module, resourcePath); } /** diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ConfigurationCondition.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ConfigurationCondition.java index 72a76b2d2718..e089491291de 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ConfigurationCondition.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ConfigurationCondition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -50,6 +50,10 @@ public static ConfigurationCondition alwaysTrue() { return OBJECT_REACHABLE; } + public static boolean isAlwaysTrue(ConfigurationCondition condition) { + return ConfigurationCondition.alwaysTrue().equals(condition); + } + public static ConfigurationCondition create(String typeReachability) { Objects.requireNonNull(typeReachability); if (OBJECT_REACHABLE.typeName.equals(typeReachability)) { diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeResourceSupport.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeResourceSupport.java index 68242b311d69..6147690f249c 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeResourceSupport.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeResourceSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -46,6 +46,8 @@ public interface RuntimeResourceSupport { void addResources(ConfigurationCondition condition, String pattern); + void addResource(Module module, String resourcePath); + void injectResource(Module module, String resourcePath, byte[] resourceContent); void ignoreResources(ConfigurationCondition condition, String pattern); diff --git a/substratevm/ci/ci.jsonnet b/substratevm/ci/ci.jsonnet index c69709ebeb5a..934381c07417 100644 --- a/substratevm/ci/ci.jsonnet +++ b/substratevm/ci/ci.jsonnet @@ -130,6 +130,6 @@ }, // END MAIN BUILD DEFINITION processed_builds::run_spec.process(task_dict), - builds: [{'defined_in': std.thisFile} + util.add_gate_predicate(b, gate_triggering_suites) for b in self.processed_builds.list], + builds: util.add_defined_in([util.add_gate_predicate(b, gate_triggering_suites) for b in self.processed_builds.list], std.thisFile), assert tools.check_names($.builds), } diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index a2013afb94e5..3c873193198e 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -28,6 +28,7 @@ import tempfile from glob import glob from contextlib import contextmanager +from distutils.dir_util import mkpath # pylint: disable=no-name-in-module from os.path import join, exists, dirname import pipes from argparse import ArgumentParser @@ -475,9 +476,26 @@ def native_unittests_task(extra_build_args=None): # GR-24075 mx_unittest.add_global_ignore_glob('com.oracle.svm.test.ProcessPropertiesTest') + # add resources that are not in jar but in the separate directory + cp_entry_name = join(svmbuild_dir(), 'cpEntryDir') + resources_from_dir = join(cp_entry_name, 'resourcesFromDir') + simple_dir = join(cp_entry_name, 'simpleDir') + + mkpath(cp_entry_name) + mkpath(resources_from_dir) + mkpath(simple_dir) + + for i in range(4): + with open(join(cp_entry_name, "resourcesFromDir", f'cond-resource{i}.txt'), 'w') as out: + out.write(f"Conditional file{i}" + '\n') + + with open(join(cp_entry_name, "simpleDir", f'simple-resource{i}.txt'), 'w') as out: + out.write(f"Simple file{i}" + '\n') + additional_build_args = svm_experimental_options([ '-H:AdditionalSecurityProviders=com.oracle.svm.test.SecurityServiceTest$NoOpProvider', '-H:AdditionalSecurityServiceTypes=com.oracle.svm.test.SecurityServiceTest$JCACompliantNoOpService', + '-cp', cp_entry_name ]) if extra_build_args is not None: additional_build_args += extra_build_args diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index 5e5b4dad7517..2bbbca0263a0 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -37,7 +37,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ForkJoinPool; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.debug.DebugContext; @@ -52,7 +51,6 @@ import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; import com.oracle.graal.pointsto.AnalysisPolicy; -import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.bytecode.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; @@ -135,7 +133,6 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { SnippetReflectionProvider snippetReflection = originalProviders.getSnippetReflection(); MetaAccessProvider originalMetaAccess = originalProviders.getMetaAccess(); debugContext = new DebugContext.Builder(options, new GraalDebugHandlersFactory(snippetReflection)).build(); - ForkJoinPool executor = PointsToAnalysis.createExecutor(debugContext, Math.min(Runtime.getRuntime().availableProcessors(), 32)); StandaloneHost standaloneHost = new StandaloneHost(options, analysisClassLoader); int wordSize = getWordSize(); AnalysisPolicy analysisPolicy = PointstoOptions.AllocationSiteSensitiveHeap.getValue(options) ? new BytecodeSensitiveAnalysisPolicy(options) @@ -154,7 +151,8 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { originalProviders.getPlatformConfigurationProvider(), aMetaAccessExtensionProvider, originalProviders.getLoopsDataProvider()); standaloneHost.initializeProviders(aProviders); analysisName = getAnalysisName(mainEntryClass); - bigbang = new StandalonePointsToAnalysis(options, aUniverse, standaloneHost, aMetaAccess, snippetReflection, aConstantReflection, aProviders.getWordTypes(), executor, new TimerCollection()); + bigbang = new StandalonePointsToAnalysis(options, aUniverse, standaloneHost, aMetaAccess, snippetReflection, aConstantReflection, aProviders.getWordTypes(), debugContext, + new TimerCollection()); standaloneHost.setImageName(analysisName); aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java index 439ada3ef91a..e48d66606b73 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java @@ -28,11 +28,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ForkJoinPool; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; @@ -43,17 +38,18 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.TimerCollection; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.ConstantReflectionProvider; public class StandalonePointsToAnalysis extends PointsToAnalysis { private final Set addedClinits = ConcurrentHashMap.newKeySet(); - public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, - AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, - ForkJoinPool executorService, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, executorService, new UnsupportedFeatures(), timerCollection, - true); + public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection, true); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 5bad5d06986f..be32d2919e5a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -27,7 +27,6 @@ import java.io.PrintWriter; import java.util.Collections; import java.util.List; -import java.util.concurrent.ForkJoinPool; import java.util.function.Function; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; @@ -101,7 +100,7 @@ public abstract class AbstractAnalysisEngine implements BigBang { @SuppressWarnings("this-escape") public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, ForkJoinPool executorService, UnsupportedFeatures unsupportedFeatures, + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection) { this.options = options; this.universe = universe; @@ -110,7 +109,7 @@ public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, H this.metaAccess = metaAccess; this.analysisPolicy = universe.analysisPolicy(); this.hostVM = hostVM; - this.executor = new CompletionExecutor(this, executorService); + this.executor = new CompletionExecutor(debugContext, this); this.unsupportedFeatures = unsupportedFeatures; this.processFeaturesTimer = timerCollection.get(TimerCollection.Registry.FEATURES); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 9b782a19ea96..cda851aa7c95 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -37,22 +37,11 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLongArray; import java.util.function.Consumer; import java.util.stream.StreamSupport; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.SuppressFBWarnings; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.Indent; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeList; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; - import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -84,8 +73,14 @@ import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.util.ClassUtil; -import com.oracle.svm.util.ImageGeneratorThreadMarker; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeList; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; @@ -111,9 +106,9 @@ public abstract class PointsToAnalysis extends AbstractAnalysisEngine { @SuppressWarnings("this-escape") public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, ForkJoinPool executorService, UnsupportedFeatures unsupportedFeatures, TimerCollection timerCollection, + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, boolean strengthenGraalGraphs) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, executorService, unsupportedFeatures, timerCollection); + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); this.typeFlowTimer = timerCollection.createTimer("(typeflow)"); this.strengthenGraalGraphs = strengthenGraalGraphs; @@ -537,16 +532,6 @@ public boolean doTypeflow() throws InterruptedException { return didSomeWork; } - @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "ForkJoinPool does support null for the exception handler.") - public static ForkJoinPool createExecutor(DebugContext debug, int numberOfThreads) { - ForkJoinPool.ForkJoinWorkerThreadFactory factory = debugThreadFactory(debug.areScopesEnabled() || debug.areMetricsEnabled() ? debug : null); - return new ForkJoinPool(numberOfThreads, factory, null, false); - } - - private static ForkJoinPool.ForkJoinWorkerThreadFactory debugThreadFactory(DebugContext debug) { - return pool -> new SubstrateWorkerThread(pool, debug); - } - @Override public void onTypeInstantiated(AnalysisType type, AnalysisType.UsageKind usageKind) { /* Register the type as instantiated with all its super types. */ @@ -735,21 +720,4 @@ public void print() { System.out.println(); } } - - private static class SubstrateWorkerThread extends ForkJoinWorkerThread - implements ImageGeneratorThreadMarker { - private final DebugContext debug; - - SubstrateWorkerThread(ForkJoinPool pool, DebugContext debug) { - super(pool); - this.debug = debug; - } - - @Override - protected void onTermination(Throwable exception) { - if (debug != null) { - debug.closeDumpHandlers(true); - } - } - } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index 13f22c94df56..d72d31940e9c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -27,13 +27,8 @@ import static com.oracle.graal.pointsto.ObjectScanner.ScanReason; import java.util.Objects; -import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; -import jdk.graal.compiler.options.OptionType; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.ObjectScanner.ReusableSet; @@ -46,6 +41,10 @@ import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.svm.util.LogUtils; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionType; import jdk.vm.ci.meta.JavaConstant; public class HeapSnapshotVerifier { @@ -74,8 +73,8 @@ public HeapSnapshotVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner sc verbosity = Options.HeapVerifierVerbosity.getValue(bb.getOptions()); } - public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, ForkJoinPool threadPool, String stage) { - CompletionExecutor executor = new CompletionExecutor(bb, threadPool); + public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAccess, String stage) { + CompletionExecutor executor = new CompletionExecutor(debug, bb); executor.init(); return checkHeapSnapshot(metaAccess, executor, stage, false); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java index bfbecae57b10..a57aa9dda6c1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java @@ -28,22 +28,20 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.LongAdder; +import com.oracle.graal.pointsto.BigBang; + import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Activation; import jdk.graal.compiler.debug.DebugContext.Description; import jdk.graal.compiler.debug.DebugContext.Scope; import jdk.graal.compiler.debug.DebugHandlersFactory; import jdk.graal.compiler.options.OptionValues; - -import com.oracle.graal.pointsto.BigBang; - import jdk.vm.ci.common.JVMCIError; /** @@ -64,8 +62,7 @@ private enum State { private List postedBeforeStart; private final CopyOnWriteArrayList exceptions = new CopyOnWriteArrayList<>(); - private ExecutorService executorService; - + private final DebugContext debug; private final BigBang bb; private Timing timing; private Object vmConfig; @@ -82,9 +79,9 @@ public interface Timing { void print(); } - public CompletionExecutor(BigBang bb, ForkJoinPool forkJoin) { + public CompletionExecutor(DebugContext debugContext, BigBang bb) { + this.debug = debugContext.areScopesEnabled() || debugContext.areMetricsEnabled() ? debugContext : null; this.bb = bb; - executorService = forkJoin; state = new AtomicReference<>(State.UNUSED); postedOperations = new LongAdder(); completedOperations = new LongAdder(); @@ -146,18 +143,7 @@ public void execute(DebugContextRunnable command) { if (timing != null) { timing.addScheduled(command); } - - if (isSequential()) { - bb.getHostVM().recordActivity(); - try (DebugContext debug = command.getDebug(bb.getOptions(), bb.getDebugHandlerFactories()); - Scope s = debug.scope("Operation")) { - command.run(debug); - } - completedOperations.increment(); - } else { - executeService(command); - } - + executeService(command); break; default: throw JVMCIError.shouldNotReachHere(); @@ -165,9 +151,7 @@ public void execute(DebugContextRunnable command) { } private void executeService(DebugContextRunnable command) { - executorService.execute(() -> { - executeCommand(command); - }); + ForkJoinPool.commonPool().execute(() -> executeCommand(command)); } @SuppressWarnings("try") @@ -212,14 +196,6 @@ private void setState(State newState) { } public long complete() throws InterruptedException { - - if (isSequential()) { - long completed = completedOperations.sum(); - long posted = postedOperations.sum(); - assert completed == posted : completed + ", " + posted; - return posted; - } - long lastPrint = 0; if (timing != null) { timing.printHeader(); @@ -227,36 +203,37 @@ public long complete() throws InterruptedException { lastPrint = System.nanoTime(); } - while (true) { - assert state.get() == State.STARTED : state.get(); + try { + while (true) { + assert state.get() == State.STARTED : state.get(); - boolean quiescent; - if (executorService instanceof ForkJoinPool) { - quiescent = ((ForkJoinPool) executorService).awaitQuiescence(100, TimeUnit.MILLISECONDS); - } else { - quiescent = executorService.awaitTermination(100, TimeUnit.MILLISECONDS); - } - if (timing != null && !quiescent) { - long curTime = System.nanoTime(); - if (curTime - lastPrint > timing.getPrintIntervalNanos()) { - timing.print(); - lastPrint = curTime; + boolean quiescent = ForkJoinPool.commonPool().awaitQuiescence(100, TimeUnit.MILLISECONDS); + if (timing != null && !quiescent) { + long curTime = System.nanoTime(); + if (curTime - lastPrint > timing.getPrintIntervalNanos()) { + timing.print(); + lastPrint = curTime; + } } - } - long completed = completedOperations.sum(); - long posted = postedOperations.sum(); - assert completed <= posted : completed + ", " + posted; - if (completed == posted && exceptions.isEmpty()) { - if (timing != null) { - timing.print(); - } + long completed = completedOperations.sum(); + long posted = postedOperations.sum(); + assert completed <= posted : completed + ", " + posted; + if (completed == posted && exceptions.isEmpty()) { + if (timing != null) { + timing.print(); + } - return posted; + return posted; + } + if (!exceptions.isEmpty()) { + setState(State.UNUSED); + throw new ParallelExecutionException(exceptions); + } } - if (!exceptions.isEmpty()) { - setState(State.UNUSED); - throw new ParallelExecutionException(exceptions); + } finally { + if (debug != null) { + debug.closeDumpHandlers(true); } } } @@ -265,12 +242,8 @@ public long getPostedOperations() { return postedOperations.sum() + (postedBeforeStart == null ? 0 : postedBeforeStart.size()); } - public boolean isSequential() { - return executorService == null; - } - public void shutdown() { - assert isSequential() || !(executorService instanceof ForkJoinPool) || !((ForkJoinPool) executorService).hasQueuedSubmissions() : "There should be no queued submissions on shutdown."; + assert !ForkJoinPool.commonPool().hasQueuedSubmissions() : "There should be no queued submissions on shutdown."; assert completedOperations.sum() == postedOperations.sum() : "Posted operations (" + postedOperations.sum() + ") must match completed (" + completedOperations.sum() + ") operations"; setState(State.UNUSED); } @@ -286,19 +259,4 @@ public boolean isStarted() { public State getState() { return state.get(); } - - public int parallelism() { - if (executorService instanceof ForkJoinPool) { - return ((ForkJoinPool) executorService).getParallelism(); - } - return 1; - } - - public ExecutorService getExecutorService() { - return executorService; - } - - public void setExecutorService(ExecutorService executorService) { - this.executorService = executorService; - } } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index ea0912b41eef..2e0e854b4834 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -30,13 +30,6 @@ import java.util.Deque; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ForkJoinPool; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.type.TypedConstant; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.api.HostVM; @@ -53,6 +46,12 @@ import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.svm.common.meta.MultiMethod; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.core.common.type.TypedConstant; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; @@ -80,9 +79,9 @@ public abstract class ReachabilityAnalysisEngine extends AbstractAnalysisEngine @SuppressWarnings("this-escape") public ReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, ForkJoinPool executorService, UnsupportedFeatures unsupportedFeatures, TimerCollection timerCollection, + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, executorService, unsupportedFeatures, timerCollection); + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); this.executor.init(getTiming()); this.reachabilityTimer = timerCollection.createTimer("(reachability)"); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 45befb0a0fd0..636429db224b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -43,7 +43,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; import java.util.stream.StreamSupport; @@ -1295,7 +1294,7 @@ public Element getOffsetBootstrapElement() { private final Map> dependenciesByDependingElement = new IdentityHashMap<>(); private final Map> dependenciesByDependedOnElement = new IdentityHashMap<>(); - public void write(DebugContext context, Path outputFile, @SuppressWarnings("unused") ForkJoinPool forkJoinPool) throws IOException { + public void write(DebugContext context, Path outputFile) throws IOException { try (FileChannel channel = FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { withDebugContext(context, "ObjectFile.write", () -> { write(channel); diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java index 206d05a7b024..4fe924e444a8 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java @@ -99,13 +99,13 @@ private static void printArray(JsonWriter json, Object[] array) throws IOExcepti } private static void printValue(JsonWriter json, Object value) throws IOException { - String s = null; + Object s = null; if (value instanceof byte[]) { s = Base64.getEncoder().encodeToString((byte[]) value); } else if (value != null) { - s = value.toString(); + s = value; } - json.quote(s); + json.printValue(s); } private void traceEntry(String s) throws IOException { diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java index 600b21440bb4..d4007bbee5e6 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java @@ -38,9 +38,10 @@ import org.junit.Test; import com.oracle.svm.configure.config.ResourceConfiguration; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ResourceConfigurationParser; import com.oracle.svm.core.configure.ResourcesRegistry; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonWriter; public class ResourceConfigurationTest { @@ -93,6 +94,11 @@ public void addResources(ConfigurationCondition condition, String pattern) { addedResources.add(pattern); } + @Override + public void addResource(Module module, String resourcePath) { + throw VMError.shouldNotReachHere("Unused function."); + } + @Override public void injectResource(Module module, String resourcePath, byte[] resourceContent) { } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java index 5f6e146f6d31..a42c37f372ad 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java @@ -146,6 +146,7 @@ protected static void generate(Iterator argumentsIterator, boolean accep boolean builtinCallerFilter = true; boolean builtinHeuristicFilter = true; List callerFilters = new ArrayList<>(); + List accessFilters = new ArrayList<>(); ConfigurationFileCollection omittedCollection = new ConfigurationFileCollection(); ConfigurationFileCollection inputCollection = new ConfigurationFileCollection(); @@ -220,6 +221,9 @@ protected static void generate(Iterator argumentsIterator, boolean accep case "--caller-filter-file": callerFilters.add(requirePathUri(option, value)); break; + case "--access-filter-file": + accessFilters.add(requirePathUri(option, value)); + break; case "--": if (acceptTraceFileArgs) { argumentsIterator.forEachRemaining(arg -> traceInputs.add(Paths.get(arg).toUri())); @@ -248,15 +252,12 @@ protected static void generate(Iterator argumentsIterator, boolean accep callersFilterHierarchyFilterNode = AccessAdvisor.copyBuiltinCallerFilterTree(); callersFilter = new ComplexFilter(callersFilterHierarchyFilterNode); } - for (URI uri : callerFilters) { - try { - FilterConfigurationParser parser = new FilterConfigurationParser(callersFilter); - parser.parseAndRegister(uri); - } catch (Exception e) { - throw new ConfigurationUsageException("Cannot parse filter file " + uri + ": " + e); - } - } - callersFilter.getHierarchyFilterNode().removeRedundantNodes(); + parseFilterFiles(callersFilter, callerFilters); + } + ComplexFilter accessFilter = null; + if (!accessFilters.isEmpty()) { + accessFilter = new ComplexFilter(AccessAdvisor.copyBuiltinAccessFilterTree()); + parseFilterFiles(accessFilter, accessFilters); } ConfigurationSet configurationSet; @@ -287,6 +288,9 @@ protected static void generate(Iterator argumentsIterator, boolean accep if (callersFilter != null) { advisor.setCallerFilterTree(callersFilter); } + if (accessFilter != null) { + advisor.setAccessFilterTree(accessFilter); + } TraceProcessor processor = new TraceProcessor(advisor); for (URI uri : traceInputs) { @@ -331,6 +335,17 @@ protected static void generate(Iterator argumentsIterator, boolean accep } } + private static void parseFilterFiles(ComplexFilter filter, List filterFiles) { + for (URI uri : filterFiles) { + try { + new FilterConfigurationParser(filter).parseAndRegister(uri); + } catch (Exception e) { + throw new ConfigurationUsageException("Cannot parse filter file " + uri + ": " + e); + } + } + filter.getHierarchyFilterNode().removeRedundantNodes(); + } + @SuppressWarnings("fallthrough") private static void failIfAgentLockFilesPresent(ConfigurationFileCollection... collections) { Set paths = null; diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java index 803fbb86fa34..6a561ee133e7 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java @@ -38,13 +38,13 @@ import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonPrinter; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.configure.ResourceConfigurationParser; import com.oracle.svm.core.configure.ResourcesRegistry; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonPrinter; +import com.oracle.svm.core.util.json.JsonWriter; public final class ResourceConfiguration extends ConfigurationBase { @@ -63,6 +63,11 @@ public void addResources(ConfigurationCondition condition, String pattern) { configuration.addResourcePattern(condition, pattern); } + @Override + public void addResource(Module module, String resourcePath) { + throw VMError.shouldNotReachHere("Unused function."); + } + @Override public void injectResource(Module module, String resourcePath, byte[] resourceContent) { VMError.shouldNotReachHere("Resource injection is only supported via Feature implementation"); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index 0c8de6681173..1611f7ce4ba4 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -42,7 +42,6 @@ import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -72,6 +71,7 @@ import com.oracle.svm.core.graal.llvm.util.LLVMStackMapInfo; import com.oracle.svm.core.heap.SubstrateReferenceMap; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicInteger; +import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.image.NativeImage.NativeTextSectionImpl; import com.oracle.svm.hosted.image.NativeImageCodeCache; import com.oracle.svm.hosted.image.NativeImageHeap; @@ -117,9 +117,9 @@ public int codeSizeFor(HostedMethod method) { @Override @SuppressWarnings({"unused", "try"}) - public void layoutMethods(DebugContext debug, BigBang bb, ForkJoinPool threadPool) { + public void layoutMethods(DebugContext debug, BigBang bb) { try (Indent indent = debug.logAndIndent("layout methods")) { - BatchExecutor executor = new BatchExecutor(bb, threadPool); + BatchExecutor executor = new BatchExecutor(debug, bb); try (StopTimer t = TimerCollection.createTimerAndStart("(bitcode)")) { writeBitcode(executor); } @@ -153,7 +153,7 @@ private void writeBitcode(BatchExecutor executor) { private int createBitcodeBatches(BatchExecutor executor, DebugContext debug) { batchSize = LLVMOptions.LLVMMaxFunctionsPerBatch.getValue(); - int numThreads = executor.getExecutor().parallelism(); + int numThreads = NativeImageOptions.getActualNumberOfThreads(); int idealSize = NumUtil.divideAndRoundUp(methodIndex.length, numThreads); if (idealSize < batchSize) { batchSize = idealSize; diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMToolchainUtils.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMToolchainUtils.java index 15bb3af478f5..b10092fff482 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMToolchainUtils.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMToolchainUtils.java @@ -29,7 +29,6 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ForkJoinPool; import java.util.function.Function; import java.util.function.IntFunction; @@ -170,8 +169,8 @@ public static void llvmCleanupStackMaps(DebugContext debug, String inputPath, Pa public static final class BatchExecutor { private CompletionExecutor executor; - public BatchExecutor(BigBang bb, ForkJoinPool threadPool) { - this.executor = new CompletionExecutor(bb, threadPool); + public BatchExecutor(DebugContext debug, BigBang bb) { + this.executor = new CompletionExecutor(debug, bb); executor.init(); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java index 54a0e6b30775..bc3801c339a8 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java @@ -41,7 +41,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -183,7 +182,7 @@ public SymbolTable getSymbolTable() { @Override @SuppressWarnings("try") - public final void write(DebugContext context, Path outputFile, ForkJoinPool forkJoinPool) throws IOException { + public final void write(DebugContext context, Path outputFile) throws IOException { List sortedObjectFileElements = new ArrayList<>(); bake(sortedObjectFileElements); @@ -192,7 +191,7 @@ public final void write(DebugContext context, Path outputFile, ForkJoinPool fork writeParts(); - BatchExecutor batchExecutor = new BatchExecutor(bb, forkJoinPool); + BatchExecutor batchExecutor = new BatchExecutor(context, bb); compileBitcodeBatches(batchExecutor, context, numBatches); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java index 4c7e0aaca4ad..aa53efe3871a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java @@ -25,14 +25,16 @@ package com.oracle.svm.core; import java.io.IOException; -import java.io.InputStream; import java.net.URI; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; +import java.util.Set; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.impl.ConfigurationCondition; @Platforms(Platform.HOSTED_ONLY.class) public abstract class ClassLoaderSupport { @@ -51,12 +53,11 @@ public boolean isNativeImageClassLoader(ClassLoader classLoader) { protected abstract boolean isNativeImageClassLoaderImpl(ClassLoader classLoader); public interface ResourceCollector { + List isIncluded(Module module, String resourceName, URI resourceURI); - boolean isIncluded(Module module, String resourceName, URI resourceURI); + void addResource(Module module, String resourceName); - void addResource(Module module, String resourceName, InputStream resourceStream, boolean fromJar); - - void addDirectoryResource(Module module, String dir, String content, boolean fromJar); + void addResourceConditionally(Module module, String resourceName, ConfigurationCondition condition); void registerNegativeQuery(Module module, String resourceName); @@ -66,4 +67,6 @@ public interface ResourceCollector { public abstract void collectResources(ResourceCollector resourceCollector); public abstract List getResourceBundle(String bundleName, Locale locale); + + public abstract Map> getPackageToModules(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java index 00faeab2e2cb..069e34e89dfe 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java @@ -166,7 +166,7 @@ private void updateTimeStamp() { } @Platforms(Platform.HOSTED_ONLY.class) - private ResourceStorageEntryBase addEntry(Module module, String resourceName, ResourceStorageEntryBase newEntry, boolean isDirectory, boolean fromJar) { + private void addEntry(Module module, String resourceName, boolean isDirectory, byte[] data, boolean fromJar, boolean isNegativeQuery) { VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to add a resource entry after analysis."); Module m = module != null && module.isNamed() ? module : null; if (m != null) { @@ -175,18 +175,27 @@ private ResourceStorageEntryBase addEntry(Module module, String resourceName, Re synchronized (resources) { Pair key = createStorageKey(m, resourceName); ResourceStorageEntryBase entry = resources.get(key); + if (isNegativeQuery) { + if (entry == null) { + resources.put(key, NEGATIVE_QUERY_MARKER); + } + return; + } + if (entry == null || entry == NEGATIVE_QUERY_MARKER) { - entry = newEntry == null ? new ResourceStorageEntry(isDirectory, fromJar) : newEntry; updateTimeStamp(); + entry = new ResourceStorageEntry(isDirectory, fromJar); resources.put(key, entry); + } else { + if (key.getLeft() != null) { + // if the entry already exists, and it comes from a module, it is the same entry + // that we registered at some point before + return; + } } - return entry; - } - } - private void addEntry(Module module, String resourceName, boolean isDirectory, byte[] data, boolean fromJar) { - ResourceStorageEntryBase entry = addEntry(module, resourceName, null, isDirectory, fromJar); - entry.getData().add(data); + entry.getData().add(data); + } } @Platforms(Platform.HOSTED_ONLY.class) @@ -194,39 +203,14 @@ public static void registerResource(String resourceName, InputStream is) { singleton().registerResource(null, resourceName, is, true); } - @Platforms(Platform.HOSTED_ONLY.class) - public void registerResource(String resourceName, InputStream is, boolean fromJar) { - registerResource(null, resourceName, is, fromJar); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void registerResource(Module module, String resourceName, InputStream is) { - registerResource(module, resourceName, is, true); - } - @Platforms(Platform.HOSTED_ONLY.class) public void registerResource(Module module, String resourceName, byte[] resourceContent) { - addEntry(module, resourceName, false, resourceContent, true); + addEntry(module, resourceName, false, resourceContent, true, false); } @Platforms(Platform.HOSTED_ONLY.class) public void registerResource(Module module, String resourceName, InputStream is, boolean fromJar) { - addEntry(module, resourceName, false, inputStreamToByteArray(is), fromJar); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void registerDirectoryResource(String resourceDirName, String content) { - registerDirectoryResource(null, resourceDirName, content, true); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void registerDirectoryResource(String resourceDirName, String content, boolean fromJar) { - registerDirectoryResource(null, resourceDirName, content, fromJar); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void registerDirectoryResource(Module module, String resourceDirName, String content) { - registerDirectoryResource(module, resourceDirName, content, true); + addEntry(module, resourceName, false, inputStreamToByteArray(is), fromJar, false); } @Platforms(Platform.HOSTED_ONLY.class) @@ -236,21 +220,16 @@ public void registerDirectoryResource(Module module, String resourceDirName, Str * specified directory, separated with new line delimiter and joined into one string which * is later converted into a byte array and placed into the resources map. */ - addEntry(module, resourceDirName, true, content.getBytes(), fromJar); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void registerIOException(String resourceName, IOException e, boolean linkAtBuildTime) { - registerIOException(null, resourceName, e, linkAtBuildTime); + addEntry(module, resourceDirName, true, content.getBytes(), fromJar, false); } @Platforms(Platform.HOSTED_ONLY.class) public void registerIOException(Module module, String resourceName, IOException e, boolean linkAtBuildTime) { if (linkAtBuildTime) { if (SubstrateOptions.ThrowLinkAtBuildTimeIOExceptions.getValue()) { - throw new RuntimeException("Resource " + resourceName + " from module " + module.getName() + " produced an IOException.", e); + throw new RuntimeException("Resource " + resourceName + " from module " + moduleName(module) + " produced an IOException.", e); } else { - LogUtils.warning("Resource " + resourceName + " from module " + module.getName() + " produced the following IOException: " + e.getClass().getTypeName() + ": " + e.getMessage()); + LogUtils.warning("Resource " + resourceName + " from module " + moduleName(module) + " produced the following IOException: " + e.getClass().getTypeName() + ": " + e.getMessage()); } } Pair key = createStorageKey(module, resourceName); @@ -267,7 +246,7 @@ public void registerNegativeQuery(String resourceName) { @Platforms(Platform.HOSTED_ONLY.class) public void registerNegativeQuery(Module module, String resourceName) { - addEntry(module, resourceName, NEGATIVE_QUERY_MARKER, false, false); + addEntry(module, resourceName, false, null, false, true); } @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java index 9f918232531e..a178d797270b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java @@ -30,14 +30,15 @@ import java.util.ListResourceBundle; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ForkJoinPool; +import java.util.function.Function; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import jdk.graal.compiler.debug.GraalError; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -49,6 +50,7 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.debug.GraalError; import sun.util.resources.OpenListResourceBundle; import sun.util.resources.ParallelListResourceBundle; @@ -172,8 +174,8 @@ public boolean isNotIncluded(String bundleName) { } @Override - public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { - super.prepareBundle(bundleName, bundle, locale); + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { + super.prepareBundle(bundleName, bundle, findModule, locale); /* Initialize ResourceBundle.keySet eagerly */ bundle.keySet(); this.existingBundles.add(control.toBundleName(bundleName, locale)); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java index d6ab244df836..a036d9c5520a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java @@ -25,18 +25,23 @@ package com.oracle.svm.core.jdk.localization; +import static com.oracle.svm.util.StringUtil.toDotSeparated; +import static com.oracle.svm.util.StringUtil.toSlashSeparated; + import java.nio.charset.Charset; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.IllformedLocaleException; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; -import jdk.graal.compiler.debug.GraalError; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -45,10 +50,13 @@ import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; import org.graalvm.nativeimage.impl.RuntimeResourceSupport; +import com.oracle.svm.core.ClassLoaderSupport; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.debug.GraalError; + /** * Holder for localization information that is computed during image generation and used at run * time. @@ -98,17 +106,31 @@ public Map getBundleContentOf(Object bundle) { } @Platforms(Platform.HOSTED_ONLY.class) - public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { if (bundle instanceof PropertyResourceBundle) { String[] bundleNameWithModule = SubstrateUtil.split(bundleName, ":", 2); - String resultingPattern; + String resourceName; if (bundleNameWithModule.length < 2) { - resultingPattern = control.toBundleName(bundleName, locale).replace('.', '/'); + resourceName = toSlashSeparated(control.toBundleName(bundleName, locale)).concat(".properties"); + + Map> packageToModules = ImageSingletons.lookup(ClassLoaderSupport.class).getPackageToModules(); + Set modules = packageToModules.getOrDefault(packageName(bundleName), Collections.emptySet()); + + for (Module m : modules) { + ImageSingletons.lookup(RuntimeResourceSupport.class).addResource(m, resourceName); + } + + if (modules.isEmpty()) { + ImageSingletons.lookup(RuntimeResourceSupport.class).addResource(null, resourceName); + } } else { - String patternWithLocale = control.toBundleName(bundleNameWithModule[1], locale).replace('.', '/'); - resultingPattern = bundleNameWithModule[0] + ':' + patternWithLocale; + if (findModule != null) { + resourceName = toSlashSeparated(control.toBundleName(bundleNameWithModule[1], locale)).concat(".properties"); + Optional module = findModule.apply(bundleNameWithModule[0]); + String finalResourceName = resourceName; + module.ifPresent(m -> ImageSingletons.lookup(RuntimeResourceSupport.class).addResource(m, finalResourceName)); + } } - ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), resultingPattern + "\\.properties"); } else { registerRequiredReflectionAndResourcesForBundle(bundleName, Set.of(locale)); RuntimeReflection.register(bundle.getClass()); @@ -117,6 +139,15 @@ public void prepareBundle(String bundleName, ResourceBundle bundle, Locale local } } + private static String packageName(String bundleName) { + String uniformBundleName = toDotSeparated(bundleName); + int classSep = uniformBundleName.lastIndexOf('.'); + if (classSep == -1) { + return ""; /* unnamed package */ + } + return uniformBundleName.substring(0, classSep); + } + public String getResultingPattern(String bundleName, Locale locale) { String fixedBundleName = bundleName.replace("$", "\\$"); return getBundleName(fixedBundleName, locale); @@ -125,9 +156,9 @@ public String getResultingPattern(String bundleName, Locale locale) { private String getBundleName(String fixedBundleName, Locale locale) { String[] bundleNameWithModule = SubstrateUtil.split(fixedBundleName, ":", 2); if (bundleNameWithModule.length < 2) { - return control.toBundleName(fixedBundleName, locale).replace('.', '/'); + return toSlashSeparated(control.toBundleName(fixedBundleName, locale)); } else { - String patternWithLocale = control.toBundleName(bundleNameWithModule[1], locale).replace('.', '/'); + String patternWithLocale = toSlashSeparated(control.toBundleName(bundleNameWithModule[1], locale)); return bundleNameWithModule[0] + ':' + patternWithLocale; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java index 91187cdc9bd8..5a8a29f4a1b4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java @@ -30,8 +30,10 @@ import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; +import java.util.function.Function; import java.util.spi.LocaleServiceProvider; import org.graalvm.collections.Pair; @@ -89,12 +91,21 @@ public void prepareClassResourceBundle(String basename, Class bundleClass) { /*- Set the basename and locale to be consistent with JVM lookup process */ bundleNameField.set(bundle, basename); bundleLocaleField.set(bundle, locale); - prepareBundle(basename, bundle, locale); + + // override in this class does not use findModule + prepareBundle(basename, bundle, null, locale); } catch (ReflectionUtil.ReflectionUtilError | ReflectiveOperationException e) { throw UserError.abort(e, "Failed to instantiated bundle from class %s, reason %s", bundleClass, e.getCause().getMessage()); } } + @Platforms(Platform.HOSTED_ONLY.class) + @Override + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { + bundle.keySet(); + this.resourceBundles.put(Pair.create(bundleName, locale), bundle); + } + private static Locale extractLocale(Class bundleClass) { String name = bundleClass.getName(); int split = name.lastIndexOf('_'); @@ -104,13 +115,6 @@ private static Locale extractLocale(Class bundleClass) { return parseLocaleFromTag(name.substring(split + 1)); } - @Platforms(Platform.HOSTED_ONLY.class) - @Override - public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { - bundle.keySet(); - this.resourceBundles.put(Pair.create(bundleName, locale), bundle); - } - @Override public boolean shouldSubstituteLoadLookup(String className) { /*- All bundles are stored in the image heap as objects, no need to keep the content around */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java index 9b4bb45e80f0..5c2151bddc45 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java @@ -175,16 +175,18 @@ public static String commandArgument(OptionKey option, String value) { */ @Platforms(Platform.HOSTED_ONLY.class) public static String commandArgument(OptionKey option, String value, String apiOptionName) { + /* Ensure descriptor is loaded */ + OptionDescriptor optionDescriptor = option.loadDescriptor(); Field field; try { - field = option.getDescriptor().getDeclaringClass().getDeclaredField(option.getDescriptor().getFieldName()); + field = optionDescriptor.getDeclaringClass().getDeclaredField(optionDescriptor.getFieldName()); } catch (ReflectiveOperationException ex) { throw VMError.shouldNotReachHere(ex); } APIOption[] apiOptions = field.getAnnotationsByType(APIOption.class); - if (option.getDescriptor().getOptionValueType() == Boolean.class) { + if (optionDescriptor.getOptionValueType() == Boolean.class) { VMError.guarantee(value.equals("+") || value.equals("-"), "Boolean option value can be only + or -"); for (APIOption apiOption : apiOptions) { String selected = selectVariant(apiOption, apiOptionName); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java index b59d6f0143da..10b803b8a17b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java @@ -82,11 +82,11 @@ public JsonWriter appendFieldSeparator() throws IOException { } public JsonWriter appendKeyValue(String key, Object value) throws IOException { - return quote(key).appendFieldSeparator().quote(value); + return quote(key).appendFieldSeparator().printValue(value); } @SuppressWarnings({"unchecked", "rawtypes"}) - public void print(Object value) throws IOException { + public JsonWriter print(Object value) throws IOException { if (value instanceof Map map) { printMap(map); // Must always be } else if (value instanceof Iterator it) { @@ -94,8 +94,9 @@ public void print(Object value) throws IOException { } else if (value instanceof List list) { printIterator(list.iterator()); } else { - quote(value); + printValue(value); } + return this; } @SuppressWarnings("unchecked") @@ -130,15 +131,26 @@ private void printIterator(Iterator iter) throws IOException { append(']'); } - public JsonWriter quote(Object o) throws IOException { + public JsonWriter printValue(Object o) throws IOException { if (o == null) { return append("null"); - } else if (Boolean.TRUE.equals(o)) { - return append("true"); - } else if (Boolean.FALSE.equals(o)) { - return append("false"); - } else if (o instanceof Number) { + } else if (o instanceof Boolean || o instanceof Byte || o instanceof Short || o instanceof Integer || o instanceof Long) { + /* + * Note that sub-integer values here most likely become Integer objects when parsing, + * and comparisons such as equals() or compareTo() on boxed values only work on the + * exact same type. (Boolean values, however, should be deserialized as Boolean). + */ return append(o.toString()); + } else if (o instanceof Float f) { + if (f.isNaN() || f.isInfinite()) { + return quote(f.toString()); // cannot express, best we can do without failing + } + return append(f.toString()); + } else if (o instanceof Double d) { + if (d.isNaN() || d.isInfinite()) { + return quote(d.toString()); // cannot express, best we can do without failing + } + return append(d.toString()); } else { return quote(o.toString()); } diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java index 5eb2678dec0c..dba05ac7d47f 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java @@ -860,8 +860,8 @@ private static Manifest createManifest() { private static final String substitutionMapDstField = "dst"; private static void printPathMapping(Map.Entry entry, JsonWriter w) throws IOException { - w.append('{').quote(substitutionMapSrcField).append(':').quote(entry.getKey()); - w.append(',').quote(substitutionMapDstField).append(':').quote(entry.getValue()); + w.append('{').quote(substitutionMapSrcField).append(':').printValue(entry.getKey()); + w.append(',').quote(substitutionMapDstField).append(':').printValue(entry.getValue()); w.append('}'); } diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index ca573188bb4e..3057cce3bb9b 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -97,7 +97,6 @@ import com.oracle.svm.driver.metainf.NativeImageMetaInfResourceProcessor; import com.oracle.svm.driver.metainf.NativeImageMetaInfWalker; import com.oracle.svm.hosted.NativeImageGeneratorRunner; -import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.NativeImageSystemClassLoader; import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ModuleSupport; @@ -269,8 +268,6 @@ private static String oR(OptionKey option) { final String oHInspectServerContentPath = oH(PointstoOptions.InspectServerContentPath); final String oHDeadlockWatchdogInterval = oH(SubstrateOptions.DeadlockWatchdogInterval); - static final String oHNumberOfThreads = oH(NativeImageOptions.NumberOfThreads); - final Map imageBuilderEnvironment = new HashMap<>(); private final ArrayList imageBuilderArgs = new ArrayList<>(); private final LinkedHashSet imageBuilderModulePath = new LinkedHashSet<>(); @@ -1096,19 +1093,6 @@ private int completeImageBuild() { } imageClasspath.addAll(customImageClasspath); - Integer maxNumberOfThreads = getMaxNumberOfThreads(); - if (maxNumberOfThreads != null) { - if (maxNumberOfThreads >= 2) { - /* - * Set number of threads in common pool. Subtract one because the main thread helps - * to process tasks. - */ - imageBuilderJavaArgs.add("-Djava.util.concurrent.ForkJoinPool.common.parallelism=" + (maxNumberOfThreads - 1)); - } else { - throw showError("The number of threads was set to " + maxNumberOfThreads + ". Please set the '--parallelism' option to at least 2."); - } - } - /* * Work around "JDK-8315810: Reimplement * sun.reflect.ReflectionFactory::newConstructorForSerialization with method handles" @@ -1359,20 +1343,6 @@ private static Boolean getHostedOptionFinalBooleanArgumentValue(List arg return result; } - private Integer getMaxNumberOfThreads() { - String numberOfThreadsValue = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHNumberOfThreads); - if (numberOfThreadsValue != null) { - try { - return Integer.parseInt(numberOfThreadsValue); - } catch (NumberFormatException e) { - /* Validated already by CommonOptionParser. */ - throw VMError.shouldNotReachHere(e); - } - } else { - return null; - } - } - private boolean shouldAddCWDToCP() { if (config.buildFallbackImage() || printFlagsOptionQuery != null || printFlagsWithExtraHelpOptionQuery != null) { return false; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java index 51fdbcb121fd..32019015dce9 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java @@ -53,6 +53,7 @@ import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.phases.LIRPhase; import jdk.graal.compiler.lir.phases.LIRSuites; +import jdk.graal.compiler.loop.phases.SpeculativeGuardMovementPhase; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.GraphDecoder; import jdk.graal.compiler.nodes.StructuredGraph; @@ -60,6 +61,7 @@ import jdk.graal.compiler.phases.BasePhase; import jdk.graal.compiler.phases.FloatingGuardPhase; import jdk.graal.compiler.phases.Speculative; +import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.serviceprovider.GraalServices; @@ -208,6 +210,8 @@ private static Suites getWithoutSpeculative(Suites s) { effectiveSuites.getHighTier().removeSubTypePhases(Speculative.class); effectiveSuites.getMidTier().removeSubTypePhases(Speculative.class); effectiveSuites.getLowTier().removeSubTypePhases(Speculative.class); + // remove after GR-49600 is resolved: + effectiveSuites.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); return effectiveSuites; } @@ -219,6 +223,8 @@ private static Suites getWithExplicitExceptions(Suites s) { effectiveSuites.getHighTier().removeSubTypePhases(Speculative.class); effectiveSuites.getMidTier().removeSubTypePhases(Speculative.class); effectiveSuites.getLowTier().removeSubTypePhases(Speculative.class); + // remove after GR-49600 is resolved: + effectiveSuites.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); return effectiveSuites; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java index 37dfcb4134b8..433b0680c4b1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java @@ -39,7 +39,6 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -55,6 +54,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.graalvm.nativeimage.impl.ConfigurationCondition; + import com.oracle.svm.core.ClassLoaderSupport; import com.oracle.svm.core.util.ClasspathUtils; import com.oracle.svm.core.util.UserError; @@ -71,6 +72,9 @@ public class ClassLoaderSupportImpl extends ClassLoaderSupport { private final Map> packageToModules; + private record ConditionalResource(ConfigurationCondition condition, String resourceName) { + } + public ClassLoaderSupportImpl(NativeImageClassLoaderSupport classLoaderSupport) { this.classLoaderSupport = classLoaderSupport; imageClassLoader = classLoaderSupport.getClassLoader(); @@ -107,57 +111,60 @@ public void collectResources(ResourceCollector resourceCollector) { /* Collect resources from modules */ NativeImageClassLoaderSupport.allLayers(classLoaderSupport.moduleLayerForImageBuild).stream() .flatMap(ClassLoaderSupportImpl::extractModuleLookupData) + .parallel() .forEach(lookup -> collectResourceFromModule(resourceCollector, lookup)); /* Collect remaining resources from classpath */ - for (Path classpathFile : classLoaderSupport.classpath()) { - boolean includeAll = classLoaderSupport.getJavaPathsToInclude().contains(classpathFile); + classLoaderSupport.classpath().stream().parallel().forEach(classpathFile -> { + boolean includeCurrent = classLoaderSupport.getJavaPathsToInclude().contains(classpathFile); try { if (Files.isDirectory(classpathFile)) { - scanDirectory(classpathFile, resourceCollector, includeAll); + scanDirectory(classpathFile, resourceCollector, includeCurrent); } else if (ClasspathUtils.isJar(classpathFile)) { - scanJar(classpathFile, resourceCollector, includeAll); + scanJar(classpathFile, resourceCollector, includeCurrent); } } catch (IOException ex) { throw UserError.abort("Unable to handle classpath element '%s'. Make sure that all classpath entries are either directories or valid jar files.", classpathFile); } - } + }); } private void collectResourceFromModule(ResourceCollector resourceCollector, ResourceLookupInfo info) { ModuleReference moduleReference = info.resolvedModule.reference(); try (ModuleReader moduleReader = moduleReference.open()) { - var includeAll = classLoaderSupport.getJavaModuleNamesToInclude().contains(info.resolvedModule().name()); - List foundResources = moduleReader.list() - .filter(resourceName -> shouldIncludeEntry(info.module(), resourceCollector, resourceName, moduleReference.location().orElse(null), includeAll)) - .toList(); + boolean includeCurrent = classLoaderSupport.getJavaModuleNamesToInclude().contains(info.resolvedModule().name()); + List resourcesFound = new ArrayList<>(); + moduleReader.list().forEach(resourceName -> { + List conditions = shouldIncludeEntry(info.module, resourceCollector, resourceName, moduleReference.location().orElse(null), includeCurrent); + for (ConfigurationCondition condition : conditions) { + resourcesFound.add(new ConditionalResource(condition, resourceName)); + } + }); - for (String resName : foundResources) { + for (ConditionalResource entry : resourcesFound) { + ConfigurationCondition condition = entry.condition(); + String resName = entry.resourceName(); if (resName.endsWith("/")) { - resourceCollector.addDirectoryResource(info.module, resName, "", false); + includeResource(resourceCollector, info.module, resName, condition); continue; } + Optional content = moduleReader.open(resName); if (content.isEmpty()) { /* This is to be resilient, but the resources returned by list() should exist */ resourceCollector.registerNegativeQuery(info.module, resName); continue; } - try (InputStream is = content.get()) { - resourceCollector.addResource(info.module, resName, is, false); - } catch (IOException resourceException) { - resourceCollector.registerIOException(info.module, resName, resourceException, LinkAtBuildTimeSupport.singleton().moduleLinkAtBuildTime(info.module.getName())); - } + + includeResource(resourceCollector, info.module, resName, condition); } + } catch (IOException e) { throw VMError.shouldNotReachHere(e); } } - private static void scanDirectory(Path root, ResourceCollector collector, boolean includeAll) { - Map> matchedDirectoryResources = new HashMap<>(); - Set allEntries = new HashSet<>(); - + private static void scanDirectory(Path root, ResourceCollector collector, boolean includeCurrent) { ArrayDeque queue = new ArrayDeque<>(); queue.push(root); while (!queue.isEmpty()) { @@ -167,15 +174,20 @@ private static void scanDirectory(Path root, ResourceCollector collector, boolea String relativeFilePath; if (entry != root) { relativeFilePath = root.relativize(entry).toString().replace(File.separatorChar, RESOURCES_INTERNAL_PATH_SEPARATOR); - allEntries.add(relativeFilePath); } else { - relativeFilePath = ""; + relativeFilePath = String.valueOf(RESOURCES_INTERNAL_PATH_SEPARATOR); + } + + List conditions = shouldIncludeEntry(null, collector, relativeFilePath, Path.of(relativeFilePath).toUri(), includeCurrent); + for (ConfigurationCondition condition : conditions) { + includeResource(collector, null, relativeFilePath, condition); } if (Files.isDirectory(entry)) { - if (shouldIncludeEntry(null, collector, relativeFilePath, Path.of(relativeFilePath).toUri(), includeAll)) { - matchedDirectoryResources.put(relativeFilePath, new ArrayList<>()); + if (conditions.isEmpty()) { + collector.registerNegativeQuery(null, relativeFilePath); } + try (Stream pathStream = Files.list(entry)) { Stream filtered = pathStream; if (ClassUtil.CLASS_MODULE_PATH_EXCLUDE_DIRECTORIES_ROOT.equals(entry)) { @@ -185,62 +197,42 @@ private static void scanDirectory(Path root, ResourceCollector collector, boolea } catch (IOException resourceException) { collector.registerIOException(null, relativeFilePath, resourceException, LinkAtBuildTimeSupport.singleton().packageOrClassAtBuildTime(relativeFilePath)); } - } else { - if (shouldIncludeEntry(null, collector, relativeFilePath, Path.of(relativeFilePath).toUri(), includeAll)) { - try (InputStream is = Files.newInputStream(entry)) { - collector.addResource(null, relativeFilePath, is, false); - } catch (IOException resourceException) { - collector.registerIOException(null, relativeFilePath, resourceException, LinkAtBuildTimeSupport.singleton().packageOrClassAtBuildTime(relativeFilePath)); - } - } } } - - for (String entry : allEntries) { - int last = entry.lastIndexOf(RESOURCES_INTERNAL_PATH_SEPARATOR); - String key = last == -1 ? "" : entry.substring(0, last); - List dirContent = matchedDirectoryResources.get(key); - if (dirContent != null && !dirContent.contains(entry)) { - dirContent.add(entry.substring(last + 1)); - } else if (dirContent == null) { - collector.registerNegativeQuery(null, key); - } - } - - matchedDirectoryResources.forEach((dir, content) -> { - content.sort(Comparator.naturalOrder()); - collector.addDirectoryResource(null, dir, String.join(System.lineSeparator(), content), false); - }); } - private static void scanJar(Path jarPath, ResourceCollector collector, boolean includeAll) throws IOException { + private static void scanJar(Path jarPath, ResourceCollector collector, boolean includeCurrent) throws IOException { try (JarFile jf = new JarFile(jarPath.toFile())) { Enumeration entries = jf.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); - URI uri = jarPath.toUri(); + String entryName = entry.getName(); if (entry.isDirectory()) { - String dirName = entry.getName().substring(0, entry.getName().length() - 1); - if (shouldIncludeEntry(null, collector, dirName, uri, includeAll)) { - // Register the directory with empty content to preserve Java behavior - collector.addDirectoryResource(null, dirName, "", true); - } - } else { - if (shouldIncludeEntry(null, collector, entry.getName(), uri, includeAll)) { - try (InputStream is = jf.getInputStream(entry)) { - collector.addResource(null, entry.getName(), is, true); - } catch (IOException resourceException) { - collector.registerIOException(null, entry.getName(), resourceException, LinkAtBuildTimeSupport.singleton().packageOrClassAtBuildTime(entry.getName())); - } - } + entryName = entryName.substring(0, entry.getName().length() - 1); + } + + List conditions = shouldIncludeEntry(null, collector, entryName, jarPath.toUri(), includeCurrent); + for (ConfigurationCondition condition : conditions) { + includeResource(collector, null, entryName, condition); } } } } - private static boolean shouldIncludeEntry(Module module, ResourceCollector collector, String fileName, URI uri, boolean includeAll) { - var isIncluded = collector.isIncluded(module, fileName, uri); - return isIncluded || (includeAll && !(fileName.endsWith(".class") || fileName.endsWith(".jar"))); + private static void includeResource(ResourceCollector collector, Module module, String name, ConfigurationCondition condition) { + if (ConfigurationCondition.isAlwaysTrue(condition)) { + collector.addResource(module, name); + } else { + collector.addResourceConditionally(module, name, condition); + } + } + + private static List shouldIncludeEntry(Module module, ResourceCollector collector, String fileName, URI uri, boolean includeCurrent) { + if (includeCurrent && !(fileName.endsWith(".class") || fileName.endsWith(".jar"))) { + return Collections.singletonList(ConfigurationCondition.alwaysTrue()); + } + + return collector.isIncluded(module, fileName, uri); } @Override @@ -282,6 +274,11 @@ public List getResourceBundle(String bundleSpec, Locale locale) return resourceBundles; } + @Override + public Map> getPackageToModules() { + return packageToModules; + } + private static String packageName(String bundleName) { int classSep = bundleName.lastIndexOf('.'); if (classSep == -1) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DeadlockWatchdog.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DeadlockWatchdog.java index 040eaa642c99..f098d86b8c0e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DeadlockWatchdog.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DeadlockWatchdog.java @@ -82,28 +82,8 @@ void watchdogThread() { while (!stopped) { long now = System.currentTimeMillis(); if (enabled && now >= nextDeadline) { - System.err.println(); - System.err.println("=== Image generator watchdog detected no activity. This can be a sign of a deadlock during image building. Dumping all stack traces. Current time: " + new Date()); - threadDump(); - Runtime runtime = Runtime.getRuntime(); - final long heapSizeUnit = 1024 * 1024; - long usedHeapSize = runtime.totalMemory() / heapSizeUnit; - long freeHeapSize = runtime.freeMemory() / heapSizeUnit; - long maximumHeapSize = runtime.maxMemory() / heapSizeUnit; - System.err.printf("=== Memory statistics (in MB):%n=== Used heap size: %d%n=== Free heap size: %d%n=== Maximum heap size: %d%n", usedHeapSize, freeHeapSize, maximumHeapSize); - System.err.flush(); - - if (watchdogExitOnTimeout) { - System.err.println("=== Image generator watchdog is aborting image generation. To configure the watchdog, use the options " + - SubstrateOptionsParser.commandArgument(SubstrateOptions.DeadlockWatchdogInterval, Integer.toString(watchdogInterval), null) + " and " + - SubstrateOptionsParser.commandArgument(SubstrateOptions.DeadlockWatchdogExitOnTimeout, "+", null)); - /* - * Since there is a likely deadlock somewhere, there is no less intrusive way to - * abort other than a hard exit of the image builder VM. - */ - System.exit(ExitStatus.WATCHDOG_EXIT.getValue()); - - } else { + reportFailureState(); + if (!watchdogExitOnTimeout) { recordActivity(); } } @@ -116,6 +96,30 @@ void watchdogThread() { } } + public void reportFailureState() { + System.err.println(); + System.err.println("=== Image generator watchdog detected no activity. This can be a sign of a deadlock during image building. Dumping all stack traces. Current time: " + new Date()); + threadDump(); + Runtime runtime = Runtime.getRuntime(); + final long heapSizeUnit = 1024 * 1024; + long usedHeapSize = runtime.totalMemory() / heapSizeUnit; + long freeHeapSize = runtime.freeMemory() / heapSizeUnit; + long maximumHeapSize = runtime.maxMemory() / heapSizeUnit; + System.err.printf("=== Memory statistics (in MB):%n=== Used heap size: %d%n=== Free heap size: %d%n=== Maximum heap size: %d%n", usedHeapSize, freeHeapSize, maximumHeapSize); + System.err.flush(); + + if (watchdogExitOnTimeout) { + System.err.println("=== Image generator watchdog is aborting image generation. To configure the watchdog, use the options " + + SubstrateOptionsParser.commandArgument(SubstrateOptions.DeadlockWatchdogInterval, Integer.toString(watchdogInterval), null) + " and " + + SubstrateOptionsParser.commandArgument(SubstrateOptions.DeadlockWatchdogExitOnTimeout, "+", null)); + /* + * Since there is a likely deadlock somewhere, there is no less intrusive way to abort + * other than a hard exit of the image builder VM. + */ + System.exit(ExitStatus.WATCHDOG_EXIT.getValue()); + } + } + public void setEnabled(boolean enable) { if (enable == this.enabled) { return; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index 0465a396fe21..769a01f4c27a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -30,7 +30,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ForkJoinPool; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.CompressEncoding; @@ -173,10 +172,10 @@ public SVMHost createHostVM(OptionValues options, ClassLoader classLoader, Class return new SVMHost(options, classLoader, classInitializationSupport, automaticSubstitutions, platform); } - public CompileQueue createCompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse hostedUniverse, - RuntimeConfiguration runtimeConfiguration, boolean deoptimizeAll, SnippetReflectionProvider aSnippetReflection, ForkJoinPool executor) { + public CompileQueue createCompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse hostedUniverse, RuntimeConfiguration runtimeConfiguration, boolean deoptimizeAll, + SnippetReflectionProvider aSnippetReflection) { - return new CompileQueue(debug, featureHandler, hostedUniverse, runtimeConfiguration, deoptimizeAll, aSnippetReflection, executor); + return new CompileQueue(debug, featureHandler, hostedUniverse, runtimeConfiguration, deoptimizeAll, aSnippetReflection); } public MethodTypeFlowBuilder createMethodTypeFlowBuilder(PointsToAnalysis bb, PointsToAnalysisMethod method, MethodFlowsGraph flowsGraph, MethodFlowsGraph.GraphKind graphKind) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java index d861bcca5010..624b129bf195 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import com.oracle.svm.util.LogUtils; import org.graalvm.collections.EconomicSet; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.word.Word; @@ -53,13 +54,6 @@ public final class ImageClassLoader { - /* - * This cannot be a HostedOption because the option parsing already relies on the list of loaded - * classes. - */ - private static final int CLASS_LOADING_MAX_SCALING = 8; - private static final int CLASS_LOADING_TIMEOUT_IN_MINUTES = 10; - static { /* * ImageClassLoader is one of the first classes used during image generation, so early @@ -87,20 +81,18 @@ public final class ImageClassLoader { } public void loadAllClasses() throws InterruptedException { - ForkJoinPool executor = new ForkJoinPool(Math.min(Runtime.getRuntime().availableProcessors(), CLASS_LOADING_MAX_SCALING)) { - @Override - public void execute(Runnable task) { - super.execute(() -> { - task.run(); - watchdog.recordActivity(); - }); - } - }; + ForkJoinPool executor = ForkJoinPool.commonPool(); try { classLoaderSupport.loadAllClasses(executor, this); } finally { - executor.shutdown(); - executor.awaitTermination(CLASS_LOADING_TIMEOUT_IN_MINUTES, TimeUnit.MINUTES); + boolean isQuiescence = false; + while (!isQuiescence) { + isQuiescence = executor.awaitQuiescence(10, TimeUnit.MINUTES); + if (!isQuiescence) { + LogUtils.warning("Class loading is slow. Waiting for tasks to complete..."); + /* DeadlockWatchdog should fail the build eventually. */ + } + } } classLoaderSupport.reportBuilderClassesInApplication(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index be6d69b18ad1..9822516daf8c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -879,6 +879,7 @@ private void handleClassFileName(URI container, Module module, String className, } imageClassLoader.handleClass(clazz); } + imageClassLoader.watchdog.recordActivity(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index c159659fdfc2..17af801976d9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -53,7 +53,6 @@ import java.util.Map; import java.util.ServiceLoader; import java.util.Set; -import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BooleanSupplier; import java.util.stream.Stream; @@ -83,6 +82,7 @@ import jdk.graal.compiler.java.BciBlockMapping; import jdk.graal.compiler.lir.phases.LIRSuites; import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; +import jdk.graal.compiler.loop.phases.SpeculativeGuardMovementPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.gc.BarrierSet; import jdk.graal.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; @@ -519,46 +519,40 @@ public void run(Map entryPoints, JavaMainSupport javaMainSupport, String imageName, NativeImageKind k, SubstitutionProcessor harnessSubstitutions, - ForkJoinPool compilationExecutor, ForkJoinPool analysisExecutor, EconomicSet allOptionNames, TimerCollection timerCollection) { - try { - if (!buildStarted.compareAndSet(false, true)) { - throw UserError.abort("An image build has already been performed with this generator."); - } + if (!buildStarted.compareAndSet(false, true)) { + throw UserError.abort("An image build has already been performed with this generator."); + } - try { - /* - * JVMCI 20.2-b01 introduced new methods for linking and querying whether an - * interface has default methods. Fail early if these methods are missing. - */ - ResolvedJavaType.class.getDeclaredMethod("link"); - } catch (ReflectiveOperationException ex) { - throw UserError.abort("JVMCI version provided %s is missing the 'ResolvedJavaType.link()' method added in jvmci-20.2-b01. " + - "Please use the latest JVMCI JDK from %s.", System.getProperty("java.home"), OPEN_LABSJDK_RELEASE_URL_PATTERN); - } + try { + /* + * JVMCI 20.2-b01 introduced new methods for linking and querying whether an interface + * has default methods. Fail early if these methods are missing. + */ + ResolvedJavaType.class.getDeclaredMethod("link"); + } catch (ReflectiveOperationException ex) { + throw UserError.abort("JVMCI version provided %s is missing the 'ResolvedJavaType.link()' method added in jvmci-20.2-b01. " + + "Please use the latest JVMCI JDK from %s.", System.getProperty("java.home"), OPEN_LABSJDK_RELEASE_URL_PATTERN); + } - setSystemPropertiesForImageLate(k); + setSystemPropertiesForImageLate(k); - ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement()); + ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement()); - ImageSingletons.add(ProgressReporter.class, reporter); - ImageSingletons.add(DeadlockWatchdog.class, loader.watchdog); - ImageSingletons.add(TimerCollection.class, timerCollection); - ImageSingletons.add(ImageBuildStatistics.TimerCollectionPrinter.class, timerCollection); - ImageSingletons.add(AnnotationExtractor.class, loader.classLoaderSupport.annotationExtractor); - ImageSingletons.add(BuildArtifacts.class, (type, artifact) -> buildArtifacts.computeIfAbsent(type, t -> new ArrayList<>()).add(artifact)); - ImageSingletons.add(HostedOptionValues.class, new HostedOptionValues(optionProvider.getHostedValues())); - ImageSingletons.add(RuntimeOptionValues.class, new RuntimeOptionValues(optionProvider.getRuntimeValues(), allOptionNames)); + ImageSingletons.add(ProgressReporter.class, reporter); + ImageSingletons.add(DeadlockWatchdog.class, loader.watchdog); + ImageSingletons.add(TimerCollection.class, timerCollection); + ImageSingletons.add(ImageBuildStatistics.TimerCollectionPrinter.class, timerCollection); + ImageSingletons.add(AnnotationExtractor.class, loader.classLoaderSupport.annotationExtractor); + ImageSingletons.add(BuildArtifacts.class, (type, artifact) -> buildArtifacts.computeIfAbsent(type, t -> new ArrayList<>()).add(artifact)); + ImageSingletons.add(HostedOptionValues.class, new HostedOptionValues(optionProvider.getHostedValues())); + ImageSingletons.add(RuntimeOptionValues.class, new RuntimeOptionValues(optionProvider.getRuntimeValues(), allOptionNames)); - try (TemporaryBuildDirectoryProviderImpl tempDirectoryProvider = new TemporaryBuildDirectoryProviderImpl()) { - ImageSingletons.add(TemporaryBuildDirectoryProvider.class, tempDirectoryProvider); - doRun(entryPoints, javaMainSupport, imageName, k, harnessSubstitutions, compilationExecutor, analysisExecutor); - } finally { - reporter.ensureCreationStageEndCompleted(); - } + try (TemporaryBuildDirectoryProviderImpl tempDirectoryProvider = new TemporaryBuildDirectoryProviderImpl()) { + ImageSingletons.add(TemporaryBuildDirectoryProvider.class, tempDirectoryProvider); + doRun(entryPoints, javaMainSupport, imageName, k, harnessSubstitutions); } finally { - analysisExecutor.shutdownNow(); - compilationExecutor.shutdownNow(); + reporter.ensureCreationStageEndCompleted(); } } @@ -581,10 +575,7 @@ public static void clearSystemPropertiesForImage() { } @SuppressWarnings("try") - protected void doRun(Map entryPoints, - JavaMainSupport javaMainSupport, String imageName, NativeImageKind k, - SubstitutionProcessor harnessSubstitutions, - ForkJoinPool compilationExecutor, ForkJoinPool analysisExecutor) { + protected void doRun(Map entryPoints, JavaMainSupport javaMainSupport, String imageName, NativeImageKind k, SubstitutionProcessor harnessSubstitutions) { List hostedEntryPoints = new ArrayList<>(); OptionValues options = HostedOptionValues.singleton(); @@ -592,7 +583,7 @@ protected void doRun(Map entryPoints, try (DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(originalSnippetReflection)).build(); DebugCloseable featureCleanup = () -> featureHandler.forEachFeature(Feature::cleanup)) { - setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, analysisExecutor, originalSnippetReflection, debug); + setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, originalSnippetReflection, debug); boolean returnAfterAnalysis = runPointsToAnalysis(imageName, options, debug); if (returnAfterAnalysis) { @@ -670,8 +661,7 @@ protected void doRun(Map entryPoints, NativeImageCodeCache codeCache; CompileQueue compileQueue; try (StopTimer t = TimerCollection.createTimerAndStart(TimerCollection.Registry.COMPILE_TOTAL)) { - compileQueue = HostedConfiguration.instance().createCompileQueue(debug, featureHandler, hUniverse, runtimeConfiguration, DeoptTester.enabled(), - bb.getSnippetReflectionProvider(), compilationExecutor); + compileQueue = HostedConfiguration.instance().createCompileQueue(debug, featureHandler, hUniverse, runtimeConfiguration, DeoptTester.enabled(), bb.getSnippetReflectionProvider()); if (ImageSingletons.contains(RuntimeCompilationSupport.class)) { ImageSingletons.lookup(RuntimeCompilationSupport.class).onCompileQueueCreation(bb, hUniverse, compileQueue); } @@ -684,8 +674,8 @@ protected void doRun(Map entryPoints, codeCache = NativeImageCodeCacheFactory.get().newCodeCache(compileQueue, heap, loader.platform, ImageSingletons.lookup(TemporaryBuildDirectoryProvider.class).getTemporaryBuildDirectory()); codeCache.layoutConstants(); - codeCache.layoutMethods(debug, bb, compilationExecutor); - codeCache.buildRuntimeMetadata(bb.getSnippetReflectionProvider(), compilationExecutor); + codeCache.layoutMethods(debug, bb); + codeCache.buildRuntimeMetadata(debug, bb.getSnippetReflectionProvider()); } AfterCompilationAccessImpl config = new AfterCompilationAccessImpl(featureHandler, loader, aUniverse, hUniverse, compileQueue.getCompilations(), codeCache, heap, debug, @@ -695,7 +685,7 @@ protected void doRun(Map entryPoints, } /* Re-run shadow heap verification after compilation. */ - aUniverse.getHeapVerifier().checkHeapSnapshot(hMetaAccess, compilationExecutor, "after compilation"); + aUniverse.getHeapVerifier().checkHeapSnapshot(debug, hMetaAccess, "after compilation"); CodeCacheProvider codeCacheProvider = runtimeConfiguration.getBackendForNormalMethod().getProviders().getCodeCache(); reporter.printCreationStart(); @@ -714,7 +704,7 @@ protected void doRun(Map entryPoints, featureHandler.forEachFeature(feature -> feature.afterHeapLayout(config)); /* Re-run shadow heap verification after heap layout. */ - aUniverse.getHeapVerifier().checkHeapSnapshot(hMetaAccess, compilationExecutor, "after heap layout"); + aUniverse.getHeapVerifier().checkHeapSnapshot(debug, hMetaAccess, "after heap layout"); createAbstractImage(k, hostedEntryPoints, heap, hMetaAccess, codeCache); @@ -755,7 +745,7 @@ protected void doRun(Map entryPoints, * not is an implementation detail of the image. */ Path tmpDir = ImageSingletons.lookup(TemporaryBuildDirectoryProvider.class).getTemporaryBuildDirectory(); - LinkerInvocation inv = image.write(debug, generatedFiles(HostedOptionValues.singleton()), tmpDir, imageName, beforeConfig, compilationExecutor); + LinkerInvocation inv = image.write(debug, generatedFiles(HostedOptionValues.singleton()), tmpDir, imageName, beforeConfig); if (NativeImageOptions.ExitAfterRelocatableImageWrite.getValue()) { return; } @@ -869,7 +859,7 @@ protected boolean verifyAssignableTypes() { @SuppressWarnings("try") protected void setupNativeImage(OptionValues options, Map entryPoints, JavaMainSupport javaMainSupport, - SubstitutionProcessor harnessSubstitutions, ForkJoinPool analysisExecutor, SnippetReflectionProvider originalSnippetReflection, DebugContext debug) { + SubstitutionProcessor harnessSubstitutions, SnippetReflectionProvider originalSnippetReflection, DebugContext debug) { try (Indent ignored = debug.logAndIndent("setup native-image builder")) { try (StopTimer ignored1 = TimerCollection.createTimerAndStart(TimerCollection.Registry.SETUP)) { SubstrateTargetDescription target = createTarget(); @@ -934,7 +924,7 @@ protected void setupNativeImage(OptionValues options, Map c) { suites.getHighTier().removeSubTypePhases(c); suites.getMidTier().removeSubTypePhases(c); suites.getLowTier().removeSubTypePhases(c); + // remove after GR-49600 is resolved: + suites.getMidTier().replaceAllPhases(SpeculativeGuardMovementPhase.class, () -> new SpeculativeGuardMovementPhase(CanonicalizerPhase.create(), false, false)); } @SuppressWarnings("unused") diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 637698c13170..7de0c7713c42 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -42,15 +42,10 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.TimerTask; -import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; import java.util.stream.Collectors; import org.graalvm.collections.Pair; -import jdk.graal.compiler.core.riscv64.ShadowedRISCV64; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.nativeimage.c.type.CCharPointerPointer; @@ -74,7 +69,6 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.option.HostedOptionParser; @@ -84,6 +78,8 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; +import jdk.graal.compiler.core.riscv64.ShadowedRISCV64; +import jdk.graal.compiler.options.OptionValues; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; @@ -296,6 +292,12 @@ public static ImageClassLoader installNativeImageClassLoader(String[] classpath, */ NativeImageGenerator.setSystemPropertiesForImageEarly(); + /* + * Size the common pool before creating the image class loader because it is the first + * component to use the common pool. + */ + NativeImageOptions.setCommonPoolParallelism(nativeImageClassLoaderSupport.getParsedHostedOptions()); + return new ImageClassLoader(NativeImageGenerator.getTargetPlatform(nativeImageClassLoader), nativeImageClassLoaderSupport); } @@ -375,9 +377,6 @@ private int buildImage(ImageClassLoader classLoader) { return ExitStatus.OK.getValue(); } - ForkJoinPool analysisExecutor = null; - ForkJoinPool compilationExecutor = null; - ProgressReporter reporter = new ProgressReporter(parsedHostedOptions); Throwable vmError = null; boolean wasSuccessfulBuild = false; @@ -386,9 +385,6 @@ private int buildImage(ImageClassLoader classLoader) { try (StopTimer ignored1 = classlistTimer.start()) { classLoader.loadAllClasses(); } - - DebugContext debug = new DebugContext.Builder(parsedHostedOptions, new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build(); - if (imageName.length() == 0) { throw UserError.abort("No output file name specified. Use '%s'", SubstrateOptionsParser.commandArgument(SubstrateOptions.Name, "")); } @@ -524,21 +520,8 @@ private int buildImage(ImageClassLoader classLoader) { mainEntryPointData = createMainEntryPointData(imageKind, mainEntryPoint); } - /* - * Since the main thread helps to process analysis and compilation tasks (see use of - * awaitQuiescence() in CompletionExecutor), subtract one to determine the number of - * dedicated threads in ForkJoinPools. - */ - final int numberOfHelpingThreads = 1; // main thread - int numberOfThreads = NativeImageOptions.NumberOfThreads.getValue(parsedHostedOptions); - int numberOfAnalysisThreads = NativeImageOptions.getNumberOfAnalysisThreads(numberOfThreads, parsedHostedOptions) - numberOfHelpingThreads; - int numberOfCompilationThreads = numberOfThreads - numberOfHelpingThreads; - analysisExecutor = NativeImagePointsToAnalysis.createExecutor(debug, numberOfAnalysisThreads); - compilationExecutor = NativeImagePointsToAnalysis.createExecutor(debug, numberOfCompilationThreads); - generator = createImageGenerator(classLoader, optionParser, mainEntryPointData, reporter); - generator.run(entryPoints, javaMainSupport, imageName, imageKind, SubstitutionProcessor.IDENTITY, - compilationExecutor, analysisExecutor, optionParser.getRuntimeOptionNames(), timerCollection); + generator.run(entryPoints, javaMainSupport, imageName, imageKind, SubstitutionProcessor.IDENTITY, optionParser.getRuntimeOptionNames(), timerCollection); wasSuccessfulBuild = true; } finally { if (!wasSuccessfulBuild) { @@ -546,12 +529,6 @@ private int buildImage(ImageClassLoader classLoader) { } } } catch (InterruptImageBuilding e) { - if (analysisExecutor != null) { - analysisExecutor.shutdownNow(); - } - if (compilationExecutor != null) { - compilationExecutor.shutdownNow(); - } throw e; } catch (FallbackFeature.FallbackImageRequest e) { if (FallbackExecutor.class.getName().equals(SubstrateOptions.Class.getValue())) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java index 18adab11e2a8..56cd319598a5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java @@ -31,7 +31,9 @@ import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.ForkJoinPool; +import com.oracle.svm.util.LogUtils; import org.graalvm.collections.EconomicMap; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; @@ -40,7 +42,6 @@ import jdk.graal.compiler.serviceprovider.GraalServices; import com.oracle.graal.pointsto.reports.ReportUtils; -import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.APIOption; import com.oracle.svm.core.option.BundleMember; @@ -49,7 +50,6 @@ import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; -import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions; import com.oracle.svm.hosted.util.CPUType; import com.oracle.svm.util.StringUtil; @@ -189,20 +189,58 @@ public static CStandards getCStandard() { } /** - * Configures the number of threads used by the {@link CompletionExecutor}. + * Configures the number of threads of the common pool (see driver). */ - @APIOption(name = "parallelism")// + private static final String PARALLELISM_OPTION_NAME = "parallelism"; + @APIOption(name = PARALLELISM_OPTION_NAME)// @Option(help = "The maximum number of threads to use concurrently during native image generation.")// - public static final HostedOptionKey NumberOfThreads = new HostedOptionKey<>(Math.max(2, Math.min(Runtime.getRuntime().availableProcessors(), 32)), key -> { + public static final HostedOptionKey NumberOfThreads = new HostedOptionKey<>(Math.max(1, Math.min(Runtime.getRuntime().availableProcessors(), 32)), key -> { int numberOfThreads = key.getValue(); - VMError.guarantee(numberOfThreads >= 2, "Number of threads must be at least 2. Validation should have happened in driver."); + if (numberOfThreads < 1) { + throw UserError.abort("The number of threads was set to %s. Please set the '--%s' option to at least 1.", numberOfThreads, PARALLELISM_OPTION_NAME); + } }); - /* - * Analysis scales well up to 12 cores and gives slight improvements until 18 cores. We set the - * default value to 16 to minimize wasted resources in large machines. - */ - @Option(help = "The number of threads to use for analysis during native image generation. The number must be smaller than the NumberOfThreads.", deprecated = true, deprecationMessage = "Please use '--parallelism' instead.")// + public static int getActualNumberOfThreads() { + int commonThreadParallelism = ForkJoinPool.getCommonPoolParallelism(); + if (NumberOfThreads.getValue() == 1) { + assert commonThreadParallelism == 1 : "Disabled common pool expected to report parallelism of 1"; + commonThreadParallelism = 0; /* A disabled common pool has no actual threads */ + } + /* + * Main thread plus common pool threads. setCommonPoolParallelism() asserts that this number + * matches NumberOfThreads. + */ + return 1 + commonThreadParallelism; + } + + public static void setCommonPoolParallelism(OptionValues optionValues) { + if (NativeImageOptions.NumberOfThreads.hasBeenSet(optionValues)) { + /* + * The main thread always helps to process tasks submitted to the common pool (e.g., see + * ForkJoinPool#awaitTermination()), so subtract one from the number of threads. The + * common pool can be disabled "by setting the parallelism property to zero" (see + * ForkJoinPool's javadoc). + */ + int numberOfCommonPoolThreads = NativeImageOptions.NumberOfThreads.getValue(optionValues) - 1; + String commonPoolParallelismProperty = "java.util.concurrent.ForkJoinPool.common.parallelism"; + assert System.getProperty(commonPoolParallelismProperty) == null : commonPoolParallelismProperty + " already set"; + System.setProperty(commonPoolParallelismProperty, "" + numberOfCommonPoolThreads); + int actualCommonPoolParallelism = ForkJoinPool.commonPool().getParallelism(); + /* + * getParallelism() returns at least 1, even in single-threaded mode where common pool + * is disabled. + */ + boolean isSingleThreadedMode = numberOfCommonPoolThreads == 0 && actualCommonPoolParallelism == 1; + if (!isSingleThreadedMode && actualCommonPoolParallelism != numberOfCommonPoolThreads) { + String warning = "Failed to set parallelism of common pool (actual parallelism is %s).".formatted(actualCommonPoolParallelism); + assert false : warning; + LogUtils.warning(warning); + } + } + } + + @Option(help = "Deprecated, option no longer has any effect", deprecated = true, deprecationMessage = "Please use '--parallelism' instead.")// public static final HostedOptionKey NumberOfAnalysisThreads = new HostedOptionKey<>(-1); @Option(help = "Return after analysis")// @@ -214,13 +252,13 @@ public static CStandards getCStandard() { @Option(help = "Exit after writing relocatable file")// public static final HostedOptionKey ExitAfterRelocatableImageWrite = new HostedOptionKey<>(false); - @Option(help = "Throw unsafe operation offset errors.)")// + @Option(help = "Throw unsafe operation offset errors.")// public static final HostedOptionKey ThrowUnsafeOffsetErrors = new HostedOptionKey<>(true); - @Option(help = "Print unsafe operation offset warnings.)")// + @Option(help = "Print unsafe operation offset warnings.")// public static final HostedOptionKey ReportUnsafeOffsetWarnings = new HostedOptionKey<>(false); - @Option(help = "Print unsafe operation offset warnings.)")// + @Option(help = "Print unsafe operation offset warnings.")// public static final HostedOptionKey UnsafeOffsetWarningsAreFatal = new HostedOptionKey<>(false); /** @@ -272,22 +310,4 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o } } }; - - public static int getNumberOfAnalysisThreads(int maxNumberOfThreads, OptionValues optionValues) { - int analysisThreads; - if (NumberOfAnalysisThreads.hasBeenSet(optionValues)) { - analysisThreads = NumberOfAnalysisThreads.getValue(optionValues); - } else { - analysisThreads = Math.min(maxNumberOfThreads, DEFAULT_MAX_ANALYSIS_SCALING); - } - if (analysisThreads < 2) { - throw UserError.abort("Number of analysis threads was set to " + analysisThreads + ". Please set the '-H:NumberOfAnalysisThreads' option to at least 2."); - } - if (analysisThreads > maxNumberOfThreads) { - throw UserError.abort( - "NumberOfAnalysisThreads is not allowed to be larger than the number of threads set with the '--parallelism' option. Please set the '-H:NumberOfAnalysisThreads' option to a value between 1 and " + - (maxNumberOfThreads + 1) + "."); - } - return analysisThreads; - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index 64dceb12a375..d36baa66971a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -392,7 +392,7 @@ private void printResourceInfo() { maxHeapSuffix = "set via '%s'".formatted(xmxValueOrNull); } - int maxNumberOfThreads = NativeImageOptions.NumberOfThreads.getValue(); + int maxNumberOfThreads = NativeImageOptions.getActualNumberOfThreads(); recordJsonMetric(ResourceUsageKey.PARALLELISM, maxNumberOfThreads); int availableProcessors = runtime.availableProcessors(); recordJsonMetric(ResourceUsageKey.CPU_CORES_TOTAL, availableProcessors); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index 99f6b23593fe..f46a8f9c3d77 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -32,32 +32,36 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.JarURLConnection; import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +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.Collection; import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.LongAdder; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionType; -import jdk.graal.compiler.phases.util.Providers; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; import org.graalvm.nativeimage.impl.ConfigurationCondition; @@ -83,12 +87,21 @@ import com.oracle.svm.core.option.LocatableMultiOptionValue; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.config.ConfigurationParserUtils; import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.util.LogUtils; +import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionType; +import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -133,13 +146,21 @@ public static class Options { } private boolean sealed = false; - private final Set resourcePatternWorkSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); + + private record ConditionalPattern(ConfigurationCondition condition, String pattern) { + } + + private record CompiledConditionalPattern(ConfigurationCondition condition, ResourcePattern compiledPattern) { + } + + private Set resourcePatternWorkSet = Collections.newSetFromMap(new ConcurrentHashMap<>()); private final Set excludedResourcePatterns = Collections.newSetFromMap(new ConcurrentHashMap<>()); private int loadedConfigurations; private ImageClassLoader imageClassLoader; private class ResourcesRegistryImpl extends ConditionalConfigurationRegistry implements ResourcesRegistry { private final ConfigurationTypeResolver configurationTypeResolver; + private final Set alreadyAddedResources = new HashSet<>(); ResourcesRegistryImpl(ConfigurationTypeResolver configurationTypeResolver) { this.configurationTypeResolver = configurationTypeResolver; @@ -150,10 +171,26 @@ public void addResources(ConfigurationCondition condition, String pattern) { if (configurationTypeResolver.resolveConditionType(condition.getTypeName()) == null) { return; } - registerConditionalConfiguration(condition, () -> { - UserError.guarantee(!sealed, "Resources added too late: %s", pattern); - resourcePatternWorkSet.add(pattern); - }); + + try { + resourcePatternWorkSet.add(new ConditionalPattern(condition, pattern)); + } catch (UnsupportedOperationException e) { + throw UserError.abort("Resource registration should be performed before beforeAnalysis phase."); + } + } + + /* Adds single resource defined with its module and name */ + @Override + public void addResource(Module module, String resourcePath) { + if (!shouldRegisterResource(module, resourcePath)) { + return; + } + + if (module != null && module.isNamed()) { + processResourceFromModule(module, resourcePath); + } else { + processResourceFromClasspath(resourcePath); + } } @Override @@ -196,6 +233,181 @@ public void addResourceBundles(ConfigurationCondition condition, String basename } registerConditionalConfiguration(condition, () -> ImageSingletons.lookup(LocalizationFeature.class).prepareBundle(basename, locales)); } + + /* + * It is possible that one resource can be registered under different conditions + * (typeReachable). In some cases, few conditions will be satisfied, and we will try to + * register same resource for each satisfied condition. This function will check if the + * resource is already registered and prevent multiple registrations of same resource under + * different conditions + */ + public boolean shouldRegisterResource(Module module, String resourceName) { + // we only do this if we are on the classPath + if ((module == null || !module.isNamed())) { + /* + * This check is not thread safe! If the resource is not added yet, maybe some other + * thread is attempting to do it, so we have to perform same check again in + * synchronized block (in that case). Anyway this check will cut the case when we + * are sure that resource is added (so we don't need to enter synchronized block) + */ + if (alreadyAddedResources.contains(resourceName)) { + return false; + } + + // addResources can be called from multiple threads + synchronized (alreadyAddedResources) { + if (!alreadyAddedResources.contains(resourceName)) { + alreadyAddedResources.add(resourceName); + return true; + } else { + return false; + } + } + } else { + // always try to register module entries (we will check duplicates in addEntries) + return true; + } + } + + private void processResourceFromModule(Module module, String resourcePath) { + try { + String resourcePackage = jdk.internal.module.Resources.toPackageName(resourcePath); + if (!resourcePackage.isEmpty()) { + // if processing resource package, make sure that module exports that package + if (module.getPackages().contains(resourcePackage)) { + // Use Access.OPEN to find ALL resources within resource package + ModuleSupport.accessModuleByClass(ModuleSupport.Access.OPEN, ResourcesFeature.class, module, resourcePackage); + } + } + + InputStream is = module.getResourceAsStream(resourcePath); + boolean isDirectory = Files.isDirectory(Path.of(resourcePath)); + if (isDirectory) { + String content = getDirectoryContent(resourcePath, false); + Resources.singleton().registerDirectoryResource(module, resourcePath, content, false); + } else { + registerResource(module, resourcePath, false, is); + } + } catch (IOException e) { + Resources.singleton().registerIOException(module, resourcePath, e, LinkAtBuildTimeSupport.singleton().packageOrClassAtBuildTime(resourcePath)); + } + } + + private void processResourceFromClasspath(String resourcePath) { + Enumeration urls; + try { + /* + * There is an edge case where same resource name can be present in multiple jars + * (different resources), so we are collecting all resources with given name in all + * jars on classpath + */ + urls = imageClassLoader.getClassLoader().getResources(resourcePath); + } catch (IOException e) { + throw VMError.shouldNotReachHere("getResources for resourcePath " + resourcePath + " failed", e); + } + + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + try { + InputStream is = url.openStream(); + boolean fromJar = url.getProtocol().equalsIgnoreCase("jar"); + boolean isDirectory = resourceIsDirectory(url, fromJar, resourcePath); + if (isDirectory) { + String content = getDirectoryContent(fromJar ? url.toString() : Paths.get(url.toURI()).toString(), fromJar); + Resources.singleton().registerDirectoryResource(null, resourcePath, content, fromJar); + } else { + registerResource(null, resourcePath, fromJar, is); + } + } catch (IOException e) { + Resources.singleton().registerIOException(null, resourcePath, e, LinkAtBuildTimeSupport.singleton().packageOrClassAtBuildTime(resourcePath)); + return; + } catch (URISyntaxException e) { + throw VMError.shouldNotReachHere("resourceIsDirectory for resourcePath " + resourcePath + " failed", e); + } + } + } + + private void registerResource(Module module, String resourcePath, boolean fromJar, InputStream is) { + if (is == null) { + return; + } + + Resources.singleton().registerResource(module, resourcePath, is, fromJar); + + try { + is.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /* Util functions for resource attributes calculations */ + private String urlToJarPath(URL url) { + try { + return ((JarURLConnection) url.openConnection()).getJarFileURL().getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private boolean resourceIsDirectory(URL url, boolean fromJar, String resourcePath) throws IOException, URISyntaxException { + if (fromJar) { + try (JarFile jf = new JarFile(urlToJarPath(url))) { + return jf.getEntry(resourcePath).isDirectory(); + } + } else { + return Files.isDirectory(Path.of(url.toURI())); + } + } + + private String getDirectoryContent(String path, boolean fromJar) throws IOException { + Set content = new TreeSet<>(); + if (fromJar) { + try (JarFile jf = new JarFile(urlToJarPath(URI.create(path).toURL()))) { + String pathSeparator = FileSystems.getDefault().getSeparator(); + String directoryPath = path.split("!")[1]; + + // we are removing leading slash because jar entry names don't start with slash + if (directoryPath.startsWith(pathSeparator)) { + directoryPath = directoryPath.substring(1); + } + + Enumeration entries = jf.entries(); + while (entries.hasMoreElements()) { + String entry = entries.nextElement().getName(); + if (entry.startsWith(directoryPath)) { + String contentEntry = entry.substring(directoryPath.length()); + + // remove the leading slash + if (contentEntry.startsWith(pathSeparator)) { + contentEntry = contentEntry.substring(1); + } + + // prevent adding empty strings as a content + if (!contentEntry.isEmpty()) { + // get top level content only + int firstSlash = contentEntry.indexOf(pathSeparator); + if (firstSlash != -1) { + content.add(contentEntry.substring(0, firstSlash)); + } else { + content.add(contentEntry); + } + } + } + } + + } + } else { + try (Stream contentStream = Files.list(Path.of(path))) { + content = new TreeSet<>(contentStream + .map(Path::getFileName) + .map(Path::toString) + .toList()); + } + } + + return String.join(System.lineSeparator(), content); + } } @Override @@ -217,30 +429,60 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "resource", ConfigurationFiles.Options.ResourceConfigurationFiles, ConfigurationFiles.Options.ResourceConfigurationResources, ConfigurationFile.RESOURCES.getFileName()); - - resourcePatternWorkSet.addAll(Options.IncludeResources.getValue().values()); + resourcePatternWorkSet.addAll(Options.IncludeResources.getValue() + .values() + .stream() + .map(e -> new ConditionalPattern(ConfigurationCondition.alwaysTrue(), e)) + .toList()); excludedResourcePatterns.addAll(Options.ExcludeResources.getValue().values()); + + if (!resourcePatternWorkSet.isEmpty()) { + FeatureImpl.BeforeAnalysisAccessImpl beforeAnalysisAccess = (FeatureImpl.BeforeAnalysisAccessImpl) access; + Set includePatterns = resourcePatternWorkSet + .stream() + .map(e -> new CompiledConditionalPattern(e.condition(), makeResourcePattern(e.pattern()))) + .collect(Collectors.toSet()); + if (MissingRegistrationUtils.throwMissingRegistrationErrors()) { + includePatterns.stream() + .map(pattern -> pattern.compiledPattern) + .forEach(resourcePattern -> { + Resources.singleton().registerIncludePattern(resourcePattern.moduleName, resourcePattern.pattern.pattern()); + }); + } + ResourcePattern[] excludePatterns = compilePatterns(excludedResourcePatterns); + ResourceCollectorImpl collector = new ResourceCollectorImpl(includePatterns, excludePatterns, beforeAnalysisAccess); + try { + collector.prepareProgressReporter(); + ImageSingletons.lookup(ClassLoaderSupport.class).collectResources(collector); + } finally { + collector.shutDownProgressReporter(); + } + + // We set resourcePatternWorkSet to empty unmodifiable set, so we can be sure that it + // won't be populated in some later phase + resourcePatternWorkSet = Set.of(); + } + resourceRegistryImpl().flushConditionalConfiguration(access); } private static final class ResourceCollectorImpl implements ResourceCollector { - private final DebugContext debugContext; - private final ResourcePattern[] includePatterns; + private final Set includePatterns; private final ResourcePattern[] excludePatterns; - private static final int WATCHDOG_RESET_AFTER_EVERY_N_RESOURCES = 1000; private static final int WATCHDOG_INITIAL_WARNING_AFTER_N_SECONDS = 60; private static final int WATCHDOG_WARNING_AFTER_EVERY_N_SECONDS = 20; + private final FeatureImpl.BeforeAnalysisAccessImpl access; private final LongAdder reachedResourceEntries; private boolean initialReport; private volatile String currentlyProcessedEntry; ScheduledExecutorService scheduledExecutor; - private ResourceCollectorImpl(DebugContext debugContext, ResourcePattern[] includePatterns, ResourcePattern[] excludePatterns) { - this.debugContext = debugContext; + private ResourceCollectorImpl(Set includePatterns, ResourcePattern[] excludePatterns, FeatureImpl.BeforeAnalysisAccessImpl access) { this.includePatterns = includePatterns; this.excludePatterns = excludePatterns; + this.access = access; this.reachedResourceEntries = new LongAdder(); this.initialReport = true; this.currentlyProcessedEntry = null; @@ -267,7 +509,7 @@ private void shutDownProgressReporter() { } @Override - public boolean isIncluded(Module module, String resourceName, URI resource) { + public List isIncluded(Module module, String resourceName, URI resource) { this.currentlyProcessedEntry = resource.getScheme().equals("jrt") ? (resource + "/" + resourceName) : resource.toString(); this.reachedResourceEntries.increment(); @@ -283,30 +525,32 @@ public boolean isIncluded(Module module, String resourceName, URI resource) { continue; } if (rp.pattern.matcher(resourceName).matches() || rp.pattern.matcher(relativePathWithTrailingSlash).matches()) { - return false; + return List.of(); // nothing should match excluded resource } } - for (ResourcePattern rp : includePatterns) { - if (!rp.moduleNameMatches(moduleName)) { + // Possibly we can have multiple conditions for one resource + List conditions = new ArrayList<>(); + for (CompiledConditionalPattern rp : includePatterns) { + if (!rp.compiledPattern().moduleNameMatches(moduleName)) { continue; } - if (rp.pattern.matcher(resourceName).matches() || rp.pattern.matcher(relativePathWithTrailingSlash).matches()) { - return true; + if (rp.compiledPattern().pattern.matcher(resourceName).matches() || rp.compiledPattern().pattern.matcher(relativePathWithTrailingSlash).matches()) { + conditions.add(rp.condition()); } } - return false; + return conditions; } @Override - public void addResource(Module module, String resourceName, InputStream resourceStream, boolean fromJar) { - registerResource(debugContext, module, resourceName, resourceStream, fromJar); + public void addResource(Module module, String resourceName) { + ImageSingletons.lookup(RuntimeResourceSupport.class).addResource(module, resourceName); } @Override - public void addDirectoryResource(Module module, String dir, String content, boolean fromJar) { - registerDirectoryResource(debugContext, module, dir, content, fromJar); + public void addResourceConditionally(Module module, String resourceName, ConfigurationCondition condition) { + access.registerReachabilityHandler(e -> addResource(module, resourceName), access.findClassByName(condition.getTypeName())); } @Override @@ -320,34 +564,6 @@ public void registerNegativeQuery(Module module, String resourceName) { } } - @Override - public void duringAnalysis(DuringAnalysisAccess access) { - resourceRegistryImpl().flushConditionalConfiguration(access); - if (resourcePatternWorkSet.isEmpty()) { - return; - } - - access.requireAnalysisIteration(); - - DuringAnalysisAccessImpl duringAnalysisAccess = ((DuringAnalysisAccessImpl) access); - ResourcePattern[] includePatterns = compilePatterns(resourcePatternWorkSet); - if (MissingRegistrationUtils.throwMissingRegistrationErrors()) { - for (ResourcePattern resourcePattern : includePatterns) { - Resources.singleton().registerIncludePattern(resourcePattern.moduleName, resourcePattern.pattern.pattern()); - } - } - ResourcePattern[] excludePatterns = compilePatterns(excludedResourcePatterns); - DebugContext debugContext = duringAnalysisAccess.getDebugContext(); - ResourceCollectorImpl collector = new ResourceCollectorImpl(debugContext, includePatterns, excludePatterns); - try { - collector.prepareProgressReporter(); - ImageSingletons.lookup(ClassLoaderSupport.class).collectResources(collector); - } finally { - collector.shutDownProgressReporter(); - } - resourcePatternWorkSet.clear(); - } - private ResourcePattern[] compilePatterns(Set patterns) { return patterns.stream() .filter(s -> s.length() > 0) @@ -366,14 +582,7 @@ private ResourcePattern makeResourcePattern(String rawPattern) { } } - private static final class ResourcePattern { - final String moduleName; - final Pattern pattern; - - private ResourcePattern(String moduleName, Pattern pattern) { - this.moduleName = moduleName; - this.pattern = pattern; - } + private record ResourcePattern(String moduleName, Pattern pattern) { boolean moduleNameMatches(String resourceContainerModuleName) { if (moduleName == null) { @@ -404,24 +613,6 @@ public void beforeCompilation(BeforeCompilationAccess access) { } } - @SuppressWarnings("try") - private static void registerResource(DebugContext debugContext, Module module, String resourceName, InputStream resourceStream, boolean fromJar) { - try (DebugContext.Scope s = debugContext.scope("registerResource")) { - String moduleNamePrefix = module == null ? "" : module.getName() + ":"; - debugContext.log(DebugContext.VERBOSE_LEVEL, "ResourcesFeature: registerResource: %s%s", moduleNamePrefix, resourceName); - Resources.singleton().registerResource(module, resourceName, resourceStream, fromJar); - } - } - - @SuppressWarnings("try") - private static void registerDirectoryResource(DebugContext debugContext, Module module, String dir, String content, boolean fromJar) { - try (DebugContext.Scope s = debugContext.scope("registerResource")) { - String moduleNamePrefix = module == null ? "" : module.getName() + ":"; - debugContext.log(DebugContext.VERBOSE_LEVEL, "ResourcesFeature: registerResource: %s%s", moduleNamePrefix, dir); - Resources.singleton().registerDirectoryResource(module, dir, content, fromJar); - } - } - @Override public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) { if (!reason.duringAnalysis() || reason == ParsingReason.JITCompilation) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index f096d25329d0..063263b7ef68 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -27,11 +27,6 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.concurrent.ForkJoinPool; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -51,6 +46,10 @@ import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -66,9 +65,9 @@ public class NativeImagePointsToAnalysis extends PointsToAnalysis implements Inf public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse universe, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, - AnnotationSubstitutionProcessor annotationSubstitutionProcessor, ForkJoinPool executor, UnsupportedFeatures unsupportedFeatures, - TimerCollection timerCollection) { - super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, executor, unsupportedFeatures, timerCollection, + AnnotationSubstitutionProcessor annotationSubstitutionProcessor, UnsupportedFeatures unsupportedFeatures, + DebugContext debugContext, TimerCollection timerCollection) { + super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, SubstrateOptions.parseOnce()); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java index 0b129a9cf1c8..7d013ac2f524 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java @@ -24,12 +24,6 @@ */ package com.oracle.svm.hosted.analysis; -import java.util.concurrent.ForkJoinPool; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.word.WordTypes; - import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -41,6 +35,10 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.ConstantReflectionProvider; public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisEngine implements Inflation { @@ -51,12 +49,10 @@ public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisE private final CustomTypeFieldHandler unknownFieldHandler; @SuppressWarnings("this-escape") - public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, - AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, - AnnotationSubstitutionProcessor annotationSubstitutionProcessor, - ForkJoinPool executor, TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { - super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, executor, new SubstrateUnsupportedFeatures(), timerCollection, + public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, DebugContext debugContext, + TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { + super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new SubstrateUnsupportedFeatures(), debugContext, timerCollection, reachabilityMethodProcessingHandler); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; this.strengthenGraalGraphs = SubstrateOptions.parseOnce(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index b7592f7e9287..52fac102b699 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -37,7 +37,6 @@ import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ForkJoinPool; import org.graalvm.collections.EconomicMap; import jdk.graal.compiler.api.replacements.Fold; @@ -361,14 +360,14 @@ public Description getDescription() { @SuppressWarnings("this-escape") public CompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse universe, RuntimeConfiguration runtimeConfiguration, Boolean deoptimizeAll, - SnippetReflectionProvider snippetReflection, ForkJoinPool executorService) { + SnippetReflectionProvider snippetReflection) { this.universe = universe; this.compilations = new ConcurrentHashMap<>(); this.runtimeConfig = runtimeConfiguration; this.metaAccess = runtimeConfiguration.getProviders().getMetaAccess(); this.deoptimizeAll = deoptimizeAll; this.dataCache = new ConcurrentHashMap<>(); - this.executor = new CompletionExecutor(universe.getBigBang(), executorService); + this.executor = new CompletionExecutor(debug, universe.getBigBang()); this.featureHandler = featureHandler; this.snippetReflection = snippetReflection; this.graphTransplanter = createGraphTransplanter(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java index 8efb24238a98..1937ff5c7081 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.util.List; -import java.util.concurrent.ForkJoinPool; import jdk.graal.compiler.debug.DebugContext; @@ -54,16 +53,12 @@ public enum NativeImageKind { SHARED_LIBRARY(false) { @Override public String getFilenameSuffix() { - switch (ObjectFile.getNativeFormat()) { - case ELF: - return ".so"; - case MACH_O: - return ".dylib"; - case PECOFF: - return ".dll"; - default: - throw new AssertionError("Unreachable"); - } + return switch (ObjectFile.getNativeFormat()) { + case ELF -> ".so"; + case MACH_O -> ".dylib"; + case PECOFF -> ".dll"; + default -> throw new AssertionError("Unreachable"); + }; } }, EXECUTABLE(true), @@ -123,17 +118,17 @@ public NativeLibraries getNativeLibs() { /** * Write the image to the named file. */ - public abstract LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config, ForkJoinPool forkJoinPool); + public abstract LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config); // factory method public static AbstractImage create(NativeImageKind k, HostedUniverse universe, HostedMetaAccess metaAccess, NativeLibraries nativeLibs, NativeImageHeap heap, NativeImageCodeCache codeCache, List entryPoints, ClassLoader classLoader) { - switch (k) { - case SHARED_LIBRARY: - return new SharedLibraryImageViaCC(universe, metaAccess, nativeLibs, heap, codeCache, entryPoints, classLoader); - default: - return new ExecutableImageViaCC(k, universe, metaAccess, nativeLibs, heap, codeCache, entryPoints, classLoader); - } + return switch (k) { + case SHARED_LIBRARY -> + new SharedLibraryImageViaCC(universe, metaAccess, nativeLibs, heap, codeCache, entryPoints, classLoader); + case EXECUTABLE, STATIC_EXECUTABLE -> + new ExecutableImageViaCC(k, universe, metaAccess, nativeLibs, heap, codeCache, entryPoints, classLoader); + }; } public abstract String[] makeLaunchCommand(AbstractImage.NativeImageKind k, String imageName, Path binPath, Path workPath, java.lang.reflect.Method method); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java index 41597934921c..959bd979b12c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java @@ -50,7 +50,6 @@ import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.util.ImageGeneratorThreadMarker; /** * Complain if there are types that can not move from the image generator heap to the image heap. @@ -113,10 +112,6 @@ private static String[] getDisallowedSubstrings(String... substrings) { } private Object replacer(Object original) { - if (original instanceof Thread && original instanceof ImageGeneratorThreadMarker) { - return ((ImageGeneratorThreadMarker) original).asTerminated(); - } - checkDisallowedMBeanObjects(original); if (original instanceof String && disallowedSubstrings != null) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java index ad1db7eb3ffd..ff00eea47e36 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java @@ -216,7 +216,7 @@ public void printSummaryInfoForEveryObjectInConnectedComponents(PrintWriter out) for (Iterator iterator = connectedComponents.iterator(); iterator.hasNext();) { ConnectedComponent connectedComponent = iterator.next(); writer.append('{').newline(); - writer.quote("componentId").append(':').quote(connectedComponent.getId()).append(',').newline(); + writer.quote("componentId").append(':').printValue(connectedComponent.getId()).append(',').newline(); writer.quote("sizeInBytes").append(':').append(String.valueOf(connectedComponent.getSizeInBytes())).append(',').newline(); writer.quote("objects").append(":["); List objects = connectedComponent.getObjects(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index efa5b82136b4..c7cf1c37bec5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -30,7 +30,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -139,7 +138,7 @@ private boolean verifyMethodLayout() { @SuppressWarnings("try") @Override - public void layoutMethods(DebugContext debug, BigBang bb, ForkJoinPool threadPool) { + public void layoutMethods(DebugContext debug, BigBang bb) { try (Indent indent = debug.logAndIndent("layout methods")) { // Assign initial location to all methods. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index d2cc85366598..695c6ca05d6b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -46,7 +46,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; import org.graalvm.collections.Pair; @@ -159,13 +158,13 @@ public NativeImage(NativeImageKind k, HostedUniverse universe, HostedMetaAccess @Override public abstract String[] makeLaunchCommand(NativeImageKind k, String imageName, Path binPath, Path workPath, java.lang.reflect.Method method); - protected final void write(DebugContext context, Path outputFile, ForkJoinPool forkJoinPool) { + protected final void write(DebugContext context, Path outputFile) { try { Path outFileParent = outputFile.normalize().getParent(); if (outFileParent != null) { Files.createDirectories(outFileParent); } - objectFile.write(context, outputFile, forkJoinPool); + objectFile.write(context, outputFile); } catch (Exception ex) { throw shouldNotReachHere(ex); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index 195f666b8952..768433377bc8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -46,7 +46,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; import com.oracle.svm.hosted.DeadlockWatchdog; @@ -191,7 +190,7 @@ protected CompilationResult compilationResultFor(HostedMethod method) { return compilations.get(method); } - public abstract void layoutMethods(DebugContext debug, BigBang bb, ForkJoinPool threadPool); + public abstract void layoutMethods(DebugContext debug, BigBang bb); public void layoutConstants() { for (Pair pair : getOrderedCompilations()) { @@ -263,11 +262,11 @@ public int getAlignedConstantsSize() { return ConfigurationValues.getObjectLayout().alignUp(getConstantsSize()); } - public void buildRuntimeMetadata(SnippetReflectionProvider snippetReflectionProvider, ForkJoinPool threadPool) { - buildRuntimeMetadata(snippetReflectionProvider, threadPool, new MethodPointer(getFirstCompilation().getLeft(), true), WordFactory.signed(getCodeAreaSize())); + public void buildRuntimeMetadata(DebugContext debug, SnippetReflectionProvider snippetReflectionProvider) { + buildRuntimeMetadata(debug, snippetReflectionProvider, new MethodPointer(getFirstCompilation().getLeft(), true), WordFactory.signed(getCodeAreaSize())); } - protected void buildRuntimeMetadata(SnippetReflectionProvider snippetReflection, ForkJoinPool threadPool, CFunctionPointer firstMethod, UnsignedWord codeSize) { + protected void buildRuntimeMetadata(DebugContext debug, SnippetReflectionProvider snippetReflection, CFunctionPointer firstMethod, UnsignedWord codeSize) { // Build run-time metadata. HostedFrameInfoCustomization frameInfoCustomization = new HostedFrameInfoCustomization(); CodeInfoEncoder.Encoders encoders = new CodeInfoEncoder.Encoders(); @@ -425,7 +424,7 @@ protected void buildRuntimeMetadata(SnippetReflectionProvider snippetReflection, verifyDeoptEntries(imageCodeInfo); } - assert verifyMethods(hUniverse, threadPool, codeInfoEncoder, imageCodeInfo); + assert verifyMethods(debug, hUniverse, codeInfoEncoder, imageCodeInfo); } protected HostedImageCodeInfo installCodeInfo(SnippetReflectionProvider snippetReflection, CFunctionPointer firstMethod, UnsignedWord codeSize, CodeInfoEncoder codeInfoEncoder, @@ -568,12 +567,12 @@ private static boolean error(HostedMethod method, long encodedBci, String msg) { return true; } - protected boolean verifyMethods(HostedUniverse hUniverse, ForkJoinPool threadPool, CodeInfoEncoder codeInfoEncoder, CodeInfo codeInfo) { + protected boolean verifyMethods(DebugContext debug, HostedUniverse hUniverse, CodeInfoEncoder codeInfoEncoder, CodeInfo codeInfo) { /* * Run method verification in parallel to reduce computation time. */ BigBang bb = hUniverse.getBigBang(); - CompletionExecutor executor = new CompletionExecutor(bb, threadPool); + CompletionExecutor executor = new CompletionExecutor(debug, bb); try { executor.init(); executor.start(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageViaCC.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageViaCC.java index 7870870bc43f..cce7224184ac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageViaCC.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageViaCC.java @@ -34,7 +34,6 @@ import java.util.Collections; import java.util.Formatter; import java.util.List; -import java.util.concurrent.ForkJoinPool; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -89,13 +88,13 @@ private static List diagnoseLinkerFailure(String linkerOutput) { @Override @SuppressWarnings("try") - public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config, ForkJoinPool forkJoinPool) { + public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config) { try (Indent indent = debug.logAndIndent("Writing native image")) { // 0. Free codecache to make space for writing the objectFile codeCache.purge(); // 1. write the relocatable file - write(debug, tempDirectory.resolve(imageName + ObjectFile.getFilenameSuffix()), forkJoinPool); + write(debug, tempDirectory.resolve(imageName + ObjectFile.getFilenameSuffix())); if (NativeImageOptions.ExitAfterRelocatableImageWrite.getValue()) { return null; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/SharedLibraryImageViaCC.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/SharedLibraryImageViaCC.java index 44e18ba9c9c0..2f4d73adc14f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/SharedLibraryImageViaCC.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/SharedLibraryImageViaCC.java @@ -28,7 +28,6 @@ import java.lang.reflect.Method; import java.nio.file.Path; import java.util.List; -import java.util.concurrent.ForkJoinPool; import jdk.graal.compiler.debug.DebugContext; @@ -53,8 +52,8 @@ public String[] makeLaunchCommand(NativeImageKind k, String imageName, Path binP } @Override - public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config, ForkJoinPool forkJoinPool) { - LinkerInvocation inv = super.write(debug, outputDirectory, tempDirectory, imageName, config, forkJoinPool); + public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config) { + LinkerInvocation inv = super.write(debug, outputDirectory, tempDirectory, imageName, config); writeHeaderFiles(outputDirectory, imageName, false); writeHeaderFiles(outputDirectory, imageName, true); return inv; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java index 0d54073ac9ba..8da31a190df0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java @@ -24,17 +24,16 @@ */ package com.oracle.svm.hosted.jdk.localization; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.impl.ConfigurationCondition; +import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; -import com.oracle.svm.core.configure.ResourcesRegistry; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; @AutomaticallyRegisteredFeature class CharsetSubstitutionsFeature implements InternalFeature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - ImageSingletons.lookup(ResourcesRegistry.class).addResources(ConfigurationCondition.create("java.lang.CharacterName"), "java/lang/uniName.dat"); + access.registerReachabilityHandler((e) -> RuntimeResourceAccess.addResource(Class.class.getModule(), + "java/lang/uniName.dat"), access.findClassByName("java.lang.CharacterName")); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java index 573ef4ddb6d9..89dc8f45fdcf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java @@ -61,12 +61,6 @@ import java.util.stream.Collectors; import org.graalvm.collections.Pair; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionStability; -import jdk.graal.compiler.options.OptionType; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -89,7 +83,14 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; +import com.oracle.svm.hosted.ImageClassLoader; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionStability; +import jdk.graal.compiler.options.OptionType; import jdk.internal.access.SharedSecrets; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -161,6 +162,7 @@ public class LocalizationFeature implements InternalFeature { private Field localeObjectCacheMapField; private Field langAliasesCacheField; private Field parentLocalesMapField; + @Platforms(Platform.HOSTED_ONLY.class) private ImageClassLoader imageClassLoader; public static class Options { @Option(help = "Comma separated list of bundles to be included into the image.", type = OptionType.User)// @@ -292,6 +294,8 @@ public void duringSetup(DuringSetupAccess a) { String reason = "All ResourceBundleControlProvider that are registered as services end up as objects in the image heap, and are therefore registered to be initialized at image build time"; ServiceLoader.load(ResourceBundleControlProvider.class).stream() .forEach(provider -> ImageSingletons.lookup(RuntimeClassInitializationSupport.class).initializeAtBuildTime(provider.type(), reason)); + + this.imageClassLoader = access.getImageClassLoader(); } /** @@ -639,14 +643,14 @@ private void prepareBundle(String bundleName, ResourceBundle bundle, Locale loca */ for (ResourceBundle cur = bundle; cur != null; cur = SharedSecrets.getJavaUtilResourceBundleAccess().getParent(cur)) { /* Register all bundles with their corresponding locales */ - support.prepareBundle(bundleName, cur, cur.getLocale()); + support.prepareBundle(bundleName, cur, this.imageClassLoader::findModule, cur.getLocale()); } /* * Finally, register the requested bundle with requested locale (Requested might be more * specific than the actual bundle locale */ - support.prepareBundle(bundleName, bundle, locale); + support.prepareBundle(bundleName, bundle, this.imageClassLoader::findModule, locale); } @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/xml/XMLParsersRegistration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/xml/XMLParsersRegistration.java index ed1cb565df8f..13940b2be407 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/xml/XMLParsersRegistration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/xml/XMLParsersRegistration.java @@ -135,7 +135,20 @@ void registerResources() { ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xml.internal.serializer.utils.SerializerMessages"); ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMessages"); - ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), "com.sun.*.properties"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xml.internal.serializer.Encodings"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xml.internal.serializer.HTMLEntities"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xml.internal.serializer.XMLEntities"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.xpath.regex.message"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.DOMMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.DatatypeMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.JAXPValidationMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.SAXMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.XIncludeMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.XMLMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.XMLSchemaMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.XMLSerializerMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xerces.internal.impl.msg.XPointerMessages"); + ImageSingletons.lookup(RuntimeResourceSupport.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), "com.sun.org.apache.xalan.internal.res.XSLTInfo"); classInitializationSupport.setConfigurationSealed(true); } diff --git a/substratevm/src/com.oracle.svm.test/src/META-INF/native-image/com.oracle.svm.test/resource-config.json b/substratevm/src/com.oracle.svm.test/src/META-INF/native-image/com.oracle.svm.test/resource-config.json new file mode 100644 index 000000000000..16146de3e580 --- /dev/null +++ b/substratevm/src/com.oracle.svm.test/src/META-INF/native-image/com.oracle.svm.test/resource-config.json @@ -0,0 +1,13 @@ +{ + "bundles": [], + "resources": { + "includes": [ + { + "condition": { + "typeReachable": "java.lang.String" + }, + "pattern": "resourcesFromDir" + } + ] + } +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceTest.java index 2afbe70d49cb..a4fe9af3cfbf 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceTest.java @@ -30,21 +30,26 @@ import static com.oracle.svm.test.NativeImageResourceUtils.RESOURCE_FILE_2; import static com.oracle.svm.test.NativeImageResourceUtils.RESOURCE_FILE_3; import static com.oracle.svm.test.NativeImageResourceUtils.RESOURCE_FILE_4; +import static com.oracle.svm.test.NativeImageResourceUtils.SIMPLE_RESOURCE_DIR; import static com.oracle.svm.test.NativeImageResourceUtils.compareTwoURLs; import static com.oracle.svm.test.NativeImageResourceUtils.resourceNameToURL; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.StreamSupport; import org.junit.Assert; @@ -126,6 +131,36 @@ public void classGetDirectoryResource() { resourceNameToURL(nonCanonicalResourceDirectoryName, false); } + @Test + public void registeredResourceDirectoryHasContent() throws IOException { + URL directory = NativeImageResourceUtils.class.getResource(SIMPLE_RESOURCE_DIR); + Assert.assertNotNull("Resource " + SIMPLE_RESOURCE_DIR + " is not found!", directory); + + BufferedReader reader = new BufferedReader(new InputStreamReader(directory.openStream())); + Assert.assertNotNull("Resource" + SIMPLE_RESOURCE_DIR + " should have content", reader.readLine()); + } + + @Test + public void getConditionalDirectoryResource() throws IOException { + // check if resource is added conditionally + String directoryName = "/resourcesFromDir"; + URL directory = NativeImageResourceUtils.class.getResource(directoryName); + Assert.assertNotNull("Resource " + directoryName + " is not found!", directory); + + // check content of resource + List expected = IntStream.range(0, 4).mapToObj(i -> "cond-resource" + i + ".txt").toList(); + BufferedReader reader = new BufferedReader(new InputStreamReader(directory.openStream())); + List actual = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + actual.add(line); + } + + for (String resource : expected) { + Assert.assertTrue(actual.contains(resource)); + } + } + /** *

* Access a resource using {@link URLClassLoader}. diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceUtils.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceUtils.java index 8d07f56f7f91..7cd52b889c7a 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceUtils.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/NativeImageResourceUtils.java @@ -42,6 +42,7 @@ public class NativeImageResourceUtils { public static final String ROOT_DIRECTORY = "/"; public static final String RESOURCE_DIR = "/resources"; + public static final String SIMPLE_RESOURCE_DIR = "/simpleDir"; public static final String RESOURCE_EMPTY_DIR = RESOURCE_DIR + "/empty"; public static final String RESOURCE_FILE_1 = RESOURCE_DIR + "/resource-test1.txt"; public static final String RESOURCE_FILE_2 = RESOURCE_DIR + "/resource-test2.txt"; @@ -55,6 +56,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { // Remove leading / for the resource patterns Module resourceModule = TestFeature.class.getModule(); RuntimeResourceAccess.addResource(resourceModule, RESOURCE_DIR.substring(1)); + RuntimeResourceAccess.addResource(resourceModule, SIMPLE_RESOURCE_DIR.substring(1)); RuntimeResourceAccess.addResource(resourceModule, RESOURCE_EMPTY_DIR.substring(1)); RuntimeResourceAccess.addResource(resourceModule, RESOURCE_FILE_1.substring(1)); RuntimeResourceAccess.addResource(resourceModule, RESOURCE_FILE_2.substring(1)); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 75f89555ad7b..5bc549275818 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -229,8 +229,6 @@ public boolean getAsBoolean() { private final Set> registeredClasses = new HashSet<>(); private final Map, PossibleReplaceCandidatesSubtypeHandler> subtypeChecks = new HashMap<>(); private boolean profilingEnabled; - private boolean needsAllEncodings; - private Field uncachedDispatchField; private Field layoutInfoMapField; private Field layoutMapField; @@ -241,6 +239,8 @@ public boolean getAsBoolean() { private Consumer markAsUnsafeAccessed; private final ConcurrentMap processedInlinedFields = new ConcurrentHashMap<>(); + private boolean needsAllEncodings; + private static void initializeTruffleReflectively(ClassLoader imageClassLoader) { invokeStaticMethod("com.oracle.truffle.api.impl.Accessor", "getTVMCI", Collections.emptyList()); invokeStaticMethod("com.oracle.truffle.polyglot.InternalResourceCache", "initializeNativeImageState", @@ -449,6 +449,10 @@ public void duringSetup(DuringSetupAccess access) { if (Options.TruffleCheckPreinitializedFiles.getValue()) { access.registerObjectReplacer(new TruffleFileCheck(((FeatureImpl.DuringSetupAccessImpl) access).getHostVM().getClassInitializationSupport())); } + + if (needsAllEncodings) { + ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), "org/graalvm/shadowed/org/jcodings/tables/.*bin$"); + } } void setGraalGraphObjectReplacer(GraalGraphObjectReplacer graalGraphObjectReplacer) { @@ -482,9 +486,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { config.registerSubtypeReachabilityHandler(TruffleBaseFeature::registerTruffleLibrariesAsInHeap, LibraryExport.class); - if (needsAllEncodings) { - ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), "org/graalvm/shadowed/org/jcodings/tables/.*bin$"); - } Class frameClass = config.findClassByName("com.oracle.truffle.api.impl.FrameWithoutBoxing"); config.registerFieldValueTransformer(config.findField(frameClass, "ASSERTIONS_ENABLED"), new AssertionStatusFieldTransformer(frameClass)); } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ImageGeneratorThreadMarker.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ImageGeneratorThreadMarker.java deleted file mode 100644 index d11e1e338fd1..000000000000 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ImageGeneratorThreadMarker.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.util; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -/** - * Marker interface to identify threads that are only used by SubstateVM infrastructure and will not - * be present in the image heap at run time. Each of such threads has a {@link #asTerminated() way} - * to obtain the terminated replacement of itself. - *

- * Not intented to be implemented by customer threads. Allowing background threads that are not - * terminated can lead to very hard to debug errors. If you have background threads running while - * the static analysis is running, then bad race conditions can happen: the static analysis looks at - * a heap snapshot at a "random" time from the point of view of the background thread. If the - * background thread makes new objects available after the last heap snapshot, then the static - * analysis misses objects of the image heap, which leads to either strange errors during image - * generation (when the image heap is written), or even worse strange behavior at run time (when a - * field is, e.g., constant folded to {@code null} because the static analysis only saw the - * {@code null} value). - */ -@Platforms(Platform.HOSTED_ONLY.class) -public interface ImageGeneratorThreadMarker /* extends Thread */ { - default Thread asTerminated() { - return TerminatedThread.SINGLETON; - } -} - -final class TerminatedThread extends Thread { - static final TerminatedThread SINGLETON; - static { - SINGLETON = new TerminatedThread("Terminated Infrastructure Thread"); - SINGLETON.start(); - try { - SINGLETON.join(); - } catch (InterruptedException ex) { - throw new IllegalStateException(ex); - } - } - - TerminatedThread(String name) { - super(name); - } -} diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java index 03ec51bdfa18..4b5738a6116d 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java @@ -131,7 +131,7 @@ public static void accessPackagesToClass(Access access, Class accessingClass, } @Platforms(Platform.HOSTED_ONLY.class) - private static void accessModuleByClass(Access access, Class accessingClass, Module declaringModule, String packageName) { + public static void accessModuleByClass(Access access, Class accessingClass, Module declaringModule, String packageName) { Module namedAccessingModule = null; if (accessingClass != null) { Module accessingModule = accessingClass.getModule(); diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java index f6061945d9d2..d8c339153c63 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java @@ -97,4 +97,12 @@ public static final String joinSingleQuoted(Object[] values) { public static final String joinSingleQuoted(List strings) { return joinSingleQuoted(strings.toArray(new String[strings.size()])); } + + public static String toSlashSeparated(String string) { + return string.replace('.', '/'); + } + + public static String toDotSeparated(String string) { + return string.replace('/', '.'); + } } diff --git a/vm/ci/ci_common/common-bench.jsonnet b/vm/ci/ci_common/common-bench.jsonnet index a3a8a1428f0c..c79e172d5232 100644 --- a/vm/ci/ci_common/common-bench.jsonnet +++ b/vm/ci/ci_common/common-bench.jsonnet @@ -1,5 +1,6 @@ # note: this file needs to be in sync between CE and EE +local utils = import '../../../ci/ci_common/common-utils.libsonnet'; local vm = import '../ci_includes/vm.jsonnet'; local common = import '../../../ci/ci_common/common.jsonnet'; local vm_common = import '../ci_common/common.jsonnet'; @@ -322,5 +323,5 @@ local repo_config = import '../../../ci/repo-configuration.libsonnet'; vm_common.gate_vm_linux_amd64 + self.vm_gate_polybench_linux + {name: 'gate-vm-' + vm.vm_setup.short_name + '-polybench-linux-amd64'}, ], - builds: [{'defined_in': std.thisFile} + b for b in builds], + builds: utils.add_defined_in(builds, std.thisFile), } diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 9dc6d7f375fe..55873d1a6d99 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -1,5 +1,6 @@ local vm = import '../ci_includes/vm.jsonnet'; local graal_common = import '../../../ci/ci_common/common.jsonnet'; +local utils = import '../../../ci/ci_common/common-utils.libsonnet'; local repo_config = import '../../../repo-configuration.libsonnet'; local devkits = graal_common.devkits; @@ -857,5 +858,5 @@ local devkits = graal_common.devkits; vm.vm_java_Latest + sulong_vm_tests, ] + (import 'libgraal.jsonnet').builds, - builds:: [{'defined_in': std.thisFile} + b for b in builds], + builds:: utils.add_defined_in(builds, std.thisFile), } diff --git a/vm/ci/ci_includes/vm-bench.jsonnet b/vm/ci/ci_includes/vm-bench.jsonnet index bdd1215ac269..84d43f916cf8 100644 --- a/vm/ci/ci_includes/vm-bench.jsonnet +++ b/vm/ci/ci_includes/vm-bench.jsonnet @@ -1,3 +1,4 @@ +local utils = import '../../../ci/ci_common/common-utils.libsonnet'; local vm = import 'vm.jsonnet'; local vm_common = import '../ci_common/common.jsonnet'; local vm_common_bench = import '../ci_common/common-bench.jsonnet'; @@ -5,5 +6,5 @@ local vm_common_bench = import '../ci_common/common-bench.jsonnet'; { local builds = [], - builds: [{'defined_in': std.thisFile} + b for b in builds], -} \ No newline at end of file + builds: utils.add_defined_in(builds, std.thisFile) +} diff --git a/vm/ci/ci_includes/vm-native.jsonnet b/vm/ci/ci_includes/vm-native.jsonnet index 1ffd8fdae4d5..d2012f7ef46e 100644 --- a/vm/ci/ci_includes/vm-native.jsonnet +++ b/vm/ci/ci_includes/vm-native.jsonnet @@ -1,3 +1,4 @@ +local utils = import '../../../ci/ci_common/common-utils.libsonnet'; local vm = import 'vm.jsonnet'; local vm_common = import '../ci_common/common.jsonnet'; @@ -74,5 +75,5 @@ local vm_common = import '../ci_common/common.jsonnet'; vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + truffle_maven_downloader, ], - builds: [{'defined_in': std.thisFile} + b for b in builds], + builds: utils.add_defined_in(builds, std.thisFile), } diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 810ad59fc9d4..31b37dc31999 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -179,7 +179,8 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ['set-export', 'BRANCH_NAME', ['git', 'rev-parse', '--abbrev-ref', 'HEAD']], ['bash', '-c', 'if [[ ${BRANCH_NAME} == master ]] || [[ ${BRANCH_NAME} == release/* ]] || [[ ${BRANCH_NAME} == cpu/* ]]; then git -C ${MX_HOME} push origin +HEAD:refs/heads/graal/${BRANCH_NAME}; fi'] ], - name: 'post-merge-vm-update-stable-mx-branch-linux-amd64', + name: 'post-merge-vm-update-stable-mx-branch-linux-amd64', + notify_groups:: ['deploy'], }, @@ -224,7 +225,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; self.notify_releaser_build, ], - builds: [vm_common.verify_name(b1) for b1 in vm_common.builds + vm_common_bench.builds + vm_bench.builds + vm_native.builds + [{'defined_in': std.thisFile} + b2 for b2 in builds]], + builds: [vm_common.verify_name(b) for b in vm_common.builds + vm_common_bench.builds + vm_bench.builds + vm_native.builds + utils.add_defined_in(builds, std.thisFile)], compiler_gate:: (import '../../../compiler/ci/ci_common/gate.jsonnet') }