Files
esp32-lua-api/native
evan 5d44234046 perf(ui): pass the label as an argument and share one empty spec
The label was the last field the wrapper wrote into a caller's spec, and on
a two-key text spec it was the key that forced a rehash. It now rides as an
argument like type, so ui.text writes nothing at all, and a button's padding
and centring are the tree's defaults rather than fields patched in from Lua.

With no builder writing into a spec any more, every spec-less call can share
one immutable table instead of allocating its own. It is frozen with a
__newindex that raises, because reintroducing a write would otherwise leak a
field into every spec-less node built afterwards -- a fault with no symptom
anywhere near its cause. One lua_State exists at a time, so the guard costs
about 100 bytes in total.

ui.spacer passes its spec through rather than copying w and h into a fresh
table, and the style alias on a text spec is dropped for textStyle, which no
caller used.

ui.rebuild now collects before the repaint rather than after it. The collect
was already there and its comment already named the hazard, but the painter
is the very next thing to want a large contiguous block for its band, and it
was being handed a heap still holding a screen's worth of dead spec tables --
a C++ allocation gets no emergency collection the way a failed Lua one does.
Worth 5.6kB of free heap at paint time; the largest block is unchanged,
because the freed specs are small and scattered.

Measured in the emulator, 12 sensors / 131 nodes: live Lua at build end
79.9kB -> 79.7kB and build time unchanged at 52ms. The raw heap figure looks
worse because removing the rehashes also removed the allocation pressure that
had been pacing the incremental collector, so the dead spec tables now sit
uncollected until something asks for them; live usage is what did not change.
ui.lua stripped bytecode 9499 -> 9340 bytes.
2026-08-08 12:19:53 -04:00
..