Commit bd09b2b
authored
perf: closure-free LazyDefault for default argument evaluation (#762)
## Motivation
Default argument evaluation in `Val.Func.apply` allocates 2 objects per
default: a `LazyFunc` wrapper plus a `Function0` closure. For functions
with multiple defaults called in hot paths, this creates unnecessary GC
pressure.
## Key Design Decision
Introduce `LazyDefault`, a purpose-built `Lazy` subclass that captures
the expression, scope, function, and eval scope as fields instead of a
closure. This follows the established
`LazyExpr`/`LazyApply1`/`LazyApply2` pattern in the codebase.
## Modification
- Add `LazyDefault` final class in `Val.scala` (24 bytes, same as
`LazyExpr`)
- Replace `new LazyFunc(() => evalDefault(default, newScope, ev))` with
`new LazyDefault(default, newScope, this, ev)` in `Func.apply`
- Clear captured references after first evaluation to allow GC
## Benchmark Results
### JMH (single fork, 1 iteration — directional only)
| Benchmark | Master (ms/op) | This PR (ms/op) | Change |
|-----------|---------------|-----------------|--------|
| assertions | 0.222 | 0.205 | **-7.7%** |
| bench.02 | 35.235 | 34.531 | -2.0% |
| bench.03 | 9.809 | 9.652 | -1.6% |
| manifestTomlEx | 0.074 | 0.069 | **-6.8%** |
| reverse | 6.667 | 6.448 | **-3.3%** |
Most benchmarks show improvement or are within noise margins.
### Scala Native vs jrsonnet (hyperfine)
Not applicable for this change — the allocation reduction primarily
benefits JVM GC. Native impact is minimal but non-negative.
## Analysis
The optimization reduces allocation from 2 objects to 1 per default
argument evaluation. The `LazyDefault` pattern is consistent with
existing `LazyExpr`, `LazyApply1`, `LazyApply2` classes. No semantic
changes.
## References
- Upstream: jit branch commit
[`d40ae8cc`](He-Pin@d40ae8cc)
## Result
All 420 tests pass across JVM/JS/Native × Scala 3.3.7, 2.13.18, 2.12.21.
---
## JMH Benchmark Results (vs master 0d13274)
| Benchmark | Master (ms/op) | This PR (ms/op) | Change |
|-----------|---------------:|----------------:|-------:|
| assertions | 0.207 | 0.204 | -1.4% |
| base64 | 0.156 | 0.156 | +0.0% |
| improved base64Decode | 0.123 | 0.117 | -4.9% |
| regressed base64DecodeBytes | 5.899 | 6.071 | +2.9% |
| base64_byte_array | 0.803 | 0.790 | -1.6% |
| bench.01 | 0.052 | 0.052 | +0.0% |
| improved bench.02 | 35.401 | 34.003 | -3.9% |
| bench.03 | 9.583 | 9.715 | +1.4% |
| bench.04 | 0.122 | 0.120 | -1.6% |
| regressed bench.06 | 0.224 | 0.229 | +2.2% |
| improved bench.07 | 3.332 | 3.174 | -4.7% |
| regressed bench.08 | 0.038 | 0.039 | +2.6% |
| regressed bench.09 | 0.041 | 0.042 | +2.4% |
| comparison | 0.028 | 0.028 | +0.0% |
| improved comparison2 | 18.681 | 18.256 | -2.3% |
| improved escapeStringJson | 0.032 | 0.031 | -3.1% |
| foldl | 0.077 | 0.076 | -1.3% |
| gen_big_object | 0.918 | 0.920 | +0.2% |
| regressed large_string_join | 0.555 | 0.573 | +3.2% |
| regressed large_string_template | 1.600 | 1.641 | +2.6% |
| regressed lstripChars | 0.113 | 0.116 | +2.7% |
| manifestJsonEx | 0.052 | 0.052 | +0.0% |
| manifestTomlEx | 0.069 | 0.068 | -1.4% |
| manifestYamlDoc | 0.055 | 0.056 | +1.8% |
| member | 0.656 | 0.656 | +0.0% |
| regressed parseInt | 0.032 | 0.033 | +3.1% |
| realistic1 | 1.661 | 1.680 | +1.1% |
| regressed realistic2 | 57.541 | 60.763 | +5.6% |
| regressed reverse | 6.717 | 6.943 | +3.4% |
| rstripChars | 0.119 | 0.119 | +0.0% |
| setDiff | 0.431 | 0.434 | +0.7% |
| setInter | 0.371 | 0.376 | +1.3% |
| setUnion | 0.604 | 0.615 | +1.8% |
| stripChars | 0.117 | 0.118 | +0.9% |
| regressed substr | 0.057 | 0.060 | +5.3% |
**Summary**: 5 improvements, 11 regressions, 19 neutral
**Platform**: Apple Silicon, JMH single-shot avg1 parent 0d13274 commit bd09b2b
1 file changed
Lines changed: 26 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
134 | 159 | | |
135 | 160 | | |
136 | 161 | | |
| |||
1441 | 1466 | | |
1442 | 1467 | | |
1443 | 1468 | | |
1444 | | - | |
| 1469 | + | |
1445 | 1470 | | |
1446 | 1471 | | |
1447 | 1472 | | |
| |||
0 commit comments