codegen: inline 1-byte varint fast path for packed scalar elements (aah)
Per-element wire.encode_<type>(v) calls in packed-repeated fields paid a
full function-call boundary even though encode_varint's small-positive-int
hot path is a single CHARS[n] lookup. Inline the check + lookup at
codegen time at every packed emit site:
- Repeated packed scalar (mode=full)
- Repeated packed enum (after string->int resolve)
- Proto2 extension packed scalar + enum
For varint scalars (int32/int64/uint32/uint64): fast path triggers when
v is a Lua number in [0, 128). For sint32/sint64: 7-bit zigzag range
-64..63 is inlined with bit ops. For bool: always 1 byte via
CHARS[v and 1 or 0] (no fast/slow split). Fixed-width scalars keep the
wire.encode_<type> call shape — already optimal.
Also pre-sizes the parts accumulator with table_new(#v, 0) instead of
{}; same pattern qwt+2sn used decode-side. Eliminates rehash cascade
as elements push.
Tests: 752/752 pass. JIT trace gate: 37/37.
Bench (work.lab.local, median of 3, c_repeated.Holder packed N elems):
packed_int32: +90% / +113% / +106% (N=10/100/1000)
packed_sint32: +66% / +236% / +156%
packed_uint32: +73% / +105% / +102%
packed_bool: +44% / +51% / +39%
packed_int64: +22% / +21% / +23% (cdata; gain from table_new only)
Headline hello.Person 1KB +3.6%, proto2 BenchPayload mid +10.5%.
See bench/PERF_LOG.md 2026-05-24 aah entry for the full breakdown
including the sint32 +236% mid-size analysis (three function layers
collapsed into one CHARS lookup).