~bigbes/tarantool

tarantool-protobuf

feecf8e0fd69221131d1ea4a4f10f687e80def11 — Eugene Blikh 3 months ago c85386b
codegen: inline 1-byte tag fast path at decode call sites

Hoists wire.decode_tag's 1-byte fast path into every generated
M.X_decode while-loop, falling back to the helper for multi-byte
tags (field ids > 15). The 1-byte case covers every protobuf field
with id 1..15 and is the dominant decode dispatch in real payloads.

Header now localizes string.byte, bit.band, and bit.rshift so the
inlined ops compile to straight local calls.

Bench (Person full decode, msgs/s, median-of-3 vs proper post-h8v
3-run baseline): 10B +14.7%, 100B +8.9%, 1KB +7.5%, 10KB +7.0%,
100KB +8.5%. Full encode is flat to small (-0.1% to -2.6%) at large
sizes, plausibly from header-upvalue layout. JIT trace gate: 37/37,
all bridges still 0. Tests: 745/745.

Also documented in bench/PERF_LOG.md, including the methodology
note that h8v's earlier numbers used single-run baselines and are
therefore ~3-5% optimistic; medians-of-3 are the standard now.

beads-tarantool-protobuf-4kj
M bench/PERF_LOG.md => bench/PERF_LOG.md +94 -0
@@ 84,6 84,100 @@ macOS arm64.

<!-- Append new entries below this line. Newest at the top. -->

## 2026-05-18 — 4kj: inline 1-byte tag fast path at decode call sites

**Task:** [tarantool-protobuf-4kj] Decoder: generated tag/length fast path
for full-mode decode. Profile attributed ~21% of hello.Person 1KB decode
time to `wire.decode_tag` dispatch.

**Change:** In `cmd/protoc-gen-tarantool/internal/gen/inline.go`, the
generated `M.X_decode` while-loop now decodes the 1-byte tag form inline
before falling back to `wire.decode_tag` for multi-byte. A header tweak
in `gen.go` localizes `string.byte`, `bit.band`, and `bit.rshift` at the
top of every generated file so each call inside the loop becomes a
straight-line local-call.

```lua
-- Before:
local id, wt
id, wt, pos = wire.decode_tag(buf, pos)

-- After:
local id, wt
local _b = string_byte(buf, pos)
if _b ~= nil and _b < 0x80 then
    wt = band(_b, 7)
    if wt >= 6 then error("illegal wire type " .. wt, 0) end
    id = rshift(_b, 3)
    if id == 0 then error("illegal field number 0", 0) end
    pos = pos + 1
else
    id, wt, pos = wire.decode_tag(buf, pos)
end
```

Field numbers 1..15 always encode as a single byte; that's the
overwhelmingly dominant case in real payloads, including every Person
field in the bench corpus.

**Tests:** 745/745 pass. JIT trace gate: 37/37, all bridges still 0.

**Bench (Person full, msgs/s, median-of-3 vs proper post-h8v median-of-3
baseline):**

| size  | dir | post-h8v    | 4kj       | Δ         |
|-------|-----|-------------|-----------|-----------|
| 10B   | dec | 2,247,620   | 2,579,347 | **+14.7%** |
| 100B  | dec | 1,949,565   | 2,122,601 | **+8.9%**  |
| 1KB   | dec | 102,175     | 109,792   | **+7.5%**  |
| 10KB  | dec | 14,100      | 15,084    | **+7.0%**  |
| 100KB | dec | 1,393       | 1,512     | **+8.5%**  |
| 10B   | enc | 2,291,108   | 2,272,701 | -0.8%     |
| 100B  | enc | 2,250,757   | 2,313,101 | +2.8%     |
| 1KB   | enc | 293,677     | 293,367   | -0.1%     |
| 10KB  | enc | 60,269      | 59,390    | -1.5%     |
| 100KB | enc | 6,746       | 6,570     | -2.6%     |

**Methodology note (lesson from gcy):** the post-h8v "single-run"
baseline I'd captured for h8v was a peak run (the bench is noisier than
I'd expected on macOS arm64). For 4kj I re-baselined post-h8v with a
3-run median *before* comparing, which made the decode win obvious and
exposed the encode -1 to -3% as small/within-noise. Going forward,
medians-of-3 are the comparison standard; PERF_LOG entries earlier than
this one used single-run baselines (h8v's numbers are likely tilted
~3-5% optimistic).

**Bench (proto2_basic.BenchPayload full):** roughly flat — proto2 mid
encode/decode within ±1% of post-h8v. Expected: BenchPayload doesn't
have a tight decode loop the way Person 1KB does.

**Bench (runtime mode):** the runtime mode wrappers don't see the
inlined fast path — they delegate to `pb.codec.decode`. Runtime decode
1KB measured at 97,285 vs an earlier baseline 103,503, but that baseline
was single-run and inconsistent with the variance I've seen since.
Treating this as noise; no semantic change is plausible for runtime
mode here (only file-header upvalues added, three locals never
referenced by runtime wrappers).

**Caveats / leftovers:**
- Multi-byte tags (field ids > 15) still pay the `wire.decode_tag` call.
  Generated protobuf rarely uses high field numbers, but extensions
  often do; the fallback keeps them correct.
- Encode regressed slightly at 10KB+. Plausible cause: three extra
  file-level upvalues (band/rshift/string_byte) shift LuaJIT's
  function-prologue layout for `Person_encode` even though that
  function doesn't use them. Not currently worth optimizing.
- `wire.decode_len` is still a function call. Inlining its byte-read
  half can come next, but the substring it produces is unavoidable.
- The richer "order-prediction" form of this task — emit a literal
  tag-byte equality check per declared field — is deferred. It would
  double-dispatch (literal-match + id-match fallback) and the simple
  inline already captures ~half the available gain.

**Commit:** see git history for SHA.

---

## 2026-05-18 — gcy: inline nested-message decode at the call site (REVERTED)

**Task:** [tarantool-protobuf-gcy] Decoder: inline nested-message decode at

M cmd/protoc-gen-tarantool/internal/gen/gen.go => cmd/protoc-gen-tarantool/internal/gen/gen.go +6 -0
@@ 177,6 177,12 @@ func emitHeader(w *writer, file *protogen.File) {
	w.line("")
	w.line("local pb = require(%q)", runtimeRequire)
	w.line("local wire = pb.wire")
	// Hot-path locals used by the inlined tag/length fast paths in each
	// generated _decode function. Localizing turns the LuaJIT references
	// into upvalue reads on the trace instead of repeated global lookups.
	w.line("local string_byte = string.byte")
	w.line("local band = bit.band")
	w.line("local rshift = bit.rshift")
}

// collectImports returns the deduplicated set of Lua require paths for all

M cmd/protoc-gen-tarantool/internal/gen/inline.go => cmd/protoc-gen-tarantool/internal/gen/inline.go +16 -1
@@ 373,7 373,22 @@ func emitInlineDecode(w *writer, name string, m *protogen.Message, file *protoge
	w.line("    while pos <= len do")
	w.line("        local _tag_start = pos")
	w.line("        local id, wt")
	w.line("        id, wt, pos = wire.decode_tag(buf, pos)")
	// Inline the 1-byte tag fast path. The protobuf spec encodes field
	// numbers 1..15 (with any wire type) in a single byte, and the
	// codegen orderings + our test corpora keep nearly every dispatch
	// here on the fast branch. Removes the wire.decode_tag function
	// frame for the dominant case; multi-byte tags fall back to the
	// generic decoder.
	w.line("        local _b = string_byte(buf, pos)")
	w.line("        if _b ~= nil and _b < 0x80 then")
	w.line("            wt = band(_b, 7)")
	w.line("            if wt >= 6 then error(\"illegal wire type \" .. wt, 0) end")
	w.line("            id = rshift(_b, 3)")
	w.line("            if id == 0 then error(\"illegal field number 0\", 0) end")
	w.line("            pos = pos + 1")
	w.line("        else")
	w.line("            id, wt, pos = wire.decode_tag(buf, pos)")
	w.line("        end")

	first := true
	for _, f := range m.Fields {

M examples/expected/full/conformance/conformance_pb.lua => examples/expected/full/conformance/conformance_pb.lua +53 -5
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 271,7 274,16 @@ function M.TestStatus_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 367,7 379,16 @@ function M.FailureSet_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 2 then
            local list = result.test
            if list == nil then list = {}; result.test = list end


@@ 551,7 572,16 @@ function M.ConformanceRequest_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_bytes(buf, pos)


@@ 790,7 820,16 @@ function M.ConformanceResponse_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 972,7 1011,16 @@ function M.JspbEncodingConfig_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_bool(buf, pos)

M examples/expected/full/hello/hello_pb.lua => examples/expected/full/hello/hello_pb.lua +63 -6
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 287,7 290,16 @@ function M.Result_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 394,7 406,16 @@ function M.HelloRequest_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 478,7 499,16 @@ function M.HelloReply_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 705,7 735,16 @@ function M.Event_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 863,7 902,16 @@ function M.Address_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 1150,7 1198,16 @@ function M.Person_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)

M examples/expected/full/proto2_basic/proto2_basic_pb.lua => examples/expected/full/proto2_basic/proto2_basic_pb.lua +103 -10
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 344,7 347,16 @@ function M.Defaults_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 541,7 553,16 @@ function M.Cardinality_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 700,7 721,16 @@ function M.Nested_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local payload
            payload, pos = wire.decode_len(buf, pos)


@@ 798,7 828,16 @@ function M.Nested_Inner_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 888,7 927,16 @@ function M.WithGroup_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local payload
            payload, pos = pb.codec.decode_group(M.WithGroup_SingleGroup_descriptor, buf, pos, 1)


@@ 994,7 1042,16 @@ function M.WithGroup_SingleGroup_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 2 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 1086,7 1143,16 @@ function M.WithGroup_RepGroup_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 5 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 1241,7 1307,16 @@ function M.BenchPayload_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 1394,7 1469,16 @@ function M.BenchPayload_Stats_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 8 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 1499,7 1583,16 @@ function M.BenchPayload_Inner_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)

M examples/expected/full/protobuf_test_messages/proto2/test_messages_proto2_pb.lua => examples/expected/full/protobuf_test_messages/proto2/test_messages_proto2_pb.lua +213 -21
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 2612,7 2615,16 @@ function M.TestAllTypesProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4541,7 4553,16 @@ function M.TestAllTypesProto2_NestedMessage_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4644,7 4665,16 @@ function M.TestAllTypesProto2_Data_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 202 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4742,7 4772,16 @@ function M.TestAllTypesProto2_MultiWordGroupField_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 205 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4834,7 4873,16 @@ function M.ForeignMessageProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4923,7 4971,16 @@ function M.GroupField_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 122 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 5062,7 5119,16 @@ function M.UnknownToTestAllTypes_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1001 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 5208,7 5274,16 @@ function M.UnknownToTestAllTypes_OptionalGroup_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 5285,7 5360,16 @@ function M.NullHypothesisProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.NullHypothesisProto2_descriptor.extensions_by_id


@@ 5354,7 5438,16 @@ function M.EnumOnlyProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.EnumOnlyProto2_descriptor.extensions_by_id


@@ 5435,7 5528,16 @@ function M.OneStringProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_string(buf, pos)


@@ 5546,7 5648,16 @@ function M.ProtoWithKeywords_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 5995,7 6106,16 @@ function M.TestAllRequiredTypesProto2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 6283,7 6403,16 @@ function M.TestAllRequiredTypesProto2_NestedMessage_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 6392,7 6521,16 @@ function M.TestAllRequiredTypesProto2_Data_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 202 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 6539,7 6677,16 @@ function M.TestLargeOneof_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local payload
            payload, pos = wire.decode_len(buf, pos)


@@ 6672,7 6819,16 @@ function M.TestLargeOneof_A1_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.TestLargeOneof_A1_descriptor.extensions_by_id


@@ 6741,7 6897,16 @@ function M.TestLargeOneof_A2_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.TestLargeOneof_A2_descriptor.extensions_by_id


@@ 6810,7 6975,16 @@ function M.TestLargeOneof_A3_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.TestLargeOneof_A3_descriptor.extensions_by_id


@@ 6879,7 7053,16 @@ function M.TestLargeOneof_A4_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.TestLargeOneof_A4_descriptor.extensions_by_id


@@ 6948,7 7131,16 @@ function M.TestLargeOneof_A5_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.TestLargeOneof_A5_descriptor.extensions_by_id

M examples/expected/full/protobuf_test_messages/proto3/test_messages_proto3_pb.lua => examples/expected/full/protobuf_test_messages/proto3/test_messages_proto3_pb.lua +53 -5
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 2766,7 2769,16 @@ function M.TestAllTypesProto3_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4488,7 4500,16 @@ function M.TestAllTypesProto3_NestedMessage_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4575,7 4596,16 @@ function M.ForeignMessage_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)


@@ 4647,7 4677,16 @@ function M.NullHypothesisProto3_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.NullHypothesisProto3_descriptor.extensions_by_id


@@ 4716,7 4755,16 @@ function M.EnumOnlyProto3_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if true then
        else
            local _ebid = M.EnumOnlyProto3_descriptor.extensions_by_id

M examples/expected/full/quickstart/quickstart_pb.lua => examples/expected/full/quickstart/quickstart_pb.lua +13 -1
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}



@@ 137,7 140,16 @@ function M.User_decode(buf)
    while pos <= len do
        local _tag_start = pos
        local id, wt
        id, wt, pos = wire.decode_tag(buf, pos)
        local _b = string_byte(buf, pos)
        if _b ~= nil and _b < 0x80 then
            wt = band(_b, 7)
            if wt >= 6 then error("illegal wire type " .. wt, 0) end
            id = rshift(_b, 3)
            if id == 0 then error("illegal field number 0", 0) end
            pos = pos + 1
        else
            id, wt, pos = wire.decode_tag(buf, pos)
        end
        if id == 1 then
            local val
            val, pos = wire.decode_int32(buf, pos)

M examples/expected/runtime/conformance/conformance_pb.lua => examples/expected/runtime/conformance/conformance_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}


M examples/expected/runtime/hello/hello_pb.lua => examples/expected/runtime/hello/hello_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}


M examples/expected/runtime/proto2_basic/proto2_basic_pb.lua => examples/expected/runtime/proto2_basic/proto2_basic_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}


M examples/expected/runtime/protobuf_test_messages/proto2/test_messages_proto2_pb.lua => examples/expected/runtime/protobuf_test_messages/proto2/test_messages_proto2_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}


M examples/expected/runtime/protobuf_test_messages/proto3/test_messages_proto3_pb.lua => examples/expected/runtime/protobuf_test_messages/proto3/test_messages_proto3_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}


M examples/expected/runtime/quickstart/quickstart_pb.lua => examples/expected/runtime/quickstart/quickstart_pb.lua +3 -0
@@ 5,6 5,9 @@

local pb = require("pb")
local wire = pb.wire
local string_byte = string.byte
local band = bit.band
local rshift = bit.rshift

local M = {}