Skip to content

Commit f135f28

Browse files
committed
Implement HostCompilerDirectives.InliningRoot and increase exploration budget and maximum subtree invokes for the host inlining heuristic.
1 parent 2b59bc4 commit f135f28

File tree

12 files changed

+100
-12
lines changed

12 files changed

+100
-12
lines changed

compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/LibGraalTruffleHostEnvironment.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ protected HostMethodInfo computeValue(ResolvedJavaMethod method) {
106106
boolean isBytecodeInterpreterSwitch = false;
107107
boolean isBytecodeInterpreterSwitchBoundary = false;
108108
boolean isInliningCutoff = false;
109+
boolean isInliningRoot = false;
109110
for (AnnotationData annotationData : annotationDataList) {
110111
String annotationTypeFqn = annotationData.getAnnotationType().getName();
111112
if (hostTypes.TruffleBoundary.getName().equals(annotationTypeFqn)) {
@@ -116,9 +117,11 @@ protected HostMethodInfo computeValue(ResolvedJavaMethod method) {
116117
isBytecodeInterpreterSwitchBoundary = true;
117118
} else if (hostTypes.InliningCutoff.getName().equals(annotationTypeFqn)) {
118119
isInliningCutoff = true;
120+
} else if (hostTypes.InliningRoot != null && hostTypes.InliningRoot.getName().equals(annotationTypeFqn)) {
121+
isInliningRoot = true;
119122
}
120123
}
121-
return new HostMethodInfo(isTruffleBoundary, isBytecodeInterpreterSwitch, isBytecodeInterpreterSwitchBoundary, isInliningCutoff);
124+
return new HostMethodInfo(isTruffleBoundary, isBytecodeInterpreterSwitch, isBytecodeInterpreterSwitchBoundary, isInliningCutoff, isInliningRoot);
122125
}
123126

124127
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5050
import com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitch;
5151
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
52+
import com.oracle.truffle.api.HostCompilerDirectives.InliningRoot;
5253
import com.oracle.truffle.api.Truffle;
5354
import com.oracle.truffle.api.dsl.Cached;
5455
import com.oracle.truffle.api.dsl.ImplicitCast;
@@ -150,13 +151,14 @@ public void test() {
150151
runTest("testImplicitCast");
151152
runTest("testNativeCall");
152153
runTest("testBCDSLPrologIfVersion");
154+
runTest("testInliningRoot");
153155
}
154156

155157
/*
156158
* Test for GR-69170
157159
*/
158160
@BytecodeInterpreterSwitch
159-
static Object testBCDSLPrologIfVersion(int value) {
161+
static Object testBCDSLPrologIfVersion(@SuppressWarnings("unused") int value) {
160162
Object o = null;
161163
if (!CompilerDirectives.inInterpreter() && CompilerDirectives.hasNextTier()) {
162164
GraalDirectives.deoptimize();
@@ -1002,6 +1004,13 @@ static int testIndirectIntrinsicsImpl(A a) {
10021004
return a.intrinsic(); // inlined and intrinsic
10031005
}
10041006

1007+
@InliningRoot
1008+
static int testInliningRoot(int value) {
1009+
// should work just like bytecode interpreter switches
1010+
trivialMethod();
1011+
return value;
1012+
}
1013+
10051014
@Retention(RetentionPolicy.RUNTIME)
10061015
@Target(ElementType.METHOD)
10071016
@interface ExpectSameGraph {

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ public static class Options {
106106
@Option(help = "Maximum budget for Truffle host inlining for runtime compiled methods.")//
107107
public static final OptionKey<Integer> TruffleHostInliningBaseBudget = new OptionKey<>(5_000);
108108

109+
@Option(help = "Maximum exploration budget for Truffle host inlining when exploring inlining candidates.")//
110+
public static final OptionKey<Integer> TruffleHostInliningExploreBudget = new OptionKey<>(10_000);
111+
109112
@Option(help = "Maximum budget for Truffle host inlining for runtime compiled methods with a BytecodeInterpreterSwitch annotation.")//
110113
public static final OptionKey<Integer> TruffleHostInliningByteCodeInterpreterBudget = new OptionKey<>(100_000);
111114

@@ -116,7 +119,7 @@ public static class Options {
116119
public static final OptionKey<Integer> TruffleHostInliningMaxExplorationDepth = new OptionKey<>(1000);
117120

118121
@Option(help = "Maximum number of subtree invokes for a subtree to get inlined until it is considered too complex.")//
119-
public static final OptionKey<Integer> TruffleHostInliningMaxSubtreeInvokes = new OptionKey<>(20);
122+
public static final OptionKey<Integer> TruffleHostInliningMaxSubtreeInvokes = new OptionKey<>(32);
120123

121124
@Option(help = "Minimum relative frequency for calls to get inlined. Default 0.001 on HotSpot and no minimum frequency on SVM.")//
122125
public static final OptionKey<Double> TruffleHostInliningMinFrequency = new OptionKey<>(DEFAULT_MIN_FREQUENCY);
@@ -144,7 +147,7 @@ public HostInliningPhase(CanonicalizerPhase canonicalizer, double defaultMinProf
144147
}
145148

146149
protected boolean isEnabledFor(TruffleHostEnvironment env, ResolvedJavaMethod method) {
147-
return isBytecodeInterpreterSwitch(env, method);
150+
return isBytecodeInterpreterSwitch(env, method) || isInliningRoot(env, method);
148151
}
149152

150153
protected String isTruffleBoundary(TruffleHostEnvironment env, ResolvedJavaMethod targetMethod) {
@@ -154,14 +157,18 @@ protected String isTruffleBoundary(TruffleHostEnvironment env, ResolvedJavaMetho
154157
return null;
155158
}
156159

157-
private boolean isBytecodeInterpreterSwitch(TruffleHostEnvironment env, ResolvedJavaMethod targetMethod) {
160+
protected final boolean isBytecodeInterpreterSwitch(TruffleHostEnvironment env, ResolvedJavaMethod targetMethod) {
158161
return env.getHostMethodInfo(translateMethod(targetMethod)).isBytecodeInterpreterSwitch();
159162
}
160163

161164
private boolean isInliningCutoff(TruffleHostEnvironment env, ResolvedJavaMethod targetMethod) {
162165
return env.getHostMethodInfo(translateMethod(targetMethod)).isInliningCutoff();
163166
}
164167

168+
private boolean isInliningRoot(TruffleHostEnvironment env, ResolvedJavaMethod targetMethod) {
169+
return env.getHostMethodInfo(translateMethod(targetMethod)).isInliningRoot();
170+
}
171+
165172
protected ResolvedJavaMethod translateMethod(ResolvedJavaMethod method) {
166173
return method;
167174
}
@@ -213,11 +220,10 @@ private void runImpl(InliningPhaseContext context) {
213220
* all together and fail if the graph becomes too big.
214221
*/
215222
sizeLimit = Options.TruffleHostInliningByteCodeInterpreterBudget.getValue(context.graph.getOptions());
216-
exploreLimit = Options.TruffleHostInliningBaseBudget.getValue(context.graph.getOptions());
217223
} else {
218224
sizeLimit = Options.TruffleHostInliningBaseBudget.getValue(context.graph.getOptions());
219-
exploreLimit = sizeLimit;
220225
}
226+
exploreLimit = Options.TruffleHostInliningExploreBudget.getValue(context.graph.getOptions());
221227

222228
if (sizeLimit < 0) {
223229
/*

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public final class TruffleKnownHostTypes extends AbstractKnownTruffleTypes {
5454
public final ResolvedJavaType BytecodeInterpreterSwitch = lookupType("com.oracle.truffle.api.HostCompilerDirectives$BytecodeInterpreterSwitch");
5555
public final ResolvedJavaType BytecodeInterpreterSwitchBoundary = lookupType("com.oracle.truffle.api.HostCompilerDirectives$BytecodeInterpreterSwitchBoundary");
5656
public final ResolvedJavaType InliningCutoff = lookupType("com.oracle.truffle.api.HostCompilerDirectives$InliningCutoff");
57+
public final ResolvedJavaType InliningRoot = lookupTypeOptional("com.oracle.truffle.api.HostCompilerDirectives$InliningRoot");
5758

5859
public final ResolvedJavaType HostCompilerDirectives = lookupTypeCached("com.oracle.truffle.api.HostCompilerDirectives");
5960
public final ResolvedJavaMethod HostCompilerDirectives_inInterpreterFastPath = findMethod(HostCompilerDirectives, "inInterpreterFastPath");

truffle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan
1111
* GR-67702: Specialization DSL: For nodes annotated with `@GenerateInline`, inlining warnings emitted for `@Cached` expressions are now suppressed if the inlined node is explicitly annotated with `@GenerateInline(false)`. This avoids unnecessary warnings if inlining for a node was explicitly disabled.
1212
* GR-66310: Added support for passing arrays of primitive types to native code through the Truffle NFI Panama backend.
1313
* GR-61292 Specialization DSL: Single specialization nodes no longer specialize on first execution unless they use assumptions, cached state, or multiple instances. This was done to improve the interpreter performance and memory footprint of such nodes. As a result, these nodes no longer invalidate on first execution, which means they can no longer be used as an implicit branch profile. Language implementations are encouraged to check whether they are relying on this behavior and insert explicit branch profiles instead (see `BranchProfile` or `InlinedBranchProfile`).
14+
* GR-69188: Added `@HostCompilerDirectives.InliningRoot` to explicitly trigger host inlining for a method designed for partial evaluation. Note that on SubstrateVM, host inlining is automatically enabled for all runtime-compilable methods, while on HotSpot you must add either `@HostCompilerDirectives.InliningRoot` or `@HostCompilerDirectives.BytecodeInterpreterSwitch` to enable it. Host inlining is only enabled if Graal is enabled as a Java host compiler.
1415

1516
## Version 25.0
1617
* GR-31495 Added ability to specify language and instrument specific options using `Source.Builder.option(String, String)`. Languages may describe available source options by implementing `TruffleLanguage.getSourceOptionDescriptors()` and `TruffleInstrument.getSourceOptionDescriptors()` respectively.

truffle/src/com.oracle.truffle.api/snapshot.sigtest

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ CLSS public final com.oracle.truffle.api.HostCompilerDirectives
139139
innr public abstract interface static !annotation BytecodeInterpreterSwitch
140140
innr public abstract interface static !annotation BytecodeInterpreterSwitchBoundary
141141
innr public abstract interface static !annotation InliningCutoff
142+
innr public abstract interface static !annotation InliningRoot
142143
meth public static boolean inInterpreterFastPath()
143144
supr java.lang.Object
144145

@@ -161,6 +162,12 @@ CLSS public abstract interface static !annotation com.oracle.truffle.api.HostCom
161162
anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD, CONSTRUCTOR])
162163
intf java.lang.annotation.Annotation
163164

165+
CLSS public abstract interface static !annotation com.oracle.truffle.api.HostCompilerDirectives$InliningRoot
166+
outer com.oracle.truffle.api.HostCompilerDirectives
167+
anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME)
168+
anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD, CONSTRUCTOR])
169+
intf java.lang.annotation.Annotation
170+
164171
CLSS public final com.oracle.truffle.api.InstrumentInfo
165172
meth public java.lang.String getId()
166173
meth public java.lang.String getName()
@@ -1762,6 +1769,11 @@ meth public abstract java.lang.annotation.ElementType[] value()
17621769
CLSS public abstract interface java.lang.constant.Constable
17631770
meth public abstract java.util.Optional<? extends java.lang.constant.ConstantDesc> describeConstable()
17641771

1772+
CLSS public abstract interface !annotation jdk.internal.vm.annotation.AOTSafeClassInitializer
1773+
anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME)
1774+
anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE])
1775+
intf java.lang.annotation.Annotation
1776+
17651777
CLSS public abstract interface org.graalvm.options.OptionDescriptors
17661778
fld public final static org.graalvm.options.OptionDescriptors EMPTY
17671779
intf java.lang.Iterable<org.graalvm.options.OptionDescriptor>

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/HostCompilerDirectives.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,27 @@ public static boolean inInterpreterFastPath() {
158158
public @interface InliningCutoff {
159159
}
160160

161+
/**
162+
* Marks a method as a candidate for Truffle host inlining. The host compiler may use this
163+
* information to guide inlining and optimization decisions.
164+
* <p>
165+
* Annotated methods must be designed for partial evaluation. This annotation should not be
166+
* applied to arbitrary Java code or third-party libraries, as doing so may cause severe
167+
* performance degradation.
168+
* <p>
169+
* Typical examples include {@code execute} methods of cached nodes. The Truffle DSL
170+
* automatically applies this annotation to every generated execute method. It is recommended to
171+
* be used for manually written {@code execute} methods as well.
172+
* <p>
173+
* For more details, see the
174+
* <a href="https://github.com/oracle/graal/blob/master/truffle/docs/HostCompilation.md">
175+
* Truffle host compilation documentation</a>.
176+
*
177+
* @since 26.0
178+
*/
179+
@Retention(RetentionPolicy.RUNTIME)
180+
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
181+
public @interface InliningRoot {
182+
}
183+
161184
}

truffle/src/com.oracle.truffle.compiler/src/com/oracle/truffle/compiler/HostMethodInfo.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ public record HostMethodInfo(
5555
boolean isTruffleBoundary,
5656
boolean isBytecodeInterpreterSwitch,
5757
boolean isBytecodeInterpreterSwitchBoundary,
58-
boolean isInliningCutoff) {
58+
boolean isInliningCutoff,
59+
boolean isInliningRoot) {
60+
61+
// for compatibility
62+
public HostMethodInfo(
63+
boolean isTruffleBoundary,
64+
boolean isBytecodeInterpreterSwitch,
65+
boolean isBytecodeInterpreterSwitchBoundary,
66+
boolean isInliningCutoff) {
67+
this(isTruffleBoundary, isBytecodeInterpreterSwitch, isBytecodeInterpreterSwitchBoundary, isInliningCutoff, false);
68+
}
5969

6070
}

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ public class TruffleTypes {
136136
public static final String HostCompilerDirectives_Name = "com.oracle.truffle.api.HostCompilerDirectives";
137137
public static final String HostCompilerDirectives_BytecodeInterpreterSwitch_Name = "com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitch";
138138
public static final String HostCompilerDirectives_InliningCutoff_Name = "com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff";
139+
public static final String HostCompilerDirectives_InliningRoot_Name = "com.oracle.truffle.api.HostCompilerDirectives.InliningRoot";
139140

140141
public static final String InternalResource_Name = "com.oracle.truffle.api.InternalResource";
141142
public static final String InternalResource_Id_Name = "com.oracle.truffle.api.InternalResource.Id";
@@ -200,6 +201,7 @@ public class TruffleTypes {
200201
public final DeclaredType HostCompilerDirectives = c.getDeclaredType(HostCompilerDirectives_Name);
201202
public final DeclaredType HostCompilerDirectives_BytecodeInterpreterSwitch = c.getDeclaredType(HostCompilerDirectives_BytecodeInterpreterSwitch_Name);
202203
public final DeclaredType HostCompilerDirectives_InliningCutoff = c.getDeclaredType(HostCompilerDirectives_InliningCutoff_Name);
204+
public final DeclaredType HostCompilerDirectives_InliningRoot = c.getDeclaredType(HostCompilerDirectives_InliningRoot_Name);
203205
public final DeclaredType InternalResource = c.getDeclaredType(InternalResource_Name);
204206
public final DeclaredType InternalResource_Id = c.getDeclaredType(InternalResource_Id_Name);
205207
public final DeclaredType InvalidAssumptionException = c.getDeclaredType(InvalidAssumptionException_Name);

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,7 @@ public CodeExecutableElement createExecuteMethod(CodeTypeElement clazz, CodeExec
28052805

28062806
List<SpecializationData> implementedSpecializations = allSpecializations;
28072807
CodeExecutableElement method = createExecuteMethod(type);
2808+
method.addAnnotationMirror(new CodeAnnotationMirror(types.HostCompilerDirectives_InliningRoot));
28082809
FrameState frameState = FrameState.load(this, type, Integer.MAX_VALUE, NodeExecutionMode.FAST_PATH, method);
28092810
if (type.getMethod() == null) {
28102811
frameState.addParametersTo(method, Integer.MAX_VALUE, FRAME_VALUE);
@@ -2830,6 +2831,10 @@ private CodeExecutableElement createExecute(CodeTypeElement clazz, ExecutableTyp
28302831
}
28312832

28322833
CodeExecutableElement method = createExecuteMethod(type);
2834+
// exclude inlined nodes they do not make good inlining roots as they rely on being inlined
2835+
if (!inlined) {
2836+
method.addAnnotationMirror(new CodeAnnotationMirror(types.HostCompilerDirectives_InliningRoot));
2837+
}
28332838
FrameState frameState = FrameState.load(this, type, Integer.MAX_VALUE, NodeExecutionMode.FAST_PATH, method);
28342839
frameState.setInlinedNode(inlined);
28352840
if (type.getMethod() == null) {

0 commit comments

Comments
 (0)