Make listing/mapping typecasts more PE-friendly (#1837)

This rewrites the listing/mapping typecast nodes to be more friendly
to partial-evaluation.

This is because the compiler bails out of deeply recursive calls.
This commit is contained in:
Daniel Chao
2026-09-02 10:00:59 -07:00
committed by GitHub
parent adee565a8c
commit 9f28c1cb11
3 changed files with 25 additions and 27 deletions
@@ -51,7 +51,7 @@ public abstract class ElementOrEntryNode extends RegularMemberNode {
@Cached("create()") @Shared("callNode") IndirectCallNode callNode) { @Cached("create()") @Shared("callNode") IndirectCallNode callNode) {
var result = bodyNode.executeGeneric(frame); var result = bodyNode.executeGeneric(frame);
return VmUtils.shouldRunTypeCheck(frame) return VmUtils.shouldRunTypeCheck(frame)
? receiver.executeTypeCasts(result, VmUtils.getOwner(frame), callNode, null, null) ? receiver.executeTypeCasts(result, VmUtils.getOwner(frame), callNode, null)
: result; : result;
} }
@@ -62,7 +62,7 @@ public abstract class ElementOrEntryNode extends RegularMemberNode {
@Cached("create()") @Shared("callNode") IndirectCallNode callNode) { @Cached("create()") @Shared("callNode") IndirectCallNode callNode) {
var result = bodyNode.executeGeneric(frame); var result = bodyNode.executeGeneric(frame);
return VmUtils.shouldRunTypeCheck(frame) return VmUtils.shouldRunTypeCheck(frame)
? receiver.executeTypeCasts(result, VmUtils.getOwner(frame), callNode, null, null) ? receiver.executeTypeCasts(result, VmUtils.getOwner(frame), callNode, null)
: result; : result;
} }
@@ -55,30 +55,24 @@ public abstract class VmListingOrMapping extends VmObject {
this.typeCheckOwner = typeCheckOwner; this.typeCheckOwner = typeCheckOwner;
} }
// Recursively executes type casts between `owner` and `this` and returns the resulting value. // Executes type casts for every parent between `owner` and `this` and returns the resulting
// value.
public final Object executeTypeCasts( public final Object executeTypeCasts(
Object value, Object value,
VmObjectLike owner, VmObjectLike owner,
IndirectCallNode callNode, IndirectCallNode callNode,
// if non-null, a stack frame for this member is inserted if a type cast fails // if non-null, a stack frame for this member is inserted if a type cast fails
@Nullable ObjectMember member, @Nullable ObjectMember member) {
// Next type cast to be performed by the caller. var result = value;
// Avoids repeating the same type cast in some cases. VmObject parent = this;
@Nullable ListingOrMappingTypeCastNode nextTypeCastNode) { ListingOrMappingTypeCastNode prevTypeCastNode = null;
var newNextTypeCastNode = typeCastNode != null ? typeCastNode : nextTypeCastNode; while (parent != null && parent != owner) {
Object result; var obj = (VmListingOrMapping) parent;
if (this == owner) { if (obj.typeCastNode != null && obj.typeCastNode != prevTypeCastNode) {
result = value; var callTarget = obj.typeCastNode.getCallTarget();
} else {
assert parent != null;
result =
((VmListingOrMapping) parent)
.executeTypeCasts(value, owner, callNode, member, newNextTypeCastNode);
}
if (typeCastNode == null || typeCastNode == nextTypeCastNode) return result;
var callTarget = typeCastNode.getCallTarget();
try { try {
return callNode.call(callTarget, typeCheckReceiver, typeCheckOwner, result); result = callNode.call(callTarget, obj.typeCheckReceiver, obj.typeCheckOwner, result);
prevTypeCastNode = obj.typeCastNode;
} catch (VmException e) { } catch (VmException e) {
CompilerDirectives.transferToInterpreter(); CompilerDirectives.transferToInterpreter();
if (member != null) { if (member != null) {
@@ -87,6 +81,10 @@ public abstract class VmListingOrMapping extends VmObject {
throw e; throw e;
} }
} }
parent = parent.parent;
}
return result;
}
@Override @Override
@TruffleBoundary @TruffleBoundary
@@ -396,7 +396,7 @@ public final class VmUtils {
&& owner instanceof VmListingOrMapping) { && owner instanceof VmListingOrMapping) {
// `owner instanceof VmListingOrMapping` guards against // `owner instanceof VmListingOrMapping` guards against
// PropertiesRenderer amending VmDynamic with VmListing (hack?) // PropertiesRenderer amending VmDynamic with VmListing (hack?)
result = listingOrMapping.executeTypeCasts(constantValue, owner, callNode, member, null); result = listingOrMapping.executeTypeCasts(constantValue, owner, callNode, member);
} }
receiver.setCachedValue(memberKey, result); receiver.setCachedValue(memberKey, result);