Skip to content

Performance: Remove unnecessary dereferencing from YulString storage#16763

Open
DanielVF wants to merge 1 commit into
argotorg:developfrom
DanielVF:optimize-yul-strings
Open

Performance: Remove unnecessary dereferencing from YulString storage#16763
DanielVF wants to merge 1 commit into
argotorg:developfrom
DanielVF:optimize-yul-strings

Conversation

@DanielVF
Copy link
Copy Markdown
Contributor

Description

~3% speed up to Yul compilation times with a small change.

Benchmark

contract optimized, no via-ir via-ir
WETH9 -1.79% ✅ -2.21% ✅
ENSRegistryWithFallback -0.94% ✅ -3.77% ✅
TetherToken -1.09% ✅ -0.80% ✅
OETH -1.54% ✅ -2.16% ✅
BoredApeYachtClub -1.75% ✅ -2.33% ✅
RocketDepositPool -1.34% ✅ -3.56% ✅
Poap -1.04% ✅ -3.50% ✅
FiatTokenV2_2 -2.89% ✅ -4.69% ✅
Morpho -0.81% ✅ -4.06% ✅
AccessControlledOCR2Aggregator -1.83% ✅ -1.67% ✅
PoolManager -1.49% ✅ -2.17% ✅
EulerSwap -1.06% ✅ -4.28% ✅
EtherfiLiquidityPool -2.44% ✅ -3.83% ✅
AaveV4HubInstance -1.46% ✅ -2.65% ✅
UniswapV3Pool -1.27% ✅ -2.93% ✅
Total -1.89% ✅ -3.23% ✅

Details

Yul compilation creates many YulString/YulName objects, most of these auto generated names. Compiling the AaveV4HubInstance contract creates around 100,000 of these instances. The current implementation around these strings is unnecessarily slow because there is an extra layer of indirection.

A core requirement for YulString.h is that the underlying string storage never changes a string's memory location and thus the underlying string can be safely pointed to from other places in the code. A shared pointer is used in the current code because when a vector resizes it may move where its immediate children are stored in memory. The shared pointer means these resizes never affect underlying string storage.

[vector][] -> [shared_pointer] -> [string]

However, by switching the vector to an indexedable data structure that does not move the underlying memory when expanding (deque), the overhead of the intermediate shared pointer can be skipped and short strings can be stored directly into the container, without even a pointer to the heap. This has a major effect on the speed of working with strings in the compiler, since this speeds up creation, id based lookups, and string based lookups (as those also go through id based lookups).

[deque][] -> [string]

This PR changes the type from std::vector<std::shared_ptr<std::string>> to std::deque<std::string> and then removes the now unnecessary pointer dereferencing from where the strings are looked up.

Checklist

AI Disclosure

  • No AI tools were used
  • AI tools were used (details below)

Codex 5.5

@clonker
Copy link
Copy Markdown
Member

clonker commented May 22, 2026

Memory consumption is interesting here. Without having looked too closely at it, I think the shared pointers were deliberate to guard against (re)allocations.

Perhaps interesting in this context though: #15969

@DanielVF
Copy link
Copy Markdown
Contributor Author

Thanks for the link to the other PR. I do think it's a lot of unnecessary work to pre-create string labels for everything - would be great to see it removed.

@DanielVF
Copy link
Copy Markdown
Contributor Author

If the other PR is planned for inclusion in the next release, we could close this PR.

Otherwise, we could roll this PR in now since it is a minimal change with no effects but performance, and hopefully get the big PR in the release after.

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.

2 participants