~bigbes/tarantool-protobuf: 8014163c

codec: precompute per-field writers for singular scalar/enum/message (~+50% small-msg encode)

pb.finalize_message now calls codec.compile_writers(desc), which
attaches `f._writer` to each field whose shape we can specialize:
singular scalar, singular enum, singular message — i.e. not maps,
not repeated, not oneof. Each writer is a monomorphic closure that
knows its tag bytes, encoder function, and default predicate. The
encode_message hot loop calls writer(data, out) per field and only
falls through to encode_field for shapes we haven't specialized.

This eliminates the per-field `encode_field` dispatch chain
(kind/proto_type branch + `is_default_scalar` call), which was the
source of the remaining trace bridges in runtime mode (codec.lua:41
and codec.lua:110 in `make jit-trace` output).

Effect (bench/bench.lua, hello.Person):
  runtime/10B  encode:  5.0 →  8.1 MB/s  (+62%)
  runtime/100B encode: 48.2 → 75.2 MB/s  (+56%)
  runtime/1KB  encode: 49.5 → 56.1 MB/s  (+13%)
  runtime/10KB+ encode: unchanged (dominated by repeated-field
                                   iteration — not yet specialized)
  full mode encode: +10% across small sizes (writer closures also
                    help when codegen calls back into the runtime)
  decode: unchanged
  alloc/op: unchanged (bench-compare clean)
  bridges across 10 jit-trace runs: 7 → 4

Eugene Blikh <bigbes@gmail.com> — 2026-05-15 10:59:11 UTC

Commit 8014163c25e3b4c8aa61f04b4412b656f54ba495view raw patch

Parent(s): 9f3bfb8f

2 changed file(s)

FileStatus+
runtime/pb/codec.lua M +117 -1
runtime/pb/init.lua M +6