From 25c8c9279c586fef627444fa5e924b4684aef36f Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Tue, 29 Sep 2026 00:37:56 +0300 Subject: [PATCH] intern: past its store or its table, the fence's overflow - said once Past the 4 MB store lp_copystr falls back to the heap, and past the table (49152 texts, or 64 probes) lp_intern copies on every call: either way a program interning without bound would grow unseen. Both paths now call lp_intern_over, which reports through lp_cap_over once ("intern (4 MB of text, 49152 distinct texts) is full"), so warn says it and fail stops the run (exit 87) like any capacity past its promise. Checked with a compiler built from these sources (selfhost-build): 60000 distinct texts under R3D_ALLOC_FENCE=warn print the line once and every text comes back right; under fail the run exits 87. Co-Authored-By: Claude Opus 5.5 --- selfhost/backend/emit_fence_ir.ludic | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/selfhost/backend/emit_fence_ir.ludic b/selfhost/backend/emit_fence_ir.ludic index e4dfc5ee..983eecb5 100644 --- a/selfhost/backend/emit_fence_ir.ludic +++ b/selfhost/backend/emit_fence_ir.ludic @@ -1897,6 +1897,21 @@ function emit_fence_intern() -> void { # only past its 4 MB emith("@lp_istore = internal global [4194304 x i8] zeroinitializer\n") emith("@lp_ipos = internal global i64 0\n") + # past the store or the table a text is made on the heap every time: the fence's overflow, said once + emith("@lp_iover = internal global i8 0\n") + emith("@.lpi_over = private unnamed_addr constant [44 x i8] c\"intern (4 MB of text, 49152 distinct texts)\\00\"\n") + emith("define internal void @lp_intern_over() {\n") + emith("entry:\n") + emith(" %o = load i8, ptr @lp_iover\n") + emith(" %said = icmp ne i8 %o, 0\n") + emith(" br i1 %said, label %out, label %say\n") + emith("say:\n") + emith(" store i8 1, ptr @lp_iover\n") + emith(" call void @lp_cap_over(ptr @.lpi_over, i32 0, i32 0)\n") + emith(" br label %out\n") + emith("out:\n") + emith(" ret void\n") + emith("}\n") emith("define internal ptr @lp_copystr(ptr %s, i64 %n) {\n") emith("entry:\n") emith(" %n1 = add i64 %n, 1\n") @@ -1910,6 +1925,7 @@ function emit_fence_intern() -> void { emith(" call ptr @memcpy(ptr %b, ptr %s, i64 %n1)\n") emith(" ret ptr %b\n") emith("heap:\n") + emith(" call void @lp_intern_over()\n") emith(" %p = call ptr @lp_malloc(i64 %n1)\n") emith(" call ptr @memcpy(ptr %p, ptr %s, i64 %n1)\n") emith(" ret ptr %p\n") @@ -1964,6 +1980,7 @@ function emit_fence_intern() -> void { emith(" store i64 %cnt1, ptr @lp_icount\n") emith(" ret ptr %c2\n") emith("copy_only:\n") + emith(" call void @lp_intern_over()\n") emith(" %c3 = call ptr @lp_copystr(ptr %s, i64 %i)\n") emith(" ret ptr %c3\n") emith("}\n")