Behavior
The checker, interpreter and JS accept a program in which a function or continuation keeps more than WIDE one-word values live across a call. The C build refuses it with an arity over 247 (an arity over 255 before #1068). Example: a record of 300 String fields where each field is built with a call.
import Base
type R is Data:
Mk{f0: String, f1: String, ..., f299: String}
def mk(+s: String) -> R:
Mk{(s ++ "0"), (s ++ "1"), ..., (s ++ "299")}
Each ++ is a call, so the continuation after the k-th field (mk$k265 to mk$k300) carries every field built so far as a parameter, up to 300 words. FID_ARITY_T passes WIDE and the build stops.
Why the limit is real
This isn't the node limit fixed in #1068. A segment's parameters live in the register bank and are passed through preserve_none / musttail calls. With the table check lifted, clang 21 crashes on this program at every optimization level:
fatal error: error in backend: live register clobbered by inserted prologue instructions
#944 handles part of this: a def whose parameters span past WIDE words takes its multi-word parameters boxed. But one-word live values have nothing to box, the same gap #991 had for constructor fields.
Possible direction
When a segment's live set is still past WIDE words after multi-word values are boxed, spill a run of the one-word values into a boxed tuple, and read them back in the continuation.
Found while reviewing #1044, with the reproducer run on the interpreter (correct), JS (correct) and C (refused).
Behavior
The checker, interpreter and JS accept a program in which a function or continuation keeps more than
WIDEone-word values live across a call. The C build refuses it withan arity over 247(an arity over 255before #1068). Example: a record of 300Stringfields where each field is built with a call.Each
++is a call, so the continuation after the k-th field (mk$k265tomk$k300) carries every field built so far as a parameter, up to 300 words.FID_ARITY_TpassesWIDEand the build stops.Why the limit is real
This isn't the node limit fixed in #1068. A segment's parameters live in the register bank and are passed through
preserve_none/musttailcalls. With the table check lifted, clang 21 crashes on this program at every optimization level:#944 handles part of this: a def whose parameters span past
WIDEwords takes its multi-word parameters boxed. But one-word live values have nothing to box, the same gap #991 had for constructor fields.Possible direction
When a segment's live set is still past
WIDEwords after multi-word values are boxed, spill a run of the one-word values into a boxed tuple, and read them back in the continuation.Found while reviewing #1044, with the reproducer run on the interpreter (correct), JS (correct) and C (refused).