Skip to content

Commit 404a5cc

Browse files
committed
[GR-66037] Don't use TruffleConstantFieldProvider for caching in CachingPEGraphDecoder.
PullRequest: graal/21183
2 parents 5a809ba + 72dd8ab commit 404a5cc

File tree

6 files changed

+133
-13
lines changed

6 files changed

+133
-13
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ private StructuredGraph test(String methodName, EconomicMap<ResolvedJavaMethod,
232232
registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
233233
targetGraph = new StructuredGraph.Builder(debug.getOptions(), debug, AllowAssumptions.YES).method(testMethod).build();
234234
GraphBuilderPhase.Instance instance = new TestGraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, null);
235-
CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig,
235+
CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), getProviders(), graphBuilderConfig,
236236
null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null, null, graphCache, () -> null, instance, false, false, true);
237237

238238
decoder.decode(testMethod);

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/DeoptLoopDetectionTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import org.graalvm.polyglot.Context;
3636
import org.junit.After;
37+
import org.junit.Assert;
3738
import org.junit.Assume;
3839
import org.junit.Before;
3940
import org.junit.Test;
@@ -150,6 +151,32 @@ public Object execute(VirtualFrame frame) {
150151
}, 1);
151152
}
152153

154+
static class StaticAssumptionRootNode extends BaseRootNode {
155+
@CompilationFinal static volatile Assumption assumption = Assumption.create();
156+
157+
@Override
158+
public Object execute(VirtualFrame frame) {
159+
if (!assumption.isValid()) {
160+
CompilerDirectives.transferToInterpreterAndInvalidate();
161+
}
162+
return 0;
163+
}
164+
}
165+
166+
@Test
167+
public void testStaticAssumptionNoDeopt() {
168+
boolean[] firstExecution = new boolean[]{true};
169+
AssertionError expectedError = Assert.assertThrows(AssertionError.class, () -> assertDeoptLoop(new StaticAssumptionRootNode(), "staticAssumptionNoDeopt", (target) -> {
170+
target.call();
171+
if (firstExecution[0]) {
172+
StaticAssumptionRootNode.assumption.invalidate();
173+
StaticAssumptionRootNode.assumption = Assumption.create();
174+
firstExecution[0] = false;
175+
}
176+
}, 1));
177+
Assert.assertEquals("No deopt loop detected after " + MAX_EXECUTIONS + " executions", expectedError.getMessage());
178+
}
179+
153180
@Test
154181
public void testLocalDeoptWithChangedCode() {
155182
assertDeoptLoop(new BaseRootNode() {

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/CachingPEGraphDecoder.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class CachingPEGraphDecoder extends PEGraphDecoder {
6666

6767
private static final TimerKey BuildGraphTimer = DebugContext.timer("PartialEvaluation-GraphBuilding");
6868

69-
protected final Providers providers;
69+
protected final Providers graphCacheProviders;
7070
protected final GraphBuilderConfiguration graphBuilderConfig;
7171
private final EconomicMap<ResolvedJavaMethod, EncodedGraph> persistentGraphCache;
7272
private final EconomicMap<ResolvedJavaMethod, EncodedGraph> localGraphCache;
@@ -84,7 +84,8 @@ public class CachingPEGraphDecoder extends PEGraphDecoder {
8484
*/
8585
public CachingPEGraphDecoder(Architecture architecture,
8686
StructuredGraph graph,
87-
Providers providers,
87+
Providers graphCacheProviders,
88+
Providers decodingProviders,
8889
GraphBuilderConfiguration graphBuilderConfig,
8990
LoopExplosionPlugin loopExplosionPlugin,
9091
InvocationPlugins invocationPlugins,
@@ -100,13 +101,13 @@ public CachingPEGraphDecoder(Architecture architecture,
100101
boolean allowAssumptionsDuringParsing,
101102
boolean needsExplicitException,
102103
boolean forceLink) {
103-
super(architecture, graph, providers, loopExplosionPlugin,
104+
super(architecture, graph, decodingProviders, loopExplosionPlugin,
104105
invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, peRootForInlining, sourceLanguagePositionProvider,
105106
new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), needsExplicitException, forceLink);
106107

107108
assert !graphBuilderConfig.trackNodeSourcePosition() || graph.trackNodeSourcePosition();
108109

109-
this.providers = providers;
110+
this.graphCacheProviders = graphCacheProviders;
110111
this.graphBuilderConfig = graphBuilderConfig;
111112
this.postParsingPhase = postParsingPhase;
112113
this.persistentGraphCache = persistentGraphCache;
@@ -132,9 +133,9 @@ private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider int
132133
* initial graph.
133134
*/
134135
try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) {
135-
new ConvertDeoptimizeToGuardPhase(canonicalizer).apply(graphToEncode, providers);
136+
new ConvertDeoptimizeToGuardPhase(canonicalizer).apply(graphToEncode, graphCacheProviders);
136137
if (GraalOptions.EarlyGVN.getValue(graphToEncode.getOptions())) {
137-
new DominatorBasedGlobalValueNumberingPhase(canonicalizer).apply(graphToEncode, providers);
138+
new DominatorBasedGlobalValueNumberingPhase(canonicalizer).apply(graphToEncode, graphCacheProviders);
138139
}
139140
} catch (Throwable t) {
140141
throw debug.handle(t);
@@ -166,9 +167,9 @@ private StructuredGraph buildGraph(ResolvedJavaMethod method, BytecodeProvider i
166167
throw GraalError.shouldNotReachHere("isn't this dead?"); // ExcludeFromJacocoGeneratedReport
167168
}
168169
graphBuilderPhaseInstance.apply(graphToEncode);
169-
canonicalizer.apply(graphToEncode, providers);
170+
canonicalizer.apply(graphToEncode, graphCacheProviders);
170171
if (postParsingPhase != null) {
171-
postParsingPhase.apply(graphToEncode, providers);
172+
postParsingPhase.apply(graphToEncode, graphCacheProviders);
172173
}
173174
} catch (Throwable ex) {
174175
throw debug.handle(ex);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PartialEvaluator.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public abstract class PartialEvaluator {
114114
protected boolean persistentEncodedGraphCache;
115115

116116
protected final TruffleConstantFieldProvider constantFieldProvider;
117+
private final TruffleCachingConstantFieldProvider graphCacheConstantFieldProvider;
117118

118119
@SuppressWarnings("this-escape")
119120
public PartialEvaluator(TruffleCompilerConfiguration config, GraphBuilderConfiguration configForRoot) {
@@ -124,6 +125,7 @@ public PartialEvaluator(TruffleCompilerConfiguration config, GraphBuilderConfigu
124125
this.lastTierDecodingPlugins = createDecodingInvocationPlugins(config.lastTier().partialEvaluator(), configForRoot.getPlugins(), config.lastTier().providers());
125126
this.nodePlugins = createNodePlugins(configForRoot.getPlugins());
126127
this.constantFieldProvider = new TruffleConstantFieldProvider(this, getProviders().getConstantFieldProvider());
128+
this.graphCacheConstantFieldProvider = new TruffleCachingConstantFieldProvider(this, getProviders().getConstantFieldProvider());
127129
}
128130

129131
protected void initialize(OptionValues options) {
@@ -401,14 +403,14 @@ protected PEGraphDecoder createGraphDecoder(TruffleTierContext context, Invocati
401403
DeoptimizeOnExceptionPhase postParsingPhase = new DeoptimizeOnExceptionPhase(
402404
method -> getMethodInfo(method).inlineForPartialEvaluation() == InlineKind.DO_NOT_INLINE_WITH_SPECULATIVE_EXCEPTION);
403405

404-
Providers baseProviders = config.lastTier().providers();
405-
Providers compilationUnitProviders = config.lastTier().providers().copyWith(constantFieldProvider);
406+
Providers graphCacheProviders = config.lastTier().providers().copyWith(graphCacheConstantFieldProvider);
407+
Providers decoderProviders = config.lastTier().providers().copyWith(constantFieldProvider);
406408

407409
assert !allowAssumptionsDuringParsing || !persistentEncodedGraphCache;
408-
return new CachingPEGraphDecoder(config.architecture(), context.graph, compilationUnitProviders, newConfig,
410+
return new CachingPEGraphDecoder(config.architecture(), context.graph, graphCacheProviders, decoderProviders, newConfig,
409411
loopExplosionPlugin, decodingPlugins, inlineInvokePlugins, parameterPlugin, nodePluginList, types.OptimizedCallTarget_callInlined,
410412
sourceLanguagePositionProvider, postParsingPhase, graphCache, createCachedGraphScope,
411-
createGraphBuilderPhaseInstance(compilationUnitProviders, newConfig, TruffleCompilerImpl.Optimizations),
413+
createGraphBuilderPhaseInstance(graphCacheProviders, newConfig, TruffleCompilerImpl.Optimizations),
412414
allowAssumptionsDuringParsing, false, true);
413415
}
414416

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2013, 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.truffle;
26+
27+
import com.oracle.truffle.compiler.ConstantFieldInfo;
28+
29+
import jdk.graal.compiler.core.common.spi.ConstantFieldProvider;
30+
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
31+
import jdk.graal.compiler.replacements.CachingPEGraphDecoder;
32+
import jdk.vm.ci.meta.ResolvedJavaField;
33+
34+
/**
35+
* Constant field provider used for parsing into the graph cache on HotSpot in
36+
* {@link CachingPEGraphDecoder}.
37+
*/
38+
final class TruffleCachingConstantFieldProvider implements ConstantFieldProvider {
39+
40+
private final PartialEvaluator partialEvaluator;
41+
private final ConstantFieldProvider delegate;
42+
43+
TruffleCachingConstantFieldProvider(PartialEvaluator partialEvaluator, ConstantFieldProvider delegate) {
44+
this.partialEvaluator = partialEvaluator;
45+
this.delegate = delegate;
46+
}
47+
48+
@Override
49+
public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) {
50+
boolean isStaticField = field.isStatic();
51+
if (!isStaticField && tool.getReceiver().isNull()) {
52+
return null;
53+
}
54+
ConstantFieldInfo info = partialEvaluator.getConstantFieldInfo(field);
55+
if (info != null) {
56+
/*
57+
* Non-null info means the field is annotated by one of the
58+
* annotations @CompilationFinal, @Child or @Children. We are not folding such fields
59+
* for the code cache on HotSpot. Not even static final fields. We delay this to the
60+
* partial evaluation phase to ensure we are not losing the annotation information and
61+
* are not reading values that are not yet stable when creating the graph for the cache.
62+
* For example, a static final array annotated by '@CompilationFinal(dimensions = 1)':
63+
* We cannot fold the array with 'stableDimension=1', because for the cache, the first
64+
* dimension is not stable. We cannot fold it with 'stableDimension=0' either, because
65+
* we would lose the information about the first dimension being stable for the partial
66+
* evaluation phase.
67+
**/
68+
return null;
69+
} else {
70+
// otherwise do regular constant folding.
71+
return delegate.readConstantField(field, tool);
72+
}
73+
}
74+
75+
@Override
76+
public boolean maybeFinal(ResolvedJavaField field) {
77+
return delegate.maybeFinal(field);
78+
}
79+
80+
@Override
81+
public boolean isTrustedFinal(CanonicalizerTool tool, ResolvedJavaField field) {
82+
return delegate.isTrustedFinal(tool, field);
83+
}
84+
85+
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleConstantFieldProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
import jdk.vm.ci.meta.JavaKind;
3333
import jdk.vm.ci.meta.ResolvedJavaField;
3434

35+
/**
36+
* Constant field provider used for Truffle partial evaluation.
37+
*
38+
* @see TruffleCachingConstantFieldProvider
39+
*/
3540
final class TruffleConstantFieldProvider implements ConstantFieldProvider {
3641

3742
private final PartialEvaluator partialEvaluator;

0 commit comments

Comments
 (0)