Skip to content

fix(runtime): release tail-drop frames before the last child - #1438

Open
oxura wants to merge 3 commits into
bendlang:mainfrom
oxura:fix/1307-stable-wrapped-erasure
Open

oxura wants to merge 3 commits into
bendlang:mainfrom
oxura:fix/1307-stable-wrapped-erasure

Conversation

@oxura

@oxura oxura commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Fixes #1307. Repeatedly building and automatically erasing the reported 524,283-element affine list progressively slows down within one process; the structural-disposal control stays steady.

Change

When the iterative native drop reaches a node’s last nontrivial field, capture that child and the parent-frame link before returning the node to its existing size-class free chain. The last child no longer needs that frame. Earlier children, shared-reference accounting and trivial-field traversal remain unchanged. No sorting, new allocation, recursion, runtime flag, ABI, checker, gate or cap change. The drop remains O(n).

Actual verification

Linux x86_64, current main 60fa05d. The issue’s exact 24 × 524283 workload is retained, with only its old Chan.send Bool annotation adapted to today’s Result contract.

Fresh processes, before/after/after/before, then structural/after/before:

workload measured wall time samples
main, automatic disposal 2849 ms median 3
this branch, automatic disposal 623 ms median 3
main, structural disposal control 229 ms 1

Observed automatic-workload ratio: 4.57×. This is not a universal speedup claim. Across three 24-cycle patched runs, build times stay at 4–5 ms after each first allocation and disposal at 20–22 ms; main reaches 89–90 ms build and 130–134 ms disposal. The generic drop still costs more than the explicit traversal.

  • Fifteen established boxed-array, borrowed-element, wide-record, closure, shared-owner and fork regressions: all exact outputs pass at 1 and 4 native threads (30 actual consumer runs).
  • The full reported workload also completes under clang ASan + UBSan, exit 0 and no diagnostic. The custom arena’s freed cells are not ASan-poisoned, so this is not a proof against every arena use-after-free.
  • Repository gate: PASS 54/54.
  • Initial peak RSS: main 30752 KiB, patched 30856 KiB; no claim of a memory-usage improvement.

No new timing assertion: this performance regression is demonstrated by the actual issue workload and interleaved runs rather than a machine-sensitive permanent test. Existing behavior regressions are intentionally unchanged. No mini-cluster, Metal, CUDA, macOS or Windows execution claimed.

AI-assisted: omp / GPT-6.1 Sol, working alone without subagents.

Release-note policy

Removed my unreleased changelog entry following maintainer review. CHANGELOG.md is now unchanged from main; implementation and previously exercised verification are unchanged.

@nicolas-abril nicolas-abril self-assigned this Oct 9, 2026
nicolas-abril added a commit to oxura/bend that referenced this pull request Oct 9, 2026
…ld order

compile_book puts each constructor's spine in CID_T: the word of its
last field whose type holds its own datatype (255 when none). term_drop
swaps the spine into the last slot when it opens the node, so the last
child's early free of bendlang#1438 fires on the spine whatever the field
order: a list with its tail first, before a word or behind a List drops
in constant frames. The inner loop has one pop for the last and the
exhausted child, and skips the dead counter and cursor writes there.
tests/rfc/drop_spine covers the three shapes, owned and shared.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
oxura and others added 3 commits October 11, 2026 18:41
…ld order

compile_book puts each constructor's spine in CID_T: the word of its
last field whose type holds its own datatype (255 when none). term_drop
swaps the spine into the last slot when it opens the node, so the last
child's early free of bendlang#1438 fires on the spine whatever the field
order: a list with its tail first, before a word or behind a List drops
in constant frames. The inner loop has one pop for the last and the
exhausted child, and skips the dead counter and cursor writes there.
tests/rfc/drop_spine covers the three shapes, owned and shared.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@nicolas-abril
nicolas-abril force-pushed the fix/1307-stable-wrapped-erasure branch from d3bc283 to d757f53 Compare October 11, 2026 19:44
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.

Native automatic erasure progressively slows repeated wrapped-list allocation; explicit traversal stays fast

2 participants