diff options
Diffstat (limited to 'vere')
-rw-r--r-- | vere/C_INSIGHTS.md | 41 | ||||
-rw-r--r-- | vere/pkg/vere/ivory_boot_test.c | 18 |
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. |