Skip to content

Commit a3fa18a

Browse files
committed
Permit GVN of class initialization checks
1 parent c87f7e3 commit a3fa18a

File tree

3 files changed

+94
-45
lines changed

3 files changed

+94
-45
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassBeingInitializedCheckNode.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@
3434
import jdk.graal.compiler.nodeinfo.InputType;
3535
import jdk.graal.compiler.nodeinfo.NodeInfo;
3636
import jdk.graal.compiler.nodes.DeoptimizingFixedWithNextNode;
37+
import jdk.graal.compiler.nodes.FixedGlobalValueNumberable;
3738
import jdk.graal.compiler.nodes.ValueNode;
3839
import jdk.graal.compiler.nodes.memory.SingleMemoryKill;
3940
import jdk.graal.compiler.nodes.spi.Lowerable;
4041

4142
@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_4, size = SIZE_16)
42-
public class KlassBeingInitializedCheckNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill {
43+
public class KlassBeingInitializedCheckNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill, FixedGlobalValueNumberable {
4344
public static final NodeClass<KlassBeingInitializedCheckNode> TYPE = NodeClass.create(KlassBeingInitializedCheckNode.class);
4445

4546
@Input protected ValueNode klass;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.graal.compiler.nodes;
26+
27+
/**
28+
* Marker for a {@link FixedNode} that can be replaced by another node via
29+
* {@link jdk.graal.compiler.phases.common.DominatorBasedGlobalValueNumberingPhase}. This permits
30+
* unusual nodes to explicitly opt into processing by dominator GVN. Note that it's the
31+
* responsibility of the implementor to ensure the node and its subclasses can be safely value
32+
* numbered even in the presence of memory kills.
33+
*/
34+
public interface FixedGlobalValueNumberable extends FixedNodeInterface {
35+
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/DominatorBasedGlobalValueNumberingPhase.java

+57-44
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import jdk.graal.compiler.graph.NodeBitMap;
4242
import jdk.graal.compiler.graph.spi.NodeWithIdentity;
4343
import jdk.graal.compiler.nodes.ControlSinkNode;
44+
import jdk.graal.compiler.nodes.FixedGlobalValueNumberable;
4445
import jdk.graal.compiler.nodes.FixedGuardNode;
4546
import jdk.graal.compiler.nodes.FixedNode;
4647
import jdk.graal.compiler.nodes.FixedWithNextNode;
@@ -313,18 +314,22 @@ private static void processNode(FixedWithNextNode cur, LocationSet thisLoopKille
313314
final LoopBeginNode exitedLoop = ((LoopExitNode) cur).loopBegin();
314315
killLoopLocations(((HIRLoop) cfg.blockFor(exitedLoop).getLoop()).getKillLocations(), blockMap);
315316
}
317+
boolean mustGVN = (cur instanceof FixedGlobalValueNumberable);
318+
if (!mustGVN) {
319+
// Handle nodes which don't explicitly opt into DGVN
320+
if (MemoryKill.isMemoryKill(cur)) {
321+
blockMap.killValuesByPotentialMemoryKill(cur);
322+
return;
323+
}
316324

317-
if (MemoryKill.isMemoryKill(cur)) {
318-
blockMap.killValuesByPotentialMemoryKill(cur);
319-
return;
320-
}
321-
322-
if (!canGVN(cur)) {
323-
return;
325+
if (!canGVN(cur)) {
326+
return;
327+
}
324328
}
325329

326330
boolean canSubsitute = blockMap.hasSubstitute(cur);
327-
boolean canLICM = loopCandidate != null;
331+
// assume FixedGlobalValueNumberable nodes shouldn't be moved
332+
boolean canLICM = loopCandidate != null && !mustGVN;
328333
if (cur instanceof MemoryAccess) {
329334
MemoryAccess access = (MemoryAccess) cur;
330335
if (loopKillsLocation(thisLoopKilledLocations, access.getLocationIdentity())) {
@@ -347,15 +352,21 @@ private static void processNode(FixedWithNextNode cur, LocationSet thisLoopKille
347352
* a limited form of LICM for nodes that are dominated by the loop header and dominate
348353
* all exits. Such operations that are unconditionally executed in the particular loop.
349354
*/
355+
boolean substituted = false;
350356
if (canSubsitute) {
351357
// GVN node
352-
blockMap.substitute(cur, cfg, licmNodes, canLICM ? loopCandidate : null);
358+
substituted = blockMap.substitute(cur, cfg, licmNodes, canLICM ? loopCandidate : null);
353359
} else {
354360
if (canLICM) {
355361
tryPerformLICM(loopCandidate, cur, licmNodes);
356362
}
357363
blockMap.rememberNodeForGVN(cur);
358364
}
365+
if (mustGVN && !substituted) {
366+
if (MemoryKill.isMemoryKill(cur)) {
367+
blockMap.killValuesByPotentialMemoryKill(cur);
368+
}
369+
}
359370
}
360371

361372
@Override
@@ -589,47 +600,49 @@ public boolean hasSubstitute(Node n) {
589600
* Perform actual global value numbering. Replace node {@code n} with an equal node (inputs
590601
* and data fields) up in the dominance chain.
591602
*/
592-
public void substitute(Node n, ControlFlowGraph cfg, NodeBitMap licmNodes, Loop invariantInLoop) {
603+
public boolean substitute(Node n, ControlFlowGraph cfg, NodeBitMap licmNodes, Loop invariantInLoop) {
593604
Node edgeDataEqual = find(n);
594-
if (edgeDataEqual != null) {
595-
assert edgeDataEqual.graph() != null;
596-
assert edgeDataEqual instanceof FixedNode : "Only process fixed nodes";
597-
StructuredGraph graph = (StructuredGraph) edgeDataEqual.graph();
598-
599-
HIRBlock defBlock = cfg.blockFor(edgeDataEqual);
600-
601-
if (invariantInLoop != null) {
602-
HIRBlock loopDefBlock = cfg.blockFor(invariantInLoop.loopBegin()).getLoop().getHeader().getDominator();
603-
if (loopDefBlock.strictlyDominates(defBlock)) {
604-
/*
605-
* The LICM location strictly dominates the GVN location so it must be the
606-
* final location. Move the GVN node to the LICM location and then perform
607-
* the substitution normally.
608-
*/
609-
if (!tryPerformLICM(invariantInLoop, (FixedNode) edgeDataEqual, licmNodes)) {
610-
GraalError.shouldNotReachHere("tryPerformLICM must succeed for " + edgeDataEqual); // ExcludeFromJacocoGeneratedReport
611-
}
612-
} else {
613-
GraalError.guarantee(defBlock.dominates(loopDefBlock), "No dominance relation between GVN and LICM locations: %s and %s", defBlock, loopDefBlock);
605+
if (edgeDataEqual == null) {
606+
return false;
607+
}
608+
assert edgeDataEqual.graph() != null;
609+
assert edgeDataEqual instanceof FixedNode : "Only process fixed nodes";
610+
StructuredGraph graph = (StructuredGraph) edgeDataEqual.graph();
611+
612+
HIRBlock defBlock = cfg.blockFor(edgeDataEqual);
613+
614+
if (invariantInLoop != null) {
615+
HIRBlock loopDefBlock = cfg.blockFor(invariantInLoop.loopBegin()).getLoop().getHeader().getDominator();
616+
if (loopDefBlock.strictlyDominates(defBlock)) {
617+
/*
618+
* The LICM location strictly dominates the GVN location so it must be the final
619+
* location. Move the GVN node to the LICM location and then perform the
620+
* substitution normally.
621+
*/
622+
if (!tryPerformLICM(invariantInLoop, (FixedNode) edgeDataEqual, licmNodes)) {
623+
GraalError.shouldNotReachHere("tryPerformLICM must succeed for " + edgeDataEqual); // ExcludeFromJacocoGeneratedReport
614624
}
625+
} else {
626+
GraalError.guarantee(defBlock.dominates(loopDefBlock), "No dominance relation between GVN and LICM locations: %s and %s", defBlock, loopDefBlock);
615627
}
628+
}
616629

617-
if (!LoopUtility.canUseWithoutProxy(cfg, edgeDataEqual, n)) {
618-
earlyGVNAbort.increment(graph.getDebug());
619-
return;
620-
}
630+
if (!LoopUtility.canUseWithoutProxy(cfg, edgeDataEqual, n)) {
631+
earlyGVNAbort.increment(graph.getDebug());
632+
return false;
633+
}
621634

622-
graph.getDebug().log(DebugContext.VERY_DETAILED_LEVEL, "Early GVN: replacing %s with %s", n, edgeDataEqual);
623-
graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "Before replacing %s with %s", n, edgeDataEqual);
624-
n.replaceAtUsages(edgeDataEqual);
625-
GraphUtil.unlinkFixedNode((FixedWithNextNode) n);
626-
n.safeDelete();
627-
graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After replacing %s with %s", n, edgeDataEqual);
628-
earlyGVN.increment(graph.getDebug());
629-
if (graph.getDebug().isCountEnabled()) {
630-
DebugContext.counter(earlyGVN.getName() + "_" + edgeDataEqual.getClass().getSimpleName()).increment(graph.getDebug());
631-
}
635+
graph.getDebug().log(DebugContext.VERY_DETAILED_LEVEL, "Early GVN: replacing %s with %s", n, edgeDataEqual);
636+
graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "Before replacing %s with %s", n, edgeDataEqual);
637+
n.replaceAtUsages(edgeDataEqual);
638+
GraphUtil.unlinkFixedNode((FixedWithNextNode) n);
639+
n.safeDelete();
640+
graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After replacing %s with %s", n, edgeDataEqual);
641+
earlyGVN.increment(graph.getDebug());
642+
if (graph.getDebug().isCountEnabled()) {
643+
DebugContext.counter(earlyGVN.getName() + "_" + edgeDataEqual.getClass().getSimpleName()).increment(graph.getDebug());
632644
}
645+
return true;
633646
}
634647

635648
/**

0 commit comments

Comments
 (0)