Skip to content

perf(compiler): optimize HtmlEscaper escape path - #313

Open
spullara wants to merge 2 commits into
mainfrom
perf/htmlescaper-fastclean
Open

perf(compiler): optimize HtmlEscaper escape path#313
spullara wants to merge 2 commits into
mainfrom
perf/htmlescaper-fastclean

Conversation

@spullara

Copy link
Copy Markdown
Owner

Summary

Standalone performance PR for HtmlEscaper (split out from dotted-name work on PR #312).

Changes

  • Avoid per-call String.toCharArray() allocation in HtmlEscaper.escape
  • Scan with charAt and write clean spans via Writer.write(String, off, len)
  • Preserve the existing escape table (codepoints 0-13, amp lt gt quote apos eq backtick)
  • Simple final span write (if start < length) with no extra clean-path flag

Motivation

Profiling of TweetBench / Main.benchEscapeHTML showed escape was a top CPU path and allocated a full copy of every escaped string. Short/clean values (common in template rendering) benefit most; semantics are unchanged.

Test plan

  • mvn -q -pl compiler -Dtest=HtmlEscaperTest test
  • mvn -q -pl compiler -am test (optional full module)

spullara added 2 commits July 31, 2026 10:45
Add fast-path optimization for strings that require no HTML escaping,
reducing unnecessary allocations for clean input.

Agent-Id: agent-30acfca6-f8b9-4bef-a5e5-6e1c93a9ca93
Linked-Note-Id: d7b598f2-2448-4691-89a3-69092fb9f304
Remove intermediate variable assignment by directly returning the clean flag check result.

Agent-Id: agent-6007c205-7a4c-42ec-9cfc-3013821dc4c1
Linked-Note-Id: 14632543-8212-46c4-b9c2-f1c2d31b96a3
@augmentcode

augmentcode Bot commented Jul 31, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: Optimizes HTML escaping by removing the per-call String.toCharArray() allocation and scanning via charAt.
Changes: Writes unescaped spans using Writer.write(String, off, len) and avoids the final empty write when no tail span remains.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

if (c <= 96 && (escaped = ESC[c]) != null) {
// Write from the last replacement to before this one
if (i > start) writer.write(chars, start, i - start);
if (i > start) writer.write(value, start, i - start);

@augmentcode augmentcode Bot Jul 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writer.write(String, int, int)’s default implementation allocates a new char[] per call; wrappers like LatchedWriter/IndentWriter that only override write(char[], …) may now allocate per clean span and potentially regress perf vs the previous toCharArray+slice approach. Consider validating benchmarks with those writers in the call chain to ensure this stays a win in typical rendering paths.

Other locations where this applies: compiler/src/main/java/com/github/mustachejava/util/HtmlEscaper.java:75

Severity: medium

Other Locations
  • compiler/src/main/java/com/github/mustachejava/util/HtmlEscaper.java:75

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@spullara
spullara force-pushed the perf/htmlescaper-fastclean branch from a71b412 to d7a99b8 Compare July 31, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant