Skip to content

Parser: Lazily allocate hb_array_T for AST_NODE->errors#1425

Draft
marcoroth wants to merge 1 commit intomainfrom
lazily-allocate-error-arrays
Draft

Parser: Lazily allocate hb_array_T for AST_NODE->errors#1425
marcoroth wants to merge 1 commit intomainfrom
lazily-allocate-error-arrays

Conversation

@marcoroth
Copy link
Copy Markdown
Owner

@marcoroth marcoroth commented Mar 19, 2026

Previously, every AST node allocated an hb_array_T with a capacity of 8 for its errors array upfront, even on the happy path where no errors ever occur. This wasted 96 bytes per node (32 bytes for the hb_array_T struct + 64 bytes for the items buffer).

This pull request introduces hb_array_append_lazy, which skips the allocation entirely until the first error is actually appended. All append_*_error functions now take hb_array_T** and use lazy initialization. Parser locals are initialized as NULL instead of hb_array_init(8, ...).

I measured it against app/views/wrapped/index.html.erb in RubyEvents, which is the view that uses up the most memory in that app.

On current main eda3aa0 using ./herb parse ../rubyevents/app/views/wrapped/index.html.erb

╔════════════════════════════════════════════════════════════════════════════════════════════════════╗
║                                        ARENA MEMORY LAYOUT                                         ║
╠════════════════════════════════════════════════════════════════════════════════════════════════════╣
║  Statistics:                                                                                       ║
║    • Pages: 136                                                                                    ║
║    • Default Page Size: 16 KB                                                                      ║
║    • Total Capacity: 2.19 MB                                                                       ║
║    • Total Used: 2.06 MB                                                                           ║
║    • Total Available: 130 KB                                                                       ║
║    • Usage: 94.2%                                                                                  ║
║    • Allocations: 24894                                                                            ║
║    • Fragmentation: 126 KB                                                                         ║
║      (5.7% skipped in non-tail pages)                                                              ║
╚════════════════════════════════════════════════════════════════════════════════════════════════════╝

Compared to this pull request:

╔════════════════════════════════════════════════════════════════════════════════════════════════════╗
║                                        ARENA MEMORY LAYOUT                                         ║
╠════════════════════════════════════════════════════════════════════════════════════════════════════╣
║  Statistics:                                                                                       ║
║    • Pages: 125                                                                                    ║
║    • Default Page Size: 16 KB                                                                      ║
║    • Total Capacity: 2.02 MB                                                                       ║
║    • Total Used: 1.92 MB                                                                           ║
║    • Total Available: 106 KB                                                                       ║
║    • Usage: 94.9%                                                                                  ║
║    • Allocations: 21459                                                                            ║
║    • Fragmentation: 103 KB                                                                         ║
║      (5.0% skipped in non-tail pages)                                                              ║
╚════════════════════════════════════════════════════════════════════════════════════════════════════╝
Total arena used:  2.06 MB   → 1.92 MB  (−140 KB)
Allocations:        24,894   → 21,459   (−3,435)
Fragmentation:      126 KB   → 103 KB   (−23 KB)

I think this is kind of nice improvement for just changing the way error arrays are initialized. There is probably more we can do in the same realm.

Resolves #1343
Related: #1381

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 19, 2026

npx https://pkg.pr.new/@herb-tools/formatter@1425
npx https://pkg.pr.new/@herb-tools/language-server@1425
npx https://pkg.pr.new/@herb-tools/linter@1425

commit: 406f72c

@github-actions
Copy link
Copy Markdown

🌿 Interactive Playground and Documentation Preview

A preview deployment has been built for this pull request. Try out the changes live in the interactive playground:


🌱 Grown from commit 406f72c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C: Lazily allocate errors arrays in parser

1 participant