Problem
The Lua codegen emits every data constructor as a curried chain of closures. In the IR.Ctor case of lib/Language/PureScript/Backend/Lua.hs, foldr wrap value args wraps the table constructor in one single-parameter Lua function per field, so a two-field constructor C becomes function(a) return function(b) return { ... } end end. A saturated application C x y then pays two closure allocations and two calls to build one table, the same per-argument cost that #24 removes for ordinary functions. Constructor applications are among the most common applications in typical PureScript, so this is a broad and hot cost.
Approach
Give constructors the worker/wrapper treatment #24 gives functions. At a saturated constructor site, emit the table directly from the arguments, with no intermediate closures. Keep a curried wrapper for partial applications and for a constructor used as a first-class value, so that map Just xs and a partially applied constructor still work unchanged. The split can live in the IR (a constructor worker that is an n-ary AbsN over the fields, building the table) so that the existing saturated-site rewrite and the downstream DCE and beta passes handle it exactly as they do for functions, rather than as a special case in the Lua backend.
Prerequisites / Relations
Same family as #24, applied to the constructor side of application rather than the function side.
Verification / Measurement
bench/micro/ctor_match.lua already measures constructor allocation and tag matching and is the natural before/after anchor. The win is the removal of the per-field closure allocations on saturated construction, both the PUC Lua call overhead and the LuaJIT trace aborts that closure creation triggers.
Problem
The Lua codegen emits every data constructor as a curried chain of closures. In the
IR.Ctorcase oflib/Language/PureScript/Backend/Lua.hs,foldr wrap value argswraps the table constructor in one single-parameter Lua function per field, so a two-field constructorCbecomesfunction(a) return function(b) return { ... } end end. A saturated applicationC x ythen pays two closure allocations and two calls to build one table, the same per-argument cost that #24 removes for ordinary functions. Constructor applications are among the most common applications in typical PureScript, so this is a broad and hot cost.Approach
Give constructors the worker/wrapper treatment #24 gives functions. At a saturated constructor site, emit the table directly from the arguments, with no intermediate closures. Keep a curried wrapper for partial applications and for a constructor used as a first-class value, so that
map Just xsand a partially applied constructor still work unchanged. The split can live in the IR (a constructor worker that is an n-aryAbsNover the fields, building the table) so that the existing saturated-site rewrite and the downstream DCE and beta passes handle it exactly as they do for functions, rather than as a special case in the Lua backend.Prerequisites / Relations
Same family as #24, applied to the constructor side of application rather than the function side.
Verification / Measurement
bench/micro/ctor_match.luaalready measures constructor allocation and tag matching and is the natural before/after anchor. The win is the removal of the per-field closure allocations on saturated construction, both the PUC Lua call overhead and the LuaJIT trace aborts that closure creation triggers.