bench: lazy decode/encode scenarios + jit-trace coverage
Adds bench/lazy_bench.lua comparing eager decode/encode against
decode_lazy:encode across three workloads (passthrough, sparse-read,
mutate-then-reencode) at 1KB/10KB/100KB on emails-heavy Person.
Output is stderr-only (varies with CPU load; not committed to
baseline.json).
Findings (LuaJIT 2.1.0-beta3, both modes):
- Passthrough re-encode: lazy 1.0–1.5× faster. Untouched views skip
field-walk entirely and return their original bytes verbatim.
- Sparse :get x2: lazy 0.60–0.77× of eager. Per-segment Lua tables
allocated during the index pass cancel the decode-skip savings on
this flat shape (no large subtrees to skip_field over).
- Mutate-then-reencode: lazy 0.81–1.07× of eager — roughly
break-even. Both paths traverse the full byte range; lazy
splices, eager re-emits per field.
Lazy is a byte-passthrough optimization, not a universal speedup. Use
it when you decode, touch few fields, and re-encode — the proxy /
router shape.
Also extends bench/jit_trace.lua with three lazy hot-path checks:
index pass, sparse :get x2, and untouched :encode. All compile with
no fatal aborts (19/19 trace-stability checks pass; one harmless
side-trace bridge per scenario at lazy.lua's index loop, same pattern
as the existing decode_varint bridge).