From 0f0f56223076b42ab0263ba5c7ee1c1c5886006c Mon Sep 17 00:00:00 2001 From: Matthew LeVan Date: Fri, 1 Sep 2023 16:42:34 -0400 Subject: [PATCH 01/17] loom: compile-time pointer compression with migration --- pkg/noun/BUILD.bazel | 5 +- pkg/noun/allocate.c | 51 +++----- pkg/noun/allocate.h | 70 ++++------- pkg/noun/hashtable.c | 14 --- pkg/noun/hashtable.h | 4 +- pkg/noun/jets.c | 1 - pkg/noun/manage.c | 222 +++++----------------------------- pkg/noun/manage.h | 10 +- pkg/noun/options.h | 8 -- pkg/noun/v1/allocate.c | 261 ++++++++++++++++++++++++++++++++++++++++ pkg/noun/v1/allocate.h | 78 ++++++++++++ pkg/noun/v1/hashtable.c | 173 ++++++++++++++++++++++++++ pkg/noun/v1/hashtable.h | 51 ++++++++ pkg/noun/v1/jets.c | 101 ++++++++++++++++ pkg/noun/v1/jets.h | 33 +++++ pkg/noun/v1/manage.c | 20 +++ pkg/noun/v1/manage.h | 17 +++ pkg/noun/v1/nock.c | 70 +++++++++++ pkg/noun/v1/nock.h | 24 ++++ pkg/noun/v1/vortex.c | 17 +++ pkg/noun/v1/vortex.h | 21 ++++ pkg/noun/v2/allocate.c | 73 +++++++++++ pkg/noun/v2/allocate.h | 133 ++++++++++++++++++++ pkg/noun/v2/hashtable.c | 143 ++++++++++++++++++++++ pkg/noun/v2/hashtable.h | 41 +++++++ pkg/noun/v2/jets.c | 37 ++++++ pkg/noun/v2/jets.h | 22 ++++ pkg/noun/v2/manage.c | 177 +++++++++++++++++++++++++++ pkg/noun/v2/manage.h | 14 +++ pkg/noun/v2/nock.c | 28 +++++ pkg/noun/v2/nock.h | 18 +++ pkg/noun/v2/options.h | 14 +++ pkg/noun/v2/vortex.c | 25 ++++ pkg/noun/v2/vortex.h | 40 ++++++ pkg/noun/vortex.h | 3 - 35 files changed, 1711 insertions(+), 308 deletions(-) create mode 100644 pkg/noun/v1/allocate.c create mode 100644 pkg/noun/v1/allocate.h create mode 100644 pkg/noun/v1/hashtable.c create mode 100644 pkg/noun/v1/hashtable.h create mode 100644 pkg/noun/v1/jets.c create mode 100644 pkg/noun/v1/jets.h create mode 100644 pkg/noun/v1/manage.c create mode 100644 pkg/noun/v1/manage.h create mode 100644 pkg/noun/v1/nock.c create mode 100644 pkg/noun/v1/nock.h create mode 100644 pkg/noun/v1/vortex.c create mode 100644 pkg/noun/v1/vortex.h create mode 100644 pkg/noun/v2/allocate.c create mode 100644 pkg/noun/v2/allocate.h create mode 100644 pkg/noun/v2/hashtable.c create mode 100644 pkg/noun/v2/hashtable.h create mode 100644 pkg/noun/v2/jets.c create mode 100644 pkg/noun/v2/jets.h create mode 100644 pkg/noun/v2/manage.c create mode 100644 pkg/noun/v2/manage.h create mode 100644 pkg/noun/v2/nock.c create mode 100644 pkg/noun/v2/nock.h create mode 100644 pkg/noun/v2/options.h create mode 100644 pkg/noun/v2/vortex.c create mode 100644 pkg/noun/v2/vortex.h diff --git a/pkg/noun/BUILD.bazel b/pkg/noun/BUILD.bazel index 964e4bf60f..1949a7d878 100644 --- a/pkg/noun/BUILD.bazel +++ b/pkg/noun/BUILD.bazel @@ -8,9 +8,8 @@ vere_library( name = "noun", srcs = glob( [ - "*.c", - "*.h", - "jets/tree.c", + "**/*.c", + "**/*.h", "jets/*.h", "jets/**/*.c", ], diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index ace4473a4a..44f7175879 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -16,15 +16,6 @@ u3_road* u3a_Road; c3_w u3_Code; #endif -// declarations of inline functions -// - -void u3a_config_loom(c3_w ver_w); -void *u3a_into(c3_w x); -c3_w u3a_outa(void *p); -c3_w u3a_to_off(c3_w som); -void *u3a_to_ptr(c3_w som); -c3_w *u3a_to_wtr(c3_w som); c3_w u3a_to_pug(c3_w off); c3_w u3a_to_pom(c3_w off); @@ -67,12 +58,12 @@ _box_count(c3_ws siz_ws) { } _box_count, (others?) should have perhaps its own header and certainly its own prefix. having to remind yourself that _box_count doesn't actually do anything unless U3_CPU_DEBUG is defined is annoying. */ -#define _box_vaal(box_u) \ - do { \ - c3_dessert(((uintptr_t)u3a_boxto(box_u) \ - & u3C.balign_d-1) == 0); \ - c3_dessert((((u3a_box*)(box_u))->siz_w \ - & u3C.walign_w-1) == 0); \ +#define _box_vaal(box_u) \ + do { \ + c3_dessert(((uintptr_t)u3a_boxto(box_u) \ + & u3a_balign-1) == 0); \ + c3_dessert((((u3a_box*)(box_u))->siz_w \ + & u3a_walign-1) == 0); \ } while(0) /* _box_slot(): select the right free list to search for a block. @@ -302,7 +293,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w off_w, c3_w use_w) all_p += c3_wiseof(u3a_box) + off_w; pad_w = c3_align(all_p, ald_w, C3_ALGHI) - all_p; - siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); + siz_w = c3_align(len_w + pad_w, u3a_walign, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -316,7 +307,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w off_w, c3_w use_w) all_p += c3_wiseof(u3a_box) + off_w; pad_w = all_p - c3_align(all_p, ald_w, C3_ALGLO); - siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); + siz_w = c3_align(len_w + pad_w, u3a_walign, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -508,7 +499,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w off_w) box_p = all_p = *pfr_p; all_p += c3_wiseof(u3a_box) + off_w; c3_w pad_w = c3_align(all_p, ald_w, C3_ALGHI) - all_p; - c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, C3_ALGHI); + c3_w des_w = c3_align(siz_w + pad_w, u3a_walign, C3_ALGHI); /* calls maximally requesting DWORD alignment of returned pointer shouldn't require padding. */ @@ -711,17 +702,17 @@ u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w) c3_w* box_w = (void*)u3a_botox(nov_w); c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */ - u3C.balign_d, + u3a_balign, C3_ALGHI); c3_w asz_w = (end_w - box_w); /* total size in words of new allocation */ if (box_u->siz_w <= asz_w) return; c3_w bsz_w = box_u->siz_w - asz_w; /* size diff in words between old and new */ - c3_dessert(asz_w && ((asz_w & u3C.walign_w-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */ + c3_dessert(asz_w && ((asz_w & u3a_walign-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */ c3_dessert(end_w < (box_w + box_u->siz_w)); /* desired alloc end must not exceed existing boundaries */ - c3_dessert(((uintptr_t)end_w & u3C.balign_d-1) == 0); /* address of box getting freed must be DWORD aligned */ - c3_dessert((bsz_w & u3C.walign_w-1) == 0); /* size of box getting freed must be DWORD multiple */ + c3_dessert(((uintptr_t)end_w & u3a_balign-1) == 0); /* address of box getting freed must be DWORD aligned */ + c3_dessert((bsz_w & u3a_walign-1) == 0); /* size of box getting freed must be DWORD multiple */ _box_attach(_box_make(end_w, bsz_w, 0)); /* free the unneeded space */ @@ -1747,24 +1738,12 @@ u3a_rewritten_noun(u3_noun som) return som; } u3_post som_p = u3a_rewritten(u3a_to_off(som)); - - /* If this is being called during a migration, one-bit pointer compression - needs to be temporarily enabled so the rewritten reference is compressed */ - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 1; - if ( c3y == u3a_is_pug(som) ) { - som_p = u3a_to_pug(som_p); + return u3a_to_pug(som_p); } else { - som_p = u3a_to_pom(som_p); + return u3a_to_pom(som_p); } - - /* likewise, pointer compression is disabled until migration is complete */ - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 0; - - return som_p; } /* u3a_mark_mptr(): mark a malloc-allocated ptr for gc. diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 7355954abd..be50793002 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -3,7 +3,6 @@ #include "error.h" #include "manage.h" -#include "options.h" /** Constants. **/ @@ -11,14 +10,21 @@ */ # define u3a_bits U3_OS_LoomBits /* 30 */ - /* u3a_vits_max: number of virtual bits in a reference gained via pointer - compression + /* u3a_vits: number of virtual bits in a noun reference gained via shifting */ -# define u3a_vits_max 1 +# define u3a_vits 1 + + /* u3a_walign: references into the loom are guaranteed to be word-aligned to: + */ +# define u3a_walign (1 << u3a_vits) + + /* u3a_balign: u3a_walign in bytes + */ +# define u3a_balign (sizeof(c3_w)*u3a_walign) /* u3a_bits_max: max loom bex */ -# define u3a_bits_max (8 * sizeof(c3_w) + u3a_vits_max) +# define u3a_bits_max (8 * sizeof(c3_w) + u3a_vits) /* u3a_page: number of bits in word-addressed page. 12 == 16K page */ @@ -26,11 +32,11 @@ /* u3a_pages: maximum number of pages in memory. */ -# define u3a_pages (1ULL << (u3a_bits + u3a_vits_max - u3a_page) ) +# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) ) /* u3a_words: maximum number of words in memory. */ -# define u3a_words ( 1ULL << (u3a_bits + u3a_vits_max )) +# define u3a_words ( 1ULL << (u3a_bits + u3a_vits)) /* u3a_bytes: maximum number of bytes in memory. */ @@ -355,7 +361,7 @@ # define _rod_vaal(rod_u) \ do { \ c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \ - & u3C.walign_w-1) == 0); \ + & u3a_walign-1) == 0); \ } while(0) @@ -374,68 +380,40 @@ # define u3_Loom ((c3_w *)(void *)U3_OS_LoomBase) - /** inline functions. + /** Inline functions. **/ - /* u3a_config_loom(): configure loom information by u3v version - */ - inline void u3a_config_loom(c3_w ver_w) { - switch (ver_w) { - case U3V_VER1: - u3C.vits_w = 0; - break; - case U3V_VER2: - u3C.vits_w = 1; - break; - default: - u3_assert(0); - } - - u3C.walign_w = 1 << u3C.vits_w; - u3C.balign_d = sizeof(c3_w) * u3C.walign_w; -} - /* u3a_into(): convert loom offset [x] into generic pointer. */ - inline void *u3a_into(c3_w x) { - return u3_Loom + x; - } +# define u3a_into(x) ((void *)(u3_Loom + (x))) /* u3a_outa(): convert pointer [p] into word offset into loom. */ - inline c3_w u3a_outa(void *p) { - return ((c3_w *)p) - u3_Loom; - } +# define u3a_outa(p) ((c3_w *)(void *)(p) - u3_Loom) /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. */ - inline c3_w u3a_to_off(c3_w som) { - return (som & 0x3fffffff) << u3C.vits_w; - } +# define u3a_to_off(som) (((som) & 0x3fffffff) << u3a_vits) /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. */ - inline void *u3a_to_ptr(c3_w som) { - return u3a_into(u3a_to_off(som)); - } +# define u3a_to_ptr(som) (u3a_into(u3a_to_off(som))) /* u3a_to_wtr(): convert noun [som] into word pointer into loom. */ - inline c3_w *u3a_to_wtr(c3_w som) { - return (c3_w *)u3a_to_ptr(som); - } +# define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som)) /* u3a_to_pug(): set bit 31 of [off]. */ inline c3_w u3a_to_pug(c3_w off) { - c3_dessert((off & u3C.walign_w-1) == 0); - return (off >> u3C.vits_w) | 0x80000000; + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0x80000000; } /* u3a_to_pom(): set bits 30 and 31 of [off]. */ inline c3_w u3a_to_pom(c3_w off) { - c3_dessert((off & u3C.walign_w-1) == 0); - return (off >> u3C.vits_w) | 0xc0000000; + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0xc0000000; } /** road stack. diff --git a/pkg/noun/hashtable.c b/pkg/noun/hashtable.c index 5915de5944..bc5d751b8c 100644 --- a/pkg/noun/hashtable.c +++ b/pkg/noun/hashtable.c @@ -1017,15 +1017,8 @@ _ch_rewrite_node(u3h_node* han_u, c3_w lef_w) else { void* hav_v = u3h_slot_to_node(sot_w); u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,hav_v))); - - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 1; - han_u->sot_w[i_w] = u3h_node_to_slot(nod_u); - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 0; - if ( 0 == lef_w ) { _ch_rewrite_buck(hav_v); } else { @@ -1057,15 +1050,8 @@ u3h_rewrite(u3p(u3h_root) har_p) else if ( _(u3h_slot_is_node(sot_w)) ) { u3h_node* han_u = u3h_slot_to_node(sot_w); u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,han_u))); - - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 1; - har_u->sot_w[i_w] = u3h_node_to_slot(nod_u); - if (u3C.migration_state == MIG_REWRITE_COMPRESSED) - u3C.vits_w = 0; - _ch_rewrite_node(han_u, 25); } } diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index be1d3f93be..a117f50011 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -79,8 +79,8 @@ # define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) # define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) # define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) -# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3C.vits_w)) -# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3C.vits_w) | 0x40000000) +# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits)) +# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000) # define u3h_noun_be_warm(sot) ((sot) | 0x40000000) # define u3h_noun_be_cold(sot) ((sot) & ~0x40000000) # define u3h_slot_to_noun(sot) (0x40000000 | (sot)) diff --git a/pkg/noun/jets.c b/pkg/noun/jets.c index 00edefec40..dcabcdb559 100644 --- a/pkg/noun/jets.c +++ b/pkg/noun/jets.c @@ -2377,7 +2377,6 @@ u3j_reclaim(void) // if ( &(u3H->rod_u) == u3R ) { // u3j_ream(); // } - // clear the jet hank cache // u3h_walk(u3R->jed.han_p, _cj_free_hank); diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 5ff7d7b129..60787bde34 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -488,7 +488,7 @@ _pave_parts(void) static u3_road* _pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) { - c3_dessert(((uintptr_t)rut_w & u3C.balign_d-1) == 0); + c3_dessert(((uintptr_t)rut_w & u3a_balign-1) == 0); u3_road* rod_u = (void*) mat_w; // enable in case of corruption @@ -529,8 +529,8 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w, c3_o kid_o) // 00~~~|R|---|H|######|C|+++|M|~~~FF // ^--u3R which _pave_road returns (u3H for home road) // - c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, C3_ALGLO); - c3_w* rut_w = c3_align(mem_w, u3C.balign_d, C3_ALGHI); + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, C3_ALGLO); + c3_w* rut_w = c3_align(mem_w, u3a_balign, C3_ALGHI); c3_w* cap_w = mat_w; if ( c3y == kid_o ) { @@ -560,8 +560,8 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) // 00~~~|M|+++|C|######|H|---|R|~~~FFF // ^---u3R which _pave_road returns // - c3_w* mat_w = c3_align(mem_w, u3C.balign_d, C3_ALGHI); - c3_w* rut_w = c3_align(mem_w + len_w, u3C.balign_d, C3_ALGLO); + c3_w* mat_w = c3_align(mem_w, u3a_balign, C3_ALGHI); + c3_w* rut_w = c3_align(mem_w + len_w, u3a_balign, C3_ALGLO); c3_w* cap_w = mat_w + siz_w; u3e_ward(u3of(c3_w, cap_w) - 1, u3of(c3_w, rut_w)); @@ -574,12 +574,9 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) static void _pave_home(void) { - /* a pristine home road will always have compressed references */ - u3a_config_loom(U3V_VERLAT); - - c3_w* mem_w = u3_Loom + u3C.walign_w; + c3_w* mem_w = u3_Loom + u3a_walign; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - u3C.walign_w; + c3_w len_w = u3C.wor_i - u3a_walign; u3H = (void *)_pave_north(mem_w, siz_w, len_w, c3n); u3H->ver_w = U3V_VERLAT; @@ -597,14 +594,24 @@ static void _find_home(void) { c3_w ver_w = *(u3_Loom + u3C.wor_i - 1); - u3a_config_loom(ver_w); + + switch ( ver_w ) { + case 1: u3m_v2_migrate(); + case 2: break; + default: { + fprintf(stderr, "loom: checkpoint version mismatch: " + "have %u, need %u\r\n", + ver_w, U3V_VERLAT); + abort(); + } + } // NB: the home road is always north // - c3_w* mem_w = u3_Loom + u3C.walign_w; + c3_w* mem_w = u3_Loom + u3a_walign; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - u3C.walign_w; - c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, C3_ALGLO); + c3_w len_w = u3C.wor_i - u3a_walign; + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, C3_ALGLO); u3H = (void *)mat_w; u3R = &u3H->rod_u; @@ -642,18 +649,6 @@ _find_home(void) /* As a further guard against any sneaky loom corruption */ u3a_loom_sane(); - if (U3V_VERLAT > ver_w) { - u3m_migrate(U3V_VERLAT); - u3a_config_loom(U3V_VERLAT); - } - else if ( U3V_VERLAT < ver_w ) { - fprintf(stderr, "loom: checkpoint version mismatch: " - "have %u, need %u\r\n", - ver_w, - U3V_VERLAT); - abort(); - } - _rod_vaal(u3R); } @@ -748,13 +743,6 @@ u3m_dump(void) c3_i u3m_bail(u3_noun how) { - if ( &(u3H->rod_u) == u3R ) { - // XX set exit code - // - fprintf(stderr, "home: bailing out\r\n"); - abort(); - } - // printf some metadata // switch ( how ) { @@ -779,6 +767,13 @@ u3m_bail(u3_noun how) } } + if ( &(u3H->rod_u) == u3R ) { + // XX set exit code + // + fprintf(stderr, "home: bailing out\r\n"); + abort(); + } + // intercept fatal errors // switch ( how ) { @@ -865,7 +860,7 @@ u3m_leap(c3_w pad_w) } pad_w += c3_wiseof(u3a_road); len_w = u3a_open(u3R) - pad_w; - c3_align(len_w, u3C.walign_w, C3_ALGHI); + c3_align(len_w, u3a_walign, C3_ALGHI); } /* Allocate a region on the cap. @@ -2174,7 +2169,7 @@ u3m_boot_lite(size_t len_i) return 0; } -/* u3m_reclaim: clear persistent caches to reclaim memory +/* u3m_reclaim: clear persistent caches to reclaim memory. */ void u3m_reclaim(void) @@ -2190,7 +2185,7 @@ u3m_reclaim(void) static void _cm_pack_rewrite(void) { - // XX fix u3a_rewrit* to support south roads + // XX fix u3a_rewrite* to support south roads // u3_assert( &(u3H->rod_u) == u3R ); @@ -2228,158 +2223,3 @@ u3m_pack(void) return (u3a_open(u3R) - pre_w); } - -static void -_migrate_reclaim() -{ - fprintf(stderr, "loom: migration reclaim\r\n"); - u3m_reclaim(); -} - -static void -_migrate_seek(const u3a_road *rod_u) -{ - /* - very much like u3a_pack_seek with the following changes: - - there is no need to account for free space as |pack is performed before - the migration - - odd sized boxes will be padded by one word to achieve an even size - - rut will be moved from one word ahead of u3_Loom to two words ahead - */ - c3_w * box_w = u3a_into(rod_u->rut_p); - c3_w * end_w = u3a_into(rod_u->hat_p); - u3_post new_p = (rod_u->rut_p + 1 + c3_wiseof(u3a_box)); - u3a_box * box_u = (void *)box_w; - - fprintf(stderr, "loom: migration seek\r\n"); - - for (; box_w < end_w - ; box_w += box_u->siz_w - , box_u = (void*)box_w) - { - if (!box_u->use_w) - continue; - u3_assert(box_u->siz_w); - u3_assert(box_u->use_w); - box_w[box_u->siz_w - 1] = new_p; - new_p = c3_align(new_p + box_u->siz_w, 2, C3_ALGHI); - } -} - -static void -_migrate_rewrite() -{ - fprintf(stderr, "loom: migration rewrite\r\n"); - - /* So that rewritten pointers are compressed, this flag is set */ - u3C.migration_state = MIG_REWRITE_COMPRESSED; - _cm_pack_rewrite(); - u3C.migration_state = MIG_NONE; -} - -static void -_migrate_move(u3a_road *rod_u) -{ - fprintf(stderr, "loom: migration move\r\n"); - - c3_z hiz_z = u3a_heap(rod_u) * sizeof(c3_w); - - /* calculate required shift distance to prevent write head overlapping read head */ - c3_w off_w = 1; /* at least 1 word because u3R->rut_p migrates from 1 to 2 */ - for (u3a_box *box_u = u3a_into(rod_u->rut_p) - ; (void *)box_u < u3a_into(rod_u->hat_p) - ; box_u = (void *)((c3_w *)box_u + box_u->siz_w)) - off_w += box_u->siz_w & 1; /* odd-sized boxes are padded by one word */ - - /* shift */ - memmove(u3a_into(u3H->rod_u.rut_p + off_w), - u3a_into(u3H->rod_u.rut_p), - hiz_z); - /* manually zero the former rut */ - *(c3_w *)u3a_into(rod_u->rut_p) = 0; - - /* relocate boxes to DWORD-aligned addresses stored in trailing size word */ - c3_w *box_w = u3a_into(rod_u->rut_p + off_w); - c3_w *end_w = u3a_into(rod_u->hat_p + off_w); - u3a_box *old_u = (void *)box_w; - c3_w siz_w = old_u->siz_w; - u3p(c3_w) new_p = rod_u->rut_p + 1 + c3_wiseof(u3a_box); - c3_w *new_w; - - for (; box_w < end_w - ; box_w += siz_w - , old_u = (void *)box_w - , siz_w = old_u->siz_w) { - old_u->use_w &= 0x7fffffff; - - if (!old_u->use_w) - continue; - - new_w = (void *)u3a_botox(u3a_into(new_p)); - u3_assert(box_w[siz_w - 1] == new_p); - u3_assert(new_w <= box_w); - - c3_w i_w; - for (i_w = 0; i_w < siz_w - 1; i_w++) - new_w[i_w] = box_w[i_w]; - - if (siz_w & 1) { - new_w[i_w++] = 0; /* pad odd sized boxes */ - new_w[i_w++] = siz_w + 1; /* restore trailing size word */ - new_w[0] = siz_w + 1; /* and the leading size word */ - } - else { - new_w[i_w++] = siz_w; - } - - new_p += i_w; - } - - /* restore proper heap state */ - rod_u->rut_p = 2; - rod_u->hat_p = new_p - c3_wiseof(u3a_box); - - /* like |pack, clear the free lists and cell allocator */ - for (c3_w i_w = 0; i_w < u3a_fbox_no; i_w++) - u3R->all.fre_p[i_w] = 0; - - u3R->all.fre_w = 0; - u3R->all.cel_p = 0; -} - - -/* u3m_migrate: perform loom migration if necessary. - ver_w - target version -*/ -void -u3m_migrate(u3v_version ver_w) -{ - if (u3H->ver_w == ver_w) - return; - - /* 1 -> 2 is all that is currently supported */ - c3_dessert(u3H->ver_w == U3V_VER1 && - ver_w == U3V_VER2); - - /* only home road migration is supported */ - c3_dessert((uintptr_t)u3H == (uintptr_t)u3R); - - fprintf(stderr, "loom: migration running. This may take several minutes to perform.\r\n"); - fprintf(stderr, "loom: have version: %"PRIc3_w" migrating to version: %"PRIc3_w"\r\n", - u3H->ver_w, ver_w); - - /* packing first simplifies migration logic and minimizes required buffer space */ - u3m_pack(); - - /* perform the migration in a pattern similar to |pack */ - _migrate_reclaim(); - _migrate_seek(&u3H->rod_u); - _migrate_rewrite(); - _migrate_move(&u3H->rod_u); - - /* finally update the version and commit to disk */ - u3H->ver_w = ver_w; - /* extra assurance we haven't corrupted the loom before writing to disk */ - u3a_loom_sane(); - u3m_save(); -} diff --git a/pkg/noun/manage.h b/pkg/noun/manage.h index 297585c486..bc8ff97390 100644 --- a/pkg/noun/manage.h +++ b/pkg/noun/manage.h @@ -3,6 +3,9 @@ #ifndef U3_MANAGE_H #define U3_MANAGE_H +#include "v1/manage.h" +#include "v2/manage.h" + #include "c3.h" #include "types.h" #include "version.h" @@ -180,7 +183,7 @@ void u3m_wall(u3_noun wol); - /* u3m_reclaim: clear persistent caches to reclaim memory + /* u3m_reclaim: clear persistent caches to reclaim memory. */ void u3m_reclaim(void); @@ -190,10 +193,9 @@ c3_w u3m_pack(void); - /* u3m_migrate: perform loom migration if necessary. - ver_w - target version + /* u3m_migrate: perform loom migrations. */ void - u3m_migrate(u3v_version ver_w); + u3m_migrate(); #endif /* ifndef U3_MANAGE_H */ diff --git a/pkg/noun/options.h b/pkg/noun/options.h index 1bd65320fc..52732d2655 100644 --- a/pkg/noun/options.h +++ b/pkg/noun/options.h @@ -15,14 +15,6 @@ c3_c* dir_c; // execution directory (pier) c3_c* eph_c; // ephemeral file c3_w wag_w; // flags (both ways) - c3_w vits_w; // number of virtual bits in reference - c3_w walign_w; // word alignment - c3_d balign_d; // byte alignment - enum { - MIG_NONE, - MIG_REWRITE_COMPRESSED, - } migration_state; - size_t wor_i; // loom word-length (<= u3a_words) c3_w tos_w; // loom toss skip-length void (*stderr_log_f)(c3_c*); // errors from c code diff --git a/pkg/noun/v1/allocate.c b/pkg/noun/v1/allocate.c new file mode 100644 index 0000000000..226aa33f00 --- /dev/null +++ b/pkg/noun/v1/allocate.c @@ -0,0 +1,261 @@ +/// @file + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" + +#include "pkg/noun/v1/hashtable.h" + +/* _box_v1_slot(): select the right free list to search for a block. +*/ +static c3_w +_box_v1_slot(c3_w siz_w) +{ + if ( siz_w < u3a_v1_minimum ) { + return 0; + } + else { + c3_w i_w = 1; + + while ( 1 ) { + if ( i_w == u3a_v1_fbox_no ) { + return (i_w - 1); + } + if ( siz_w < 16 ) { + return i_w; + } + siz_w = (siz_w + 1) >> 1; + i_w += 1; + } + } +} + +/* _box_v1_make(): construct a box. +*/ +static u3a_v1_box* +_box_v1_make(void* box_v, c3_w siz_w, c3_w use_w) +{ + u3a_v1_box* box_u = box_v; + c3_w* box_w = box_v; + + u3_assert(siz_w >= u3a_v1_minimum); + + box_w[0] = siz_w; + box_w[siz_w - 1] = siz_w; + box_u->use_w = use_w; + +# ifdef U3_MEMORY_DEBUG + box_u->cod_w = u3_Code; + box_u->eus_w = 0; +# endif + + return box_u; +} + +/* _box_v1_attach(): attach a box to the free list. +*/ +static void +_box_v1_attach(u3a_v1_box* box_u) +{ + u3_assert(box_u->siz_w >= (1 + c3_wiseof(u3a_v1_fbox))); + u3_assert(0 != u3of(u3a_v1_fbox, box_u)); + +#if 0 + // For debugging, fill the box with beef. + { + c3_w* box_w = (void *)box_u; + c3_w i_w; + + for ( i_w = c3_wiseof(u3a_v1_box); (i_w + 1) < box_u->siz_w; i_w++ ) { + box_w[i_w] = 0xdeadbeef; + } + } +#endif + + { + c3_w sel_w = _box_v1_slot(box_u->siz_w); + u3p(u3a_v1_fbox) fre_p = u3of(u3a_v1_fbox, box_u); + u3p(u3a_v1_fbox)* pfr_p = &u3R_v1->all.fre_p[sel_w]; + u3p(u3a_v1_fbox) nex_p = *pfr_p; + + u3to(u3a_v1_fbox, fre_p)->pre_p = 0; + u3to(u3a_v1_fbox, fre_p)->nex_p = nex_p; + if ( u3to(u3a_v1_fbox, fre_p)->nex_p ) { + u3to(u3a_v1_fbox, u3to(u3a_v1_fbox, fre_p)->nex_p)->pre_p = fre_p; + } + (*pfr_p) = fre_p; + } +} + +/* _box_v1_detach(): detach a box from the free list. +*/ +static void +_box_v1_detach(u3a_v1_box* box_u) +{ + u3p(u3a_v1_fbox) fre_p = u3of(u3a_v1_fbox, box_u); + u3p(u3a_v1_fbox) pre_p = u3to(u3a_v1_fbox, fre_p)->pre_p; + u3p(u3a_v1_fbox) nex_p = u3to(u3a_v1_fbox, fre_p)->nex_p; + + + if ( nex_p ) { + if ( u3to(u3a_v1_fbox, nex_p)->pre_p != fre_p ) { + u3_assert(!"loom: corrupt"); + } + u3to(u3a_v1_fbox, nex_p)->pre_p = pre_p; + } + if ( pre_p ) { + if( u3to(u3a_v1_fbox, pre_p)->nex_p != fre_p ) { + u3_assert(!"loom: corrupt"); + } + u3to(u3a_v1_fbox, pre_p)->nex_p = nex_p; + } + else { + c3_w sel_w = _box_v1_slot(box_u->siz_w); + + if ( fre_p != u3R_v1->all.fre_p[sel_w] ) { + u3_assert(!"loom: corrupt"); + } + u3R_v1->all.fre_p[sel_w] = nex_p; + } +} + +/* _box_v1_free(): free and coalesce. +*/ +static void +_box_v1_free(u3a_v1_box* box_u) +{ + c3_w* box_w = (c3_w *)(void *)box_u; + + u3_assert(box_u->use_w != 0); + box_u->use_w -= 1; + if ( 0 != box_u->use_w ) { + return; + } + +#if 0 + /* Clear the contents of the block, for debugging. + */ + { + c3_w i_w; + + for ( i_w = c3_wiseof(u3a_v1_box); (i_w + 1) < box_u->siz_w; i_w++ ) { + box_w[i_w] = 0xdeadbeef; + } + } +#endif + + if ( c3y == u3a_v1_is_north(u3R_v1) ) { + /* Try to coalesce with the block below. + */ + if ( box_w != u3a_v1_into(u3R_v1->rut_p) ) { + c3_w laz_w = *(box_w - 1); + u3a_v1_box* pox_u = (u3a_v1_box*)(void *)(box_w - laz_w); + + if ( 0 == pox_u->use_w ) { + _box_v1_detach(pox_u); + _box_v1_make(pox_u, (laz_w + box_u->siz_w), 0); + + box_u = pox_u; + box_w = (c3_w*)(void *)pox_u; + } + } + + /* Try to coalesce with the block above, or the wilderness. + */ + if ( (box_w + box_u->siz_w) == u3a_v1_into(u3R_v1->hat_p) ) { + u3R_v1->hat_p = u3a_v1_outa(box_w); + } + else { + u3a_v1_box* nox_u = (u3a_v1_box*)(void *)(box_w + box_u->siz_w); + + if ( 0 == nox_u->use_w ) { + _box_v1_detach(nox_u); + _box_v1_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); + } + _box_v1_attach(box_u); + } + } +} + +/* u3a_v1_wfree(): free storage. +*/ +void +u3a_v1_wfree(void* tox_v) +{ + _box_v1_free(u3a_v1_botox(tox_v)); +} + +/* u3a_v1_free(): free for aligned malloc. +*/ +void +u3a_v1_free(void* tox_v) +{ + if (NULL == tox_v) + return; + + c3_w* tox_w = tox_v; + c3_w pad_w = tox_w[-1]; + c3_w* org_w = tox_w - (pad_w + 1); + + // u3l_log("free %p %p", org_w, tox_w); + u3a_v1_wfree(org_w); +} + +/* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3a_v1_reclaim(void) +{ + // clear the memoization cache + // + u3h_v1_free_nodes(u3R_v1->cax.har_p); +} + +/* _me_lose_north(): lose on a north road. +*/ +static void +_me_lose_north(u3_noun dog) +{ +top: + { + c3_w* dog_w = u3a_v1_to_ptr(dog); + u3a_v1_box* box_u = u3a_v1_botox(dog_w); + + if ( box_u->use_w > 1 ) { + box_u->use_w -= 1; + } + else { + if ( 0 == box_u->use_w ) { + u3m_v1_bail(c3__foul); + } + else { + if ( _(u3a_v1_is_pom(dog)) ) { + u3a_v1_cell* dog_u = (void *)dog_w; + u3_noun h_dog = dog_u->hed; + u3_noun t_dog = dog_u->tel; + + if ( !_(u3a_v1_is_cat(h_dog)) ) { + _me_lose_north(h_dog); + } + u3a_v1_wfree(dog_w); + if ( !_(u3a_v1_is_cat(t_dog)) ) { + dog = t_dog; + goto top; + } + } + else { + u3a_v1_wfree(dog_w); + } + } + } + } +} + +/* u3a_v1_lose(): lose a reference count. +*/ +void +u3a_v1_lose(u3_noun som) +{ + if ( !_(u3a_v1_is_cat(som)) ) { + _me_lose_north(som); + } +} diff --git a/pkg/noun/v1/allocate.h b/pkg/noun/v1/allocate.h new file mode 100644 index 0000000000..4544417b78 --- /dev/null +++ b/pkg/noun/v1/allocate.h @@ -0,0 +1,78 @@ +#ifndef U3_ALLOCATE_V1_H +#define U3_ALLOCATE_V1_H + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v2/allocate.h" + + /** Aliases. + **/ +# define u3R_v1 u3R_v2 +# define u3a_v1_botox u3a_v2_botox +# define u3a_v1_box u3a_v2_box +# define u3a_v1_cell u3a_v2_cell +# define u3a_v1_fbox u3a_v2_fbox +# define u3a_v1_fbox_no u3a_v2_fbox_no +# define u3a_v1_into u3a_v2_into +# define u3a_v1_is_cat u3a_v2_is_cat +# define u3a_v1_is_north u3a_v2_is_north +# define u3a_v1_is_pom u3a_v2_is_pom +# define u3a_v1_minimum u3a_v2_minimum +# define u3a_v1_outa u3a_v2_outa + + /** Structures. + **/ + /** Macros. Should be better commented. + **/ + /* Inside a noun. + */ + /* u3a_v1_to_off(): mask off bits 30 and 31 from noun [som]. + */ +# define u3a_v1_to_off(som) ((som) & 0x3fffffff) + + /* u3a_v1_to_ptr(): convert noun [som] into generic pointer into loom. + */ +# define u3a_v1_to_ptr(som) (u3a_v1_into(u3a_v1_to_off(som))) + + /* u3a_v1_to_wtr(): convert noun [som] into word pointer into loom. + */ +# define u3a_v1_to_wtr(som) ((c3_w *)u3a_v1_to_ptr(som)) + + /* u3a_v1_to_pug(): set bit 31 of [off]. + */ +# define u3a_v1_to_pug(off) (off | 0x80000000) + + /* u3a_v1_to_pom(): set bits 30 and 31 of [off]. + */ +# define u3a_v1_to_pom(off) (off | 0xc0000000) + + /** Functions. + **/ + /** Allocation. + **/ + /* Word-aligned allocation. + */ + /* u3a_v1_wfree(): free storage. + */ + void + u3a_v1_wfree(void* lag_v); + + /* C-style aligned allocation - *not* compatible with above. + */ + /* u3a_v1_free(): free for aligned malloc. + */ + void + u3a_v1_free(void* tox_v); + + /* Reference and arena control. + */ + /* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3a_v1_reclaim(void); + + /* u3a_v1_lose(): lose a reference count. + */ + void + u3a_v1_lose(u3_noun som); + +#endif /* ifndef U3_ALLOCATE_H */ diff --git a/pkg/noun/v1/hashtable.c b/pkg/noun/v1/hashtable.c new file mode 100644 index 0000000000..aa3a9b7aef --- /dev/null +++ b/pkg/noun/v1/hashtable.c @@ -0,0 +1,173 @@ +/// @file + +#include "pkg/noun/hashtable.h" +#include "pkg/noun/v1/hashtable.h" + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" + + +/* _ch_v1_popcount(): number of bits set in word. A standard intrinsic. +** NB: copy of _ch_v1_popcount in pkg/noun/hashtable.c +*/ +static c3_w +_ch_v1_popcount(c3_w num_w) +{ + return __builtin_popcount(num_w); +} + +/* _ch_v1_free_buck(): free bucket +** NB: copy of _ch_v1_free_buck in pkg/noun/hashtable.c +*/ +static void +_ch_v1_free_buck(u3h_v1_buck* hab_u) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3a_v1_lose(u3h_v1_slot_to_noun(hab_u->sot_w[i_w])); + } + u3a_v1_wfree(hab_u); +} + +/* _ch_v1_free_node(): free node. +*/ +static void +_ch_v1_free_node(u3h_v1_node* han_u, c3_w lef_w) +{ + c3_w len_w = _ch_v1_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_v1_slot_is_noun(sot_w)) ) { + u3a_v1_lose(u3h_v1_slot_to_noun(sot_w)); + } + else { + void* hav_v = u3h_v1_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + _ch_v1_free_buck(hav_v); + } else { + _ch_v1_free_node(hav_v, lef_w); + } + } + } + u3a_v1_wfree(han_u); +} + +/* u3h_v1_free_nodes(): free hashtable nodes. +*/ +void +u3h_v1_free_nodes(u3p(u3h_v1_root) har_p) +{ + u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_v1_slot_is_noun(sot_w)) ) { + u3a_v1_lose(u3h_v1_slot_to_noun(sot_w)); + } + else if ( _(u3h_v1_slot_is_node(sot_w)) ) { + u3h_v1_node* han_u = (u3h_v1_node*) u3h_v1_slot_to_node(sot_w); + + _ch_v1_free_node(han_u, 25); + } + har_u->sot_w[i_w] = 0; + } + har_u->use_w = 0; + har_u->arm_u.mug_w = 0; + har_u->arm_u.inx_w = 0; +} + +/* _ch_v1_walk_buck(): walk bucket for gc. +** NB: copy of _ch_v1_walk_buck in pkg/noun/hashtable.c +*/ +static void +_ch_v1_walk_buck(u3h_v1_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + fun_f(u3h_v1_slot_to_noun(hab_u->sot_w[i_w]), wit); + } +} + +/* _ch_v1_walk_node(): walk node for gc. +*/ +static void +_ch_v1_walk_node(u3h_v1_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit) +{ + c3_w len_w = _ch_v1_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_v1_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_v1_slot_to_noun(sot_w); + + fun_f(kev, wit); + } + else { + void* hav_v = u3h_v1_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + _ch_v1_walk_buck(hav_v, fun_f, wit); + } else { + _ch_v1_walk_node(hav_v, lef_w, fun_f, wit); + } + } + } +} + +/* u3h_v1_walk_with(): traverse hashtable with key, value fn and data + * argument; RETAINS. +*/ +void +u3h_v1_walk_with(u3p(u3h_v1_root) har_p, + void (*fun_f)(u3_noun, void*), + void* wit) +{ + u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); + c3_w i_w; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_v1_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_v1_slot_to_noun(sot_w); + + fun_f(kev, wit); + } + else if ( _(u3h_v1_slot_is_node(sot_w)) ) { + u3h_v1_node* han_u = (u3h_v1_node*) u3h_v1_slot_to_node(sot_w); + + _ch_v1_walk_node(han_u, 25, fun_f, wit); + } + } +} + +/* _ch_v1_walk_plain(): use plain u3_noun fun_f for each node + */ +static void +_ch_v1_walk_plain(u3_noun kev, void* wit) +{ + void (*fun_f)(u3_noun) = wit; + fun_f(kev); +} + +/* u3h_v1_walk(): u3h_v1_walk_with, but with no data argument +*/ +void +u3h_v1_walk(u3p(u3h_v1_root) har_p, void (*fun_f)(u3_noun)) +{ + u3h_v1_walk_with(har_p, _ch_v1_walk_plain, fun_f); +} diff --git a/pkg/noun/v1/hashtable.h b/pkg/noun/v1/hashtable.h new file mode 100644 index 0000000000..2d5fdea6f3 --- /dev/null +++ b/pkg/noun/v1/hashtable.h @@ -0,0 +1,51 @@ +#ifndef U3_HASHTABLE_V1_H +#define U3_HASHTABLE_V1_H + +#include "pkg/noun/hashtable.h" +#include "pkg/noun/v2/hashtable.h" + + /** Aliases. + **/ +# define u3h_v1_buck u3h_v2_buck +# define u3h_v1_node u3h_v2_node +# define u3h_v1_root u3h_v2_root +# define u3h_v1_slot_is_node u3h_v2_slot_is_node +# define u3h_v1_slot_is_noun u3h_v2_slot_is_noun +# define u3h_v1_slot_to_noun u3h_v2_slot_to_noun + + /** Data structures. + **/ + + /** HAMT macros. + *** + *** Coordinate with u3_noun definition! + **/ + /* u3h_v1_slot_to_node(): slot to node pointer + ** u3h_v1_node_to_slot(): node pointer to slot + */ +# define u3h_v1_slot_to_node(sot) (u3a_v1_into((sot) & 0x3fffffff)) +# define u3h_v1_node_to_slot(ptr) (u3a_v1_outa(ptr) | 0x40000000) + + /** Functions. + *** + *** Needs: delete and merge functions; clock reclamation function. + **/ + /* u3h_v1_free(): free hashtable. + */ + void + u3h_v1_free_nodes(u3p(u3h_root) har_p); + + /* u3h_v1_walk_with(): traverse hashtable with key, value fn and data + * argument; RETAINS. + */ + void + u3h_v1_walk_with(u3p(u3h_root) har_p, + void (*fun_f)(u3_noun, void*), + void* wit); + + /* u3h_v1_walk(): u3h_v1_walk_with, but with no data argument + */ + void + u3h_v1_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)); + +#endif /* ifndef U3_HASHTABLE_H */ diff --git a/pkg/noun/v1/jets.c b/pkg/noun/v1/jets.c new file mode 100644 index 0000000000..be13a63d49 --- /dev/null +++ b/pkg/noun/v1/jets.c @@ -0,0 +1,101 @@ +/// @file + +#include "pkg/noun/vortex.h" + +#include "pkg/noun/jets.h" +#include "pkg/noun/v1/jets.h" +#include "pkg/noun/v2/jets.h" + +#include "pkg/noun/v1/allocate.h" +#include "pkg/noun/v1/hashtable.h" + +/** Data structures. +**/ + +/* _cj_v1_hank: cached hook information. +** NB: copy of _cj_hank from pkg/noun/jets.c + */ +typedef struct { + u3_weak hax; // axis of hooked inner core + u3j_v1_site sit_u; // call-site data +} _cj_v1_hank; + +/** Functions. +**/ + +/* _cj_fink_free(): lose and free everything in a u3j_v1_fink. +*/ +static void +_cj_v1_fink_free(u3p(u3j_v1_fink) fin_p) +{ + c3_w i_w; + u3j_v1_fink* fin_u = u3to(u3j_v1_fink, fin_p); + u3a_v1_lose(fin_u->sat); + for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { + u3j_v1_fist* fis_u = &(fin_u->fis_u[i_w]); + u3a_v1_lose(fis_u->bat); + u3a_v1_lose(fis_u->pax); + } + u3a_v1_wfree(fin_u); +} + +/* u3j_v1_rite_lose(): lose references of u3j_v1_rite (but do not free). + */ +void +u3j_v1_rite_lose(u3j_v1_rite* rit_u) +{ + if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { + u3a_v1_lose(rit_u->clu); + _cj_v1_fink_free(rit_u->fin_p); + } +} + + +/* u3j_v1_site_lose(): lose references of u3j_v1_site (but do not free). + */ +void +u3j_v1_site_lose(u3j_v1_site* sit_u) +{ + u3a_v1_lose(sit_u->axe); + if ( u3_none != sit_u->bat ) { + u3a_v1_lose(sit_u->bat); + } + if ( u3_none != sit_u->bas ) { + u3a_v1_lose(sit_u->bas); + } + if ( u3_none != sit_u->loc ) { + u3a_v1_lose(sit_u->loc); + u3a_v1_lose(sit_u->lab); + if ( c3y == sit_u->fon_o ) { + if ( sit_u->fin_p ) { + _cj_v1_fink_free(sit_u->fin_p); + } + } + } +} + +/* _cj_v1_free_hank(): free an entry from the hank cache. +** NB: copy of _cj_v1_free_hank() from pkg/noun/jets.c +*/ +static void +_cj_v1_free_hank(u3_noun kev) +{ + u3a_v1_cell* cel_u = (u3a_v1_cell*) u3a_v1_to_ptr(kev); + _cj_v1_hank* han_u = u3to(_cj_v1_hank, cel_u->tel); + if ( u3_none != han_u->hax ) { + u3a_v1_lose(han_u->hax); + u3j_v1_site_lose(&(han_u->sit_u)); + } + u3a_v1_wfree(han_u); +} + +/* u3j_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3j_v1_reclaim(void) +{ + // clear the jet hank cache + // + u3h_v1_walk(u3R_v1->jed.han_p, _cj_v1_free_hank); + u3h_v1_free_nodes(u3R_v1->jed.han_p); +} diff --git a/pkg/noun/v1/jets.h b/pkg/noun/v1/jets.h new file mode 100644 index 0000000000..1711a0e675 --- /dev/null +++ b/pkg/noun/v1/jets.h @@ -0,0 +1,33 @@ +/// @file + +#ifndef U3_JETS_V1_H +#define U3_JETS_V1_H + +#include "pkg/noun/jets.h" +#include "pkg/noun/v2/jets.h" + + /** Aliases. + **/ +# define u3j_v1_fink u3j_v2_fink +# define u3j_v1_fist u3j_v2_fist +# define u3j_v1_rite u3j_v2_rite +# define u3j_v1_site u3j_v2_site + + /** Functions. + **/ + /* u3j_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3j_v1_reclaim(void); + + /* u3j_v1_rite_lose(): lose references of u3j_rite (but do not free). + */ + void + u3j_v1_rite_lose(u3j_rite* rit_u); + + /* u3j_v1_site_lose(): lose references of u3j_site (but do not free). + */ + void + u3j_v1_site_lose(u3j_site* sit_u); + +#endif /* ifndef U3_JETS_V1_H */ diff --git a/pkg/noun/v1/manage.c b/pkg/noun/v1/manage.c new file mode 100644 index 0000000000..0eac6a8d7b --- /dev/null +++ b/pkg/noun/v1/manage.c @@ -0,0 +1,20 @@ +/// @file + +#include "pkg/noun/v1/manage.h" + +#include "pkg/noun/v1/allocate.h" +#include "pkg/noun/v1/hashtable.h" +#include "pkg/noun/v1/jets.h" +#include "pkg/noun/v1/nock.h" +#include "pkg/noun/v1/vortex.h" + +/* u3m_v1_reclaim: clear persistent caches to reclaim memory +*/ +void +u3m_v1_reclaim(void) +{ + u3v_v1_reclaim(); + u3j_v1_reclaim(); + u3n_v1_reclaim(); + u3a_v1_reclaim(); +} diff --git a/pkg/noun/v1/manage.h b/pkg/noun/v1/manage.h new file mode 100644 index 0000000000..669d69ea36 --- /dev/null +++ b/pkg/noun/v1/manage.h @@ -0,0 +1,17 @@ +/// @file + +#ifndef U3_MANAGE_V1_H +#define U3_MANAGE_V1_H + + /** Aliases. + **/ +# define u3m_v1_bail u3m_bail + + /** System management. + **/ + /* u3m_v1_reclaim: clear persistent caches to reclaim memory + */ + void + u3m_v1_reclaim(void); + +#endif /* ifndef U3_MANAGE_V1_H */ diff --git a/pkg/noun/v1/nock.c b/pkg/noun/v1/nock.c new file mode 100644 index 0000000000..4e0de27dc2 --- /dev/null +++ b/pkg/noun/v1/nock.c @@ -0,0 +1,70 @@ +/// @file + +#include "pkg/noun/nock.h" +#include "pkg/noun/v1/nock.h" + +#include "pkg/noun/v1/allocate.h" +#include "pkg/noun/v1/hashtable.h" +#include "pkg/noun/jets.h" +#include "pkg/noun/v1/jets.h" + +/* u3n_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3n_v1_reclaim(void) +{ + // clear the bytecode cache + // + // We can't just u3h_v1_free() -- the value is a post to a u3n_v1_prog. + // Note that the hank cache *must* also be freed (in u3j_v1_reclaim()) + // + u3n_v1_free(); +} + +/* _cn_v1_prog_free(): free memory retained by program pog_u +** NB: copy of _cn_v1_prog_free in pkg/noun/nock.c +*/ +static void +_cn_v1_prog_free(u3n_v1_prog* pog_u) +{ + // fix up pointers for loom portability + // pog_u->byc_u.ops_y = (c3_y*) ((void*) pog_u) + sizeof(u3n_v1_prog); + // pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); + // pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); + // pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); + // pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + + c3_w dex_w; + for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { + u3a_v1_lose(pog_u->lit_u.non[dex_w]); + } + for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) { + u3a_v1_lose(pog_u->mem_u.sot_u[dex_w].key); + } + for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) { + u3j_v1_site_lose(&(pog_u->cal_u.sit_u[dex_w])); + } + for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) { + u3j_v1_rite_lose(&(pog_u->reg_u.rit_u[dex_w])); + } + u3a_v1_free(pog_u); +} + +/* _n_feb(): u3h_v1_walk helper for u3n_v1_free + */ +static void +_n_feb(u3_noun kev) +{ + u3a_v1_cell *cel_u = (u3a_v1_cell*) u3a_v1_to_ptr(kev); + _cn_v1_prog_free(u3to(u3n_v1_prog, cel_u->tel)); +} + +/* u3n_v1_free(): free bytecode cache + */ +void +u3n_v1_free() +{ + u3p(u3h_v1_root) har_p = u3R_v1->byc.har_p; + u3h_v1_walk(har_p, _n_feb); + u3h_v1_free_nodes(har_p); +} diff --git a/pkg/noun/v1/nock.h b/pkg/noun/v1/nock.h new file mode 100644 index 0000000000..08a7a5959a --- /dev/null +++ b/pkg/noun/v1/nock.h @@ -0,0 +1,24 @@ +/// @file + +#ifndef U3_NOCK_V1_H +#define U3_NOCK_V1_H + +#include "pkg/noun/v2/nock.h" + + /** Aliases. + **/ +# define u3n_v1_prog u3n_v2_prog + + /** Functions. + **/ + /* u3n_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3n_v1_reclaim(void); + + /* u3n_v1_free(): free bytecode cache. + */ + void + u3n_v1_free(void); + +#endif /* ifndef U3_NOCK_V1_H */ diff --git a/pkg/noun/v1/vortex.c b/pkg/noun/v1/vortex.c new file mode 100644 index 0000000000..e1ec21b22d --- /dev/null +++ b/pkg/noun/v1/vortex.c @@ -0,0 +1,17 @@ +/// @file + +#include "pkg/noun/vortex.h" +#include "pkg/noun/v1/vortex.h" + +#include "pkg/noun/v1/allocate.h" + +/* u3v_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3v_v1_reclaim(void) +{ + // clear the u3v_wish cache + // + u3a_v1_lose(u3A_v1->yot); + u3A_v1->yot = u3_nul; +} diff --git a/pkg/noun/v1/vortex.h b/pkg/noun/v1/vortex.h new file mode 100644 index 0000000000..f6c0b223d6 --- /dev/null +++ b/pkg/noun/v1/vortex.h @@ -0,0 +1,21 @@ +/// @file + +#ifndef U3_VORTEX_V1_H +#define U3_VORTEX_V1_H + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v2/vortex.h" + + /** Aliases. + **/ +# define u3H_v1 u3H_v2 +# define u3A_v1 u3A_v2 + + /** Functions. + **/ + /* u3v_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3v_v1_reclaim(void); + +#endif /* ifndef U3_VORTEX_V1_H */ diff --git a/pkg/noun/v2/allocate.c b/pkg/noun/v2/allocate.c new file mode 100644 index 0000000000..dfae7b8213 --- /dev/null +++ b/pkg/noun/v2/allocate.c @@ -0,0 +1,73 @@ +/// @file + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" +#include "pkg/noun/v2/allocate.h" + +#include "pkg/noun/v2/hashtable.h" +#include "log.h" +#include "pkg/noun/v2/manage.h" +#include "options.h" +#include "retrieve.h" +#include "trace.h" +#include "vortex.h" + +u3a_v2_road* u3a_v2_Road; + +u3_noun +u3a_v2_rewritten_noun(u3_noun som) +{ + if ( c3y == u3a_v2_is_cat(som) ) { + return som; + } + u3_post som_p = u3a_v2_rewritten(u3a_v1_to_off(som)); + + if ( c3y == u3a_v2_is_pug(som) ) { + som_p = u3a_v2_to_pug(som_p); + } + else { + som_p = u3a_v2_to_pom(som_p); + } + + return som_p; +} + +/* u3a_v2_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. +*/ +void +u3a_v2_rewrite_compact(void) +{ + u3a_v2_rewrite_noun(u3R_v2->ski.gul); + u3a_v2_rewrite_noun(u3R_v2->bug.tax); + u3a_v2_rewrite_noun(u3R_v2->bug.mer); + u3a_v2_rewrite_noun(u3R_v2->pro.don); + u3a_v2_rewrite_noun(u3R_v2->pro.day); + u3a_v2_rewrite_noun(u3R_v2->pro.trace); + u3h_v2_rewrite(u3R_v2->cax.har_p); + + u3R_v2->ski.gul = u3a_v2_rewritten_noun(u3R_v2->ski.gul); + u3R_v2->bug.tax = u3a_v2_rewritten_noun(u3R_v2->bug.tax); + u3R_v2->bug.mer = u3a_v2_rewritten_noun(u3R_v2->bug.mer); + u3R_v2->pro.don = u3a_v2_rewritten_noun(u3R_v2->pro.don); + u3R_v2->pro.day = u3a_v2_rewritten_noun(u3R_v2->pro.day); + u3R_v2->pro.trace = u3a_v2_rewritten_noun(u3R_v2->pro.trace); + u3R_v2->cax.har_p = u3a_v2_rewritten(u3R_v2->cax.har_p); +} + +void +u3a_v2_rewrite_noun(u3_noun som) +{ + if ( c3n == u3a_v2_is_cell(som) ) { + return; + } + + if ( c3n == u3a_v2_rewrite_ptr(u3a_v1_to_ptr((som))) ) return; + + u3a_v2_cell* cel = (u3a_v2_cell*) u3a_v1_to_ptr(som); + + u3a_v2_rewrite_noun(cel->hed); + u3a_v2_rewrite_noun(cel->tel); + + cel->hed = u3a_v2_rewritten_noun(cel->hed); + cel->tel = u3a_v2_rewritten_noun(cel->tel); +} diff --git a/pkg/noun/v2/allocate.h b/pkg/noun/v2/allocate.h new file mode 100644 index 0000000000..82b1826adb --- /dev/null +++ b/pkg/noun/v2/allocate.h @@ -0,0 +1,133 @@ +#ifndef U3_ALLOCATE_V2_H +#define U3_ALLOCATE_V2_H + +#include "pkg/noun/allocate.h" + +#include "pkg/noun/v2/manage.h" +#include "options.h" + + /** Aliases. + **/ +# define u3a_v2_botox u3a_botox +# define u3a_v2_box u3a_box +# define u3a_v2_cell u3a_cell +# define u3a_v2_fbox u3a_fbox +# define u3a_v2_fbox_no u3a_fbox_no +# define u3a_v2_free u3a_free +# define u3a_v2_heap u3a_heap +# define u3a_v2_into u3a_into +# define u3a_v2_is_cat u3a_is_cat +# define u3a_v2_is_cell u3a_is_cell +# define u3a_v2_is_north u3a_is_north +# define u3a_v2_is_pom u3a_is_pom +# define u3a_v2_is_pug u3a_is_pug +# define u3a_v2_malloc u3a_malloc +# define u3a_v2_minimum u3a_minimum +# define u3a_v2_outa u3a_outa +# define u3a_v2_pack_seek u3a_pack_seek +# define u3a_v2_rewrite u3a_rewrite +# define u3a_v2_rewrite_ptr u3a_rewrite_ptr +# define u3a_v2_rewritten u3a_rewritten +# define u3a_v2_to_off u3a_to_off +# define u3a_v2_to_ptr u3a_to_ptr +# define u3a_v2_to_wtr u3a_to_wtr +# define u3a_v2_to_pug u3a_to_pug +# define u3a_v2_to_pom u3a_to_pom +# define u3a_v2_wfree u3a_wfree + + /** Data structures. + **/ + /* u3a_v2_road: contiguous allocation and execution context. + */ + typedef struct _u3a_v2_road { + u3p(struct _u3a_v2_road) par_p; // parent road + u3p(struct _u3a_v2_road) kid_p; // child road list + u3p(struct _u3a_v2_road) nex_p; // sibling road + + u3p(c3_w) cap_p; // top of transient region + u3p(c3_w) hat_p; // top of durable region + u3p(c3_w) mat_p; // bottom of transient region + u3p(c3_w) rut_p; // bottom of durable region + u3p(c3_w) ear_p; // original cap if kid is live + + c3_w fut_w[32]; // futureproof buffer + + struct { // escape buffer + union { + jmp_buf buf; + c3_w buf_w[256]; // futureproofing + }; + } esc; + + struct { // miscellaneous config + c3_w fag_w; // flag bits + } how; // + + struct { // allocation pools + u3p(u3a_fbox) fre_p[u3a_fbox_no]; // heap by node size log + u3p(u3a_fbox) cel_p; // custom cell allocator + c3_w fre_w; // number of free words + c3_w max_w; // maximum allocated + } all; + + u3a_jets jed; // jet dashboard + + struct { // bytecode state + u3p(u3h_root) har_p; // formula->post of bytecode + } byc; + + struct { // namespace + u3_noun gul; // (list $+(* (unit (unit)))) now + } ski; + + struct { // trace stack + u3_noun tax; // (list ,*) + u3_noun mer; // emergency buffer to release + } bug; + + struct { // profile stack + c3_d nox_d; // nock steps + c3_d cel_d; // cell allocations + u3_noun don; // (list batt) + u3_noun trace; // (list trace) + u3_noun day; // doss, only in u3H (moveme) + } pro; + + struct { // memoization + u3p(u3h_root) har_p; // (map (pair term noun) noun) + } cax; + } u3a_v2_road; + + /** Globals. + **/ + /// Current road (thread-local). + extern u3a_v2_road* u3a_v2_Road; +# define u3R_v2 u3a_v2_Road + + /** Functions. + **/ + /** Allocation. + **/ + /* Reference and arena control. + */ + /* u3a_v2_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. + */ + void + u3a_v2_rewrite_compact(void); + + /* u3a_v2_rewrite_noun(): rewrite a noun for compaction. + */ + void + u3a_v2_rewrite_noun(u3_noun som); + + /* u3a_v2_rewritten(): rewrite a pointer for compaction. + */ + u3_post + u3a_v2_rewritten(u3_post som_p); + + /* u3a_v2_rewritten(): rewritten noun pointer for compaction. + */ + u3_noun + u3a_v2_rewritten_noun(u3_noun som); + +#endif /* ifndef U3_ALLOCATE_V2_H */ diff --git a/pkg/noun/v2/hashtable.c b/pkg/noun/v2/hashtable.c new file mode 100644 index 0000000000..6963d07fde --- /dev/null +++ b/pkg/noun/v2/hashtable.c @@ -0,0 +1,143 @@ +/// @file + +#include "pkg/noun/hashtable.h" +#include "pkg/noun/v1/hashtable.h" +#include "pkg/noun/v2/hashtable.h" + +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" +#include "pkg/noun/v2/allocate.h" + +/* _ch_v2_popcount(): number of bits set in word. A standard intrinsic. +** NB: copy of _ch_v2_popcount in pkg/noun/hashtable.c +*/ +static c3_w +_ch_v2_popcount(c3_w num_w) +{ + return __builtin_popcount(num_w); +} + +/* _ch_v2_free_buck(): free bucket +** NB: copy of _ch_v2_free_buck in pkg/noun/hashtable.c +*/ +static void +_ch_v2_free_buck(u3h_v2_buck* hab_u) +{ + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3z(u3h_v2_slot_to_noun(hab_u->sot_w[i_w])); + } + u3a_v2_wfree(hab_u); +} + +/* _ch_v2_free_node(): free node. +*/ +static void +_ch_v2_free_node(u3h_v2_node* han_u, c3_w lef_w) +{ + c3_w len_w = _ch_v2_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_v2_slot_is_noun(sot_w)) ) { + u3z(u3h_v2_slot_to_noun(sot_w)); + } + else { + // NB: u3h_v2_slot_to_node() + void* hav_v = u3h_v2_slot_to_node(sot_w); + + if ( 0 == lef_w ) { + _ch_v2_free_buck(hav_v); + } else { + _ch_v2_free_node(hav_v, lef_w); + } + } + } + u3a_v2_wfree(han_u); +} + +/* _ch_v2_rewrite_buck(): rewrite buck for compaction. +*/ +void +_ch_v2_rewrite_buck(u3h_v2_buck* hab_u) +{ + if ( c3n == u3a_v2_rewrite_ptr(hab_u) ) return; + c3_w i_w; + + for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { + u3_noun som = u3h_v2_slot_to_noun(hab_u->sot_w[i_w]); + hab_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(som)); + u3a_v2_rewrite_noun(som); + } +} + +/* _ch_v2_rewrite_node(): rewrite node for compaction. +*/ +void +_ch_v2_rewrite_node(u3h_v2_node* han_u, c3_w lef_w) +{ + if ( c3n == u3a_v2_rewrite_ptr(han_u) ) return; + + c3_w len_w = _ch_v2_popcount(han_u->map_w); + c3_w i_w; + + lef_w -= 5; + + for ( i_w = 0; i_w < len_w; i_w++ ) { + c3_w sot_w = han_u->sot_w[i_w]; + + if ( _(u3h_v2_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_v2_slot_to_noun(sot_w); + han_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(kev)); + + u3a_v2_rewrite_noun(kev); + } + else { + void* hav_v = u3h_v1_slot_to_node(sot_w); + u3h_v2_node* nod_u = u3to(u3h_v2_node, u3a_v2_rewritten(u3of(u3h_v2_node,hav_v))); + + han_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u); + + if ( 0 == lef_w ) { + _ch_v2_rewrite_buck(hav_v); + } else { + _ch_v2_rewrite_node(hav_v, lef_w); + } + } + } +} + +/* u3h_v2_rewrite(): rewrite pointers during compaction. +*/ +void +u3h_v2_rewrite(u3p(u3h_v2_root) har_p) +{ + u3h_v2_root* har_u = u3to(u3h_v2_root, har_p); + c3_w i_w; + + if ( c3n == u3a_v2_rewrite_ptr(har_u) ) return; + + for ( i_w = 0; i_w < 64; i_w++ ) { + c3_w sot_w = har_u->sot_w[i_w]; + + if ( _(u3h_v2_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_v2_slot_to_noun(sot_w); + har_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(kev)); + + u3a_v2_rewrite_noun(kev); + } + else if ( _(u3h_v2_slot_is_node(sot_w)) ) { + u3h_v2_node* han_u = (u3h_v2_node*) u3h_v1_slot_to_node(sot_w); + u3h_v2_node* nod_u = u3to(u3h_v2_node, u3a_v2_rewritten(u3of(u3h_v2_node,han_u))); + + har_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u); + + _ch_v2_rewrite_node(han_u, 25); + } + } +} diff --git a/pkg/noun/v2/hashtable.h b/pkg/noun/v2/hashtable.h new file mode 100644 index 0000000000..be6ab9587c --- /dev/null +++ b/pkg/noun/v2/hashtable.h @@ -0,0 +1,41 @@ +#ifndef U3_HASHTABLE_V2_H +#define U3_HASHTABLE_V2_H + +#define u3h_v2_buck u3h_buck +#define u3h_v2_free u3h_free +#define u3h_v2_node u3h_node +#define u3h_v2_noun_to_slot u3h_noun_to_slot +#define u3h_v2_root u3h_root +#define u3h_v2_slot_is_node u3h_slot_is_node +#define u3h_v2_slot_is_noun u3h_slot_is_noun +#define u3h_v2_slot_to_noun u3h_slot_to_noun +#define u3h_v2_walk u3h_walk +#define u3h_v2_walk_with u3h_walk_with + +#include "pkg/noun/hashtable.h" + +#include "c3.h" +#include "types.h" + + /** Data structures. + **/ + + /** HAMT macros. + *** + *** Coordinate with u3_noun definition! + **/ + /* u3h_v2_slot_to_node(): slot to node pointer + ** u3h_v2_node_to_slot(): node pointer to slot + */ +# define u3h_v2_slot_to_node(sot) (u3a_v2_into(((sot) & 0x3fffffff) << u3a_vits)) +# define u3h_v2_node_to_slot(ptr) ((u3a_v2_outa((ptr)) >> u3a_vits) | 0x40000000) + + /** Functions. + *** + **/ + /* u3h_v2_rewrite(): rewrite hashtable for compaction. + */ + void + u3h_v2_rewrite(u3p(u3h_root) har_p); + +#endif /* U3_HASHTABLE_V2_H */ diff --git a/pkg/noun/v2/jets.c b/pkg/noun/v2/jets.c new file mode 100644 index 0000000000..e70ef46abe --- /dev/null +++ b/pkg/noun/v2/jets.c @@ -0,0 +1,37 @@ +/// @file + +#include "pkg/noun/vortex.h" + +#include "pkg/noun/jets.h" +#include "pkg/noun/v2/jets.h" + +#include "pkg/noun/v2/allocate.h" +#include "pkg/noun/v2/hashtable.h" +#include "pkg/noun/v2/vortex.h" + +/* u3j_v2_rewrite_compact(): rewrite jet state for compaction. + * + * NB: u3R_v2->jed.han_p *must* be cleared (currently via u3j_v2_reclaim above) + * since it contains hanks which are not nouns but have loom pointers. + * Alternately, rewrite the entries with u3h_v2_walk, using u3j_v2_mark as a + * template for how to walk. There's an untested attempt at this in git + * history at e8a307a. +*/ +void +u3j_v2_rewrite_compact() +{ + u3h_v2_rewrite(u3R_v2->jed.war_p); + u3h_v2_rewrite(u3R_v2->jed.cod_p); + u3h_v2_rewrite(u3R_v2->jed.han_p); + u3h_v2_rewrite(u3R_v2->jed.bas_p); + + if ( u3R_v2 == &(u3H_v2->rod_u) ) { + u3h_v2_rewrite(u3R_v2->jed.hot_p); + u3R_v2->jed.hot_p = u3a_v2_rewritten(u3R_v2->jed.hot_p); + } + + u3R_v2->jed.war_p = u3a_v2_rewritten(u3R_v2->jed.war_p); + u3R_v2->jed.cod_p = u3a_v2_rewritten(u3R_v2->jed.cod_p); + u3R_v2->jed.han_p = u3a_v2_rewritten(u3R_v2->jed.han_p); + u3R_v2->jed.bas_p = u3a_v2_rewritten(u3R_v2->jed.bas_p); +} diff --git a/pkg/noun/v2/jets.h b/pkg/noun/v2/jets.h new file mode 100644 index 0000000000..a596170f60 --- /dev/null +++ b/pkg/noun/v2/jets.h @@ -0,0 +1,22 @@ +/// @file + +#ifndef U3_JETS_V2_H +#define U3_JETS_V2_H + + /** Aliases. + **/ +# define u3j_v2_fink u3j_fink +# define u3j_v2_fist u3j_fist +# define u3j_v2_rite u3j_rite +# define u3j_v2_rite_lose u3j_rite_lose +# define u3j_v2_site u3j_site +# define u3j_v2_site_lose u3j_site_lose + + /** Functions. + **/ + /* u3j_v2_rewrite_compact(): rewrite jet state for compaction. + */ + void + u3j_v2_rewrite_compact(); + +#endif /* ifndef U3_JETS_V2_H */ diff --git a/pkg/noun/v2/manage.c b/pkg/noun/v2/manage.c new file mode 100644 index 0000000000..525f356944 --- /dev/null +++ b/pkg/noun/v2/manage.c @@ -0,0 +1,177 @@ +/// @file + +#include "pkg/noun/v2/manage.h" + +#include "pkg/noun/v2/allocate.h" +#include "pkg/noun/v2/hashtable.h" +#include "pkg/noun/v2/jets.h" +#include "pkg/noun/v2/nock.h" +#include "pkg/noun/v2/options.h" +#include "pkg/noun/vortex.h" +#include "pkg/noun/v2/vortex.h" + +/* _cm_pack_rewrite(): trace through arena, rewriting pointers. + * XX need to version; dynamic scope insanity! +*/ +static void +_cm_pack_rewrite(void) +{ + // XX fix u3a_v2_rewrite* to support south roads + // + u3_assert( &(u3H_v2->rod_u) == u3R_v2 ); + + u3v_v2_rewrite_compact(); + u3j_v2_rewrite_compact(); + u3n_v2_rewrite_compact(); + u3a_v2_rewrite_compact(); +} + +static void +_migrate_reclaim() +{ + // XX update this and similar printfs + fprintf(stderr, "loom: migration reclaim\r\n"); + u3m_v1_reclaim(); +} + +static void +_migrate_seek(const u3a_v2_road *rod_u) +{ + /* + very much like u3a_v2_pack_seek with the following changes: + - there is no need to account for free space as |pack is performed before + the migration + - odd sized boxes will be padded by one word to achieve an even size + - rut will be moved from one word ahead of u3_Loom to two words ahead + */ + c3_w * box_w = u3a_v2_into(rod_u->rut_p); + c3_w * end_w = u3a_v2_into(rod_u->hat_p); + u3_post new_p = (rod_u->rut_p + 1 + c3_wiseof(u3a_v2_box)); + u3a_v2_box * box_u = (void *)box_w; + + fprintf(stderr, "loom: migration seek\r\n"); + + for (; box_w < end_w + ; box_w += box_u->siz_w + , box_u = (void*)box_w) + { + if (!box_u->use_w) + continue; + u3_assert(box_u->siz_w); + u3_assert(box_u->use_w); + box_w[box_u->siz_w - 1] = new_p; + new_p = c3_align(new_p + box_u->siz_w, 2, C3_ALGHI); + } +} + +static void +_migrate_rewrite() +{ + fprintf(stderr, "loom: migration rewrite\r\n"); + + _cm_pack_rewrite(); +} + +static void +_migrate_move(u3a_v2_road *rod_u) +{ + fprintf(stderr, "loom: migration move\r\n"); + + c3_z hiz_z = u3a_v2_heap(rod_u) * sizeof(c3_w); + + /* calculate required shift distance to prevent write head overlapping read head */ + c3_w off_w = 1; /* at least 1 word because u3R_v2->rut_p migrates from 1 to 2 */ + for (u3a_v2_box *box_u = u3a_v2_into(rod_u->rut_p) + ; (void *)box_u < u3a_v2_into(rod_u->hat_p) + ; box_u = (void *)((c3_w *)box_u + box_u->siz_w)) + off_w += box_u->siz_w & 1; /* odd-sized boxes are padded by one word */ + + /* shift */ + memmove(u3a_v2_into(u3H_v2->rod_u.rut_p + off_w), + u3a_v2_into(u3H_v2->rod_u.rut_p), + hiz_z); + /* manually zero the former rut */ + *(c3_w *)u3a_v2_into(rod_u->rut_p) = 0; + + /* relocate boxes to DWORD-aligned addresses stored in trailing size word */ + c3_w *box_w = u3a_v2_into(rod_u->rut_p + off_w); + c3_w *end_w = u3a_v2_into(rod_u->hat_p + off_w); + u3a_v2_box *old_u = (void *)box_w; + c3_w siz_w = old_u->siz_w; + u3p(c3_w) new_p = rod_u->rut_p + 1 + c3_wiseof(u3a_v2_box); + c3_w *new_w; + + for (; box_w < end_w + ; box_w += siz_w + , old_u = (void *)box_w + , siz_w = old_u->siz_w) { + old_u->use_w &= 0x7fffffff; + + if (!old_u->use_w) + continue; + + new_w = (void *)u3a_v2_botox(u3a_v2_into(new_p)); + u3_assert(box_w[siz_w - 1] == new_p); + u3_assert(new_w <= box_w); + + c3_w i_w; + for (i_w = 0; i_w < siz_w - 1; i_w++) + new_w[i_w] = box_w[i_w]; + + if (siz_w & 1) { + new_w[i_w++] = 0; /* pad odd sized boxes */ + new_w[i_w++] = siz_w + 1; /* restore trailing size word */ + new_w[0] = siz_w + 1; /* and the leading size word */ + } + else { + new_w[i_w++] = siz_w; + } + + new_p += i_w; + } + + /* restore proper heap state */ + rod_u->rut_p = 2; + rod_u->hat_p = new_p - c3_wiseof(u3a_v2_box); + + /* like |pack, clear the free lists and cell allocator */ + for (c3_w i_w = 0; i_w < u3a_v2_fbox_no; i_w++) + u3R_v2->all.fre_p[i_w] = 0; + + u3R_v2->all.fre_w = 0; + u3R_v2->all.cel_p = 0; +} + + +/* u3m_v2_migrate: perform loom migration if necessary. +*/ +void +u3m_v2_migrate() +{ + c3_w len_w = u3C_v2.wor_i - 1; + c3_w ver_w = *(u3_Loom + len_w); + + u3_assert( U3V_VER1 == ver_w ); + + c3_w* mem_w = u3_Loom + 1; + c3_w siz_w = c3_wiseof(u3v_v2_home); + c3_w* mat_w = (mem_w + len_w) - siz_w; + + u3H_v2 = (void *)mat_w; + u3R_v2 = &u3H_v2->rod_u; + + u3R_v2->cap_p = u3R_v2->mat_p = u3a_v2_outa(u3H_v2); + + fprintf(stderr, "loom: pointer compression migration running...\r\n"); + + /* perform the migration in a pattern similar to |pack */ + _migrate_reclaim(); + _migrate_seek(&u3H_v2->rod_u); + _migrate_rewrite(); + _migrate_move(&u3H_v2->rod_u); + + /* finally update the version and commit to disk */ + u3H_v2->ver_w = U3V_VER2; + + fprintf(stderr, "loom: pointer compression migration done\r\n"); +} diff --git a/pkg/noun/v2/manage.h b/pkg/noun/v2/manage.h new file mode 100644 index 0000000000..998a37cc65 --- /dev/null +++ b/pkg/noun/v2/manage.h @@ -0,0 +1,14 @@ +/// @file + +#ifndef U3_MANAGE_V2_H +#define U3_MANAGE_V2_H + + /** System management. + **/ + /* u3m_v2_migrate: perform pointer compression loom migration if necessary. + ver_w - target version + */ + void + u3m_v2_migrate(); + +#endif /* ifndef U3_MANAGE_V2_H */ diff --git a/pkg/noun/v2/nock.c b/pkg/noun/v2/nock.c new file mode 100644 index 0000000000..95a011e005 --- /dev/null +++ b/pkg/noun/v2/nock.c @@ -0,0 +1,28 @@ +/// @file + +#include "pkg/noun/nock.h" +#include "pkg/noun/v2/nock.h" + +#include "pkg/noun/v2/allocate.h" +#include "pkg/noun/v2/hashtable.h" +#include "pkg/noun/v2/vortex.h" + +/* u3n_v2_rewrite_compact(): rewrite the bytecode cache for compaction. + * + * NB: u3R_v2->byc.har_p *must* be cleared (currently via u3n_v2_reclaim above), + * since it contains things that look like nouns but aren't. + * Specifically, it contains "cells" where the tail is a + * pointer to a u3a_v2_malloc'ed block that contains loom pointers. + * + * You should be able to walk this with u3h_v2_walk and rewrite the + * pointers, but you need to be careful to handle that u3a_v2_malloc + * pointers can't be turned into a box by stepping back two words. You + * must step back one word to get the padding, step then step back that + * many more words (plus one?). + */ +void +u3n_v2_rewrite_compact() +{ + u3h_v2_rewrite(u3R_v2->byc.har_p); + u3R_v2->byc.har_p = u3a_v2_rewritten(u3R_v2->byc.har_p); +} diff --git a/pkg/noun/v2/nock.h b/pkg/noun/v2/nock.h new file mode 100644 index 0000000000..eddc3d2074 --- /dev/null +++ b/pkg/noun/v2/nock.h @@ -0,0 +1,18 @@ +/// @file + +#ifndef U3_NOCK_V2_H +#define U3_NOCK_V2_H + + /** Aliases. + **/ +#define u3n_v2_free u3n_free +#define u3n_v2_prog u3n_prog + + /** Functions. + **/ + /* u3n_v2_rewrite_compact(): rewrite bytecode cache for compaction. + */ + void + u3n_v2_rewrite_compact(); + +#endif /* ifndef U3_NOCK_V2_H */ diff --git a/pkg/noun/v2/options.h b/pkg/noun/v2/options.h new file mode 100644 index 0000000000..4af573f20d --- /dev/null +++ b/pkg/noun/v2/options.h @@ -0,0 +1,14 @@ +/// @file + +#ifndef U3_OPTIONS_V2_H +#define U3_OPTIONS_V2_H + +#include "pkg/noun/options.h" + + /** Globals. + **/ + /* u3_Config / u3C: global memory control. + */ +# define u3C_v2 u3C + +#endif /* ifndef U3_OPTIONS_H */ diff --git a/pkg/noun/v2/vortex.c b/pkg/noun/v2/vortex.c new file mode 100644 index 0000000000..382ed24192 --- /dev/null +++ b/pkg/noun/v2/vortex.c @@ -0,0 +1,25 @@ +/// @file + +#include "pkg/noun/vortex.h" +#include "pkg/noun/v2/vortex.h" + +#include "pkg/noun/v2/allocate.h" + +u3v_v2_home* u3v_v2_Home; + +/* u3v_v2_rewrite_compact(): rewrite arvo kernel for compaction. +*/ +void +u3v_v2_rewrite_compact() +{ + u3v_v2_arvo* arv_u = &(u3H_v2->arv_u); + + u3a_v2_rewrite_noun(arv_u->roc); + u3a_v2_rewrite_noun(arv_u->now); + u3a_v2_rewrite_noun(arv_u->yot); + + arv_u->roc = u3a_v2_rewritten_noun(arv_u->roc); + arv_u->now = u3a_v2_rewritten_noun(arv_u->now); + arv_u->yot = u3a_v2_rewritten_noun(arv_u->yot); +} + diff --git a/pkg/noun/v2/vortex.h b/pkg/noun/v2/vortex.h new file mode 100644 index 0000000000..9ef060e610 --- /dev/null +++ b/pkg/noun/v2/vortex.h @@ -0,0 +1,40 @@ +/// @file + +#ifndef U3_VORTEX_V2_H +#define U3_VORTEX_V2_H + +#include "pkg/noun/vortex.h" + +#include "pkg/noun/v2/allocate.h" +#include "pkg/noun/version.h" + + /** Aliases. + **/ +# define u3v_v2_arvo u3v_arvo + + /** Data structures. + **/ + /* u3v_v2_home: all internal (within image) state. + ** NB: version must be last for discriminability in north road + */ + typedef struct _u3v_v2_home { + u3a_v2_road rod_u; // storage state + u3v_v2_arvo arv_u; // arvo state + u3v_version ver_w; // version number + } u3v_v2_home; + + /** Globals. + **/ + /// Arvo internal state. + extern u3v_v2_home* u3v_v2_Home; +# define u3H_v2 u3v_v2_Home +# define u3A_v2 (&(u3v_v2_Home->arv_u)) + + /** Functions. + **/ + /* u3v_v2_rewrite_compact(): rewrite arvo kernel for compaction. + */ + void + u3v_v2_rewrite_compact(); + +#endif /* ifndef U3_VORTEX_V2_H */ diff --git a/pkg/noun/vortex.h b/pkg/noun/vortex.h index cbd0f295ff..2d202e831c 100644 --- a/pkg/noun/vortex.h +++ b/pkg/noun/vortex.h @@ -37,9 +37,6 @@ # define u3H u3v_Home # define u3A (&(u3v_Home->arv_u)) - /** Constants. - **/ - /** Functions. **/ /* u3v_life(): execute initial lifecycle, producing Arvo core. From f282a167ad154dd2c279963282920e800fc23b61 Mon Sep 17 00:00:00 2001 From: Matthew LeVan Date: Tue, 1 Aug 2023 12:09:44 -0400 Subject: [PATCH 02/17] vere: bump %lull kelvin to %322 --- pkg/vere/pier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vere/pier.c b/pkg/vere/pier.c index 1e39d14ef4..506a59a195 100644 --- a/pkg/vere/pier.c +++ b/pkg/vere/pier.c @@ -676,7 +676,7 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) // #define VERE_NAME "vere" #define VERE_ZUSE 412 -#define VERE_LULL 323 +#define VERE_LULL 322 /* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN */ From f18ec083824ca10df51679ea9d92595da5673c94 Mon Sep 17 00:00:00 2001 From: Matthew LeVan Date: Tue, 1 Aug 2023 12:10:18 -0400 Subject: [PATCH 03/17] vere: decrement zuse to %411 --- pkg/vere/pier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vere/pier.c b/pkg/vere/pier.c index 506a59a195..8e54dbb37e 100644 --- a/pkg/vere/pier.c +++ b/pkg/vere/pier.c @@ -675,7 +675,7 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) // XX organizing version constants // #define VERE_NAME "vere" -#define VERE_ZUSE 412 +#define VERE_ZUSE 411 #define VERE_LULL 322 /* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN From 574bf7880dbf02f810f96f5e51e23cf3522f771a Mon Sep 17 00:00:00 2001 From: Matthew LeVan Date: Tue, 25 Jul 2023 13:42:13 -0400 Subject: [PATCH 04/17] UIP-0103: Persistent Nock Caching --- pkg/noun/allocate.c | 5 +- pkg/noun/allocate.h | 17 +++--- pkg/noun/hashtable.h | 5 +- pkg/noun/jets.c | 65 ++++++++++------------- pkg/noun/jets.h | 12 +++++ pkg/noun/jets/f/ut_crop.c | 4 +- pkg/noun/jets/f/ut_fish.c | 4 +- pkg/noun/jets/f/ut_fuse.c | 4 +- pkg/noun/jets/f/ut_mint.c | 4 +- pkg/noun/jets/f/ut_mull.c | 4 +- pkg/noun/jets/f/ut_nest.c | 4 +- pkg/noun/jets/f/ut_rest.c | 4 +- pkg/noun/manage.c | 23 +++++--- pkg/noun/manage.h | 5 -- pkg/noun/nock.c | 34 ++++++++---- pkg/noun/nock.h | 2 + pkg/noun/options.h | 2 + pkg/noun/retrieve.c | 26 +++++++++ pkg/noun/retrieve.h | 8 +++ pkg/noun/v1/allocate.c | 33 ++---------- pkg/noun/v1/jets.c | 16 +----- pkg/noun/v1/jets.h | 5 +- pkg/noun/v1/nock.c | 17 +++--- pkg/noun/v1/nock.h | 1 + pkg/noun/v1/vortex.h | 5 +- pkg/noun/v2/allocate.c | 4 +- pkg/noun/v2/allocate.h | 9 ++-- pkg/noun/v2/hashtable.h | 1 + pkg/noun/v2/jets.c | 29 ++++++++--- pkg/noun/v2/jets.h | 19 +++++-- pkg/noun/v2/manage.c | 37 ++++++------- pkg/noun/v2/manage.h | 3 +- pkg/noun/v2/nock.c | 70 +++++++++++++++++++++++-- pkg/noun/v2/nock.h | 56 ++++++++++++++++++-- pkg/noun/v2/vortex.c | 4 +- pkg/noun/v2/vortex.h | 4 +- pkg/noun/v3/allocate.h | 17 ++++++ pkg/noun/v3/hashtable.c | 33 ++++++++++++ pkg/noun/v3/hashtable.h | 18 +++++++ pkg/noun/v3/jets.h | 12 +++++ pkg/noun/v3/manage.c | 107 ++++++++++++++++++++++++++++++++++++++ pkg/noun/v3/manage.h | 13 +++++ pkg/noun/v3/nock.h | 17 ++++++ pkg/noun/v3/vortex.h | 19 +++++++ pkg/noun/version.h | 3 +- pkg/noun/zave.c | 68 +++++++++++++++++++----- pkg/noun/zave.h | 37 ++++++++++--- pkg/vere/BUILD.bazel | 2 +- pkg/vere/lord.c | 8 ++- pkg/vere/main.c | 23 ++++++-- pkg/vere/vere.h | 3 +- 51 files changed, 707 insertions(+), 218 deletions(-) create mode 100644 pkg/noun/v3/allocate.h create mode 100644 pkg/noun/v3/hashtable.c create mode 100644 pkg/noun/v3/hashtable.h create mode 100644 pkg/noun/v3/jets.h create mode 100644 pkg/noun/v3/manage.c create mode 100644 pkg/noun/v3/manage.h create mode 100644 pkg/noun/v3/nock.h create mode 100644 pkg/noun/v3/vortex.h diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 44f7175879..b905ce5912 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -2131,7 +2131,8 @@ u3a_mark_road(FILE* fil_u) tot_w += u3a_maid(fil_u, " profile batteries", u3a_mark_noun(u3R->pro.don)); tot_w += u3a_maid(fil_u, " profile doss", u3a_mark_noun(u3R->pro.day)); tot_w += u3a_maid(fil_u, " new profile trace", u3a_mark_noun(u3R->pro.trace)); - tot_w += u3a_maid(fil_u, " memoization cache", u3h_mark(u3R->cax.har_p)); + tot_w += u3a_maid(fil_u, " transient memoization cache", u3h_mark(u3R->cax.har_p)); + tot_w += u3a_maid(fil_u, " persistent memoization cache", u3h_mark(u3R->cax.per_p)); return u3a_maid(fil_u, "total road stuff", tot_w); } @@ -2158,6 +2159,7 @@ u3a_rewrite_compact(void) u3a_rewrite_noun(u3R->pro.day); u3a_rewrite_noun(u3R->pro.trace); u3h_rewrite(u3R->cax.har_p); + u3h_rewrite(u3R->cax.per_p); u3R->ski.gul = u3a_rewritten_noun(u3R->ski.gul); u3R->bug.tax = u3a_rewritten_noun(u3R->bug.tax); @@ -2166,6 +2168,7 @@ u3a_rewrite_compact(void) u3R->pro.day = u3a_rewritten_noun(u3R->pro.day); u3R->pro.trace = u3a_rewritten_noun(u3R->pro.trace); u3R->cax.har_p = u3a_rewritten(u3R->cax.har_p); + u3R->cax.per_p = u3a_rewritten(u3R->cax.per_p); } /* _ca_print_box(): heuristically print the contents of an allocation box. diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index be50793002..6081b96e7d 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -154,11 +154,11 @@ u3a_jets jed; // jet dashboard - struct { // bytecode state - u3p(u3h_root) har_p; // formula->post of bytecode + struct { // bytecode state + u3p(u3h_root) har_p; // formula->post of bytecode } byc; - struct { // namespace + struct { // scry namespace u3_noun gul; // (list $+(* (unit (unit)))) now } ski; @@ -175,8 +175,9 @@ u3_noun day; // doss, only in u3H (moveme) } pro; - struct { // memoization - u3p(u3h_root) har_p; // (map (pair term noun) noun) + struct { // memoization caches + u3p(u3h_root) har_p; // transient + u3p(u3h_root) per_p; // persistent } cax; } u3a_road; typedef u3a_road u3_road; @@ -232,7 +233,7 @@ /* u3a_is_atom(): yes if noun [som] is direct atom or indirect atom. */ # define u3a_is_atom(som) c3o(u3a_is_cat(som), \ - u3a_is_pug(som)) + u3a_is_pug(som)) # define u3ud(som) u3a_is_atom(som) /* u3a_is_cell: yes if noun [som] is cell. @@ -380,8 +381,6 @@ # define u3_Loom ((c3_w *)(void *)U3_OS_LoomBase) - /** Inline functions. - **/ /* u3a_into(): convert loom offset [x] into generic pointer. */ # define u3a_into(x) ((void *)(u3_Loom + (x))) @@ -402,6 +401,8 @@ */ # define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som)) + /** Inline functions. + **/ /* u3a_to_pug(): set bit 31 of [off]. */ inline c3_w u3a_to_pug(c3_w off) { diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index a117f50011..291ef28a0c 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -16,9 +16,8 @@ *** corresponding to the 32-slot nodes for everything under *** the root node. *** - *** We store an extra "freshly warm" bit for a simple - *** clock-algorithm reclamation policy, not yet implemented. - *** Search "clock algorithm" to figure it out. + *** We store an extra "freshly warm" bit and use it for a simple + *** clock-algorithm reclamation policy. **/ /* u3h_slot: map slot. ** diff --git a/pkg/noun/jets.c b/pkg/noun/jets.c index dcabcdb559..13e417dab6 100644 --- a/pkg/noun/jets.c +++ b/pkg/noun/jets.c @@ -18,15 +18,6 @@ #include "vortex.h" #include "xtract.h" -/** Data structures. -**/ - -/* _cj_hank: cached hook information. - */ -typedef struct { - u3_weak hax; // axis of hooked inner core - u3j_site sit_u; // call-site data -} _cj_hank; /** Functions. **/ @@ -1069,7 +1060,7 @@ _cj_prog(u3_weak loc, u3_noun fol) /* cj_hank_find(): find cached hook information, keyed by arbitrary * prefix and term cords. RETAIN. */ -static _cj_hank* +static u3j_hank* _cj_hank_find(u3_noun pre, u3_noun tam) { u3_noun key = u3nc(u3k(pre), u3k(tam)); @@ -1077,10 +1068,10 @@ _cj_hank_find(u3_noun pre, u3_noun tam) if ( u3_none != got ) { u3z(key); - return u3to(_cj_hank, got); + return u3to(u3j_hank, got); } else { - _cj_hank* new_u = u3a_walloc(c3_wiseof(_cj_hank)); + u3j_hank* new_u = u3a_walloc(c3_wiseof(u3j_hank)); u3a_road* rod_u = u3R; while ( rod_u->par_p && u3_none == got ) { @@ -1092,7 +1083,7 @@ _cj_hank_find(u3_noun pre, u3_noun tam) new_u->hax = u3_none; } else { - _cj_hank* old_u = u3to(_cj_hank, got); + u3j_hank* old_u = u3to(u3j_hank, got); if ( u3_none != (new_u->hax = old_u->hax) ) { // it's unusual but safe to "take" here, because // u3a_take will no-op on senior nouns (just as u3k would) @@ -1101,7 +1092,7 @@ _cj_hank_find(u3_noun pre, u3_noun tam) } } - u3h_put(u3R->jed.han_p, key, u3of(_cj_hank, new_u)); + u3h_put(u3R->jed.han_p, key, u3of(u3j_hank, new_u)); u3z(key); return new_u; } @@ -1112,7 +1103,7 @@ _cj_hank_find(u3_noun pre, u3_noun tam) * core on return if valid. RETAIN. */ static c3_o -_cj_hank_fine(_cj_hank* han_u, u3_noun cor, u3_noun *inn) +_cj_hank_fine(u3j_hank* han_u, u3_noun cor, u3_noun *inn) { u3_noun hax = han_u->hax; if ( u3_none == hax ) { @@ -1134,7 +1125,7 @@ _cj_hank_fine(_cj_hank* han_u, u3_noun cor, u3_noun *inn) /* _cj_hank_lose(): release memory maintained in a hook cache. */ static void -_cj_hank_lose(_cj_hank* han_u) +_cj_hank_lose(u3j_hank* han_u) { if ( u3_none != han_u->hax ) { u3z(han_u->hax); @@ -1145,7 +1136,7 @@ _cj_hank_lose(_cj_hank* han_u) /* _cj_hank_fill(): slow path, populate han_u. */ static u3_noun -_cj_hank_fill(_cj_hank* han_u, u3_noun tam, u3_noun cor) +_cj_hank_fill(u3j_hank* han_u, u3_noun tam, u3_noun cor) { u3_weak loc, col; u3_noun got, pat, nam, huc; @@ -1642,7 +1633,7 @@ u3j_cook(const c3_c* key_c, const c3_c* tam_c) { u3_noun pro, key, tam, inn; - _cj_hank* han_u; + u3j_hank* han_u; u3t_on(glu_o); key = u3i_string(key_c); @@ -1992,11 +1983,11 @@ u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor) /* _cj_take_hank_cb(): u3h_take_with cb for taking hanks */ -static u3p(_cj_hank) -_cj_take_hank_cb(u3p(_cj_hank) nah_p) +static u3p(u3j_hank) +_cj_take_hank_cb(u3p(u3j_hank) nah_p) { - _cj_hank* nah_u = u3to(_cj_hank, nah_p); - _cj_hank* han_u = u3a_walloc(c3_wiseof(_cj_hank)); + u3j_hank* nah_u = u3to(u3j_hank, nah_p); + u3j_hank* han_u = u3a_walloc(c3_wiseof(u3j_hank)); if ( u3_none == nah_u->hax ) { han_u->hax = u3_none; @@ -2007,7 +1998,7 @@ _cj_take_hank_cb(u3p(_cj_hank) nah_p) u3j_site_take(&(han_u->sit_u), &(nah_u->sit_u)); } - return u3of(_cj_hank, han_u); + return u3of(u3j_hank, han_u); } /* u3j_take(): copy junior jet state. @@ -2029,25 +2020,25 @@ static void _cj_merge_hank_cb(u3_noun kev, void* wit) { u3p(u3h_root) han_p = *(u3p(u3h_root)*)wit; - _cj_hank* nah_u; + u3j_hank* nah_u; u3_noun key; - u3p(_cj_hank) nah_p; + u3p(u3j_hank) nah_p; u3x_cell(kev, &key, &nah_p); - nah_u = u3to(_cj_hank, nah_p); + nah_u = u3to(u3j_hank, nah_p); if ( u3_none == nah_u->hax ) { u3a_wfree(nah_u); } else { - _cj_hank* han_u; + u3j_hank* han_u; u3_weak got = u3h_git(u3R->jed.han_p, key); if ( u3_none == got ) { han_u = nah_u; } else { - han_u = u3to(_cj_hank, got); + han_u = u3to(u3j_hank, got); if ( u3_none != han_u->hax ) { u3z(han_u->hax); @@ -2058,7 +2049,7 @@ _cj_merge_hank_cb(u3_noun kev, void* wit) u3a_wfree(nah_u); } - u3h_put(han_p, key, u3of(_cj_hank, han_u)); + u3h_put(han_p, key, u3of(u3j_hank, han_u)); } } @@ -2170,7 +2161,7 @@ _cj_warm_tap(u3_noun kev, void* wit) static void _cj_ream_hank(u3_noun kev) { - u3j_site_ream(&(u3to(_cj_hank, u3t(kev))->sit_u)); + u3j_site_ream(&(u3to(u3j_hank, u3t(kev))->sit_u)); } /* u3j_ream(): rebuild warm state @@ -2304,7 +2295,7 @@ static void _cj_mark_hank(u3_noun kev, void* dat) { c3_w* tot_w = (c3_w*) dat; - _cj_hank* han_u = u3to(_cj_hank, u3t(kev)); + u3j_hank* han_u = u3to(u3j_hank, u3t(kev)); *tot_w += u3a_mark_ptr(han_u); if ( u3_none != han_u->hax ) { *tot_w += u3a_mark_noun(han_u->hax); @@ -2337,12 +2328,12 @@ u3j_mark(FILE* fil_u) return u3a_maid(fil_u, "total jet stuff", tot_w); } -/* _cj_free_hank(): free an entry from the hank cache. +/* u3j_free_hank(): free an entry from the hank cache. */ -static void -_cj_free_hank(u3_noun kev) +void +u3j_free_hank(u3_noun kev) { - _cj_hank* han_u = u3to(_cj_hank, u3t(kev)); + u3j_hank* han_u = u3to(u3j_hank, u3t(kev)); if ( u3_none != han_u->hax ) { u3z(han_u->hax); u3j_site_lose(&(han_u->sit_u)); @@ -2355,7 +2346,7 @@ _cj_free_hank(u3_noun kev) void u3j_free(void) { - u3h_walk(u3R->jed.han_p, _cj_free_hank); + u3h_walk(u3R->jed.han_p, u3j_free_hank); u3h_free(u3R->jed.war_p); u3h_free(u3R->jed.cod_p); u3h_free(u3R->jed.han_p); @@ -2379,7 +2370,7 @@ u3j_reclaim(void) // } // clear the jet hank cache // - u3h_walk(u3R->jed.han_p, _cj_free_hank); + u3h_walk(u3R->jed.han_p, u3j_free_hank); u3h_free(u3R->jed.han_p); u3R->jed.han_p = u3h_new(); } diff --git a/pkg/noun/jets.h b/pkg/noun/jets.h index 9c5241c5db..1440f7558a 100644 --- a/pkg/noun/jets.h +++ b/pkg/noun/jets.h @@ -126,6 +126,13 @@ u3p(u3j_fink) fin_p; // fine check } u3j_site; + /* u3j_hank: cached hook information. + */ + typedef struct { + u3_weak hax; // axis of hooked inner core + u3j_site sit_u; // call-site data + } u3j_hank; + /** Globals. **/ /* u3_Dash: jet dashboard. @@ -297,6 +304,11 @@ void u3j_free(void); + /* u3j_free_hank(): free an entry from the hank cache. + */ + void + u3j_free_hank(u3_noun kev); + /* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ void diff --git a/pkg/noun/jets/f/ut_crop.c b/pkg/noun/jets/f/ut_crop.c index 1969a13a3d..189564d0c3 100644 --- a/pkg/noun/jets/f/ut_crop.c +++ b/pkg/noun/jets/f/ut_crop.c @@ -20,7 +20,7 @@ u3wfu_crop(u3_noun cor) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__crop + ((!!vet) << 8); u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -28,7 +28,7 @@ u3wfu_crop(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/jets/f/ut_fish.c b/pkg/noun/jets/f/ut_fish.c index e7505b9345..e8acbd43cf 100644 --- a/pkg/noun/jets/f/ut_fish.c +++ b/pkg/noun/jets/f/ut_fish.c @@ -21,7 +21,7 @@ u3wfu_fish(u3_noun cor) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__fish + ((!!vet) << 8); u3_noun key = u3z_key_3(fun_m, sut, axe, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -29,7 +29,7 @@ u3wfu_fish(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/jets/f/ut_fuse.c b/pkg/noun/jets/f/ut_fuse.c index f9fac33a4d..8e4e1a6135 100644 --- a/pkg/noun/jets/f/ut_fuse.c +++ b/pkg/noun/jets/f/ut_fuse.c @@ -20,7 +20,7 @@ u3wfu_fuse(u3_noun cor) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__fuse + ((!!vet) << 8); u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -28,7 +28,7 @@ u3wfu_fuse(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/jets/f/ut_mint.c b/pkg/noun/jets/f/ut_mint.c index fc8424854a..618e7291fd 100644 --- a/pkg/noun/jets/f/ut_mint.c +++ b/pkg/noun/jets/f/ut_mint.c @@ -22,7 +22,7 @@ u3wfu_mint(u3_noun cor) c3_m fun_m = 141 + c3__mint; u3_noun vet = u3r_at(u3qfu_van_vet, van); u3_noun key = u3z_key_5(fun_m, vet, sut, gol, gen, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -30,7 +30,7 @@ u3wfu_mint(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/jets/f/ut_mull.c b/pkg/noun/jets/f/ut_mull.c index 98e62ca57e..767ab3c51a 100644 --- a/pkg/noun/jets/f/ut_mull.c +++ b/pkg/noun/jets/f/ut_mull.c @@ -23,7 +23,7 @@ u3wfu_mull(u3_noun cor) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__mull + ((!!vet) << 8); u3_noun key = u3z_key_5(fun_m, sut, gol, dox, gen, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -31,7 +31,7 @@ u3wfu_mull(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/jets/f/ut_nest.c b/pkg/noun/jets/f/ut_nest.c index 765081a5cb..9bc53bf0f9 100644 --- a/pkg/noun/jets/f/ut_nest.c +++ b/pkg/noun/jets/f/ut_nest.c @@ -27,7 +27,7 @@ u3wfu_nest_dext(u3_noun dext_core) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__dext + ((!!vet) << 8); u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -39,7 +39,7 @@ u3wfu_nest_dext(u3_noun dext_core) if ( ((c3y == pro) && (u3_nul == reg)) || ((c3n == pro) && (u3_nul == seg)) ) { - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } else { u3z(key); diff --git a/pkg/noun/jets/f/ut_rest.c b/pkg/noun/jets/f/ut_rest.c index 3fdbed23b0..87ff60fa68 100644 --- a/pkg/noun/jets/f/ut_rest.c +++ b/pkg/noun/jets/f/ut_rest.c @@ -20,7 +20,7 @@ u3wfu_rest(u3_noun cor) u3_weak vet = u3r_at(u3qfu_van_vet, van); c3_m fun_m = 141 + c3__rest + ((!!vet) << 8); u3_noun key = u3z_key_3(fun_m, sut, leg, bat); - u3_weak pro = u3z_find(key); + u3_weak pro = u3z_find(u3z_memo_toss, key); if ( u3_none != pro ) { u3z(key); @@ -28,7 +28,7 @@ u3wfu_rest(u3_noun cor) } else { pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); + return u3z_save(u3z_memo_toss, key, pro); } } } diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 60787bde34..bd2e62cb6f 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -1,6 +1,8 @@ /// @file -#include "manage.h" +#include "pkg/noun/manage.h" +#include "pkg/noun/v2/manage.h" +#include "pkg/noun/v3/manage.h" #include #include @@ -473,9 +475,8 @@ u3m_mark(FILE* fil_u) static void _pave_parts(void) { - // TODO: pass `u3_Host.ops_u.hap_w` into `noun` library as an argument and use - // as size of memo cache. - u3R->cax.har_p = u3h_new_cache(50000); + u3R->cax.har_p = u3h_new_cache(u3C.hap_w); // transient + u3R->cax.per_p = u3h_new_cache(u3C.per_w); // persistent u3R->jed.war_p = u3h_new(); u3R->jed.cod_p = u3h_new(); u3R->jed.han_p = u3h_new(); @@ -594,10 +595,15 @@ static void _find_home(void) { c3_w ver_w = *(u3_Loom + u3C.wor_i - 1); + c3_o mig_o = c3y; // did we migrate? switch ( ver_w ) { - case 1: u3m_v2_migrate(); - case 2: break; + case U3V_VER1: u3m_v2_migrate(); + case U3V_VER2: u3m_v3_migrate(); + case U3V_VER3: { + mig_o = c3n; + break; + } default: { fprintf(stderr, "loom: checkpoint version mismatch: " "have %u, need %u\r\n", @@ -623,7 +629,7 @@ _find_home(void) // check for obvious corruption // - { + if ( c3n == mig_o ) { c3_w nor_w, sou_w; u3_post low_p, hig_p; u3m_water(&low_p, &hig_p); @@ -991,6 +997,7 @@ u3m_love(u3_noun pro) // u3p(u3h_root) byc_p = u3R->byc.har_p; u3a_jets jed_u = u3R->jed; + u3p(u3h_root) per_p = u3R->cax.per_p; // fallback to parent road (child heap on parent's stack) // @@ -1001,6 +1008,7 @@ u3m_love(u3_noun pro) pro = u3a_take(pro); jed_u = u3j_take(jed_u); byc_p = u3n_take(byc_p); + per_p = u3h_take(per_p); // pop the stack // @@ -1011,6 +1019,7 @@ u3m_love(u3_noun pro) // u3j_reap(jed_u); u3n_reap(byc_p); + u3z_reap(u3z_memo_keep, per_p); return pro; } diff --git a/pkg/noun/manage.h b/pkg/noun/manage.h index bc8ff97390..35ad448168 100644 --- a/pkg/noun/manage.h +++ b/pkg/noun/manage.h @@ -193,9 +193,4 @@ c3_w u3m_pack(void); - /* u3m_migrate: perform loom migrations. - */ - void - u3m_migrate(); - #endif /* ifndef U3_MANAGE_H */ diff --git a/pkg/noun/nock.c b/pkg/noun/nock.c index 6ac08779ef..452b04c309 100644 --- a/pkg/noun/nock.c +++ b/pkg/noun/nock.c @@ -619,7 +619,7 @@ _n_melt(u3_noun ops, c3_w* byc_w, c3_w* cal_w, case SKIB: case SLIB: { c3_l tot_l = 0, - sip_l = u3h(u3t(op)); + sip_l = u3h(u3t(u3t(op))); c3_w j_w, k_w = i_w; for ( j_w = 0; j_w < sip_l; ++j_w ) { tot_l += siz_y[++k_w]; @@ -830,7 +830,9 @@ _n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip) _n_prog_asm_inx(buf_y, &i_w, mem_s, cod); mem_u = &(pog_u->mem_u.sot_u[mem_s++]); mem_u->sip_l = sip_l; - mem_u->key = u3k(u3t(u3t(op))); + // [op_y, cid, mem_w, nef] + mem_u->key = u3k(u3t(u3t(u3t(op)))); + mem_u->cid = u3h(u3t(op)); break; } @@ -1117,16 +1119,21 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) c3_w mem_w = 0; c3_y op_y; - // we just throw away the hint (why is this not a static hint?) tot_w += _n_comp(ops, hod, c3n, c3n); ++tot_w; _n_emit(ops, TOSS); - // memoizing code always loses TOS because SAVE needs [pro key] mem_w += _n_comp(&mem, nef, c3y, c3n); ++mem_w; _n_emit(&mem, SAVE); op_y = (c3y == los_o) ? SLIB : SKIB; // overflows to SLIS / SKIS - ++tot_w; _n_emit(ops, u3nt(op_y, mem_w, u3k(nef))); + u3z_cid cid = u3z_memo_toss; + { + u3_weak con = u3r_skip(hod); + if ( (u3_none != con) && (c3y == u3du(con)) ) { + cid = u3z_memo_keep; + } + } + ++tot_w; _n_emit(ops, u3nq(op_y, cid, mem_w, u3k(nef))); tot_w += mem_w; _n_apen(ops, mem); break; } @@ -2610,9 +2617,9 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) skim_out: o = u3k(mem_u->key); x = u3nc(x, o); - o = u3z_find_m(144 + c3__nock, x); + o = u3z_find_m(mem_u->cid, 144 + c3__nock, x); if ( u3_none == o ) { - _n_push(mov, off, x); + _n_push(mov, off, u3nc(mem_u->cid, x)); _n_push(mov, off, u3k(u3h(x))); } else { @@ -2623,11 +2630,16 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) BURN(); do_save: - x = _n_pep(mov, off); + x = _n_pep(mov, off); // product top = _n_peek(off); o = *top; - if ( &(u3H->rod_u) != u3R ) { - u3z_save_m(144 + c3__nock, o, x); + if ( ( u3z_memo_toss == u3h(o) ) + ? ( &(u3H->rod_u) != u3R ) + : ( 0 == u3R->ski.gul ) ) { // prevents userspace from persistence + u3z_save_m(u3h(o), 144 + c3__nock, u3t(o), x); + } + else if ( u3z_memo_keep == u3h(o) ) { + fprintf(stderr, "\r\nnock: userspace can't save to persistent cache\r\n"); } *top = x; u3z(o); @@ -2853,6 +2865,7 @@ _cn_take_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) u3n_memo* ome_u = &(dst_u->mem_u.sot_u[i_w]); ome_u->sip_l = emo_u->sip_l; ome_u->key = u3a_take(emo_u->key); + ome_u->cid = emo_u->cid; } for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { @@ -2918,6 +2931,7 @@ _cn_merge_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) u3z(emo_u->key); emo_u->sip_l = ome_u->sip_l; emo_u->key = ome_u->key; + emo_u->cid = ome_u->cid; } for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { diff --git a/pkg/noun/nock.h b/pkg/noun/nock.h index 7dded22058..7baf7351d8 100644 --- a/pkg/noun/nock.h +++ b/pkg/noun/nock.h @@ -8,6 +8,7 @@ #include "c3.h" #include "jets.h" #include "types.h" +#include "zave.h" /** Data structures. *** @@ -18,6 +19,7 @@ typedef struct { c3_l sip_l; u3_noun key; + u3z_cid cid; } u3n_memo; /* u3n_prog: program compiled from nock diff --git a/pkg/noun/options.h b/pkg/noun/options.h index 52732d2655..29ca6ce9d9 100644 --- a/pkg/noun/options.h +++ b/pkg/noun/options.h @@ -17,6 +17,8 @@ c3_w wag_w; // flags (both ways) size_t wor_i; // loom word-length (<= u3a_words) c3_w tos_w; // loom toss skip-length + c3_w hap_w; // transient memoization cache size + c3_w per_w; // persistent memoization cache size void (*stderr_log_f)(c3_c*); // errors from c code void (*slog_f)(u3_noun); // function pointer for slog void (*sign_hold_f)(void); // suspend system signal regime diff --git a/pkg/noun/retrieve.c b/pkg/noun/retrieve.c index d1790c7320..43f001fe1f 100644 --- a/pkg/noun/retrieve.c +++ b/pkg/noun/retrieve.c @@ -1903,3 +1903,29 @@ u3r_mug(u3_noun veb) return mug_l; } + +/* u3r_skip(): +** +** Extract a constant from a formula, ignoring +** safe/static hints, doing no computation. +*/ +u3_weak +u3r_skip(u3_noun fol) +{ + while ( c3y == u3du(fol) ) { + switch ( u3h(fol) ) { + default: return u3_none; + case 1: return u3t(fol); + case 11: { + u3_noun arg = u3t(fol), + hod = u3h(arg); + + if ( (c3y == u3du(hod)) && (u3_none == u3r_skip(u3t(hod))) ) { + return u3_none; + } + fol = u3t(arg); + } + } + } + return u3_none; +} diff --git a/pkg/noun/retrieve.h b/pkg/noun/retrieve.h index a98a5e4697..9a5b092c17 100644 --- a/pkg/noun/retrieve.h +++ b/pkg/noun/retrieve.h @@ -486,4 +486,12 @@ c3_y* u3r_tape(u3_noun a); + /* u3r_skip(): + ** + ** Extract a constant from a formula, ignoring + ** safe/static hints, doing no computation. + */ + u3_weak + u3r_skip(u3_noun fol); + #endif /* ifndef U3_RETRIEVE_H */ diff --git a/pkg/noun/v1/allocate.c b/pkg/noun/v1/allocate.c index 226aa33f00..7ce4521ecc 100644 --- a/pkg/noun/v1/allocate.c +++ b/pkg/noun/v1/allocate.c @@ -59,18 +59,6 @@ _box_v1_attach(u3a_v1_box* box_u) u3_assert(box_u->siz_w >= (1 + c3_wiseof(u3a_v1_fbox))); u3_assert(0 != u3of(u3a_v1_fbox, box_u)); -#if 0 - // For debugging, fill the box with beef. - { - c3_w* box_w = (void *)box_u; - c3_w i_w; - - for ( i_w = c3_wiseof(u3a_v1_box); (i_w + 1) < box_u->siz_w; i_w++ ) { - box_w[i_w] = 0xdeadbeef; - } - } -#endif - { c3_w sel_w = _box_v1_slot(box_u->siz_w); u3p(u3a_v1_fbox) fre_p = u3of(u3a_v1_fbox, box_u); @@ -131,19 +119,8 @@ _box_v1_free(u3a_v1_box* box_u) return; } -#if 0 - /* Clear the contents of the block, for debugging. - */ + // we're always migrating a north road, so no need to check for it { - c3_w i_w; - - for ( i_w = c3_wiseof(u3a_v1_box); (i_w + 1) < box_u->siz_w; i_w++ ) { - box_w[i_w] = 0xdeadbeef; - } - } -#endif - - if ( c3y == u3a_v1_is_north(u3R_v1) ) { /* Try to coalesce with the block below. */ if ( box_w != u3a_v1_into(u3R_v1->rut_p) ) { @@ -210,10 +187,10 @@ u3a_v1_reclaim(void) u3h_v1_free_nodes(u3R_v1->cax.har_p); } -/* _me_lose_north(): lose on a north road. +/* _me_v1_lose_north(): lose on a north road. */ static void -_me_lose_north(u3_noun dog) +_me_v1_lose_north(u3_noun dog) { top: { @@ -234,7 +211,7 @@ _me_lose_north(u3_noun dog) u3_noun t_dog = dog_u->tel; if ( !_(u3a_v1_is_cat(h_dog)) ) { - _me_lose_north(h_dog); + _me_v1_lose_north(h_dog); } u3a_v1_wfree(dog_w); if ( !_(u3a_v1_is_cat(t_dog)) ) { @@ -256,6 +233,6 @@ void u3a_v1_lose(u3_noun som) { if ( !_(u3a_v1_is_cat(som)) ) { - _me_lose_north(som); + _me_v1_lose_north(som); } } diff --git a/pkg/noun/v1/jets.c b/pkg/noun/v1/jets.c index be13a63d49..272930e11d 100644 --- a/pkg/noun/v1/jets.c +++ b/pkg/noun/v1/jets.c @@ -9,19 +9,6 @@ #include "pkg/noun/v1/allocate.h" #include "pkg/noun/v1/hashtable.h" -/** Data structures. -**/ - -/* _cj_v1_hank: cached hook information. -** NB: copy of _cj_hank from pkg/noun/jets.c - */ -typedef struct { - u3_weak hax; // axis of hooked inner core - u3j_v1_site sit_u; // call-site data -} _cj_v1_hank; - -/** Functions. -**/ /* _cj_fink_free(): lose and free everything in a u3j_v1_fink. */ @@ -75,13 +62,12 @@ u3j_v1_site_lose(u3j_v1_site* sit_u) } /* _cj_v1_free_hank(): free an entry from the hank cache. -** NB: copy of _cj_v1_free_hank() from pkg/noun/jets.c */ static void _cj_v1_free_hank(u3_noun kev) { u3a_v1_cell* cel_u = (u3a_v1_cell*) u3a_v1_to_ptr(kev); - _cj_v1_hank* han_u = u3to(_cj_v1_hank, cel_u->tel); + u3j_v1_hank* han_u = u3to(u3j_v1_hank, cel_u->tel); if ( u3_none != han_u->hax ) { u3a_v1_lose(han_u->hax); u3j_v1_site_lose(&(han_u->sit_u)); diff --git a/pkg/noun/v1/jets.h b/pkg/noun/v1/jets.h index 1711a0e675..bf3dfe6afe 100644 --- a/pkg/noun/v1/jets.h +++ b/pkg/noun/v1/jets.h @@ -10,6 +10,7 @@ **/ # define u3j_v1_fink u3j_v2_fink # define u3j_v1_fist u3j_v2_fist +# define u3j_v1_hank u3j_v2_hank # define u3j_v1_rite u3j_v2_rite # define u3j_v1_site u3j_v2_site @@ -23,11 +24,11 @@ /* u3j_v1_rite_lose(): lose references of u3j_rite (but do not free). */ void - u3j_v1_rite_lose(u3j_rite* rit_u); + u3j_v1_rite_lose(u3j_v1_rite* rit_u); /* u3j_v1_site_lose(): lose references of u3j_site (but do not free). */ void - u3j_v1_site_lose(u3j_site* sit_u); + u3j_v1_site_lose(u3j_v1_site* sit_u); #endif /* ifndef U3_JETS_V1_H */ diff --git a/pkg/noun/v1/nock.c b/pkg/noun/v1/nock.c index 4e0de27dc2..1ac2931a97 100644 --- a/pkg/noun/v1/nock.c +++ b/pkg/noun/v1/nock.c @@ -22,17 +22,16 @@ u3n_v1_reclaim(void) } /* _cn_v1_prog_free(): free memory retained by program pog_u -** NB: copy of _cn_v1_prog_free in pkg/noun/nock.c */ static void _cn_v1_prog_free(u3n_v1_prog* pog_u) { // fix up pointers for loom portability - // pog_u->byc_u.ops_y = (c3_y*) ((void*) pog_u) + sizeof(u3n_v1_prog); - // pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); - // pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); - // pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); - // pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + pog_u->byc_u.ops_y = (c3_y*) ((void*) pog_u) + sizeof(u3n_v1_prog); + pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); + pog_u->mem_u.sot_u = (u3n_v1_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); + pog_u->cal_u.sit_u = (u3j_v1_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); + pog_u->reg_u.rit_u = (u3j_v1_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); c3_w dex_w; for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { @@ -50,10 +49,10 @@ _cn_v1_prog_free(u3n_v1_prog* pog_u) u3a_v1_free(pog_u); } -/* _n_feb(): u3h_v1_walk helper for u3n_v1_free +/* _n_v1_feb(): u3h_v1_walk helper for u3n_v1_free */ static void -_n_feb(u3_noun kev) +_n_v1_feb(u3_noun kev) { u3a_v1_cell *cel_u = (u3a_v1_cell*) u3a_v1_to_ptr(kev); _cn_v1_prog_free(u3to(u3n_v1_prog, cel_u->tel)); @@ -65,6 +64,6 @@ void u3n_v1_free() { u3p(u3h_v1_root) har_p = u3R_v1->byc.har_p; - u3h_v1_walk(har_p, _n_feb); + u3h_v1_walk(har_p, _n_v1_feb); u3h_v1_free_nodes(har_p); } diff --git a/pkg/noun/v1/nock.h b/pkg/noun/v1/nock.h index 08a7a5959a..5320307b6b 100644 --- a/pkg/noun/v1/nock.h +++ b/pkg/noun/v1/nock.h @@ -7,6 +7,7 @@ /** Aliases. **/ +# define u3n_v1_memo u3n_v2_memo # define u3n_v1_prog u3n_v2_prog /** Functions. diff --git a/pkg/noun/v1/vortex.h b/pkg/noun/v1/vortex.h index f6c0b223d6..84cf6e405c 100644 --- a/pkg/noun/v1/vortex.h +++ b/pkg/noun/v1/vortex.h @@ -8,8 +8,9 @@ /** Aliases. **/ -# define u3H_v1 u3H_v2 -# define u3A_v1 u3A_v2 +# define u3H_v1 u3H_v2 +# define u3A_v1 u3A_v2 +# define u3v_v1_home u3v_v2_home /** Functions. **/ diff --git a/pkg/noun/v2/allocate.c b/pkg/noun/v2/allocate.c index dfae7b8213..25cf04a948 100644 --- a/pkg/noun/v2/allocate.c +++ b/pkg/noun/v2/allocate.c @@ -32,10 +32,10 @@ u3a_v2_rewritten_noun(u3_noun som) return som_p; } -/* u3a_v2_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. +/* u3a_v2_mig_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. */ void -u3a_v2_rewrite_compact(void) +u3a_v2_mig_rewrite_compact(void) { u3a_v2_rewrite_noun(u3R_v2->ski.gul); u3a_v2_rewrite_noun(u3R_v2->bug.tax); diff --git a/pkg/noun/v2/allocate.h b/pkg/noun/v2/allocate.h index 82b1826adb..1f191795fc 100644 --- a/pkg/noun/v2/allocate.h +++ b/pkg/noun/v2/allocate.h @@ -21,6 +21,7 @@ # define u3a_v2_is_north u3a_is_north # define u3a_v2_is_pom u3a_is_pom # define u3a_v2_is_pug u3a_is_pug +# define u3a_v2_lose u3a_lose # define u3a_v2_malloc u3a_malloc # define u3a_v2_minimum u3a_minimum # define u3a_v2_outa u3a_outa @@ -63,8 +64,8 @@ c3_w fag_w; // flag bits } how; // - struct { // allocation pools - u3p(u3a_fbox) fre_p[u3a_fbox_no]; // heap by node size log + struct { // allocation pools + u3p(u3a_v2_fbox) fre_p[u3a_v2_fbox_no]; // heap by node size log u3p(u3a_fbox) cel_p; // custom cell allocator c3_w fre_w; // number of free words c3_w max_w; // maximum allocated @@ -110,10 +111,10 @@ **/ /* Reference and arena control. */ - /* u3a_v2_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. + /* u3a_v2_mig_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. */ void - u3a_v2_rewrite_compact(void); + u3a_v2_mig_rewrite_compact(void); /* u3a_v2_rewrite_noun(): rewrite a noun for compaction. */ diff --git a/pkg/noun/v2/hashtable.h b/pkg/noun/v2/hashtable.h index be6ab9587c..09025fc19f 100644 --- a/pkg/noun/v2/hashtable.h +++ b/pkg/noun/v2/hashtable.h @@ -3,6 +3,7 @@ #define u3h_v2_buck u3h_buck #define u3h_v2_free u3h_free +#define u3h_v2_new u3h_new #define u3h_v2_node u3h_node #define u3h_v2_noun_to_slot u3h_noun_to_slot #define u3h_v2_root u3h_root diff --git a/pkg/noun/v2/jets.c b/pkg/noun/v2/jets.c index e70ef46abe..c22ea97f3b 100644 --- a/pkg/noun/v2/jets.c +++ b/pkg/noun/v2/jets.c @@ -9,7 +9,26 @@ #include "pkg/noun/v2/hashtable.h" #include "pkg/noun/v2/vortex.h" -/* u3j_v2_rewrite_compact(): rewrite jet state for compaction. +#include "pkg/noun/v3/hashtable.h" +#include "pkg/noun/v3/jets.h" + +/* u3j_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3j_v2_reclaim(void) +{ + // set globals (required for aliased functions) + u3H = (u3v_home*) u3H_v2; + u3R = (u3a_road*) u3R_v2; + + // clear the jet hank cache + // + u3h_v3_walk(u3R->jed.han_p, u3j_v3_free_hank); + u3h_v3_free(u3R->jed.han_p); + u3R->jed.han_p = u3h_v3_new(); +} + +/* u3j_v2_mig_rewrite_compact(): rewrite jet state for compaction. * * NB: u3R_v2->jed.han_p *must* be cleared (currently via u3j_v2_reclaim above) * since it contains hanks which are not nouns but have loom pointers. @@ -18,17 +37,15 @@ * history at e8a307a. */ void -u3j_v2_rewrite_compact() +u3j_v2_mig_rewrite_compact() { u3h_v2_rewrite(u3R_v2->jed.war_p); u3h_v2_rewrite(u3R_v2->jed.cod_p); u3h_v2_rewrite(u3R_v2->jed.han_p); u3h_v2_rewrite(u3R_v2->jed.bas_p); - if ( u3R_v2 == &(u3H_v2->rod_u) ) { - u3h_v2_rewrite(u3R_v2->jed.hot_p); - u3R_v2->jed.hot_p = u3a_v2_rewritten(u3R_v2->jed.hot_p); - } + u3h_v2_rewrite(u3R_v2->jed.hot_p); + u3R_v2->jed.hot_p = u3a_v2_rewritten(u3R_v2->jed.hot_p); u3R_v2->jed.war_p = u3a_v2_rewritten(u3R_v2->jed.war_p); u3R_v2->jed.cod_p = u3a_v2_rewritten(u3R_v2->jed.cod_p); diff --git a/pkg/noun/v2/jets.h b/pkg/noun/v2/jets.h index a596170f60..526046905d 100644 --- a/pkg/noun/v2/jets.h +++ b/pkg/noun/v2/jets.h @@ -3,20 +3,33 @@ #ifndef U3_JETS_V2_H #define U3_JETS_V2_H +#include "pkg/noun/allocate.h" +#include "pkg/noun/jets.h" + + /** Aliases. **/ +# define u3j_v2_core u3j_core # define u3j_v2_fink u3j_fink # define u3j_v2_fist u3j_fist +# define u3j_v2_hank u3j_hank +# define u3j_v2_free_hank u3j_free_hank +# define u3j_v2_harm u3j_harm # define u3j_v2_rite u3j_rite -# define u3j_v2_rite_lose u3j_rite_lose # define u3j_v2_site u3j_site +# define u3j_v2_rite_lose u3j_rite_lose # define u3j_v2_site_lose u3j_site_lose /** Functions. **/ - /* u3j_v2_rewrite_compact(): rewrite jet state for compaction. + /* u3j_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3j_v2_reclaim(void); + + /* u3j_v2_mig_rewrite_compact(): rewrite jet state for compaction. */ void - u3j_v2_rewrite_compact(); + u3j_v2_mig_rewrite_compact(); #endif /* ifndef U3_JETS_V2_H */ diff --git a/pkg/noun/v2/manage.c b/pkg/noun/v2/manage.c index 525f356944..113ecc2b6b 100644 --- a/pkg/noun/v2/manage.c +++ b/pkg/noun/v2/manage.c @@ -2,28 +2,25 @@ #include "pkg/noun/v2/manage.h" +#include "pkg/noun/v1/allocate.h" #include "pkg/noun/v2/allocate.h" #include "pkg/noun/v2/hashtable.h" #include "pkg/noun/v2/jets.h" #include "pkg/noun/v2/nock.h" #include "pkg/noun/v2/options.h" #include "pkg/noun/vortex.h" +#include "pkg/noun/v1/vortex.h" #include "pkg/noun/v2/vortex.h" /* _cm_pack_rewrite(): trace through arena, rewriting pointers. - * XX need to version; dynamic scope insanity! */ static void _cm_pack_rewrite(void) { - // XX fix u3a_v2_rewrite* to support south roads - // - u3_assert( &(u3H_v2->rod_u) == u3R_v2 ); - - u3v_v2_rewrite_compact(); - u3j_v2_rewrite_compact(); - u3n_v2_rewrite_compact(); - u3a_v2_rewrite_compact(); + u3v_v2_mig_rewrite_compact(); + u3j_v2_mig_rewrite_compact(); + u3n_v2_mig_rewrite_compact(); + u3a_v2_mig_rewrite_compact(); } static void @@ -80,7 +77,7 @@ _migrate_move(u3a_v2_road *rod_u) c3_z hiz_z = u3a_v2_heap(rod_u) * sizeof(c3_w); /* calculate required shift distance to prevent write head overlapping read head */ - c3_w off_w = 1; /* at least 1 word because u3R_v2->rut_p migrates from 1 to 2 */ + c3_w off_w = 1; /* at least 1 word because u3R_v1->rut_p migrates from 1 to 2 */ for (u3a_v2_box *box_u = u3a_v2_into(rod_u->rut_p) ; (void *)box_u < u3a_v2_into(rod_u->hat_p) ; box_u = (void *)((c3_w *)box_u + box_u->siz_w)) @@ -136,10 +133,10 @@ _migrate_move(u3a_v2_road *rod_u) /* like |pack, clear the free lists and cell allocator */ for (c3_w i_w = 0; i_w < u3a_v2_fbox_no; i_w++) - u3R_v2->all.fre_p[i_w] = 0; + u3R_v1->all.fre_p[i_w] = 0; - u3R_v2->all.fre_w = 0; - u3R_v2->all.cel_p = 0; + u3R_v1->all.fre_w = 0; + u3R_v1->all.cel_p = 0; } @@ -154,24 +151,24 @@ u3m_v2_migrate() u3_assert( U3V_VER1 == ver_w ); c3_w* mem_w = u3_Loom + 1; - c3_w siz_w = c3_wiseof(u3v_v2_home); + c3_w siz_w = c3_wiseof(u3v_v1_home); c3_w* mat_w = (mem_w + len_w) - siz_w; - u3H_v2 = (void *)mat_w; - u3R_v2 = &u3H_v2->rod_u; + u3H_v1 = (void *)mat_w; + u3R_v1 = &u3H_v1->rod_u; - u3R_v2->cap_p = u3R_v2->mat_p = u3a_v2_outa(u3H_v2); + u3R_v1->cap_p = u3R_v1->mat_p = u3a_v1_outa(u3H_v1); fprintf(stderr, "loom: pointer compression migration running...\r\n"); /* perform the migration in a pattern similar to |pack */ _migrate_reclaim(); - _migrate_seek(&u3H_v2->rod_u); + _migrate_seek(&u3H_v1->rod_u); _migrate_rewrite(); - _migrate_move(&u3H_v2->rod_u); + _migrate_move(&u3H_v1->rod_u); /* finally update the version and commit to disk */ - u3H_v2->ver_w = U3V_VER2; + u3H_v1->ver_w = U3V_VER2; fprintf(stderr, "loom: pointer compression migration done\r\n"); } diff --git a/pkg/noun/v2/manage.h b/pkg/noun/v2/manage.h index 998a37cc65..1d03b97809 100644 --- a/pkg/noun/v2/manage.h +++ b/pkg/noun/v2/manage.h @@ -3,10 +3,9 @@ #ifndef U3_MANAGE_V2_H #define U3_MANAGE_V2_H - /** System management. + /** System management. **/ /* u3m_v2_migrate: perform pointer compression loom migration if necessary. - ver_w - target version */ void u3m_v2_migrate(); diff --git a/pkg/noun/v2/nock.c b/pkg/noun/v2/nock.c index 95a011e005..e6ff116ce1 100644 --- a/pkg/noun/v2/nock.c +++ b/pkg/noun/v2/nock.c @@ -1,13 +1,77 @@ /// @file -#include "pkg/noun/nock.h" #include "pkg/noun/v2/nock.h" +#include "pkg/noun/vortex.h" + #include "pkg/noun/v2/allocate.h" #include "pkg/noun/v2/hashtable.h" #include "pkg/noun/v2/vortex.h" -/* u3n_v2_rewrite_compact(): rewrite the bytecode cache for compaction. +#include "pkg/noun/v3/hashtable.h" + +/* u3n_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3n_v2_reclaim(void) +{ + // set globals (required for aliased functions) + u3H = (u3v_home*) u3H_v2; + u3R = (u3a_road*) u3R_v2; + + // clear the bytecode cache + u3n_v2_free(); + u3R->byc.har_p = u3h_v2_new(); +} + +/* _cn_v2_prog_free(): free memory retained by program pog_u +*/ +static void +_cn_v2_prog_free(u3n_v2_prog* pog_u) +{ + // fix up pointers for loom portability + pog_u->byc_u.ops_y = (c3_y*) ((void*) pog_u) + sizeof(u3n_v2_prog); + pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); + pog_u->mem_u.sot_u = (u3n_v2_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); + pog_u->cal_u.sit_u = (u3j_v2_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); + pog_u->reg_u.rit_u = (u3j_v2_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); + + c3_w dex_w; + for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { + u3a_v2_lose(pog_u->lit_u.non[dex_w]); + } + for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) { + u3a_v2_lose(pog_u->mem_u.sot_u[dex_w].key); + } + for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) { + u3j_v2_site_lose(&(pog_u->cal_u.sit_u[dex_w])); + } + for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) { + u3j_v2_rite_lose(&(pog_u->reg_u.rit_u[dex_w])); + } + u3a_v2_free(pog_u); +} + +/* _n_v2_feb(): u3h_v2_walk helper for u3n_v2_free + */ +static void +_n_v2_feb(u3_noun kev) +{ + u3a_v2_cell *cel_u = (u3a_v2_cell*) u3a_v2_to_ptr(kev); + _cn_v2_prog_free(u3to(u3n_v2_prog, cel_u->tel)); +} + +/* u3n_v2_free(): free bytecode cache + */ +void +u3n_v2_free() +{ + u3p(u3h_v2_root) har_p = u3R_v2->byc.har_p; + u3h_v2_walk(har_p, _n_v2_feb); + u3h_v2_free(har_p); +} + +/* u3n_v2_mig_rewrite_compact(): rewrite the bytecode cache for compaction. * * NB: u3R_v2->byc.har_p *must* be cleared (currently via u3n_v2_reclaim above), * since it contains things that look like nouns but aren't. @@ -21,7 +85,7 @@ * many more words (plus one?). */ void -u3n_v2_rewrite_compact() +u3n_v2_mig_rewrite_compact() { u3h_v2_rewrite(u3R_v2->byc.har_p); u3R_v2->byc.har_p = u3a_v2_rewritten(u3R_v2->byc.har_p); diff --git a/pkg/noun/v2/nock.h b/pkg/noun/v2/nock.h index eddc3d2074..e7d44aee08 100644 --- a/pkg/noun/v2/nock.h +++ b/pkg/noun/v2/nock.h @@ -3,16 +3,62 @@ #ifndef U3_NOCK_V2_H #define U3_NOCK_V2_H - /** Aliases. +#include "pkg/noun/v3/nock.h" + +#include "pkg/noun/v2/jets.h" + +#include "types.h" + + /** Data structures. **/ -#define u3n_v2_free u3n_free -#define u3n_v2_prog u3n_prog + /* u3n_memo: %memo hint space + */ + typedef struct { + c3_l sip_l; + u3_noun key; + } u3n_v2_memo; + + /* u3n_v2_prog: program compiled from nock + */ + typedef struct _u3n_v2_prog { + struct { + c3_o own_o; // program owns ops_y? + c3_w len_w; // length of bytecode (bytes) + c3_y* ops_y; // actual array of bytes + } byc_u; // bytecode + struct { + c3_w len_w; // number of literals + u3_noun* non; // array of literals + } lit_u; // literals + struct { + c3_w len_w; // number of memo slots + u3n_v2_memo* sot_u; // array of memo slots + } mem_u; // memo slot data + struct { + c3_w len_w; // number of calls sites + u3j_v2_site* sit_u; // array of sites + } cal_u; // call site data + struct { + c3_w len_w; // number of registration sites + u3j_v2_rite* rit_u; // array of sites + } reg_u; // registration site data + } u3n_v2_prog; /** Functions. **/ - /* u3n_v2_rewrite_compact(): rewrite bytecode cache for compaction. + /* u3n_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory. + */ + void + u3n_v2_reclaim(void); + + /* u3n_v2_free(): free bytecode cache. + */ + void + u3n_v2_free(void); + + /* u3n_v2_mig_rewrite_compact(): rewrite bytecode cache for compaction. */ void - u3n_v2_rewrite_compact(); + u3n_v2_mig_rewrite_compact(); #endif /* ifndef U3_NOCK_V2_H */ diff --git a/pkg/noun/v2/vortex.c b/pkg/noun/v2/vortex.c index 382ed24192..b22dfaed4d 100644 --- a/pkg/noun/v2/vortex.c +++ b/pkg/noun/v2/vortex.c @@ -7,10 +7,10 @@ u3v_v2_home* u3v_v2_Home; -/* u3v_v2_rewrite_compact(): rewrite arvo kernel for compaction. +/* u3v_v2_mig_rewrite_compact(): rewrite arvo kernel for compaction. */ void -u3v_v2_rewrite_compact() +u3v_v2_mig_rewrite_compact() { u3v_v2_arvo* arv_u = &(u3H_v2->arv_u); diff --git a/pkg/noun/v2/vortex.h b/pkg/noun/v2/vortex.h index 9ef060e610..ee8a2f861e 100644 --- a/pkg/noun/v2/vortex.h +++ b/pkg/noun/v2/vortex.h @@ -32,9 +32,9 @@ /** Functions. **/ - /* u3v_v2_rewrite_compact(): rewrite arvo kernel for compaction. + /* u3v_v2_mig_rewrite_compact(): rewrite arvo kernel for compaction. */ void - u3v_v2_rewrite_compact(); + u3v_v2_mig_rewrite_compact(); #endif /* ifndef U3_VORTEX_V2_H */ diff --git a/pkg/noun/v3/allocate.h b/pkg/noun/v3/allocate.h new file mode 100644 index 0000000000..bacc79e174 --- /dev/null +++ b/pkg/noun/v3/allocate.h @@ -0,0 +1,17 @@ +#ifndef U3_ALLOCATE_V3_H +#define U3_ALLOCATE_V3_H + +#include "pkg/noun/allocate.h" + +#include "pkg/noun/v3/manage.h" +#include "options.h" + + /** Aliases. + **/ +# define u3R_v3 u3a_Road +# define u3a_v3_balign u3a_balign +# define u3a_v3_road u3a_road +# define u3a_v3_walign u3a_walign +# define u3a_v3_walloc u3a_walloc + +#endif /* ifndef U3_ALLOCATE_V3_H */ diff --git a/pkg/noun/v3/hashtable.c b/pkg/noun/v3/hashtable.c new file mode 100644 index 0000000000..b17d7b6e78 --- /dev/null +++ b/pkg/noun/v3/hashtable.c @@ -0,0 +1,33 @@ +/// @file + +#include "pkg/noun/v3/hashtable.h" + +#include "pkg/noun/allocate.h" +#include "pkg/noun/vortex.h" + +#include "pkg/noun/v3/allocate.h" +#include "pkg/noun/v3/vortex.h" + +/* u3h_v3_new_cache(): create hashtable with bounded size. +*/ +u3p(u3h_v3_root) +u3h_v3_new_cache(c3_w max_w) +{ + // set globals (required for aliased functions) + u3H = (u3v_home*) u3H_v3; + u3R = (u3a_road*) u3R_v3; + + u3h_v3_root* har_u = u3a_v3_walloc(c3_wiseof(u3h_v3_root)); + u3p(u3h_v3_root) har_p = u3of(u3h_v3_root, har_u); + c3_w i_w; + + har_u->max_w = max_w; + har_u->use_w = 0; + har_u->arm_u.mug_w = 0; + har_u->arm_u.inx_w = 0; + + for ( i_w = 0; i_w < 64; i_w++ ) { + har_u->sot_w[i_w] = 0; + } + return har_p; +} diff --git a/pkg/noun/v3/hashtable.h b/pkg/noun/v3/hashtable.h new file mode 100644 index 0000000000..14e0e47753 --- /dev/null +++ b/pkg/noun/v3/hashtable.h @@ -0,0 +1,18 @@ +#ifndef U3_HASHTABLE_V3_H +#define U3_HASHTABLE_V3_H + +#define u3h_v3_free u3h_free +#define u3h_v3_new u3h_new +#define u3h_v3_root u3h_root +#define u3h_v3_walk u3h_walk + +#include "pkg/noun/hashtable.h" + + /** Functions. + **/ + /* u3h_v3_new_cache(): create hashtable with bounded size. + */ + u3p(u3h_v3_root) + u3h_v3_new_cache(c3_w clk_w); + +#endif /* U3_HASHTABLE_V3_H */ diff --git a/pkg/noun/v3/jets.h b/pkg/noun/v3/jets.h new file mode 100644 index 0000000000..a0fe54f9d7 --- /dev/null +++ b/pkg/noun/v3/jets.h @@ -0,0 +1,12 @@ +/// @file + +#ifndef U3_JETS_V3_H +#define U3_JETS_V3_H + +#include "pkg/noun/jets.h" + + /** Aliases. + **/ +# define u3j_v3_free_hank u3j_free_hank + +#endif /* ifndef U3_JETS_V3_H */ diff --git a/pkg/noun/v3/manage.c b/pkg/noun/v3/manage.c new file mode 100644 index 0000000000..a15d5ad9be --- /dev/null +++ b/pkg/noun/v3/manage.c @@ -0,0 +1,107 @@ +/// @file + +#include "pkg/noun/v3/manage.h" + +#include "pkg/noun/v2/jets.h" +#include "pkg/noun/v2/nock.h" +#include "pkg/noun/v2/vortex.h" + +#include "pkg/noun/v3/allocate.h" +#include "pkg/noun/v3/hashtable.h" +#include "pkg/noun/version.h" +#include "pkg/noun/v3/vortex.h" +#include + +/* u3m_v3_migrate: perform loom migration if necessary. +*/ +void +u3m_v3_migrate() +{ + fprintf(stderr, "loom: memoization migration running...\r\n"); + + + c3_w ver_w = *(u3_Loom + u3C.wor_i - 1); + c3_w *mem_w = u3_Loom + u3a_v3_walign; + c3_w len_w = u3C.wor_i - u3a_v3_walign; + c3_w suz_w = c3_wiseof(u3v_v2_home); + c3_w *mut_w = c3_align(mem_w + len_w - suz_w, u3a_v3_balign, C3_ALGLO); + + // old road + u3v_v2_home* hum_u = (u3v_v2_home*)mut_w; + u3a_v2_road* rud_u = &hum_u->rod_u; + size_t ruz_t = sizeof(u3a_v2_road); + + // set v2 globals + u3H_v2 = (void *)mut_w; + u3R_v2 = &u3H_v2->rod_u; + u3R_v2->cap_p = u3R_v2->mat_p = u3a_v2_outa(u3H_v2); + + // free bytecode caches in old road + u3j_v2_reclaim(); + u3n_v2_reclaim(); + + // new home, new road + u3v_v3_home hom_u = {0}; + u3a_v3_road rod_u = {0}; + + // copy members, one-by-one, from old road to new road + rod_u.par_p = rud_u->par_p; + rod_u.kid_p = rud_u->kid_p; + rod_u.nex_p = rud_u->nex_p; + + rod_u.cap_p = rud_u->cap_p; + rod_u.hat_p = rud_u->hat_p; + rod_u.mat_p = rud_u->mat_p; + rod_u.rut_p = rud_u->rut_p; + rod_u.ear_p = rud_u->ear_p; + + // no need to zero-out fut_w + // no need to do anything with esc + + rod_u.how.fag_w = rud_u->how.fag_w; + + memcpy(rod_u.all.fre_p, rud_u->all.fre_p, sizeof(rud_u->all.fre_p)); + rod_u.all.cel_p = rud_u->all.cel_p; + rod_u.all.fre_w = rud_u->all.fre_w; + rod_u.all.max_w = rud_u->all.max_w; + + rod_u.jed.hot_p = rud_u->jed.hot_p; + rod_u.jed.war_p = rud_u->jed.war_p; + rod_u.jed.cod_p = rud_u->jed.cod_p; + rod_u.jed.han_p = rud_u->jed.han_p; + rod_u.jed.bas_p = rud_u->jed.bas_p; + + rod_u.byc.har_p = rud_u->byc.har_p; + + rod_u.ski.gul = rud_u->ski.gul; + + rod_u.bug.tax = rud_u->bug.tax; + rod_u.bug.mer = rud_u->bug.mer; + + rod_u.pro.nox_d = rud_u->pro.nox_d; + rod_u.pro.cel_d = rud_u->pro.cel_d; + rod_u.pro.don = rud_u->pro.don; + rod_u.pro.trace = rud_u->pro.trace; + rod_u.pro.day = rud_u->pro.day; + + rod_u.cax.har_p = rud_u->cax.har_p; + + // prepare the new home, update the version + hom_u.arv_u = hum_u->arv_u; + hom_u.rod_u = rod_u; + + // place the new home over the old one + c3_w siz_w = c3_wiseof(u3v_v3_home); + c3_w *mat_w = c3_align(mem_w + len_w - siz_w, u3a_v3_balign, C3_ALGLO); + memcpy(mat_w, &hom_u, sizeof(u3v_v3_home)); + + // set globals + u3H_v3 = (void*)mat_w; + u3R_v3 = &u3H_v3->rod_u; + u3H_v3->ver_w = U3V_VER3; + + // initialize persistent cache + u3R_v3->cax.per_p = u3h_v3_new_cache(u3C.per_w); + + fprintf(stderr, "loom: memoization migration done\r\n"); +} diff --git a/pkg/noun/v3/manage.h b/pkg/noun/v3/manage.h new file mode 100644 index 0000000000..5745a6316b --- /dev/null +++ b/pkg/noun/v3/manage.h @@ -0,0 +1,13 @@ +/// @file + +#ifndef U3_MANAGE_V3_H +#define U3_MANAGE_V3_H + + /** System management. + **/ + /* u3m_v3_migrate: perform memoization loom migration if necessary. + */ + void + u3m_v3_migrate(); + +#endif /* ifndef U3_MANAGE_V3_H */ diff --git a/pkg/noun/v3/nock.h b/pkg/noun/v3/nock.h new file mode 100644 index 0000000000..a7b208ba99 --- /dev/null +++ b/pkg/noun/v3/nock.h @@ -0,0 +1,17 @@ +/// @file + +#ifndef U3_NOCK_V3_H +#define U3_NOCK_V3_H + +#include "pkg/noun/nock.h" + +#include "types.h" + + /** Aliases. + **/ +# define u3n_v3_free u3n_free +# define u3n_v3_memo u3n_memo +# define u3n_v3_prog u3n_prog +# define u3n_v3_reclaim u3n_reclaim + +#endif /* ifndef U3_NOCK_V3_H */ diff --git a/pkg/noun/v3/vortex.h b/pkg/noun/v3/vortex.h new file mode 100644 index 0000000000..d47ac19654 --- /dev/null +++ b/pkg/noun/v3/vortex.h @@ -0,0 +1,19 @@ +/// @file + +#ifndef U3_VORTEX_V3_H +#define U3_VORTEX_V3_H + +#include "pkg/noun/vortex.h" + +#include "pkg/noun/v3/allocate.h" +#include "pkg/noun/version.h" + + /** Aliases. + **/ +# define u3v_v3_arvo u3v_arvo +# define u3H_v3 u3v_Home +# define u3A_v3 (&(u3H_v3)->arv_u) +# define u3v_v3_home u3v_home +# define u3v_v3_rewrite_compact u3v_rewrite_compact + +#endif /* ifndef U3_VORTEX_V3_H */ diff --git a/pkg/noun/version.h b/pkg/noun/version.h index f64d0a398e..bc81c83f5a 100644 --- a/pkg/noun/version.h +++ b/pkg/noun/version.h @@ -8,7 +8,8 @@ typedef c3_w u3v_version; #define U3V_VER1 1 #define U3V_VER2 2 -#define U3V_VERLAT U3V_VER2 +#define U3V_VER3 3 +#define U3V_VERLAT U3V_VER3 /* EVENTS */ diff --git a/pkg/noun/zave.c b/pkg/noun/zave.c index 0955af906c..596200f887 100644 --- a/pkg/noun/zave.c +++ b/pkg/noun/zave.c @@ -5,6 +5,7 @@ #include "allocate.h" #include "hashtable.h" #include "imprison.h" +#include "vortex.h" /* u3z_key(): construct a memo cache-key. Arguments retained. */ @@ -34,30 +35,60 @@ u3z_key_5(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua, u3_noun return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3nc(u3k(qua), u3k(qin)))); } +/* _har(): get the memo cache for the given cid. +*/ +static u3p(u3h_root) +_har(u3a_road* rod_u, u3z_cid cid) +{ + switch ( cid ) { + case u3z_memo_toss: + return rod_u->cax.har_p; + case u3z_memo_keep: + return rod_u->cax.per_p; + } + u3_assert(0); +} + /* u3z_find(): find in memo cache. Arguments retained. */ u3_weak -u3z_find(u3_noun key) +u3z_find(u3z_cid cid, u3_noun key) { - return u3h_get(u3R->cax.har_p, key); + if ( u3z_memo_toss == cid ) { + return u3h_get(_har(u3R, cid), key); + } + else { + // XX needs to be benchmarked (up vs. down search) + u3a_road* rod_u = &(u3H->rod_u); + while ( 1 ) { + u3_weak got = u3h_get(_har(rod_u, cid), key); + if ( u3_none != got ) { + return got; + } + if ( 0 == rod_u->kid_p ) { + return u3_none; + } + rod_u = u3to(u3a_road, rod_u->kid_p); + }; + } } u3_weak -u3z_find_m(c3_m fun, u3_noun one) +u3z_find_m(u3z_cid cid, c3_m fun, u3_noun one) { u3_noun key = u3nc(fun, u3k(one)); u3_weak val; - - val = u3h_get(u3R->cax.har_p, key); + val = u3z_find(cid, key); u3z(key); + return val; } /* u3z_save(): save in memo cache. TRANSFER key; RETAIN val */ u3_noun -u3z_save(u3_noun key, u3_noun val) +u3z_save(u3z_cid cid, u3_noun key, u3_noun val) { - u3h_put(u3R->cax.har_p, key, u3k(val)); + u3h_put(_har(u3R, cid), key, u3k(val)); u3z(key); return val; } @@ -65,28 +96,39 @@ u3z_save(u3_noun key, u3_noun val) /* u3z_save_m(): save in memo cache. Arguments retained. */ u3_noun -u3z_save_m(c3_m fun, u3_noun one, u3_noun val) +u3z_save_m(u3z_cid cid, c3_m fun, u3_noun one, u3_noun val) { u3_noun key = u3nc(fun, u3k(one)); - u3h_put(u3R->cax.har_p, key, u3k(val)); + u3h_put(_har(u3R, cid), key, u3k(val)); u3z(key); return val; } -/* u3z_uniq(): uniquify with memo cache. +/* u3z_uniq(): uniquify with memo cache. XX not used. */ u3_noun -u3z_uniq(u3_noun som) +u3z_uniq(u3z_cid cid, u3_noun som) { u3_noun key = u3nc(c3__uniq, u3k(som)); - u3_noun val = u3h_get(u3R->cax.har_p, key); + u3_noun val = u3h_get(_har(u3R, cid), key); if ( u3_none != val ) { u3z(key); u3z(som); return val; } else { - u3h_put(u3R->cax.har_p, key, u3k(som)); + u3h_put(_har(u3R, cid), key, u3k(som)); return som; } } + +/* u3z_reap(): promote memoization cache state. +*/ +void +u3z_reap(u3z_cid cid, u3p(u3h_root) har_p) +{ + u3_assert(u3z_memo_toss != cid); + + u3h_uni(_har(u3R, cid), har_p); + u3h_free(har_p); +} diff --git a/pkg/noun/zave.h b/pkg/noun/zave.h index 44f272da7c..feff83f664 100644 --- a/pkg/noun/zave.h +++ b/pkg/noun/zave.h @@ -12,10 +12,18 @@ *** and a noun argument to that (logical) function. Functions *** are predefined by C-level callers, but 0 means nock. *** - *** The memo cache is within its road and dies when it falls. - *** *** Memo functions RETAIN keys and transfer values. **/ + /* u3z_cid: cache id + */ + typedef enum { + u3z_memo_toss = 0, + u3z_memo_keep = 1, + // u3z_memo_ford = 2, + // u3z_memo_ames = 3, + // ... + } u3z_cid; + /* u3z_key*(): construct a memo cache-key. Arguments retained. */ u3_noun u3z_key(c3_m, u3_noun); @@ -26,20 +34,35 @@ /* u3z_find*(): find in memo cache. Arguments retained */ - u3_weak u3z_find(u3_noun key); - u3_weak u3z_find_m(c3_m fun_m, u3_noun one); + u3_weak u3z_find(u3z_cid cid, u3_noun key); + u3_weak u3z_find_m(u3z_cid cid, c3_m fun_m, u3_noun one); /* u3z_save(): save in memo cache. TRANSFER key; RETAIN val; */ - u3_noun u3z_save(u3_noun key, u3_noun val); + u3_noun u3z_save(u3z_cid cid, u3_noun key, u3_noun val); /* u3z_save_m(): save in memo cache. Arguments retained */ - u3_noun u3z_save_m(c3_m fun_m, u3_noun one, u3_noun val); + u3_noun u3z_save_m(u3z_cid cid, c3_m fun_m, u3_noun one, u3_noun val); /* u3z_uniq(): uniquify with memo cache. */ u3_noun - u3z_uniq(u3_noun som); + u3z_uniq(u3z_cid cid, u3_noun som); + + /* u3z_reap(): promote memoization cache state. + */ + void + u3z_reap(u3z_cid cid, u3p(u3h_root) har_p); + + /* u3z_free(): free memoization cache. + */ + void + u3z_free(u3z_cid cid); + + /* u3z_ream(): refresh after restoring from checkpoint. + */ + void + u3z_ream(u3z_cid cid); #endif /* ifndef U3_ZAVE_H */ diff --git a/pkg/vere/BUILD.bazel b/pkg/vere/BUILD.bazel index 76f8b47eca..f856ce0047 100644 --- a/pkg/vere/BUILD.bazel +++ b/pkg/vere/BUILD.bazel @@ -301,7 +301,7 @@ genrule( if check && sleep 10 && check; then echo "boot success" - lensa hood "+hood/exit" + lensa hood '+hood/exit' while [ -f ./pier/.vere.lock ]; do echo "waiting for pier to shut down" sleep 5 diff --git a/pkg/vere/lord.c b/pkg/vere/lord.c index cf1dfcfba9..a63824ae9b 100644 --- a/pkg/vere/lord.c +++ b/pkg/vere/lord.c @@ -1160,10 +1160,11 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) // spawn new process and connect to it // { - c3_c* arg_c[11]; + c3_c* arg_c[12]; c3_c key_c[256]; c3_c wag_c[11]; c3_c hap_c[11]; + c3_c per_c[11]; c3_c cev_c[11]; c3_c lom_c[11]; c3_c tos_c[11]; @@ -1179,6 +1180,8 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) sprintf(hap_c, "%u", u3_Host.ops_u.hap_w); + sprintf(per_c, "%u", u3_Host.ops_u.per_w); + sprintf(lom_c, "%u", u3_Host.ops_u.lom_y); sprintf(tos_c, "%u", u3C.tos_w); @@ -1208,7 +1211,8 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) } arg_c[9] = tos_c; - arg_c[10] = NULL; + arg_c[10] = per_c; + arg_c[11] = NULL; uv_pipe_init(u3L, &god_u->inn_u.pyp_u, 0); uv_timer_init(u3L, &god_u->out_u.tim_u); diff --git a/pkg/vere/main.c b/pkg/vere/main.c index f83d656e98..c35b7ff2e4 100644 --- a/pkg/vere/main.c +++ b/pkg/vere/main.c @@ -183,6 +183,9 @@ _main_init(void) u3_Host.ops_u.veb = c3n; u3_Host.ops_u.puf_c = "jam"; u3_Host.ops_u.hap_w = 50000; + u3C.hap_w = u3_Host.ops_u.hap_w; + u3_Host.ops_u.per_w = 50000; + u3C.per_w = u3_Host.ops_u.per_w; u3_Host.ops_u.kno_w = DefaultKernel; u3_Host.ops_u.sap_w = 120; /* aka 2 minutes */ @@ -247,6 +250,7 @@ _main_getopt(c3_i argc, c3_c** argv) { "loom", required_argument, NULL, c3__loom }, { "local", no_argument, NULL, 'L' }, { "lite-boot", no_argument, NULL, 'l' }, + { "keep-cache-limit", required_argument, NULL, 'M' }, { "replay-to", required_argument, NULL, 'n' }, { "profile", no_argument, NULL, 'P' }, { "ames-port", required_argument, NULL, 'p' }, @@ -279,7 +283,7 @@ _main_getopt(c3_i argc, c3_c** argv) }; while ( -1 != (ch_i=getopt_long(argc, argv, - "A:B:C:DF:G:H:I:J:K:LPRSX:Y:Z:ab:c:de:gi:jk:ln:p:qr:stu:vw:x", + "A:B:C:DF:G:H:I:J:K:LM:PRSX:Y:Z:ab:c:de:gi:jk:ln:p:qr:stu:vw:x", lop_u, &lid_i)) ) { switch ( ch_i ) { @@ -342,7 +346,7 @@ _main_getopt(c3_i argc, c3_c** argv) return c3n; } else { u3_Host.ops_u.sap_w = arg_w * 60; - if ( 0 == u3_Host.ops_u.sap_w) + if ( 0 == u3_Host.ops_u.sap_w ) return c3n; } break; @@ -365,6 +369,7 @@ _main_getopt(c3_i argc, c3_c** argv) if ( c3n == _main_readw(optarg, 1000000000, &u3_Host.ops_u.hap_w) ) { return c3n; } + u3C.hap_w = u3_Host.ops_u.hap_w; break; } case 'c': { @@ -412,6 +417,13 @@ _main_getopt(c3_i argc, c3_c** argv) u3_Host.ops_u.key_c = _main_repath(optarg); break; } + case 'M': { + if ( c3n == _main_readw(optarg, 1000000000, &u3_Host.ops_u.per_w) ) { + return c3n; + } + u3C.per_w = u3_Host.ops_u.per_w; + break; + } case 'n': { u3_Host.ops_u.til_c = strdup(optarg); break; @@ -764,6 +776,7 @@ u3_ve_usage(c3_i argc, c3_c** argv) "-L, --local Local networking only\n", " --loom Set loom to binary exponent (31 == 2GB)\n" "-l, --lite-boot Most-minimal startup\n", + "-M, --keep-cache-limit LIMIT Set persistent memo cache max size; 0 means default\n", "-n, --replay-to NUMBER Replay up to event\n", "-P, --profile Profiling\n", "-p, --ames-port PORT Set the ames port to bind to\n", @@ -1075,6 +1088,8 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) exit(1); } + // XX use named arguments and getopt + c3_d eve_d = 0; uv_loop_t* lup_u = u3_Host.lup_u = uv_default_loop(); c3_c* dir_c = argv[2]; @@ -1086,6 +1101,7 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) c3_c* eve_c = argv[7]; c3_c* eph_c = argv[8]; c3_c* tos_c = argv[9]; + c3_c* per_c = argv[10]; c3_w tos_w; _cw_init_io(lup_u); @@ -1110,7 +1126,8 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) // XX check return // sscanf(wag_c, "%" SCNu32, &u3C.wag_w); - sscanf(hap_c, "%" SCNu32, &u3_Host.ops_u.hap_w); + sscanf(hap_c, "%" SCNu32, &u3C.hap_w); + sscanf(per_c, "%" SCNu32, &u3C.per_w); sscanf(lom_c, "%" SCNu32, &lom_w); if ( 1 != sscanf(tos_c, "%" SCNu32, &u3C.tos_w) ) { diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index cef16810b6..2bf976c1dd 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -263,7 +263,7 @@ c3_o abo; // -a, abort aggressively c3_c* pil_c; // -B, bootstrap from c3_c* bin_c; // -b, http server bind ip - c3_w hap_w; // -C, cap memo cache + c3_w hap_w; // -C, cap transient memo cache c3_o dry; // -D, dry compute, no checkpoint c3_o dem; // -d, daemon c3_c* eth_c; // -e, ethereum node url @@ -281,6 +281,7 @@ c3_o lit; // -l, lite mode c3_y lom_y; // loom bex c3_y lut_y; // urth-loom bex + c3_w per_w; // -M, cap persistent memo cache c3_c* til_c; // -n, play till eve_d c3_o pro; // -P, profile c3_s per_s; // http port From f2436a6867b1b2fa60eefeb7a586f8ecd1a6e17e Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 11 Oct 2023 10:07:45 -0400 Subject: [PATCH 05/17] u3: revises free-list bounds --- pkg/noun/allocate.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index ace4473a4a..8cf2daaff9 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -76,27 +76,28 @@ _box_count(c3_ws siz_ws) { } } while(0) /* _box_slot(): select the right free list to search for a block. - TODO: do we really need a loop to do this? - - so our free list logic looks like this: - siz_w < 6 words then [0] - siz_w < 16 then [1] - siz_w < 32 then [2] - siz_w < 64 then [3] - ... - siz_w > 4G then [26] +** +** siz_w == 6 words then [0] +** siz_w < 16 then [1] +** siz_w < 32 then [2] +** siz_w < 64 then [3] +** ... +** siz_w >= 2GB then [26] */ static c3_w _box_slot(c3_w siz_w) { - if ( siz_w < u3a_minimum ) { - return 0; - } + if ( u3a_minimum == siz_w ) return 0; + + c3_dessert( u3a_minimum <= siz_w ); - for (c3_w i_w = 1; i_w < u3a_fbox_no; i_w++) { - if ( siz_w < 16 ) return i_w; - siz_w = (siz_w + 1) >> 1; + { + c3_w bit_w = c3_bits_word(siz_w); + + if ( 5 > bit_w ) return 1; + if ( (u3a_fbox_no + 1) >= bit_w ) return bit_w - 3; } + return u3a_fbox_no - 1; } From a1d23cee125b8408cb692786b0a10ceb610389d3 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 11 Oct 2023 10:08:54 -0400 Subject: [PATCH 06/17] u3: adds free-list migration to account for new bounds --- pkg/noun/allocate.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ pkg/noun/allocate.h | 5 ++++ pkg/noun/manage.c | 4 +++ 3 files changed, 72 insertions(+) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 8cf2daaff9..a23c1231a2 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -2318,6 +2318,69 @@ u3a_idle(u3a_road* rod_u) return fre_w; } +/* u3a_ream(): ream free-lists. +*/ +void +u3a_ream(void) +{ + u3p(u3a_fbox) lit_p; + u3a_fbox* fox_u; + c3_w sel_w, i_w; + + for ( i_w = 0; i_w < u3a_fbox_no; i_w++ ) { + lit_p = u3R->all.fre_p[i_w]; + + while ( lit_p ) { + fox_u = u3to(u3a_fbox, lit_p); + lit_p = fox_u->nex_p; + sel_w = _box_slot(fox_u->box_u.siz_w); + + if ( sel_w != i_w ) { + // inlined _box_detach() + // + { + u3p(u3a_fbox) fre_p = u3of(u3a_fbox, &(fox_u->box_u)); + u3p(u3a_fbox) pre_p = u3to(u3a_fbox, fre_p)->pre_p; + u3p(u3a_fbox) nex_p = u3to(u3a_fbox, fre_p)->nex_p; + + if ( nex_p ) { + if ( u3to(u3a_fbox, nex_p)->pre_p != fre_p ) { + u3_assert(!"loom: corrupt"); + } + u3to(u3a_fbox, nex_p)->pre_p = pre_p; + } + if ( pre_p ) { + if( u3to(u3a_fbox, pre_p)->nex_p != fre_p ) { + u3_assert(!"loom: corrupt"); + } + u3to(u3a_fbox, pre_p)->nex_p = nex_p; + } + else { + if ( fre_p != u3R->all.fre_p[i_w] ) { + u3_assert(!"loom: corrupt"); + } + u3R->all.fre_p[i_w] = nex_p; + } + } + + // inlined _box_attach() + { + u3p(u3a_fbox) fre_p = u3of(u3a_fbox, &(fox_u->box_u)); + u3p(u3a_fbox)* pfr_p = &u3R->all.fre_p[sel_w]; + u3p(u3a_fbox) nex_p = *pfr_p; + + u3to(u3a_fbox, fre_p)->pre_p = 0; + u3to(u3a_fbox, fre_p)->nex_p = nex_p; + if ( nex_p ) { + u3to(u3a_fbox, nex_p)->pre_p = fre_p; + } + (*pfr_p) = fre_p; + } + } + } + } +} + /* u3a_sweep(): sweep a fully marked road. */ c3_w diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 7355954abd..c6fab95102 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -683,6 +683,11 @@ c3_w u3a_idle(u3a_road* rod_u); + /* u3a_ream(): ream free-lists. + */ + void + u3a_ream(void); + /* u3a_sweep(): sweep a fully marked road. */ c3_w diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 5ff7d7b129..29833d001c 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -639,6 +639,10 @@ _find_home(void) } } + // XX move me + // + u3a_ream(); + /* As a further guard against any sneaky loom corruption */ u3a_loom_sane(); From 3553e43531eba85f7f8617152534000562dd7177 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 11 Oct 2023 10:31:41 -0400 Subject: [PATCH 07/17] u3: use u3a_celloc() in u3a_take() --- pkg/noun/allocate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index a23c1231a2..90f1b624fc 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -1123,9 +1123,7 @@ _ca_take_atom(u3a_atom* old_u) static inline u3_cell _ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel) { - // XX use u3a_celloc? - // - c3_w* new_w = u3a_walloc(c3_wiseof(u3a_cell)); + c3_w* new_w = u3a_celloc(); u3a_cell* new_u = (u3a_cell*)(void *)new_w; u3_cell new = u3a_to_pom(u3a_outa(new_u)); From 2dc7d181de8b41d5989a5dbf424980645341904d Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 12 Oct 2023 21:50:58 -0400 Subject: [PATCH 08/17] u3: refactors _box_slot() --- pkg/noun/allocate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 90f1b624fc..ae022592c2 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -87,18 +87,18 @@ _box_count(c3_ws siz_ws) { } static c3_w _box_slot(c3_w siz_w) { - if ( u3a_minimum == siz_w ) return 0; - - c3_dessert( u3a_minimum <= siz_w ); - - { - c3_w bit_w = c3_bits_word(siz_w); - - if ( 5 > bit_w ) return 1; - if ( (u3a_fbox_no + 1) >= bit_w ) return bit_w - 3; + if ( u3a_minimum == siz_w ) { + return 0; + } + else if ( !(siz_w >> 4) ) { + c3_dessert( u3a_minimum < siz_w ); + return 1; + } + else { + c3_w bit_w = c3_bits_word(siz_w) - 3; + c3_w max_w = u3a_fbox_no - 1; + return c3_min(bit_w, max_w); } - - return u3a_fbox_no - 1; } /* _box_make(): construct a box. From c19da037dbd1464f24b1d1afdffe380132667425 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 25 Oct 2023 13:49:27 -0400 Subject: [PATCH 09/17] serf: adds stateful memory-pressure thresholds --- pkg/vere/serf.c | 69 +++++++++++++++++++++++++++++++++++++------------ pkg/vere/serf.h | 1 + 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index cfbbc47be3..f61883ef29 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -198,6 +198,22 @@ u3_serf_post(u3_serf* sef_u) } } +/* _serf_curb(): check for memory threshold +*/ +static inline c3_t +_serf_curb(c3_w pre_w, c3_w pos_w, c3_w hes_w) +{ + return (pre_w > hes_w) && (pos_w <= hes_w); +} + +/* serf memory-threshold levels +*/ +enum { + _serf_init = 0, + _serf_hit1 = 1, + _serf_hit0 = 2 +}; + /* _serf_sure_feck(): event succeeded, send effects. */ static u3_noun @@ -253,38 +269,59 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) // For future flexibility, the urgency of the notification is represented // by a *decreasing* number: 0 is maximally urgent, 1 less so, &c. // - // high-priority: 2^22 contiguous words remaining (~8 MB) + // high-priority: 2^25 contiguous words remaining (~128 MB) // low-priority: 2^27 contiguous words remaining (~536 MB) - // XX maybe use 2^23 (~16 MB) and 2^26 (~268 MB? + // + // once a threshold is hit, it's not a candidate to be hit again + // until memory usage falls below: + // + // high-priority: 2^26 contiguous words remaining (~256 MB) + // low-priority: 2^26 + 2^27 contiguous words remaining (~768 MB) // // XX these thresholds should trigger notifications sent to the king // instead of directly triggering these remedial actions. // { u3_noun pri = u3_none; - c3_w pos_w = u3a_open(u3R); - c3_w low_w = (1 << 27); - c3_w hig_w = (1 << 22); + c3_w pos_w = u3a_open(u3R); - if ( (pre_w > low_w) && !(pos_w > low_w) ) { - // XX set flag(s) in u3V so we don't repeat endlessly? - // - pac_o = c3y; - rec_o = c3y; - pri = 1; + // if contiguous free space shrunk, check thresholds + // (and track state to avoid thrashing) + // + if ( pos_w < pre_w ) { + if ( (_serf_hit0 != sef_u->mas_w) + && _serf_curb(pre_w, pos_w, 1 << 25) ) + { + sef_u->mas_w = _serf_hit0; + pac_o = c3y; + pri = 0; + } + else if ( (_serf_init == sef_u->mas_w) + && _serf_curb(pre_w, pos_w, 1 << 27) ) + { + sef_u->mas_w = _serf_hit1; + rec_o = c3y; + pri = 1; + } } - else if ( (pre_w > hig_w) && !(pos_w > hig_w) ) { - pac_o = c3y; - rec_o = c3y; - pri = 0; + else if ( _serf_init != sef_u->mas_w ) { + if ( ((1 << 26) + (1 << 27)) < pos_w ) { + sef_u->mas_w = _serf_init; + } + else if ( (_serf_hit0 == sef_u->mas_w) + && ((1 << 26) < pos_w) ) + { + sef_u->mas_w = _serf_hit1; + } } + // reclaim memory from persistent caches periodically // // XX this is a hack to work two things // - bytecode caches grow rapidly and can't be simply capped // - we don't make very effective use of our free lists // - else if ( 0 == (sef_u->dun_d % 1000ULL) ) { + if ( 0 == (sef_u->dun_d % 1000ULL) ) { rec_o = c3y; } diff --git a/pkg/vere/serf.h b/pkg/vere/serf.h index 5808f362e7..08dbec9cd3 100644 --- a/pkg/vere/serf.h +++ b/pkg/vere/serf.h @@ -11,6 +11,7 @@ c3_d sen_d; // last event requested c3_d dun_d; // last event processed c3_l mug_l; // hash of state + c3_w mas_w; // memory threshold state c3_o pac_o; // pack kernel c3_o rec_o; // reclaim cache c3_o mut_o; // mutated kerne From 280ac6a5e1d274f196da895b56d79cd1ca150325 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 25 Oct 2023 14:06:25 -0400 Subject: [PATCH 10/17] serf: switch to bitmap for post-ops, track granularly --- pkg/vere/serf.c | 80 +++++++++++++++++++++++++------------------------ pkg/vere/serf.h | 4 +-- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index f61883ef29..80a5b1ccf3 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -51,6 +51,25 @@ :: next steps: -- */ +/* serf memory-threshold levels +*/ +enum { + _serf_mas_init = 0, // initial + _serf_mas_hit1 = 1, // past low threshold + _serf_mas_hit0 = 2 // have high threshold +}; + +/* serf post-op flags +*/ +enum { + _serf_fag_none = 0, // nothing to do + _serf_fag_hit1 = 1 << 0, // hit low threshold + _serf_fag_hit0 = 1 << 1, // hit high threshold + _serf_fag_mute = 1 << 2, // mutated state + _serf_fag_much = 1 << 3, // bytecode hack + _serf_fag_vega = 1 << 4 // kernel reset +}; + /* _serf_grab(): garbage collect, checking for profiling. RETAIN. */ static void @@ -174,28 +193,27 @@ u3_serf_grab(void) void u3_serf_post(u3_serf* sef_u) { - if ( c3y == sef_u->rec_o ) { + if ( sef_u->fag_w & (_serf_fag_hit1|_serf_fag_much|_serf_fag_vega) ) { u3m_reclaim(); - sef_u->rec_o = c3n; } // XX this runs on replay too, |mass s/b elsewhere // - if ( c3y == sef_u->mut_o ) { + if ( sef_u->fag_w & _serf_fag_mute ) { _serf_grab(sef_u->sac); sef_u->sac = u3_nul; - sef_u->mut_o = c3n; } - if ( c3y == sef_u->pac_o ) { + if ( sef_u->fag_w & _serf_fag_hit0 ) { u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); u3l_log(""); - sef_u->pac_o = c3n; } if ( u3C.wag_w & u3o_toss ) { u3m_toss(); } + + sef_u->fag_w = _serf_fag_none; } /* _serf_curb(): check for memory threshold @@ -206,22 +224,11 @@ _serf_curb(c3_w pre_w, c3_w pos_w, c3_w hes_w) return (pre_w > hes_w) && (pos_w <= hes_w); } -/* serf memory-threshold levels -*/ -enum { - _serf_init = 0, - _serf_hit1 = 1, - _serf_hit0 = 2 -}; - /* _serf_sure_feck(): event succeeded, send effects. */ static u3_noun _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) { - c3_o rec_o = c3n; - c3_o pac_o = c3n; - // intercept |mass, observe |reset // { @@ -252,7 +259,7 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) // reclaim memory from persistent caches on |reset // if ( c3__vega == u3h(fec) ) { - rec_o = c3y; + sef_u->fag_w |= _serf_fag_vega; } riv = u3t(riv); @@ -289,29 +296,29 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) // (and track state to avoid thrashing) // if ( pos_w < pre_w ) { - if ( (_serf_hit0 != sef_u->mas_w) + if ( (_serf_mas_hit0 != sef_u->mas_w) && _serf_curb(pre_w, pos_w, 1 << 25) ) { - sef_u->mas_w = _serf_hit0; - pac_o = c3y; - pri = 0; + sef_u->mas_w = _serf_mas_hit0; + sef_u->fag_w |= _serf_fag_hit0; + pri = 0; } - else if ( (_serf_init == sef_u->mas_w) + else if ( (_serf_mas_init == sef_u->mas_w) && _serf_curb(pre_w, pos_w, 1 << 27) ) { - sef_u->mas_w = _serf_hit1; - rec_o = c3y; - pri = 1; + sef_u->mas_w = _serf_mas_hit1; + sef_u->fag_w |= _serf_fag_hit1; + pri = 1; } } - else if ( _serf_init != sef_u->mas_w ) { + else if ( _serf_mas_init != sef_u->mas_w ) { if ( ((1 << 26) + (1 << 27)) < pos_w ) { - sef_u->mas_w = _serf_init; + sef_u->mas_w = _serf_mas_init; } - else if ( (_serf_hit0 == sef_u->mas_w) + else if ( (_serf_mas_hit0 == sef_u->mas_w) && ((1 << 26) < pos_w) ) { - sef_u->mas_w = _serf_hit1; + sef_u->mas_w = _serf_mas_hit1; } } @@ -321,8 +328,8 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) // - bytecode caches grow rapidly and can't be simply capped // - we don't make very effective use of our free lists // - if ( 0 == (sef_u->dun_d % 1000ULL) ) { - rec_o = c3y; + if ( !(sef_u->dun_d % 1024ULL) ) { + sef_u->fag_w |= _serf_fag_much; } // notify daemon of memory pressure via "fake" effect @@ -334,9 +341,6 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) } } - sef_u->rec_o = c3o(sef_u->rec_o, rec_o); - sef_u->pac_o = c3o(sef_u->pac_o, pac_o); - return vir; } @@ -351,7 +355,7 @@ _serf_sure_core(u3_serf* sef_u, u3_noun cor) u3A->roc = cor; u3A->eve_d = sef_u->dun_d; sef_u->mug_l = u3r_mug(u3A->roc); - sef_u->mut_o = c3y; + sef_u->fag_w |= _serf_fag_mute; } /* _serf_sure(): event succeeded, save state and process effects. @@ -1053,9 +1057,7 @@ u3_serf_init(u3_serf* sef_u) // } // } - sef_u->pac_o = c3n; - sef_u->rec_o = c3n; - sef_u->mut_o = c3n; + sef_u->fag_w = _serf_fag_none; sef_u->sac = u3_nul; return rip; diff --git a/pkg/vere/serf.h b/pkg/vere/serf.h index 08dbec9cd3..7cd2ca47d0 100644 --- a/pkg/vere/serf.h +++ b/pkg/vere/serf.h @@ -12,9 +12,7 @@ c3_d dun_d; // last event processed c3_l mug_l; // hash of state c3_w mas_w; // memory threshold state - c3_o pac_o; // pack kernel - c3_o rec_o; // reclaim cache - c3_o mut_o; // mutated kerne + c3_w fag_w; // post-op flags u3_noun sac; // space measurementl void (*xit_f)(void); // exit callback } u3_serf; From a887608d17bc62a48c3d0c32db35e1b54e7d435c Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Tue, 7 Nov 2023 11:10:14 -0500 Subject: [PATCH 11/17] vere: refactors event log metadata reading to avoid the loom --- pkg/vere/db/lmdb.c | 8 +-- pkg/vere/db/lmdb.h | 2 +- pkg/vere/disk.c | 138 +++++++++++++++++++++++++++++---------------- 3 files changed, 95 insertions(+), 53 deletions(-) diff --git a/pkg/vere/db/lmdb.c b/pkg/vere/db/lmdb.c index 8f8864b77f..f7554019a4 100644 --- a/pkg/vere/db/lmdb.c +++ b/pkg/vere/db/lmdb.c @@ -414,7 +414,7 @@ void u3_lmdb_read_meta(MDB_env* env_u, void* ptr_v, const c3_c* key_c, - void (*read_f)(void*, size_t, void*)) + void (*read_f)(void*, ssize_t, void*)) { MDB_txn* txn_u; MDB_dbi mdb_u; @@ -424,7 +424,7 @@ u3_lmdb_read_meta(MDB_env* env_u, // if ( (ret_w = mdb_txn_begin(env_u, 0, MDB_RDONLY, &txn_u)) ) { mdb_logerror(stderr, ret_w, "lmdb: meta read: txn_begin fail"); - return read_f(ptr_v, 0, 0); + return read_f(ptr_v, -1, 0); } // open the database in the transaction @@ -432,7 +432,7 @@ u3_lmdb_read_meta(MDB_env* env_u, if ( (ret_w = mdb_dbi_open(txn_u, "META", 0, &mdb_u)) ) { mdb_logerror(stderr, ret_w, "lmdb: meta read: dbi_open fail"); mdb_txn_abort(txn_u); - return read_f(ptr_v, 0, 0); + return read_f(ptr_v, -1, 0); } // read by string key, invoking callback with result @@ -443,7 +443,7 @@ u3_lmdb_read_meta(MDB_env* env_u, if ( (ret_w = mdb_get(txn_u, mdb_u, &key_u, &val_u)) ) { mdb_logerror(stderr, ret_w, "lmdb: read failed"); mdb_txn_abort(txn_u); - return read_f(ptr_v, 0, 0); + return read_f(ptr_v, -1, 0); } else { read_f(ptr_v, val_u.mv_size, val_u.mv_data); diff --git a/pkg/vere/db/lmdb.h b/pkg/vere/db/lmdb.h index aab4e6c9f7..43c6b433ff 100644 --- a/pkg/vere/db/lmdb.h +++ b/pkg/vere/db/lmdb.h @@ -63,7 +63,7 @@ u3_lmdb_read_meta(MDB_env* env_u, void* ptr_v, const c3_c* key_c, - void (*read_f)(void*, size_t, void*)); + void (*read_f)(void*, ssize_t, void*)); /* u3_lmdb_save_meta(): save by string into the META db. */ diff --git a/pkg/vere/disk.c b/pkg/vere/disk.c index 45a2c21cef..4f48487e1d 100644 --- a/pkg/vere/disk.c +++ b/pkg/vere/disk.c @@ -662,26 +662,26 @@ u3_disk_save_meta(MDB_env* mdb_u, return c3y; } +typedef struct { + ssize_t hav_i; + c3_y buf_y[16]; +} _mdb_val; + + /* _disk_meta_read_cb(): copy [val_p] to atom [ptr_v] if present. */ static void -_disk_meta_read_cb(void* ptr_v, size_t val_i, void* val_p) +_disk_meta_read_cb(void* ptr_v, ssize_t val_i, void* val_v) { - u3_weak* mat = ptr_v; + _mdb_val* val_u = ptr_v; + c3_y* dat_y = (c3_y*)val_v; - if ( val_p ) { - *mat = u3i_bytes(val_i, val_p); - } -} + memset(val_u->buf_y, 0, sizeof(val_u->buf_y)); + val_u->hav_i = val_i; -/* _disk_read_meta(): read metadata at [key_c], deserialize. -*/ -static u3_weak -_disk_read_meta(MDB_env* mdb_u, const c3_c* key_c) -{ - u3_weak dat = u3_none; - u3_lmdb_read_meta(mdb_u, &dat, key_c, _disk_meta_read_cb); - return dat; + if ( 0 < val_i ) { + memcpy(val_u->buf_y, dat_y, c3_min(val_i, sizeof(val_u->buf_y))); + } } /* u3_disk_read_meta(): read metadata. @@ -692,60 +692,102 @@ u3_disk_read_meta(MDB_env* mdb_u, c3_o* fak_o, c3_w* lif_w) { - u3_weak ver, who, fak, lif; + _mdb_val val_u; - if ( u3_none == (ver = _disk_read_meta(mdb_u, "version")) ) { + // version + // + u3_lmdb_read_meta(mdb_u, &val_u, "version", _disk_meta_read_cb); + + if ( 0 > val_u.hav_i ) { fprintf(stderr, "disk: read meta: no version\r\n"); return c3n; } - if ( u3_none == (who = _disk_read_meta(mdb_u, "who")) ) { - fprintf(stderr, "disk: read meta: no indentity\r\n"); + else if ( (1 != val_u.hav_i) || (1 != *val_u.buf_y) ) { + fprintf(stderr, "disk: read meta: unknown version %u\r\n", *val_u.buf_y); return c3n; } - if ( u3_none == (fak = _disk_read_meta(mdb_u, "fake")) ) { - fprintf(stderr, "disk: read meta: no fake bit\r\n"); + + // identity + // + u3_lmdb_read_meta(mdb_u, &val_u, "who", _disk_meta_read_cb); + + if ( 0 > val_u.hav_i ) { + fprintf(stderr, "disk: read meta: no identity\r\n"); return c3n; } - if ( u3_none == (lif = _disk_read_meta(mdb_u, "life")) ) { - fprintf(stderr, "disk: read meta: no lifecycle length\r\n"); - return c3n; + else if ( 16 < val_u.hav_i ) { + // NB: non-fatal + // + fprintf(stderr, "disk: read meta: strange identity\r\n"); } - { - c3_o val_o = c3y; - - if ( 1 != ver ) { - fprintf(stderr, "disk: read meta: unknown version %u\r\n", ver); - val_o = c3n; - } - else if ( !((c3y == fak ) || (c3n == fak )) ) { - fprintf(stderr, "disk: read meta: invalid fake bit\r\n"); - val_o = c3n; - } - else if ( c3n == u3a_is_cat(lif) ) { - fprintf(stderr, "disk: read meta: invalid lifecycle length\r\n"); - val_o = c3n; - } + if ( who_d ) { + c3_y* byt_y = val_u.buf_y; + + who_d[0] = (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; + + byt_y += 8; + who_d[1] = (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; + } + + // fake bit + // + u3_lmdb_read_meta(mdb_u, &val_u, "fake", _disk_meta_read_cb); - if ( c3n == val_o ) { - u3z(ver); u3z(who); u3z(fak); u3z(lif); - return c3n; + if ( 0 > val_u.hav_i ) { + fprintf(stderr, "disk: read meta: no fake bit\r\n"); + return c3n; + } + else if ( 0 == val_u.hav_i ) { + if ( fak_o ) { + *fak_o = 0; } } - - if ( who_d ) { - u3r_chubs(0, 2, who_d, who); + else if ( (1 == val_u.hav_i) || !((*val_u.buf_y) >> 1) ) { + *fak_o = 1; } + else { + fprintf(stderr, "disk: read meta: invalid fake bit %u %zd\r\n", + *val_u.buf_y, val_u.hav_i); + return c3n; + } + + // life + // + u3_lmdb_read_meta(mdb_u, &val_u, "life", _disk_meta_read_cb); - if ( fak_o ) { - *fak_o = fak; + if ( 0 > val_u.hav_i ) { + fprintf(stderr, "disk: read meta: no lifecycle length\r\n"); + return c3n; + } + else if ( 4 < val_u.hav_i ) { + // NB: non-fatal + // + fprintf(stderr, "disk: read meta: strange life\r\n"); } if ( lif_w ) { - *lif_w = lif; + c3_y* byt_y = val_u.buf_y; + *lif_w = (c3_w)byt_y[0] + | (c3_w)byt_y[1] << 8 + | (c3_w)byt_y[2] << 16 + | (c3_w)byt_y[3] << 24; } - u3z(who); return c3y; } From a85aa21aa9e5a62b332a3ba40cc088f979dcb756 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Tue, 7 Nov 2023 13:00:35 -0500 Subject: [PATCH 12/17] vere: set fake bit explicitly from event log metadata --- pkg/vere/disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vere/disk.c b/pkg/vere/disk.c index 4f48487e1d..a3cf36b8af 100644 --- a/pkg/vere/disk.c +++ b/pkg/vere/disk.c @@ -758,7 +758,7 @@ u3_disk_read_meta(MDB_env* mdb_u, } } else if ( (1 == val_u.hav_i) || !((*val_u.buf_y) >> 1) ) { - *fak_o = 1; + *fak_o = (*val_u.buf_y) & 1; } else { fprintf(stderr, "disk: read meta: invalid fake bit %u %zd\r\n", From 582edbc2468c1dd00d0ede595cdf494f6d7e0bc8 Mon Sep 17 00:00:00 2001 From: Pyry Kovanen Date: Wed, 8 Nov 2023 15:52:17 +0200 Subject: [PATCH 13/17] disk: check for null pointer when writing through fak_o --- pkg/vere/disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/vere/disk.c b/pkg/vere/disk.c index a3cf36b8af..de141988bd 100644 --- a/pkg/vere/disk.c +++ b/pkg/vere/disk.c @@ -758,7 +758,9 @@ u3_disk_read_meta(MDB_env* mdb_u, } } else if ( (1 == val_u.hav_i) || !((*val_u.buf_y) >> 1) ) { - *fak_o = (*val_u.buf_y) & 1; + if ( fak_o ) { + *fak_o = (*val_u.buf_y) & 1; + } } else { fprintf(stderr, "disk: read meta: invalid fake bit %u %zd\r\n", From b05a7dd9f7c138443ff4cd47a96d0d98af0b71de Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 25 Oct 2023 14:17:04 -0400 Subject: [PATCH 14/17] serf: trim persistent nock cache as appropriate --- pkg/vere/serf.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index 80a5b1ccf3..7cc26d2ae9 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -193,7 +193,18 @@ u3_serf_grab(void) void u3_serf_post(u3_serf* sef_u) { - if ( sef_u->fag_w & (_serf_fag_hit1|_serf_fag_much|_serf_fag_vega) ) { + if ( sef_u->fag_w & _serf_fag_hit1 ) { + u3h_trim_to(u3R->cax.per_p, u3h_wyt(u3R->cax.per_p) / 2); + u3m_reclaim(); + } + + if ( sef_u->fag_w & _serf_fag_much ) { + u3m_reclaim(); + } + + if ( sef_u->fag_w & _serf_fag_vega ) { + u3h_free(u3R->cax.per_p); + u3R->cax.per_p = u3h_new_cache(u3C.per_w); u3m_reclaim(); } @@ -205,6 +216,8 @@ u3_serf_post(u3_serf* sef_u) } if ( sef_u->fag_w & _serf_fag_hit0 ) { + u3h_free(u3R->cax.per_p); + u3R->cax.per_p = u3h_new_cache(u3C.per_w); u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); u3l_log(""); } From 5fe3d1c5ab40201d008309c188939adba5f637a3 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 25 Oct 2023 14:19:58 -0400 Subject: [PATCH 15/17] serf: adds pnc threshold printfs (under -v) --- pkg/vere/serf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index 7cc26d2ae9..4ac99db7de 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -194,6 +194,9 @@ void u3_serf_post(u3_serf* sef_u) { if ( sef_u->fag_w & _serf_fag_hit1 ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("serf: threshold 1: %u", u3h_wyt(u3R->cax.per_p)); + } u3h_trim_to(u3R->cax.per_p, u3h_wyt(u3R->cax.per_p) / 2); u3m_reclaim(); } @@ -216,6 +219,9 @@ u3_serf_post(u3_serf* sef_u) } if ( sef_u->fag_w & _serf_fag_hit0 ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("serf: threshold 0: per_p %u", u3h_wyt(u3R->cax.per_p)); + } u3h_free(u3R->cax.per_p); u3R->cax.per_p = u3h_new_cache(u3C.per_w); u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); From efe106650e8da7504b3aa3188875e9c7e06b2826 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 9 Nov 2023 15:42:34 -0500 Subject: [PATCH 16/17] u3: moves u3a_ream (free-list adjustment) into v3 migration --- pkg/noun/manage.c | 4 ---- pkg/noun/v3/allocate.h | 1 + pkg/noun/v3/manage.c | 3 +++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index fde676b463..2de555d58c 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -652,10 +652,6 @@ _find_home(void) } } - // XX move me - // - u3a_ream(); - /* As a further guard against any sneaky loom corruption */ u3a_loom_sane(); diff --git a/pkg/noun/v3/allocate.h b/pkg/noun/v3/allocate.h index bacc79e174..83db4a51b9 100644 --- a/pkg/noun/v3/allocate.h +++ b/pkg/noun/v3/allocate.h @@ -11,6 +11,7 @@ # define u3R_v3 u3a_Road # define u3a_v3_balign u3a_balign # define u3a_v3_road u3a_road +# define u3a_v3_ream u3a_ream # define u3a_v3_walign u3a_walign # define u3a_v3_walloc u3a_walloc diff --git a/pkg/noun/v3/manage.c b/pkg/noun/v3/manage.c index a15d5ad9be..9eb8a96cdb 100644 --- a/pkg/noun/v3/manage.c +++ b/pkg/noun/v3/manage.c @@ -100,6 +100,9 @@ u3m_v3_migrate() u3R_v3 = &u3H_v3->rod_u; u3H_v3->ver_w = U3V_VER3; + // recalculate free lists + u3a_v3_ream(); + // initialize persistent cache u3R_v3->cax.per_p = u3h_v3_new_cache(u3C.per_w); From 9ca215db08d801d3d57aac06f988185e29ded265 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 10 Nov 2023 11:32:04 -0500 Subject: [PATCH 17/17] serf: switch vega post-op to only trim half of persistent cache --- pkg/vere/serf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/vere/serf.c b/pkg/vere/serf.c index 4ac99db7de..cec8bece55 100644 --- a/pkg/vere/serf.c +++ b/pkg/vere/serf.c @@ -206,8 +206,7 @@ u3_serf_post(u3_serf* sef_u) } if ( sef_u->fag_w & _serf_fag_vega ) { - u3h_free(u3R->cax.per_p); - u3R->cax.per_p = u3h_new_cache(u3C.per_w); + u3h_trim_to(u3R->cax.per_p, u3h_wyt(u3R->cax.per_p) / 2); u3m_reclaim(); }