Skip to content

escape: use hex-pair lookup in curl_easy_escape - #23021

Merged
cmeister2 merged 1 commit into
masterfrom
cm2/urlencode
Sep 21, 2026
Merged

cmeister2 merged 1 commit into
masterfrom
cm2/urlencode

Conversation

@cmeister2

Copy link
Copy Markdown
Contributor

Summary

Use a precomputed uppercase hex-pair table in curl_easy_escape(),
replacing two separate digit lookups with a two-byte memcpy.

Preserve literal-run batching, allocation bounds, character classification,
and NUL termination. The table adds 513 bytes before alignment. Using
memcpy avoids alignment, aliasing, and endianness assumptions.

Add regression coverage for all 256 byte values, checking exact encoded
output and decoded bytes, length, and termination.

Performance

Saved measurements of this encoder change against baseline
acec0de3921d2e5eb435410dbe4b2171b5097e9a:

  • GCC 11.5.0, -O2 -DNDEBUG, static libcurl, Intel Core Ultra 7 165H, WSL2.
  • Five alternating baseline/candidate rounds, 3,000,000 calls each, pinned
    to CPU 2. Allocation and freeing remain inside the timed loop.
  • Input contains all 256 byte values: 190 require escaping.
  • Median urlencode: 248.942 → 186.344 ns/call, 25.15% less time.
    The candidate was faster in all five pairs.

These are earlier measurements, not a fresh benchmark of this branch.

Caveat: The unchanged urldecode benchmark was 8.69% slower
(228.330 → 248.172 ns/call) in the same comparison. Code and table placement
changed, but the cause remains unproven. Further measurements on a native
host or with other compiler/link layouts are needed before claiming a net
performance improvement.

Generated Assembly

GCC's x86-64 escaped-byte block, including loop-end control. Classification,
literal-run flushing, allocation, and termination are outside these excerpts.
At entry, r12 holds the input byte and rcx points to its output slot.

Before

mov   eax,r12d
and   r12d,0xf
mov   BYTE PTR [rcx],0x25
mov   rsi,rbx
shr   al,0x4
add   rcx,0x3
xor   r13d,r13d
and   eax,0xf
movzx eax,BYTE PTR [rax+0x4b5cc0]
mov   BYTE PTR [rcx-0x2],al
movzx eax,BYTE PTR [r12+0x4b5cc0]
mov   BYTE PTR [rcx-0x1],al
cmp   rbx,rbp
jne   40c389

After

mov   BYTE PTR [rcx],0x25
mov   rsi,rbx
add   rcx,0x3
xor   r13d,r13d
movzx eax,WORD PTR [r12+r12*1+0x4b5640]
mov   WORD PTR [rcx-0x2],ax
cmp   rbx,rbp
jne   40c389

The block shrinks from 14 to 8 instructions, with one table load instead
of two and two output stores instead of three. The two-byte memcpy is
inlined; output size is unchanged. These are instruction counts, not cycles.

Validation

  • Local Debug build and tests 543, 1396, 1560, and 1675 pass.
  • Source-style and patch-whitespace checks pass.
  • Full suite, fresh release benchmarks, and sanitizers were not run for this branch.

@github-actions github-actions Bot added the tests label Sep 21, 2026
cmeister2 added a commit that referenced this pull request Sep 21, 2026
Copy precomputed uppercase hex pairs instead of looking up each digit
separately. Preserve literal-run batching and allocation behavior.

Add coverage for all 256 byte values, checking exact encoded output
and round-trip decoding.

Closes #23021
cmeister2 added a commit that referenced this pull request Sep 21, 2026
Copy precomputed uppercase hex pairs instead of looking up each digit
separately. Preserve literal-run batching and allocation behavior.

Add coverage for all 256 byte values, checking exact encoded output
and round-trip decoding.

Closes #23021
Copy precomputed uppercase hex pairs instead of looking up each digit
separately. Preserve literal-run batching and allocation behavior.

Add coverage for all 256 byte values, checking exact encoded output
and round-trip decoding.

Closes #23021
@cmeister2
cmeister2 merged commit 53be819 into master Sep 21, 2026
322 of 327 checks passed
@cmeister2
cmeister2 deleted the cm2/urlencode branch September 21, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants