Centralize FExecuting re-entrancy guard into TGocciaIteratorHelperValue (#581)#589
Conversation
…ue base class (#581) Introduce TGocciaIteratorHelperValue as a template-method base between TGocciaIteratorValue and all 8 iterator helper classes. The base owns FExecuting and overrides AdvanceNext/DirectNext with the guard + try/finally, delegating to abstract DoAdvanceNext/DoDirectNext that subclasses implement. This mirrors the spec's GeneratorResume structure and eliminates 8 field declarations and 16 duplicated guard sites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the new intermediate class and missing Concat/Zip/ZipKeyed entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughThis PR introduces ChangesIterator Helper Base Class Centralization
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Suite TimingTest Runner (interpreted: 8,989 passed; bytecode: 8,989 passed)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.
Benchmarks (interpreted: 407; bytecode: 407)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.
Measured on ubuntu-latest x64. |
Benchmark Results407 benchmarks Interpreted: 🟢 45 improved · 🔴 75 regressed · 287 unchanged · avg -0.5% arraybuffer.js — Interp: 🟢 1, 🔴 1, 12 unch. · avg +0.3% · Bytecode: 🟢 1, 🔴 10, 3 unch. · avg -7.4%
arrays.js — Interp: 🔴 7, 12 unch. · avg -1.1% · Bytecode: 🔴 17, 2 unch. · avg -7.8%
async-await.js — Interp: 🔴 1, 5 unch. · avg -1.1% · Bytecode: 🔴 4, 2 unch. · avg -10.3%
async-generators.js — Interp: 2 unch. · avg +3.2% · Bytecode: 🔴 2 · avg -10.2%
base64.js — Interp: 🔴 4, 6 unch. · avg -2.1% · Bytecode: 🔴 10 · avg -8.9%
classes.js — Interp: 🔴 3, 28 unch. · avg -0.9% · Bytecode: 🔴 14, 17 unch. · avg -4.1%
closures.js — Interp: 11 unch. · avg -0.8% · Bytecode: 🔴 10, 1 unch. · avg -7.6%
collections.js — Interp: 🟢 1, 11 unch. · avg +1.0% · Bytecode: 🔴 12 · avg -9.7%
csv.js — Interp: 13 unch. · avg -0.5% · Bytecode: 🔴 13 · avg -8.0%
destructuring.js — Interp: 🟢 1, 🔴 2, 19 unch. · avg -0.4% · Bytecode: 🔴 18, 4 unch. · avg -6.5%
fibonacci.js — Interp: 8 unch. · avg -0.5% · Bytecode: 🔴 8 · avg -9.4%
float16array.js — Interp: 🟢 6, 🔴 7, 19 unch. · avg +0.1% · Bytecode: 🟢 4, 🔴 25, 3 unch. · avg -5.3%
for-of.js — Interp: 🟢 3, 4 unch. · avg +2.4% · Bytecode: 🔴 6, 1 unch. · avg -8.2%
generators.js — Interp: 4 unch. · avg -0.0% · Bytecode: 🔴 4 · avg -9.3%
iterators.js — Interp: 🟢 2, 🔴 11, 29 unch. · avg -1.8% · Bytecode: 🟢 2, 🔴 25, 15 unch. · avg -3.8%
json.js — Interp: 🟢 2, 🔴 11, 7 unch. · avg -3.3% · Bytecode: 🔴 20 · avg -8.8%
jsx.jsx — Interp: 🟢 11, 10 unch. · avg +3.6% · Bytecode: 🔴 20, 1 unch. · avg -6.2%
modules.js — Interp: 9 unch. · avg -1.3% · Bytecode: 🔴 9 · avg -9.1%
numbers.js — Interp: 🔴 2, 9 unch. · avg -1.8% · Bytecode: 🔴 11 · avg -7.0%
objects.js — Interp: 7 unch. · avg -0.1% · Bytecode: 🔴 6, 1 unch. · avg -7.5%
promises.js — Interp: 🟢 4, 8 unch. · avg +2.4% · Bytecode: 🔴 10, 2 unch. · avg -6.1%
regexp.js — Interp: 🔴 4, 7 unch. · avg -2.5% · Bytecode: 🔴 11 · avg -7.0%
strings.js — Interp: 🟢 4, 🔴 1, 14 unch. · avg +1.3% · Bytecode: 🔴 19 · avg -7.7%
tsv.js — Interp: 🔴 3, 6 unch. · avg -3.3% · Bytecode: 🔴 9 · avg -7.8%
typed-arrays.js — Interp: 🟢 5, 🔴 7, 10 unch. · avg -6.2% · Bytecode: 🟢 6, 🔴 12, 4 unch. · avg +6.7%
uint8array-encoding.js — Interp: 🟢 2, 🔴 1, 15 unch. · avg +1.1% · Bytecode: 🟢 7, 🔴 7, 4 unch. · avg +21.8%
weak-collections.js — Interp: 🟢 3, 🔴 10, 2 unch. · avg +5.8% · Bytecode: 🔴 14, 1 unch. · avg -24.3%
Deterministic profile diffDeterministic profile diff: no significant changes. Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
test262 Conformance
Areas closest to 100%
Per-test deltas (+1 / -0)Newly passing (1):
Steady-state failures are non-blocking; regressions vs the cached main baseline (lower total pass count, or any PASS → non-PASS transition) fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@source/units/Goccia.Values.Iterator.Lazy.pas`:
- Around line 269-307: When FIndex >= FLimit in
TGocciaLazyTakeIteratorValue.DoAdvanceNext and DoDirectNext you must perform
iterator close on FSourceIterator before marking done and returning; update both
methods to call the iterator close routine (e.g. FSourceIterator.Close or the
project’s IteratorClose helper) on FSourceIterator (safely, checking for
assigned if needed), then set FDone and return the same results as before so the
wrapped iterator is properly closed when the take limit is reached.
- Around line 505-510: The code currently calls FSourceIterator.Close directly
before calling ThrowTypeError when ResolveIterator(MappedValue) returns nil,
which can allow a Close exception to overwrite the intended
SErrorIteratorFlatMapMustReturnIterable TypeError; change both occurrences (the
block that sets FInnerIterator after ResolveIterator and the similar block
around lines 559-564) to use the existing CloseIteratorPreservingError helper:
capture the original type error, call
CloseIteratorPreservingError(FSourceIterator, originalError) inside a try/except
pattern used elsewhere in this method, and then re-raise the original type error
via ThrowTypeError(SErrorIteratorFlatMapMustReturnIterable,
SSuggestIteratorFlatMapCallable) so cleanup failures do not replace the flatMap
protocol error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 31d890f0-38e3-4ffb-9ed8-b3c38862ecec
📒 Files selected for processing (5)
docs/value-system.mdsource/units/Goccia.Values.Iterator.Concat.passource/units/Goccia.Values.Iterator.Lazy.passource/units/Goccia.Values.Iterator.Zip.passource/units/Goccia.Values.IteratorValue.pas
Summary
TGocciaIteratorHelperValueas a template-method base class betweenTGocciaIteratorValueand all 8 iterator helper classes (concat, map, filter, take, drop, flatMap, zip, zipKeyed).FExecutingand overridesAdvanceNext/DirectNextwith the re-entrancy guard + try/finally, delegating to abstractDoAdvanceNext/DoDirectNextthat subclasses implement. This mirrors the spec'sGeneratorResumestructure (ES2026 §27.1.2.1.1).docs/value-system.mdclass diagram to reflect the new hierarchy and add previously missing Concat/Zip/ZipKeyed entries.Closes #581
Testing