intern: texts copied into one store in the binary, not a malloc each; number texts interned too

Walk 9's fence named 256 frames of +16 B at gvk_tex_storage:244 and
m4_new:92, always under HudDay's and HudGuide's models. Neither site
makes 16 B: the blocks were intern's copies (lp_copystr), which never set
lp_site and so were charged to whatever allocated last. The HUD's clock
and the guide's distance are a new text every few seconds, and each first
one was a malloc kept for good.

lp_copystr now copies into @lp_istore, 4 MB in the binary (untouched pages
cost nothing), and falls back to the heap only past it; lp_free ignores a
pointer into the store, so a text freed after it was interned is no fault.
value_num_text - the text a screen shows for a number, dropped whenever
the number changed - is interned the same way and its string() given back.

Checked: a program interning 100000 texts gets every one back right, the
same text as the same pointer, a freed one harmless; the headless valley
compiles, with frame_allocs, frame_keeps and birth_leaks at 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 00:31:34 +03:00
parent 7b20f305ff
commit 47bb0e5d4d
2 changed files with 43 additions and 4 deletions

View file

@ -258,15 +258,19 @@ function value_num_set(v: Val, n: int) -> void {
}
# a number's text, kept on the Value until the number changes (a count shown in a HUD every frame wrote
# its text every frame; Ludic frees nothing)
# interned, and the text written for it given back: a number that changed dropped its last text
function value_num_text(v: Val) -> string {
if v.txt != null { return v.txt }
if v.tag == 1 { v.txt = string(v.num) }
var t: string = null
if v.tag == 1 { t = string(v.num) }
else if v.tag == 7 {
let f = float_from_bits(v.num)
if f == float(int(f)) { v.txt = string(int(f)) } else { v.txt = string(f) }
if f == float(int(f)) { t = string(int(f)) } else { t = string(f) }
}
else if v.tag == 2 { v.txt = json_fixed_str(v.num) }
if v.txt == null { return "" }
else if v.tag == 2 { t = json_fixed_str(v.num) }
if t == null { return "" }
v.txt = intern(t)
free(t)
return v.txt
}
# a list or an object emptied in place, its room kept - for one filled again every frame