Merge branch 'lang/memory-birth' into lang/foundations

This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 16:38:21 +03:00
commit 69d1db06a5
5 changed files with 57715 additions and 56121 deletions

View file

@ -25,6 +25,7 @@ var g_es_aok: int = 0 # inside a statement under @
var g_es_site_aok: []bool = new []bool # the site is (not reported by the region rule)
var g_es_site_grow: []bool = new []bool # the site is a push's growth (25.5's capacities, not the rule)
var g_es_done: bool = false
var g_es_consumed: []Node = new []Node # text used up where it is made (a + or == operand): freed at once
var g_es_ft: []int = new []int # flow edges
var g_es_ff: []int = new []int
var g_es_st: []int = new []int # store edges: value, target
@ -114,6 +115,10 @@ function es_val(e: Node) -> int {
if k == E_BIN {
es_val(e.a)
es_val(e.b)
if (e.s == "+") or (e.s == "==") or (e.s == "!=") {
if e.a != null and (e.a.kind == E_BIN or e.a.kind == E_CALL or e.a.kind == E_SLICE) { push(g_es_consumed, e.a) }
if e.b != null and (e.b.kind == E_BIN or e.b.kind == E_CALL or e.b.kind == E_SLICE) { push(g_es_consumed, e.b) }
}
if (e.s == "+") and fr_is_textish(e) { return es_site(e) }
return -1
}

View file

@ -227,4 +227,40 @@ function deps_keeps(f: pointer, seen: []bool) -> void {
}
deps_line(f, `frame_keeps {itoa(n)}`)
if g_arena_strict and n > 0 { exit(1) }
deps_births(f, seen)
}
function fr_consumed(n: Node) -> bool {
var i = 0
while i < len(g_es_consumed) { if g_es_consumed[i] == n { return true }; i += 1 }
return false
}
# 25.2's leak-at-birth: an allocation nothing keeps, made where the arena does not take it - outside
# frame code (a boot, a load), in a function spanning frames, or anywhere with the arena off - is
# made and dropped, never given back. `fbirth` lines, and the birth_leaks number
function deps_births(f: pointer, seen: []bool) -> void {
var n = 0
var s = 0
while s < len(g_es_site) {
let c = g_es_site_cls[s]
let fi = g_es_site_fn[s]
let site = g_es_site[s]
if c >= 0 and fi >= 0 and (g_es_flag[c] & ES_ESC) == 0 and not g_es_site_aok[s] and not g_es_site_grow[s] {
let d = g_es_fnode[fi]
let k = dr_index(d.s)
let inframe = k >= 0 and seen[k]
let scratch = g_arena and site.uns == ES_SCRATCH and inframe # before the first frame the arena is not running
if not scratch and d.file != null and not is_runtime_file(d.file) and not fr_alloc_ok(d.s) and not fr_consumed(site) {
var kind = fr_alloc_kind(site, false)
if kind == null { kind = "text" }
var where = "outside-a-frame"
if inframe { where = fr_chain(k) }
deps_line(f, `fbirth {kind} {d.file}:{itoa(site.line)} {d.s} {where}`)
n += 1
}
}
s += 1
}
deps_line(f, `birth_leaks {itoa(n)}`)
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,7 @@
# ludic deps --wreach N the N that can come to CHANGE the most states
# ludic deps --allocs every allocation a frame can come to (25.2), with its chain from a root
# ludic deps --keeps what frame code makes and keeps past its frame (25.3), and where
# ludic deps --births what is made, kept by nothing and not the arena's: never given back
#
# dependencies: module pairs (a, b) where a uses something of b, not counting b when b uses no
# other module (a leaf); largest_cycle: the largest set of modules that all reach each other, not
@ -54,6 +55,8 @@ var dp_fallocs: []pointer = new []pointer # 25.2: `falloc <kind> <file:li
var dp_frame_allocs: int = 0
var dp_fkeeps: []pointer = new []pointer # 25.3: `fkeep <kind> <file:line> <kept at> <chain>`
var dp_frame_keeps: int = 0
var dp_fbirths: []pointer = new []pointer # 25.2: `fbirth <kind> <file:line> <fn> <where>`
var dp_birth_leaks: int = 0
var dp_wreach_n: int = 0
var dp_wreach_at: pointer = ""
@ -94,6 +97,7 @@ function dp_load(path: pointer) -> bool {
dp_wreach_n = 0; dp_wreach_at = ""
dp_fallocs = new []pointer; dp_frame_allocs = 0
dp_fkeeps = new []pointer; dp_frame_keeps = 0
dp_fbirths = new []pointer; dp_birth_leaks = 0
dp_writes = new []pointer; dp_aliases = new []pointer; dp_wowner = new []pointer; dp_wname = new []pointer; dp_wfrom = new []pointer
let lines = split_lines(text)
for i in 0 .. len(lines) {
@ -119,6 +123,8 @@ function dp_load(path: pointer) -> bool {
if len(w) == 2 and w[0] == "frame_allocs" { dp_frame_allocs = s_to_int(w[1]) }
if len(w) >= 5 and w[0] == "fkeep" { push(dp_fkeeps, lines[i]) }
if len(w) == 2 and w[0] == "frame_keeps" { dp_frame_keeps = s_to_int(w[1]) }
if len(w) >= 4 and w[0] == "fbirth" { push(dp_fbirths, lines[i]) }
if len(w) == 2 and w[0] == "birth_leaks" { dp_birth_leaks = s_to_int(w[1]) }
if len(w) >= 5 and w[0] == "width" and w[4] == "0" and s_to_int(w[1]) > dp_wide_n {
dp_wide_n = s_to_int(w[1])
dp_wide_at = `{dp_fn_name(w[2])} ({w[3]})`
@ -318,7 +324,7 @@ var dp_vals: []int = null
var dp_cycle: []int = null
var dp_cycle_all: []int = null # the same with the layers' own edges counted
function dp_numbers() -> void {
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside", "widest_function", "widest_reach", "widest_write_reach", "frame_allocs", "frame_keeps"]
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside", "widest_function", "widest_reach", "widest_write_reach", "frame_allocs", "frame_keeps", "birth_leaks"]
var mods = 0
for k in 0 .. len(dp_mods) { if dp_own(k) { mods += 1 } }
var deps = 0
@ -340,7 +346,7 @@ function dp_numbers() -> void {
}
}
dp_reach_best()
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen), dp_wide_n, dp_reach_n, dp_wreach_n, dp_frame_allocs, dp_frame_keeps]
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen), dp_wide_n, dp_reach_n, dp_wreach_n, dp_frame_allocs, dp_frame_keeps, dp_birth_leaks]
}
# ---- the command --------------------------------------------------------------
@ -496,6 +502,7 @@ function cmd_deps() -> int {
else if a == "--writes" { mode = "writes" }
else if a == "--allocs" { mode = "allocs" }
else if a == "--keeps" { mode = "keeps" }
else if a == "--births" { mode = "births" }
else if a == "--uses" or a == "--check" or a == "--baseline" or a == "--widest" or a == "--reach" or a == "--wreach" {
if ai + 1 >= arg_count() { err(`ludic deps: {a} needs an argument\n`); return 2 }
mode = sslice(a, 2, slen(a))
@ -553,6 +560,16 @@ function cmd_deps() -> int {
print(`frame_keeps: {string(dp_frame_keeps)}`)
return 0
}
if mode == "births" { # 25.2: made, kept by nothing, and on the heap: never given back
for a in 0 .. len(dp_fbirths) {
let w = dp_words(dp_fbirths[a])
var where = ""
if len(w) >= 5 { where = w[4] }
print(`leak at birth: {w[2]} {w[1]} in {w[3]} {where}`)
}
print(`birth_leaks: {string(dp_birth_leaks)}`)
return 0
}
if mode == "widest" { dp_top(s_to_int(arg2), 0); return 0 }
if mode == "reach" { dp_top(s_to_int(arg2), 1); return 0 }
if mode == "wreach" { dp_top(s_to_int(arg2), 2); return 0 }