aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/design/destructors.md5
1 files changed, 5 insertions, 0 deletions
diff --git a/docs/design/destructors.md b/docs/design/destructors.md
index 8fb6498..1f085f3 100644
--- a/docs/design/destructors.md
+++ b/docs/design/destructors.md
@@ -165,5 +165,10 @@ untyped `rt.new(n)` blocks take a drop like any other value, so there is no sepa
- **fast paths stay correct for free.** `recycle_leaf` already sends a block to the general `recycle` unless `(f & F_LOW) == 1`, so a block with `F_HASDROP` set can't take the leaf fast path even if the compiler guessed wrong. the collector's sweep tests `(b[1] & 7) == 1` for an unmarked live block; it adds `F_HASDROP` (or a type default) as the test for the finalize list.
- **values without drop pay one test.** the runtime's free paths (unchecked `rt.free`, children found by the walk, the collector) add `if (hdr & F_HASDROP || (t = p[-1]) > 0 && t[DROP]) ...`, cheap next to `scan_ptr`. where the analyzer can see that a local never had a drop set and its type has no default, it emits today's free code, including `recycle_leaf`.
- **moving blocks.** the heap never moves a live block on its own: it is a buddy allocator in `rt.zc` (`balloc`/`bfree`), the collector marks and sweeps in place with no compaction, and `core.c` only offers word fill/copy primitives (syscall cases 18 and 19) with no relocation. the one place a payload moves is a reallocation: `dgrow` (behind `push`, `dresize`, byte arrays) allocates a bigger items block, copies, and frees the old one. any such resize must move the side-table entry and the `F_HASDROP` bit to the new block before freeing the old one, and that free must not run the drop. a future `rt.realloc` follows the same rule.
+- **clearing on free.** when a block is freed, at the same point where `release` clears the requested size n (bits 32..62 of `p[-4]`) on quarantine, and in `recycle`/`recycle_leaf`/`bfree` when the block goes back on a free list, its side-table entry is removed and `F_HASDROP` and `F_DROPPED` are cleared. this happens after the drop has run. so a reused address never inherits a drop from the block that was there before.
- **the collector.** one extra test per unmarked block in the sweep, a finalize list that grows like the mark stack (`reserve_mark`), and one extra mark root.
- **genome.** the parser adds `heap`, the three drop forms, and the type-default method. the analyzer adds set-once/set-early, the no-move-out rule, the never-bound hint, the reassignment free, and the actor send check. the runtime adds the drop test in three places, the side table, and the finalize list. a rough guess is several hundred words; zc-lines should measure the fixpoint once code exists.
+
+## 9. planned tests
+
+- **reused address inherits no drop.** set a drop on a block, free it (the drop fires once), then allocate a block of the same size, which under memdebug comes back at the same address. check the address matches, then free the new block and check that no drop fires for it and that its header has neither `F_HASDROP` nor `F_DROPPED` set.