Skip to content

[GR-66438] [GR-66439] [GR-66440] [GR-66931] [GR-66939] Improvements for large truffle graphs. #11885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@
import org.junit.Assume;
import org.junit.Test;

import jdk.graal.compiler.core.phases.EconomyHighTier;
import jdk.graal.compiler.core.phases.EconomyMidTier;
import jdk.graal.compiler.graph.Graph;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.calc.AddNode;
import jdk.graal.compiler.phases.common.CanonicalizerPhase;
import jdk.graal.compiler.phases.common.DeoptimizationGroupingPhase;
import jdk.graal.compiler.phases.common.FloatingReadPhase;
import jdk.graal.compiler.phases.common.FrameStateAssignmentPhase;
import jdk.graal.compiler.phases.common.GuardLoweringPhase;
import jdk.graal.compiler.phases.common.HighTierLoweringPhase;
import jdk.graal.compiler.phases.common.LoopSafepointInsertionPhase;
import jdk.graal.compiler.phases.common.MidTierLoweringPhase;
import jdk.graal.compiler.phases.common.OptimizeOffsetAddressPhase;
import jdk.graal.compiler.phases.common.RemoveValueProxyPhase;
import jdk.graal.compiler.phases.common.WriteBarrierAdditionPhase;
import jdk.graal.compiler.phases.tiers.Suites;

/**
Expand All @@ -55,9 +62,22 @@ public void testSnippet0() {

StructuredGraph graph = parseEager("snippet0", StructuredGraph.AllowAssumptions.YES);

new EconomyHighTier().apply(graph, getDefaultHighTierContext());
// resembling an economy phase plan with floating reads

CanonicalizerPhase canonicalizer = CanonicalizerPhase.createSingleShot();
canonicalizer.apply(graph, getDefaultHighTierContext());
new HighTierLoweringPhase(canonicalizer, true).apply(graph, getDefaultHighTierContext());

new FloatingReadPhase(createCanonicalizerPhase()).apply(graph, getDefaultMidTierContext());
new EconomyMidTier().apply(graph, getDefaultMidTierContext());

new RemoveValueProxyPhase(canonicalizer).apply(graph, getDefaultMidTierContext());
new LoopSafepointInsertionPhase().apply(graph, getDefaultMidTierContext());
new GuardLoweringPhase().apply(graph, getDefaultMidTierContext());
new MidTierLoweringPhase(canonicalizer).apply(graph, getDefaultMidTierContext());
new FrameStateAssignmentPhase().apply(graph, getDefaultMidTierContext());
new DeoptimizationGroupingPhase().apply(graph, getDefaultMidTierContext());
canonicalizer.apply(graph, getDefaultMidTierContext());
new WriteBarrierAdditionPhase().apply(graph, getDefaultMidTierContext());

assertTrue(graph.getNodes().filter(AddNode.class).count() == 4);
new OptimizeOffsetAddressPhase(createCanonicalizerPhase()).apply(graph, getDefaultLowTierContext());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
import java.util.function.Function;
import java.util.function.Supplier;

import jdk.graal.compiler.core.common.PermanentBailoutException;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.phases.contract.NodeCostUtil;
import org.graalvm.polyglot.Context;
import org.junit.Assert;
import org.junit.Assume;
Expand All @@ -44,6 +41,10 @@
import com.oracle.truffle.runtime.OptimizedCallTarget;
import com.oracle.truffle.runtime.OptimizedRuntimeOptions;

import jdk.graal.compiler.core.common.PermanentBailoutException;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.phases.contract.NodeCostUtil;

public class NodeLimitTest extends PartialEvaluationTest {

@Before
Expand All @@ -66,8 +67,48 @@ public void oneRootNodeTestEnoughGraalNodeCount() {
expectAllOK(NodeLimitTest::createRootNode);
}

// test that the timeout function during PE works
@Test(expected = PermanentBailoutException.class)
public void testTimeOutLimit() {
// note the timeout may be subject to scaling (up) because we are running with assertions
final int secondTimeout = 2;
setupContext(Context.newBuilder().allowAllAccess(true).allowExperimentalOptions(true).option("compiler.CompilationTimeout", String.valueOf(secondTimeout)).build());

// NOTE: the following code is intentionally written to explode during partial evaluation!
// It is wrong in almost every way possible.
final RootNode rootNode = new TestRootNode() {
@Override
public Object execute(VirtualFrame frame) {
recurse();
foo();
return null;
}

@ExplodeLoop
private void recurse() {
for (int i = 0; i < 1000; i++) {
getF().apply(0);
}
}

private Function<Integer, Integer> getF() {
return new Function<>() {
@Override
public Integer apply(Integer integer) {
return integer < 500 ? getF().apply(integer + 1) : 0;
}
};
}
};
partialEval((OptimizedCallTarget) rootNode.getCallTarget(), new Object[]{});
}

// test the limit by setting a small one, normally the limit is not enabled
@Test(expected = PermanentBailoutException.class)
public void testDefaultLimit() {
public void testSetLimit() {
// a small resonable default to ensure if a user sets it the functionality works
setupContext(Context.newBuilder().allowAllAccess(true).allowExperimentalOptions(true).option("compiler.MaximumGraalGraphSize", String.valueOf(5000)).build());

// NOTE: the following code is intentionally written to explode during partial evaluation!
// It is wrong in almost every way possible.
final RootNode rootNode = new TestRootNode() {
Expand All @@ -80,7 +121,7 @@ public Object execute(VirtualFrame frame) {

@ExplodeLoop
private void recurse() {
for (int i = 0; i < 100; i++) {
for (int i = 0; i < 1000; i++) {
getF().apply(0);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

import jdk.graal.compiler.code.CompilationResult;
import jdk.graal.compiler.core.common.CompilationIdentifier;
import jdk.graal.compiler.core.common.util.CompilationAlarm;
import jdk.graal.compiler.debug.DebugContext;
import jdk.graal.compiler.graph.Graph;
import jdk.graal.compiler.graph.Node;
Expand Down Expand Up @@ -265,6 +266,7 @@ protected StructuredGraph partialEvalWithNodeEventListener(OptimizedCallTarget c
return partialEval(compilable, arguments, listener);
}

@SuppressWarnings("try")
private StructuredGraph partialEval(OptimizedCallTarget compilable, Object[] arguments, Graph.NodeEventListener nodeEventListener) {
// Executed AST so that all classes are loaded and initialized.
if (!preventProfileCalls) {
Expand Down Expand Up @@ -298,7 +300,8 @@ private StructuredGraph partialEval(OptimizedCallTarget compilable, Object[] arg
TruffleTier truffleTier = compiler.getTruffleTier();
final PartialEvaluator partialEvaluator = compiler.getPartialEvaluator();
try (PerformanceInformationHandler handler = PerformanceInformationHandler.install(
compiler.getConfig().runtime(), compiler.getOrCreateCompilerOptions(compilable))) {
compiler.getConfig().runtime(), compiler.getOrCreateCompilerOptions(compilable));
CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(debug.getOptions())) {
final TruffleTierContext context = TruffleTierContext.createInitialContext(partialEvaluator,
compiler.getOrCreateCompilerOptions(compilable),
debug, compilable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ private void handleIntermediateRoots(StructuredGraph graph) {
ResolvedJavaMethod method = graph.method();
PhaseTreeNode newRoot = new PhaseTreeIntermediateRoot(String.format("IntermediateRoot -> %s", method == null ? graph : method.format("%H.%n(%p)")), graph);
newRoot.parent = currentNode;
newRoot.startTimeNS = System.nanoTime();
currentNode.addChild(newRoot);
currentNode = newRoot;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public class EconomyHighTier extends BaseTier<HighTierContext> {

@SuppressWarnings("this-escape")
public EconomyHighTier() {
CanonicalizerPhase canonicalizer = CanonicalizerPhase.create();
appendPhase(EconomyMarkFixReadsPhase.SINGLETON);
CanonicalizerPhase canonicalizer = CanonicalizerPhase.createSingleShot();
appendPhase(canonicalizer);
appendPhase(new HighTierLoweringPhase(canonicalizer, true));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import jdk.graal.compiler.phases.common.AddressLoweringPhase;
import jdk.graal.compiler.phases.common.BarrierSetVerificationPhase;
import jdk.graal.compiler.phases.common.CanonicalizerPhase;
import jdk.graal.compiler.phases.common.EconomyPiRemovalPhase;
import jdk.graal.compiler.phases.common.ExpandLogicPhase;
import jdk.graal.compiler.phases.common.InitMemoryVerificationPhase;
import jdk.graal.compiler.phases.common.LowTierLoweringPhase;
Expand All @@ -46,10 +47,12 @@ public EconomyLowTier(OptionValues options) {
if (Graph.Options.VerifyGraalGraphs.getValue(options)) {
appendPhase(new InitMemoryVerificationPhase());
}
CanonicalizerPhase canonicalizer = CanonicalizerPhase.create();
CanonicalizerPhase canonicalizer = CanonicalizerPhase.createSingleShot();
appendPhase(new LowTierLoweringPhase(canonicalizer));
appendPhase(new ExpandLogicPhase(canonicalizer));

appendPhase(new EconomyPiRemovalPhase(canonicalizer));

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

import java.util.Optional;

import jdk.graal.compiler.nodes.GraphState;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.phases.BasePhase;
import jdk.graal.compiler.phases.Phase;

public class EconomyMarkFixReadsPhase extends Phase {

@Override
public Optional<BasePhase.NotApplicable> notApplicableTo(GraphState graphState) {
return ALWAYS_APPLICABLE;
}

@Override
protected void run(StructuredGraph graph) {
}

@Override
public void updateGraphState(GraphState graphState) {
/*
* In economy we never allow floating reads for the sake of compile speed, thus we mark the
* graph as already having fix reads.
*/
super.updateGraphState(graphState);
graphState.setAfterStage(GraphState.StageFlag.FIXED_READS);
}

public static final EconomyMarkFixReadsPhase SINGLETON = new EconomyMarkFixReadsPhase();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package jdk.graal.compiler.core.phases;

import jdk.graal.compiler.phases.common.CanonicalizerPhase;
import jdk.graal.compiler.phases.common.DeoptimizationGroupingPhase;
import jdk.graal.compiler.phases.common.FrameStateAssignmentPhase;
import jdk.graal.compiler.phases.common.GuardLoweringPhase;
import jdk.graal.compiler.phases.common.LoopSafepointInsertionPhase;
Expand All @@ -37,12 +38,13 @@ public class EconomyMidTier extends BaseTier<MidTierContext> {

@SuppressWarnings("this-escape")
public EconomyMidTier() {
CanonicalizerPhase canonicalizer = CanonicalizerPhase.create();
CanonicalizerPhase canonicalizer = CanonicalizerPhase.createSingleShot();
appendPhase(new RemoveValueProxyPhase(canonicalizer));
appendPhase(new LoopSafepointInsertionPhase());
appendPhase(new GuardLoweringPhase());
appendPhase(new MidTierLoweringPhase(canonicalizer));
appendPhase(new FrameStateAssignmentPhase());
appendPhase(new DeoptimizationGroupingPhase());
appendPhase(canonicalizer);
appendPhase(new WriteBarrierAdditionPhase());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,9 @@ private void lowerKlassLayoutHelperNode(KlassLayoutHelperNode n, LoweringTool to
StructuredGraph graph = n.graph();
assert !n.getHub().isConstant();
AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().klassLayoutHelperOffset);
n.replaceAtUsagesAndDelete(graph.unique(new FloatingReadNode(address, HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(NodeView.DEFAULT), null, BarrierType.NONE)));
ReadNode memoryRead = graph.add(new ReadNode(address, HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(NodeView.DEFAULT), null, BarrierType.NONE));
graph.addAfterFixed(tool.lastFixedNode(), memoryRead);
n.replaceAtUsagesAndDelete(memoryRead);
}

private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) {
Expand Down Expand Up @@ -856,7 +858,7 @@ private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph
ResolvedJavaType receiverType = invoke.getReceiverType();
if (hsMethod.isInVirtualMethodTable(receiverType)) {
JavaKind wordKind = runtime.getTarget().wordJavaKind;
ValueNode hub = createReadHub(graph, receiver, tool);
ValueNode hub = createReadHub(graph, receiver, tool, tool.lastFixedNode());

ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType);
// We use LocationNode.ANY_LOCATION for the reads that access the
Expand Down Expand Up @@ -907,7 +909,7 @@ public ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) {
}

@Override
protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, boolean isKnownObjectArray, FixedNode anchor) {
protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, boolean isKnownObjectArray, FixedNode anchor, LoweringTool tool, FixedWithNextNode insertAfter) {
GuardingNode guard = null;
if (!isKnownObjectArray) {
/*
Expand All @@ -918,7 +920,9 @@ protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode
guard = AbstractBeginNode.prevBegin(anchor);
}
AddressNode address = createOffsetAddress(graph, arrayHub, runtime.getVMConfig().arrayClassElementOffset);
return graph.unique(new FloatingReadNode(address, HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), guard));
ReadNode read = graph.add(new ReadNode(address, HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), guard, BarrierType.NONE));
graph.addAfterFixed(insertAfter, read);
return read;
}

private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
Expand Down Expand Up @@ -1140,7 +1144,7 @@ private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, i
}

@Override
protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool) {
protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool, FixedWithNextNode insertAfter) {
GraalHotSpotVMConfig config = runtime.getVMConfig();

if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
Expand All @@ -1153,17 +1157,22 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower
hubStamp = hubStamp.compressed(config.getKlassEncoding());
}

FixedWithNextNode effectiveInsertAfter = insertAfter;

if (config.useCompactObjectHeaders) {
AddressNode address = createOffsetAddress(graph, object, config.markOffset);
FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, COMPACT_HUB_LOCATION, null, StampFactory.forKind(JavaKind.Long), null, BarrierType.NONE));
ReadNode memoryRead = graph.add(new ReadNode(address, COMPACT_HUB_LOCATION, null, StampFactory.forKind(JavaKind.Long), null, BarrierType.NONE));
graph.addAfterFixed(insertAfter, memoryRead);
effectiveInsertAfter = memoryRead;
ValueNode rawCompressedHubWordSize = graph.addOrUnique(UnsignedRightShiftNode.create(memoryRead, ConstantNode.forInt(config.markWordKlassShift, graph), NodeView.DEFAULT));
ValueNode rawCompressedHub = graph.addOrUnique(NarrowNode.create(rawCompressedHubWordSize, 32, NodeView.DEFAULT));
ValueNode compressedKlassPointer = graph.addOrUnique(PointerCastNode.create(hubStamp, rawCompressedHub));
return HotSpotCompressionNode.uncompress(graph, compressedKlassPointer, config.getKlassEncoding());
}
AddressNode address = createOffsetAddress(graph, object, config.hubOffset);
LocationIdentity hubLocation = config.useCompressedClassPointers ? COMPRESSED_HUB_LOCATION : HUB_LOCATION;
FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE));
ReadNode memoryRead = graph.add(new ReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE));
graph.addAfterFixed(effectiveInsertAfter, memoryRead);
if (config.useCompressedClassPointers) {
return HotSpotCompressionNode.uncompress(graph, memoryRead, config.getKlassEncoding());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import jdk.graal.compiler.core.common.CompilationIdentifier;
import jdk.graal.compiler.core.common.GraalOptions;
import jdk.graal.compiler.core.common.LibGraalSupport;
import jdk.graal.compiler.core.phases.EconomyHighTier;
import jdk.graal.compiler.core.phases.EconomyMarkFixReadsPhase;
import jdk.graal.compiler.core.target.Backend;
import jdk.graal.compiler.debug.DebugContext;
import jdk.graal.compiler.debug.DebugContext.Builder;
Expand Down Expand Up @@ -312,11 +314,16 @@ public void updateGraphState(GraphState graphState) {
}

protected Suites createSuites() {
Suites defaultSuites = providers.getSuites().getDefaultSuites(options, providers.getLowerer().getTarget().arch).copy();
Suites original = providers.getSuites().getDefaultSuites(options, providers.getLowerer().getTarget().arch);
Suites defaultSuites = original.copy();

PhaseSuite<HighTierContext> emptyHighTier = new PhaseSuite<>();

emptyHighTier.appendPhase(new DisableOverflownCountedLoopsPhase());
emptyHighTier.appendPhase(new EmptyHighTier());
if (original.getHighTier() instanceof EconomyHighTier) {
emptyHighTier.appendPhase(EconomyMarkFixReadsPhase.SINGLETON);
}

defaultSuites.getMidTier().removeSubTypePhases(Speculative.class);
defaultSuites.getLowTier().removeSubTypePhases(Speculative.class);
Expand Down
Loading