summaryrefslogtreecommitdiff
path: root/vere
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-06 23:06:50 +0700
committerpolwex <polwex@sortug.com>2025-10-06 23:06:50 +0700
commitfdab65f6dac4ba85ed4749f61970660d1132d453 (patch)
tree427123729c6d556f040bed6a0e461f6d0887c9bf /vere
parentbf4c5ff0fd28d94b7f22552a79e6fbe2561fe6cf (diff)
added mutable mugs
Diffstat (limited to 'vere')
-rw-r--r--vere/C_INSIGHTS.md41
-rw-r--r--vere/pkg/vere/ivory_boot_test.c18
2 files changed, 58 insertions, 1 deletions
diff --git a/vere/C_INSIGHTS.md b/vere/C_INSIGHTS.md
index 016ee83..26d1e3b 100644
--- a/vere/C_INSIGHTS.md
+++ b/vere/C_INSIGHTS.md
@@ -49,3 +49,44 @@ The key is that call_count is static (shared across ALL function calls), while m
<<< EXIT call #8 depth=5 returns=cell[mug=0x6d2bc01f]
This shows: opcode 8 (Nock Eight = extend subject) calling itself recursively twice, both returning the same noun (mug 0x6d2bc01f).
+
+
+# on vere mugs
+CLAUDE:
+
+how can C output the mugs *so fast* even for huge nouns like the huge pill. You say it's caching them but it still has to compute them at first
+
+● Excellent question! The answer is that C doesn't compute mugs on-demand - mugs are computed at allocation time and stored inline in the noun structure itself!
+
+ In C's u3 system, every noun (atom or cell) has a mug field built into its memory layout. When you allocate a noun with u3i_* or u3nc(), the mug is computed immediately and stored. So u3r_mug() is just a
+ memory read - instant!
+
+ Here's the key difference:
+
+ C (vere/pkg/noun/allocate.c):
+ // Nouns store mugs inline:
+ typedef struct {
+ c3_w mug_w; // ← Mug stored here!
+ c3_w len_w;
+ c3_w buf_w[];
+ } u3a_atom;
+
+ // u3r_mug() just reads the field:
+ c3_w u3r_mug(u3_noun veb) {
+ return u3a_to_pug(u3a_to_ptr(veb))->mug_w; // Just a memory read!
+ }
+
+ OCaml (our current approach):
+ type noun =
+ | Atom of Z.t (* No mug field! *)
+ | Cell of noun * noun (* No mug field! *)
+
+ (* We compute mugs on-demand with caching *)
+ let mug noun = (* ... expensive recursive computation ... *)
+
+ To match C's performance, we'd need to change OCaml's noun type to:
+ type noun =
+ | Atom of { z: Z.t; mutable mug: int32 option }
+ | Cell of { h: noun; t: noun; mutable mug: int32 option }
+
+ This would let us compute once and store inline like C. Should we implement this now, or continue with the current cache approach?
diff --git a/vere/pkg/vere/ivory_boot_test.c b/vere/pkg/vere/ivory_boot_test.c
index 0bd968b..cb531f9 100644
--- a/vere/pkg/vere/ivory_boot_test.c
+++ b/vere/pkg/vere/ivory_boot_test.c
@@ -21,14 +21,30 @@ _setup(void)
// Don't free ivory_jammed - it's managed by u3m_file
u3l_log("ivory_pil is_atom: %u", u3a_is_atom(pil));
+ u3l_log("ivory_pil mug: 0x%x", u3r_mug(pil));
- // Boot with ivory pill
+ // Extract the Arvo core (tail of [%ivory core])
+ u3_noun arvo_core = u3t(pil);
+ u3l_log("arvo_core mug: 0x%x", u3r_mug(arvo_core));
+
+ // Boot with ivory pill - this will call u3v_life() internally
u3l_log("Booting with ivory.pill from OCaml...");
if ( c3n == u3v_boot_lite(pil) ) {
printf("*** fail: ivory boot failed\n");
exit(1);
}
u3l_log("✓ Ivory boot completed!");
+
+ // Log kernel mugs after boot (u3A->roc is the kernel)
+ u3l_log("Kernel mug: 0x%x", u3r_mug(u3A->roc));
+
+ // Log mugs of key slots for verification
+ u3_noun slot2 = u3r_at(2, u3A->roc);
+ u3_noun slot3 = u3r_at(3, u3A->roc);
+ u3_noun slot23 = u3r_at(23, u3A->roc);
+ u3l_log("Kernel slot 2 (battery) mug: 0x%x", u3r_mug(slot2));
+ u3l_log("Kernel slot 3 (payload) mug: 0x%x", u3r_mug(slot3));
+ u3l_log("Kernel slot 23 (poke) mug: 0x%x", u3r_mug(slot23));
}
/* _test_lily(): test small noun parsing.