Merge branch 'lang/memory-fence' into lang/leaks2

# Conflicts:
#	selfhost/ludicc.seed.ll
#	selfhost/ludicc.win.seed.ll
#	tools/ludic-cli/test.ludic
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 15:46:11 +03:00
commit 84155274c4
32 changed files with 1425 additions and 111 deletions

View file

@ -0,0 +1,32 @@
# alloc_fence.ludic - the allocation fence (docs/plan 25.1) judges frames once play has settled.
# Everything a frame makes here is gone by the frame's end or goes on being reused: text only
# compared (freed once compared), records held from before play written in place. No frame
# keeps anything, so the run - which fails by default when one does - prints
# `frames 300 kept 0 bad 0`.
program AllocFence {
property Box { a: int = 0 }
function round(i: int, kept: []Box) -> int {
var bad = 0
if `{i}-{i * 2}` != string(i) + "-" + string(i * 2) { bad += 1 }
if `lake {i}` == "" { bad += 1 }
for k in 0 .. len(kept) { kept[k].a = i + k } # records reused: List.clear and new ones would keep the old
return bad
}
entry {
var kept = new []Box
for k in 0 .. 8 { push(kept, new Box) }
Mem.play()
Mem.settled()
var bad = 0
var frames = 0
for i in 0 .. 300 {
bad += round(i, kept)
Mem.frame()
frames += 1
}
let kept_now = Mem.kept() # read before the line below makes its text
print(`frames {frames} kept {kept_now} bad {Mem.bad_frames()}`)
}
}

View file

@ -0,0 +1,16 @@
# alloc_fence_auto.ludic - nothing here names the fence but the frame's mark: tracking starts at the
# first frame on its own, judging once R3D_ALLOC_WARM frames (600) in a row kept nothing, and frame
# 1500 keeping a record fails the run with exit 86. Prints nothing when it fails, `through` if not.
program AllocFenceAuto {
property Box { a: int = 0 }
entry {
var held = new []Box
for k in 0 .. 4 { push(held, new Box) }
for f in 0 .. 2000 {
if f < 300 { push(held, new Box { a: f }) } # loading: growing, not judged
if f == 1500 { push(held, new Box { a: f }) }
Mem.frame()
}
print("through")
}
}

View file

@ -0,0 +1,17 @@
# alloc_fence_leak.ludic - frame 50 keeps one record in a list that outlives it. The fence fails
# the run there (exit 86) and names this file's `new Box` line; under R3D_ALLOC_FENCE=count it
# runs on and prints `kept 80 bad 1` (the record and the list's growth, at malloc's own sizes, in one frame).
program AllocFenceLeak {
property Box { a: int = 0, b: int = 0 }
entry {
var held = new []Box
Mem.play()
Mem.settled()
for f in 0 .. 100 {
if f == 50 { push(held, new Box { a: f }) }
Mem.frame()
}
let kept_now = Mem.kept()
print(`kept {kept_now} bad {Mem.bad_frames()}`)
}
}