Skip to content

Commit 8b1bdc0

Browse files
committed
GR-73325: Preserve template state on handler return
1 parent c0fbb93 commit 8b1bdc0

15 files changed

Lines changed: 220 additions & 155 deletions

File tree

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/api/directives/BytecodeInterpreterDirectives.java

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,6 @@ private BytecodeInterpreterDirectives() {
6060
*/
6161
boolean threading() default true;
6262

63-
/**
64-
* Indicates whether this handler can be dispatched while a template variable is in a
65-
* non-zero state. If {@code false}, non-zero template handler tables dispatch this handler's
66-
* opcodes to a generated fallback stub so control returns to the interpreter switch before
67-
* the handler executes. The default is {@code true}, meaning the handler is compatible with
68-
* all template states.
69-
*/
70-
boolean templateCompatible() default true;
71-
7263
/**
7364
* Indicates whether execution of this handler should include a safepoint check.
7465
*/
@@ -132,21 +123,6 @@ enum ExpansionKind {
132123
*/
133124
boolean nonNull() default true;
134125

135-
/**
136-
* Marks this field as scratch state when template mode is enabled. Scratch fields
137-
* are carried between threaded bytecode handler stubs, but they are not initialized
138-
* from the original Java object on entry, are not written back to the original Java
139-
* object on exit, and are not preserved through pending exception state. This is
140-
* intended for register-resident interpreter state that is valid only while threaded
141-
* execution remains inside the generated handler stubs. When template mode is not
142-
* enabled, this metadata is ignored and the field remains an ordinary expanded
143-
* argument.
144-
* <p>
145-
* This property is only supported for fields of {@link ExpansionKind#VIRTUAL}
146-
* arguments. It cannot be combined with {@link #templateVariable()}.
147-
*/
148-
boolean scratch() default false;
149-
150126
/**
151127
* Marks the expanded field as the template variable used to specialize template
152128
* variants and select the template variant of the next threaded bytecode handler.
@@ -238,5 +214,4 @@ enum ExpansionKind {
238214
@Target({ElementType.METHOD})
239215
public @interface BytecodeInterpreterFetchOpcode {
240216
}
241-
242217
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/HotSpotTruffleBytecodeHandlerStub.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier com
6464
try {
6565
HotSpotGraphKit kit = new HotSpotGraphKit(debug, callsite.getEnclosingMethod(), providers, providers.getGraphBuilderPlugins(), compilationId, callsite.getStubName(), false, true);
6666
return BytecodeHandlerStubHelper.createStub(kit, callsite.getEnclosingMethod(), callsite.getBci(), false, null, null, callsite.getHandlerConfig(), callsite.getTargetMethod(),
67-
0, null);
67+
0, null, null);
6868
} catch (Exception e) {
6969
throw GraalError.shouldNotReachHere(e); // ExcludeFromJacocoGeneratedReport
7070
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/BytecodeHandlerCallSite.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.util.function.Function;
3131

3232
import jdk.graal.compiler.debug.GraalError;
33-
import jdk.graal.compiler.nodes.ConstantNode;
3433
import jdk.graal.compiler.nodes.FixedGuardNode;
3534
import jdk.graal.compiler.nodes.FixedNode;
3635
import jdk.graal.compiler.nodes.LogicNode;
@@ -118,24 +117,18 @@ public String getStubName() {
118117

119118
/**
120119
* Constructs the stub ABI argument list at the caller. Expanded arguments are lowered to field
121-
* loads from their Java owner objects, except scratch fields which are initialized with a
122-
* default value because their Java object field value is intentionally ignored. Non-expanded
123-
* arguments are forwarded unchanged.
120+
* loads from their Java owner objects; non-expanded arguments are forwarded unchanged.
124121
*/
125122
public ValueNode[] createCallerArguments(ValueNode[] oldArguments, FixedNode insertBefore, Function<ResolvedJavaField, ResolvedJavaField> fieldMap) {
126123
List<ArgumentInfo> stubAbiArgumentInfos = handlerConfig.getStubAbiArgumentInfos();
127124
List<ValueNode> newArguments = new ArrayList<>();
128125
StructuredGraph graph = insertBefore.graph();
129126
for (ArgumentInfo argumentInfo : stubAbiArgumentInfos) {
130127
if (argumentInfo.isExpanded()) {
131-
if (argumentInfo.scratch()) {
132-
newArguments.add(ConstantNode.defaultForKind(argumentInfo.type().getJavaKind(), graph));
133-
} else {
134-
ValueNode owner = oldArguments[argumentInfo.originalIndex()];
135-
LoadFieldNode load = LoadFieldNode.create(graph.getAssumptions(), owner, fieldMap.apply(argumentInfo.field()));
136-
graph.addBeforeFixed(insertBefore, graph.add(load));
137-
newArguments.add(load);
138-
}
128+
ValueNode owner = oldArguments[argumentInfo.originalIndex()];
129+
LoadFieldNode load = LoadFieldNode.create(graph.getAssumptions(), owner, fieldMap.apply(argumentInfo.field()));
130+
graph.addBeforeFixed(insertBefore, graph.add(load));
131+
newArguments.add(load);
139132
} else {
140133
newArguments.add(oldArguments[argumentInfo.originalIndex()]);
141134
}
@@ -159,7 +152,7 @@ public void updateCallerReturns(FixedNode newInvoke, ValueNode[] oldArguments, F
159152
List<ArgumentInfo> stubAbiArgumentInfos = handlerConfig.getStubAbiArgumentInfos();
160153

161154
for (ArgumentInfo argumentInfo : stubAbiArgumentInfos) {
162-
if (argumentInfo.isExpanded() && !argumentInfo.isImmutable() && !argumentInfo.scratch()) {
155+
if (argumentInfo.isExpanded() && !argumentInfo.isImmutable()) {
163156
ReadArgumentNode fetchReturn = graph.unique(new ReadArgumentNode(newInvoke,
164157
argumentInfo.type().getJavaKind(), argumentInfo.index()));
165158
ValueNode owner = oldArguments[argumentInfo.originalIndex()];

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/BytecodeHandlerConfig.java

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* Aggregates metadata derived from a {@code BytecodeInterpreterHandlerConfig} annotation which is
4343
* resolved against a concrete bytecode handler signature. The resulting model describes the stub
4444
* ABI: argument expansion, non-null guarantees, {@code returnValue}/copy-from-return slots, mutable
45-
* expanded fields, scratch fields, and the maximum opcode for which a handler exists.
45+
* expanded fields and the maximum opcode for which a handler exists.
4646
*/
4747
public final class BytecodeHandlerConfig {
4848

@@ -184,11 +184,11 @@ private static int appendReceiver(List<ArgumentInfo> arguments, AnnotationValue
184184

185185
switch (expansionKind) {
186186
case NONE -> {
187-
arguments.add(new ArgumentInfo(declaringClass, nextIndex++, originalIndex, false, false, false, null, null, false, true, nonNull, false, 0));
187+
arguments.add(new ArgumentInfo(declaringClass, nextIndex++, originalIndex, false, false, false, null, null, false, true, nonNull, 0));
188188
}
189189
case VIRTUAL -> throw GraalError.shouldNotReachHere("Receiver cannot be VIRTUAL");
190190
case MATERIALIZED -> {
191-
arguments.add(new ArgumentInfo(declaringClass, nextIndex++, originalIndex, false, true, false, null, null, false, true, nonNull, false, 0));
191+
arguments.add(new ArgumentInfo(declaringClass, nextIndex++, originalIndex, false, true, false, null, null, false, true, nonNull, 0));
192192
nextIndex = appendMaterializedFields(arguments, receiverConfig, declaringClass, declaringClass, originalIndex, nextIndex, templateModeEnabled);
193193
}
194194
default -> throw GraalError.shouldNotReachHere("Unknown expansion kind " + expansionKind);
@@ -205,30 +205,28 @@ private static int appendParameter(List<ArgumentInfo> arguments, AnnotationValue
205205

206206
switch (expansionKind) {
207207
case NONE -> {
208-
arguments.add(new ArgumentInfo(parameterType, nextIndex++, originalIndex, copyFromReturn, false, false, null, null, false, !copyFromReturn, nonNull, false, 0));
208+
arguments.add(new ArgumentInfo(parameterType, nextIndex++, originalIndex, copyFromReturn, false, false, null, null, false, !copyFromReturn, nonNull, 0));
209209
}
210210
case VIRTUAL -> {
211211
List<AnnotationValue> fields = parameterConfig.getList("fields", AnnotationValue.class);
212212
for (ResolvedJavaField javaField : parameterType.getInstanceFields(true)) {
213213
ResolvedJavaType fieldType = javaField.getType().resolve(declaringClass);
214214
boolean fieldNonNull = false;
215215
AnnotationValue fieldConfig = findFieldConfig(fields, javaField.getName());
216-
boolean scratch = templateModeEnabled && fieldConfig != null && fieldConfig.getBoolean("scratch");
217216
int templateVariants = templateModeEnabled ? getTemplateVariants(fieldConfig, javaField) : 0;
218-
GraalError.guarantee(!scratch || templateVariants == 0, "Scratch field %s cannot be a template variable", javaField.format("%H.%n"));
219217
if (!fieldType.isPrimitive()) {
220-
fieldNonNull = !scratch && fieldConfig != null && fieldConfig.getBoolean("nonNull");
218+
fieldNonNull = fieldConfig != null && fieldConfig.getBoolean("nonNull");
221219
GraalError.guarantee(templateVariants == 0, "Field %s is marked as a template variable", javaField.format("%H.%n"));
222220
} else if (templateVariants > 0) {
223221
GraalError.guarantee(fieldType.getJavaKind() == JavaKind.Int, "Template variable field %s must be int", javaField.format("%H.%n"));
224222
}
225223
int abiIndex = templateVariants > 0 ? -1 : nextIndex++;
226224
arguments.add(new ArgumentInfo(fieldType, abiIndex, originalIndex, false, false, true, parameterType, javaField, true, javaField.isFinal(),
227-
fieldNonNull, scratch, templateVariants));
225+
fieldNonNull, templateVariants));
228226
}
229227
}
230228
case MATERIALIZED -> {
231-
arguments.add(new ArgumentInfo(parameterType, nextIndex++, originalIndex, copyFromReturn, true, false, null, null, false, true, nonNull, false, 0));
229+
arguments.add(new ArgumentInfo(parameterType, nextIndex++, originalIndex, copyFromReturn, true, false, null, null, false, true, nonNull, 0));
232230
nextIndex = appendMaterializedFields(arguments, parameterConfig, parameterType, declaringClass, originalIndex, nextIndex, templateModeEnabled);
233231
}
234232
default -> throw GraalError.shouldNotReachHere("Unknown expansion kind " + expansionKind);
@@ -243,16 +241,13 @@ private static int appendMaterializedFields(List<ArgumentInfo> arguments, Annota
243241
for (ResolvedJavaField javaField : expandedType.getInstanceFields(true)) {
244242
AnnotationValue fieldConfig = findFieldConfig(fields, javaField.getName());
245243
if (fieldConfig != null) {
246-
if (templateModeEnabled) {
247-
GraalError.guarantee(!fieldConfig.getBoolean("scratch"), "Scratch field %s must belong to a VIRTUAL argument", javaField.format("%H.%n"));
248-
}
249244
ResolvedJavaType fieldType = javaField.getType().resolve(declaringClass);
250245
boolean fieldNonNull = !fieldType.isPrimitive() && fieldConfig.getBoolean("nonNull");
251246
if (templateModeEnabled) {
252247
GraalError.guarantee(getTemplateVariants(fieldConfig, javaField) == 0, "Field %s is marked as a template variable", javaField.format("%H.%n"));
253248
}
254249
arguments.add(new ArgumentInfo(fieldType, nextIndex++, originalIndex, false, false, true, declaringClass, javaField, false, javaField.isFinal(),
255-
fieldNonNull, false, 0));
250+
fieldNonNull, 0));
256251
}
257252
}
258253
return nextIndex;
@@ -336,6 +331,22 @@ public List<ResolvedJavaType> getStubAbiArgumentTypes() {
336331
return stubAbiArgumentTypes;
337332
}
338333

334+
/**
335+
* Returns the number of thread-local slots required to preserve ordinary ABI arguments and
336+
* template variables when a handler chain returns to Java.
337+
*/
338+
public int getPendingStateSlotCount() {
339+
return stubAbiArgumentInfos.size() + templateVariableArguments.size();
340+
}
341+
342+
/**
343+
* Returns the thread-local slot assigned to a template variable. Template slots follow the
344+
* dense stub ABI slots and do not form part of the stub calling convention.
345+
*/
346+
public int getTemplateVariablePendingStateSlot(int templateVariableIndex) {
347+
return stubAbiArgumentInfos.size() + templateVariableIndex;
348+
}
349+
339350
@Override
340351
public boolean equals(Object obj) {
341352
if (this == obj) {
@@ -397,10 +408,6 @@ private enum ExpansionKind {
397408
* produce multiple {@link ArgumentInfo}s that share the same {@link #originalIndex()} but map to
398409
* different stub ABI {@link #index()} values. In template mode, template variables have index
399410
* {@code -1} and are excluded from the stub ABI.
400-
* <p>
401-
* When template mode is enabled, scratch fields are still ABI arguments so threaded handlers
402-
* can pass them to each other, but they are initialized with default values at the Java caller
403-
* boundary and are not written back to the original owner object.
404411
*/
405412
public record ArgumentInfo(ResolvedJavaType type,
406413
int index,
@@ -413,7 +420,6 @@ public record ArgumentInfo(ResolvedJavaType type,
413420
boolean isOwnerVirtual,
414421
boolean isImmutable,
415422
boolean nonNull,
416-
boolean scratch,
417423
int templateVariants) {
418424
public boolean isTemplateVariable() {
419425
return templateVariants > 0;
@@ -424,7 +430,7 @@ public boolean isTemplateVariable() {
424430
* edge: the {@code copyFromReturn} value and mutable fields of virtual-expanded arguments.
425431
*/
426432
public boolean needsPendingExceptionState() {
427-
return copyFromReturn || (isExpanded && isOwnerVirtual && !isImmutable && !scratch);
433+
return copyFromReturn || (isExpanded && isOwnerVirtual && !isImmutable);
428434
}
429435
}
430436
}

0 commit comments

Comments
 (0)